Merge branch 'master' of ssh://free-cad.git.sourceforge.net/gitroot/free-cad/free-cad

This commit is contained in:
Jose Luis Cercos Pita 2012-11-25 12:18:50 +01:00
commit 271308e56c
18 changed files with 707 additions and 161 deletions

View File

@ -1378,6 +1378,11 @@ void View3DInventorViewer::viewAll()
group->mode = SoSkipBoundingGroup::EXCLUDE_BBOX;
}
// Set the height angle to 45 deg
SoCamera* cam = this->getCamera();
if (cam && cam->getTypeId().isDerivedFrom(SoPerspectiveCamera::getClassTypeId()))
static_cast<SoPerspectiveCamera*>(cam)->heightAngle = (float)(M_PI / 4.0);
// call the default implementation first to make sure everything is visible
SoQtViewer::viewAll();

View File

@ -2781,8 +2781,11 @@ class _Shape2DView(_DraftObject):
"The way the viewed object must be projected")
obj.addProperty("App::PropertyIntegerList","FaceNumbers","Base",
"The indices of the faces to be projected in Individual Faces mode")
obj.addProperty("App::PropertyBool","HiddenLines","Base",
"Show hidden lines")
obj.Projection = Vector(0,0,1)
obj.ProjectionMode = ["Solid","Individual Faces","Cutlines"]
obj.HiddenLines = False
_DraftObject.__init__(self,obj,"Shape2DView")
def execute(self,obj):
@ -2793,19 +2796,58 @@ class _Shape2DView(_DraftObject):
self.createGeometry(obj)
def clean(self,shape):
"returns a valid compound of edges"
import Part
"returns a valid compound of edges, by recreating them"
# this is because the projection algorithm somehow creates wrong shapes.
# they dispay fine, but on loading the file the shape is invalid
import Part,DraftGeomUtils
oldedges = shape.Edges
newedges = []
for e in oldedges:
try:
newedges.append(e.Curve.toShape())
if isinstance(e.Curve,Part.Line):
newedges.append(e.Curve.toShape())
elif isinstance(e.Curve,Part.Circle):
if len(e.Vertexes) > 1:
mp = DraftGeomUtils.findMidpoint(e)
a = Part.Arc(e.Vertexes[0].Point,mp,e.Vertexes[-1].Point).toShape()
newedges.append(a)
else:
newedges.append(e.Curve.toShape())
elif isinstance(e.Curve,Part.Ellipse):
if len(e.Vertexes) > 1:
a = Part.Arc(e.Curve,e.FirstParameter,e.LastParameter).toShape()
newedges.append(a)
else:
newedges.append(e.Curve.toShape())
elif isinstance(e.Curve,Part.BSplineCurve):
if DraftGeomUtils.isLine(e.Curve):
l = Part.Line(e.Vertexes[0].Point,e.Vertexes[-1].Point).toShape()
newedges.append(l)
else:
newedges.append(e.Curve.toShape())
else:
newedges.append(e)
except:
print "Debug: error cleaning edge ",e
return Part.makeCompound(newedges)
def getProjected(self,obj,shape,direction):
"returns projected edges from a shape and a direction"
import Part,Drawing
edges = []
groups = Drawing.projectEx(shape,direction)
for g in groups[0:5]:
if g:
edges.append(g)
if hasattr(obj,"HiddenLines"):
if obj.HiddenLines:
for g in groups[5:]:
edges.append(g)
#return Part.makeCompound(edges)
return self.clean(Part.makeCompound(edges))
def createGeometry(self,obj):
import Drawing, DraftGeomUtils
import DraftGeomUtils
pl = obj.Placement
if obj.Base:
if getType(obj.Base) == "SectionPlane":
@ -2828,9 +2870,7 @@ class _Shape2DView(_DraftObject):
comp = Part.makeCompound(cuts)
opl = FreeCAD.Placement(obj.Base.Placement)
proj = opl.Rotation.multVec(FreeCAD.Vector(0,0,1))
[visibleG0,visibleG1,hiddenG0,hiddenG1] = Drawing.project(comp,proj)
if visibleG0:
obj.Shape = self.clean(visibleG0)
obj.Shape = self.getProjected(obj,comp,proj)
elif obj.ProjectionMode == "Cutlines":
for sh in shapes:
if sh.Volume < 0:
@ -2846,9 +2886,7 @@ class _Shape2DView(_DraftObject):
elif obj.Base.isDerivedFrom("Part::Feature"):
if not DraftVecUtils.isNull(obj.Projection):
if obj.ProjectionMode == "Solid":
[visibleG0,visibleG1,hiddenG0,hiddenG1] = Drawing.project(obj.Base.Shape,obj.Projection)
if visibleG0:
obj.Shape = self.clean(visibleG0)
obj.Shape = self.getProjected(obj,obj.Base.Shape,obj.Projection)
elif obj.ProjectionMode == "Individual Faces":
import Part
if obj.FaceNumbers:
@ -2858,9 +2896,7 @@ class _Shape2DView(_DraftObject):
faces.append(obj.Base.Shape.Faces[i])
views = []
for f in faces:
[visibleG0,visibleG1,hiddenG0,hiddenG1] = Drawing.project(f,obj.Projection)
if visibleG0:
views.append(visibleG0)
views.append(self.getProjected(obj,f,obj.Projection))
if views:
obj.Shape = Part.makeCompound(views)
if not DraftGeomUtils.isNull(pl):
@ -3076,6 +3112,6 @@ class _ViewProviderClone(_ViewProviderDraftAlt):
def getIcon(self):
return ":/icons/Draft_Clone.svg"
if not hasattr(FreeCADGui,"Snapper"):
import DraftSnap
if gui:
if not hasattr(FreeCADGui,"Snapper"):
import DraftSnap

View File

@ -642,11 +642,13 @@ class BSpline(Line):
def finish(self,closed=False,cont=False):
"terminates the operation and closes the poly if asked"
if self.ui:
self.bsplinetrack.finalize()
if not Draft.getParam("UiMode"):
FreeCADGui.Control.closeDialog()
if (len(self.node) > 1):
old = self.obj.Name
self.doc.removeObject(old)
todo.delay(self.doc.removeObject,old)
try:
# building command string
rot,sup,pts,fil = self.getStrings()
@ -656,8 +658,6 @@ class BSpline(Line):
'Draft.makeBSpline(points,closed='+str(closed)+',face='+fil+',support='+sup+')'])
except:
print "Draft: error delaying commit"
if self.ui:
self.bsplinetrack.finalize()
Creator.finish(self)
if self.ui:
if self.ui.continueMode:
@ -1381,6 +1381,7 @@ class Dimension(Creator):
self.arcmode = False
self.point2 = None
self.force = None
self.info = None
msg(translate("draft", "Pick first point:\n"))
FreeCADGui.draftToolBar.show()
@ -1451,9 +1452,9 @@ class Dimension(Creator):
self.finish()
elif arg["Type"] == "SoLocation2Event": #mouse movement detection
shift = hasMod(arg,MODCONSTRAIN)
self.point,ctrlPoint,self.info = getPoint(self,arg)
if self.arcmode or self.point2:
setMod(arg,MODCONSTRAIN,False)
self.point,ctrlPoint,info = getPoint(self,arg)
if hasMod(arg,MODALT) and (len(self.node)<3):
self.dimtrack.off()
if not self.altdown:
@ -1534,11 +1535,11 @@ class Dimension(Creator):
if (not self.node) and (not self.support):
self.support = getSupport(arg)
if hasMod(arg,MODALT) and (len(self.node)<3):
print "snapped: ",info
if info:
ob = self.doc.getObject(info['Object'])
if 'Edge' in info['Component']:
num = int(info['Component'].lstrip('Edge'))-1
print "snapped: ",self.info
if self.info:
ob = self.doc.getObject(self.info['Object'])
if 'Edge' in self.info['Component']:
num = int(self.info['Component'].lstrip('Edge'))-1
ed = ob.Shape.Edges[num]
v1 = ed.Vertexes[0].Point
v2 = ed.Vertexes[-1].Point

View File

@ -235,7 +235,9 @@ class dimTracker(Tracker):
self.p1 = self.p2 = self.p3 = None
def update(self,pts):
if len(pts) == 1:
if not pts:
return
elif len(pts) == 1:
self.p3 = pts[0]
else:
self.p1 = pts[0]

View File

@ -158,20 +158,28 @@ PyObject *PropertyPartShape::getPyObject(void)
{
case TopAbs_COMPOUND:
prop = new TopoShapeCompoundPy(new TopoShape(sh));
break;
case TopAbs_COMPSOLID:
prop = new TopoShapeCompSolidPy(new TopoShape(sh));
break;
case TopAbs_SOLID:
prop = new TopoShapeSolidPy(new TopoShape(sh));
break;
case TopAbs_SHELL:
prop = new TopoShapeShellPy(new TopoShape(sh));
break;
case TopAbs_FACE:
prop = new TopoShapeFacePy(new TopoShape(sh));
break;
case TopAbs_WIRE:
prop = new TopoShapeWirePy(new TopoShape(sh));
break;
case TopAbs_EDGE:
prop = new TopoShapeEdgePy(new TopoShape(sh));
break;
case TopAbs_VERTEX:
prop = new TopoShapeVertexPy(new TopoShape(sh));
break;
case TopAbs_SHAPE:
default:
prop = new TopoShapePy(new TopoShape(sh));

View File

@ -1690,21 +1690,107 @@ TopoDS_Shape TopoShape::revolve(const gp_Ax1& axis, double d) const
return mkRevol.Shape();
}
TopoDS_Shape TopoShape::makeThickSolid(const TopTools_ListOfShape& remFace,
Standard_Real offset, Standard_Real tolerance) const
{
BRepOffsetAPI_MakeThickSolid mkThick(this->_Shape, remFace, offset, tolerance);
return mkThick.Shape();
}
//#include <BRepFill.hxx>
//#include <BRepTools_Quilt.hxx>
TopoDS_Shape TopoShape::makeOffset(double offset, double tol, bool intersection,
bool selfInter, short offsetMode, short join)
TopoDS_Shape TopoShape::makeOffsetShape(double offset, double tol, bool intersection,
bool selfInter, short offsetMode, short join,
bool fill) const
{
BRepOffsetAPI_MakeOffsetShape mkOffset(this->_Shape, offset, tol, BRepOffset_Mode(offsetMode),
intersection ? Standard_True : Standard_False,
selfInter ? Standard_True : Standard_False,
GeomAbs_JoinType(join));
return mkOffset.Shape();
const TopoDS_Shape& res = mkOffset.Shape();
if (!fill)
return res;
#if 1
//s=Part.makePlane(10,10)
//s.makeOffsetShape(1.0,0.01,False,False,0,0,True)
const BRepOffset_MakeOffset& off = mkOffset.MakeOffset();
const BRepAlgo_Image& img = off.OffsetEdgesFromShapes();
// build up map edge->face
TopTools_IndexedDataMapOfShapeListOfShape edge2Face;
TopExp::MapShapesAndAncestors(this->_Shape, TopAbs_EDGE, TopAbs_FACE, edge2Face);
TopTools_IndexedMapOfShape mapOfShape;
TopExp::MapShapes(this->_Shape, TopAbs_EDGE, mapOfShape);
TopoDS_Shell shell;
BRep_Builder builder;
TopExp_Explorer xp;
builder.MakeShell(shell);
for (xp.Init(this->_Shape,TopAbs_FACE); xp.More(); xp.Next()) {
builder.Add(shell, xp.Current());
}
for (int i=1; i<= edge2Face.Extent(); ++i) {
const TopTools_ListOfShape& los = edge2Face.FindFromIndex(i);
if (los.Extent() == 1) {
// set the index value as user data to use it in accept()
const TopoDS_Shape& edge = edge2Face.FindKey(i);
Standard_Boolean ok = img.HasImage(edge);
if (ok) {
const TopTools_ListOfShape& edges = img.Image(edge);
TopTools_ListIteratorOfListOfShape it;
it.Initialize(edges);
BRepOffsetAPI_ThruSections aGenerator (0,0);
aGenerator.AddWire(BRepBuilderAPI_MakeWire(TopoDS::Edge(edge)).Wire());
aGenerator.AddWire(BRepBuilderAPI_MakeWire(TopoDS::Edge(it.Value())).Wire());
aGenerator.Build();
for (xp.Init(aGenerator.Shape(),TopAbs_FACE); xp.More(); xp.Next()) {
builder.Add(shell, xp.Current());
}
//TopoDS_Face face = BRepFill::Face(TopoDS::Edge(edge), TopoDS::Edge(it.Value()));
//builder.Add(shell, face);
}
}
}
for (xp.Init(mkOffset.Shape(),TopAbs_FACE); xp.More(); xp.Next()) {
builder.Add(shell, xp.Current());
}
//BRepBuilderAPI_Sewing sew(offset);
//sew.Load(this->_Shape);
//sew.Add(mkOffset.Shape());
//sew.Perform();
//shell.Closed(Standard_True);
return shell;
#else
TopoDS_Solid Res;
TopExp_Explorer exp;
BRep_Builder B;
B.MakeSolid(Res);
BRepTools_Quilt Glue;
for (exp.Init(this->_Shape,TopAbs_FACE); exp.More(); exp.Next()) {
Glue.Add (exp.Current());
}
for (exp.Init(mkOffset.Shape(),TopAbs_FACE);exp.More(); exp.Next()) {
Glue.Add (exp.Current().Reversed());
}
TopoDS_Shape S = Glue.Shells();
for (exp.Init(S,TopAbs_SHELL); exp.More(); exp.Next()) {
B.Add(Res,exp.Current());
}
Res.Closed(Standard_True);
return Res;
#endif
}
TopoDS_Shape TopoShape::makeThickSolid(const TopTools_ListOfShape& remFace,
double offset, double tol, bool intersection,
bool selfInter, short offsetMode, short join) const
{
BRepOffsetAPI_MakeThickSolid mkThick(this->_Shape, remFace, offset, tol, BRepOffset_Mode(offsetMode),
intersection ? Standard_True : Standard_False,
selfInter ? Standard_True : Standard_False,
GeomAbs_JoinType(join));
return mkThick.Shape();
}
void TopoShape::transformGeometry(const Base::Matrix4D &rclMat)

View File

@ -158,8 +158,6 @@ public:
const Standard_Boolean isFrenet = Standard_False) const;
TopoDS_Shape makePrism(const gp_Vec&) const;
TopoDS_Shape revolve(const gp_Ax1&, double d) const;
TopoDS_Shape makeThickSolid(const TopTools_ListOfShape& remFace,
Standard_Real offset, Standard_Real tolerance) const;
TopoDS_Shape makeSweep(const TopoDS_Shape& profile, double, int) const;
TopoDS_Shape makeTube(double radius, double tol, int cont, int maxdeg, int maxsegm) const;
TopoDS_Shape makeHelix(Standard_Real pitch, Standard_Real height,
@ -168,9 +166,13 @@ public:
Standard_Real height, Standard_Real radius) const;
TopoDS_Shape makeLoft(const TopTools_ListOfShape& profiles, Standard_Boolean isSolid,
Standard_Boolean isRuled) const;
TopoDS_Shape makeOffset(double offset, double tol,
TopoDS_Shape makeOffsetShape(double offset, double tol,
bool intersection = false, bool selfInter = false,
short offsetMode = 0, short join = 0);
short offsetMode = 0, short join = 0, bool fill = false) const;
TopoDS_Shape makeThickSolid(const TopTools_ListOfShape& remFace,
double offset, double tol,
bool intersection = false, bool selfInter = false,
short offsetMode = 0, short join = 0) const;
//@}
/** @name Manipulation*/

View File

@ -189,7 +189,7 @@ the underlying geometry.</UserDocu>
</Methode>
<Methode Name="makeThickness" Const="true">
<Documentation>
<UserDocu>makeThickness(List of shapes, Ofset (Float), Tolerance (Float)) -> Shape
<UserDocu>makeThickness(List of shapes, Offset (Float), Tolerance (Float)) -> Shape
A hollowed solid is built from an initial solid and a set of faces on this solid,
which are to be removed. The remaining faces of the solid become the walls of
the hollowed solid, their thickness defined at the time of construction.</UserDocu>

View File

@ -1024,7 +1024,15 @@ PyObject* TopoShapePy::makeThickness(PyObject *args)
{
PyObject *obj;
double offset, tolerance;
if (!PyArg_ParseTuple(args, "O!dd", &(PyList_Type), &obj, &offset, &tolerance))
PyObject* inter = Py_False;
PyObject* self_inter = Py_False;
short offsetMode = 0, join = 0;
if (!PyArg_ParseTuple(args, "O!dd|O!O!hh",
&(PyList_Type), &obj,
&offset, &tolerance,
&(PyBool_Type), &inter,
&(PyBool_Type), &self_inter,
&offsetMode, &join))
return 0;
try {
@ -1037,7 +1045,8 @@ PyObject* TopoShapePy::makeThickness(PyObject *args)
}
}
TopoDS_Shape shape = this->getTopoShapePtr()->makeThickSolid(facesToRemove, offset, tolerance);
TopoDS_Shape shape = this->getTopoShapePtr()->makeThickSolid(facesToRemove, offset, tolerance,
(inter == Py_True), (self_inter == Py_True), offsetMode, join);
return new TopoShapeSolidPy(new TopoShape(shape));
}
catch (Standard_Failure) {
@ -1052,17 +1061,19 @@ PyObject* TopoShapePy::makeOffsetShape(PyObject *args)
double offset, tolerance;
PyObject* inter = Py_False;
PyObject* self_inter = Py_False;
PyObject* fill = Py_False;
short offsetMode = 0, join = 0;
if (!PyArg_ParseTuple(args, "dd|O!O!hh",
if (!PyArg_ParseTuple(args, "dd|O!O!hhO!",
&offset, &tolerance,
&(PyBool_Type), &inter,
&(PyBool_Type), &self_inter,
&offsetMode, &join))
&offsetMode, &join,
&(PyBool_Type), &fill))
return 0;
try {
TopoDS_Shape shape = this->getTopoShapePtr()->makeOffset(offset, tolerance,
(inter == Py_True), (self_inter == Py_True), offsetMode, join);
TopoDS_Shape shape = this->getTopoShapePtr()->makeOffsetShape(offset, tolerance,
(inter == Py_True), (self_inter == Py_True), offsetMode, join, (fill == Py_True));
return new TopoShapePy(new TopoShape(shape));
}
catch (Standard_Failure) {

View File

@ -41,6 +41,7 @@ set(PartGui_MOC_HDRS
TaskFaceColors.h
TaskShapeBuilder.h
TaskLoft.h
TaskOffset.h
TaskSweep.h
TaskCheckGeometry.h
)
@ -67,6 +68,7 @@ set(PartGui_UIC_SRCS
TaskFaceColors.ui
TaskShapeBuilder.ui
TaskLoft.ui
TaskOffset.ui
TaskSweep.ui
)
qt4_wrap_ui(PartGui_UIC_HDRS ${PartGui_UIC_SRCS})
@ -158,6 +160,9 @@ SET(PartGui_SRCS
TaskLoft.cpp
TaskLoft.h
TaskLoft.ui
TaskOffset.cpp
TaskOffset.h
TaskOffset.ui
TaskSweep.cpp
TaskSweep.h
TaskSweep.ui

View File

@ -62,6 +62,7 @@
#include "TaskShapeBuilder.h"
#include "TaskLoft.h"
#include "TaskSweep.h"
#include "TaskOffset.h"
#include "TaskCheckGeometry.h"
@ -990,6 +991,34 @@ bool CmdPartSweep::isActive(void)
//--------------------------------------------------------------------------------------
DEF_STD_CMD_A(CmdPartOffset);
CmdPartOffset::CmdPartOffset()
: Command("Part_Offset")
{
sAppModule = "Part";
sGroup = QT_TR_NOOP("Part");
sMenuText = QT_TR_NOOP("Offset...");
sToolTipText = QT_TR_NOOP("Utility to offset");
sWhatsThis = sToolTipText;
sStatusTip = sToolTipText;
sPixmap = "Part_Offset";
}
void CmdPartOffset::activated(int iMsg)
{
Gui::Control().showDialog(new PartGui::TaskOffset());
}
bool CmdPartOffset::isActive(void)
{
Base::Type partid = Base::Type::fromName("Part::Feature");
bool objectsSelected = Gui::Selection().countObjectsOfType(partid) == 1;
return (objectsSelected && !Gui::Control().activeDialog());
}
//--------------------------------------------------------------------------------------
DEF_STD_CMD_A(CmdShapeInfo);
CmdShapeInfo::CmdShapeInfo()
@ -1260,5 +1289,6 @@ void CreatePartCommands(void)
rcCmdMgr.addCommand(new CmdPartBuilder());
rcCmdMgr.addCommand(new CmdPartLoft());
rcCmdMgr.addCommand(new CmdPartSweep());
rcCmdMgr.addCommand(new CmdPartOffset());
rcCmdMgr.addCommand(new CmdCheckGeometry());
}

View File

@ -0,0 +1,133 @@
/***************************************************************************
* Copyright (c) 2012 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
# include <QMessageBox>
# include <QTextStream>
#endif
#include "ui_TaskOffset.h"
#include "TaskOffset.h"
#include <Gui/Application.h>
#include <Gui/BitmapFactory.h>
#include <Gui/Document.h>
#include <Gui/Selection.h>
#include <Gui/SelectionFilter.h>
#include <Gui/ViewProvider.h>
#include <Base/Console.h>
#include <Base/Interpreter.h>
#include <App/Application.h>
#include <App/Document.h>
#include <App/DocumentObject.h>
#include <Mod/Part/App/PartFeature.h>
using namespace PartGui;
class OffsetWidget::Private
{
public:
Ui_TaskOffset ui;
std::string document;
Private()
{
}
~Private()
{
}
};
/* TRANSLATOR PartGui::OffsetWidget */
OffsetWidget::OffsetWidget(QWidget* parent)
: d(new Private())
{
Gui::Application::Instance->runPythonCode("from FreeCAD import Base");
Gui::Application::Instance->runPythonCode("import Part");
d->ui.setupUi(this);
}
OffsetWidget::~OffsetWidget()
{
delete d;
}
bool OffsetWidget::accept()
{
return true;
}
bool OffsetWidget::reject()
{
return true;
}
void OffsetWidget::changeEvent(QEvent *e)
{
QWidget::changeEvent(e);
if (e->type() == QEvent::LanguageChange) {
d->ui.retranslateUi(this);
}
}
/* TRANSLATOR PartGui::TaskOffset */
TaskOffset::TaskOffset()
{
widget = new OffsetWidget();
taskbox = new Gui::TaskView::TaskBox(
Gui::BitmapFactory().pixmap("Part_Offset"),
widget->windowTitle(), true, 0);
taskbox->groupLayout()->addWidget(widget);
Content.push_back(taskbox);
}
TaskOffset::~TaskOffset()
{
}
void TaskOffset::open()
{
}
void TaskOffset::clicked(int)
{
}
bool TaskOffset::accept()
{
return widget->accept();
}
bool TaskOffset::reject()
{
return widget->reject();
}
#include "moc_TaskOffset.cpp"

View File

@ -0,0 +1,75 @@
/***************************************************************************
* Copyright (c) 2012 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef PARTGUI_TASKOFFSET_H
#define PARTGUI_TASKOFFSET_H
#include <Gui/TaskView/TaskView.h>
#include <Gui/TaskView/TaskDialog.h>
namespace PartGui {
class OffsetWidget : public QWidget
{
Q_OBJECT
public:
OffsetWidget(QWidget* parent = 0);
~OffsetWidget();
bool accept();
bool reject();
private:
void changeEvent(QEvent *e);
private:
class Private;
Private* d;
};
class TaskOffset : public Gui::TaskView::TaskDialog
{
Q_OBJECT
public:
TaskOffset();
~TaskOffset();
public:
void open();
bool accept();
bool reject();
void clicked(int);
QDialogButtonBox::StandardButtons getStandardButtons() const
{ return QDialogButtonBox::Ok|QDialogButtonBox::Cancel; }
private:
OffsetWidget* widget;
Gui::TaskView::TaskBox* taskbox;
};
} //namespace PartGui
#endif // PARTGUI_TASKOFFSET_H

View File

@ -0,0 +1,115 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PartGui::TaskOffset</class>
<widget class="QWidget" name="PartGui::TaskOffset">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>256</width>
<height>217</height>
</rect>
</property>
<property name="windowTitle">
<string>Offset</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="labelOffset">
<property name="text">
<string>Offset</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="spinOffset"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Tolerance</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="spinTolerance"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Mode</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="comboBox">
<item>
<property name="text">
<string>Skin</string>
</property>
</item>
<item>
<property name="text">
<string>Pipe</string>
</property>
</item>
<item>
<property name="text">
<string>RectoVerso</string>
</property>
</item>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Join type</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="comboBox_2">
<item>
<property name="text">
<string>Arc</string>
</property>
</item>
<item>
<property name="text">
<string>Tangent</string>
</property>
</item>
<item>
<property name="text">
<string>Intersection</string>
</property>
</item>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QCheckBox" name="checkBox">
<property name="text">
<string>Intersection</string>
</property>
</widget>
</item>
<item row="5" column="0" colspan="2">
<widget class="QCheckBox" name="checkBox_2">
<property name="text">
<string>Self-intersection</string>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>spinOffset</tabstop>
<tabstop>spinTolerance</tabstop>
<tabstop>comboBox</tabstop>
<tabstop>comboBox_2</tabstop>
<tabstop>checkBox</tabstop>
<tabstop>checkBox_2</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View File

@ -72,7 +72,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const
<< "Part_SimpleCopy" << "Part_RefineShape" << "Part_CheckGeometry" << "Separator"
<< "Part_Boolean" << "Part_CrossSections" << "Part_Extrude"
<< "Part_Revolve" << "Part_Mirror" << "Part_Fillet" << "Part_Chamfer"
<< "Part_RuledSurface" << "Part_Loft" << "Part_Sweep";
<< "Part_RuledSurface" << "Part_Loft" << "Part_Sweep" << "Part_Offset";
return root;
}

View File

@ -27,11 +27,8 @@ import math
from PyQt4 import QtGui,QtCore
# FreeCAD modules
import FreeCAD,FreeCADGui
from FreeCAD import Base, Vector
import Part, Image, ImageGui
# FreeCADShip modules
from shipUtils import Paths
import Tools
header = """ #################################################################
@ -47,32 +44,13 @@ header = """ #################################################################
"""
class Plot(object):
def __init__(self, ship, trim, drafts):
def __init__(self, ship, trim, points):
""" Constructor. performs plot and show it (Using pyxplot).
@param ship Selected ship instance
@param trim Trim in degrees.
@param drafts List of drafts to be performed.
@param points List of computed hydrostatics.
"""
# Compute data
# Get external faces
faces = self.externalFaces(ship.Shape)
if len(faces) == 0:
msg = QtGui.QApplication.translate("ship_console", "Can't detect external faces from ship object",
None,QtGui.QApplication.UnicodeUTF8)
FreeCAD.Console.PrintError(msg + '\n')
return
else:
faces = Part.makeShell(faces)
# Print data
msg = QtGui.QApplication.translate("ship_console", "Computing hydrostatics",
None,QtGui.QApplication.UnicodeUTF8)
FreeCAD.Console.PrintMessage(msg + '...\n')
self.points = []
for i in range(0,len(drafts)):
FreeCAD.Console.PrintMessage("\t%d / %d\n" % (i+1, len(drafts)))
draft = drafts[i]
point = Tools.Point(ship,faces,draft,trim)
self.points.append(point)
self.points = points[:]
# Try to plot
self.plotVolume()
self.plotStability()
@ -80,7 +58,7 @@ class Plot(object):
# Save data
if self.createDirectory():
return
if self.saveData(ship, trim, drafts):
if self.saveData(ship, trim):
return
def plotVolume(self):
@ -345,11 +323,10 @@ class Plot(object):
FreeCAD.Console.PrintError(msg + ':\n\t' + "\'"+ self.path + "\'\n")
return False
def saveData(self, ship, trim, drafts):
def saveData(self, ship, trim):
""" Write data file.
@param ship Selected ship instance
@param trim Trim in degrees.
@param drafts List of drafts to be performed.
@return True if error happens.
"""
# Open the file
@ -380,7 +357,7 @@ class Plot(object):
Output.write(" #\n")
Output.write(" #################################################################\n")
# Print data
for i in range(0,len(drafts)):
for i in range(0,len(self.points)):
point = self.points[i]
string = "%f %f %f %f %f %f %f %f %f %f %f\n" % (point.disp, point.draft, point.wet, point.mom, point.xcb, point.farea, point.KBt, point.BMt, point.Cb, point.Cf, point.Cm)
Output.write(string)
@ -392,87 +369,3 @@ class Plot(object):
FreeCAD.Console.PrintMessage(msg + ':\n\t' + "\'"+ self.dataFile + "\'\n")
return False
def lineFaceSection(self,line,surface):
""" Returns the point of section of a line with a face
@param line Line object, that can be a curve.
@param surface Surface object (must be a Part::Shape)
@return Section points array, [] if line don't cut surface
"""
# Get initial data
result = []
vertexes = line.Vertexes
nVertex = len(vertexes)
# Perform the cut
section = line.cut(surface)
# Filter all old points
points = section.Vertexes
return points
def externalFaces(self, shape):
""" Returns detected external faces.
@param shape Shape where external faces wanted.
@return List of external faces detected.
"""
result = []
faces = shape.Faces
bbox = shape.BoundBox
L = bbox.XMax - bbox.XMin
B = bbox.YMax - bbox.YMin
T = bbox.ZMax - bbox.ZMin
dist = math.sqrt(L*L + B*B + T*T)
msg = QtGui.QApplication.translate("ship_console", "Computing external faces",
None,QtGui.QApplication.UnicodeUTF8)
FreeCAD.Console.PrintMessage(msg + '...\n')
# Valid/unvalid faces detection loop
for i in range(0,len(faces)):
FreeCAD.Console.PrintMessage("\t%d / %d\n" % (i+1, len(faces)))
f = faces[i]
# Create a line normal to surface at middle point
u = 0.0
v = 0.0
try:
surf = f.Surface
u = 0.5*(surf.getUKnots()[0]+surf.getUKnots()[-1])
v = 0.5*(surf.getVKnots()[0]+surf.getVKnots()[-1])
except:
cog = f.CenterOfMass
[u,v] = f.Surface.parameter(cog)
p0 = f.valueAt(u,v)
try:
n = f.normalAt(u,v).normalize()
except:
continue
p1 = p0 + n.multiply(1.5*dist)
line = Part.makeLine(p0, p1)
# Look for faces in front of this
nPoints = 0
for j in range(0,len(faces)):
f2 = faces[j]
section = self.lineFaceSection(line, f2)
if len(section) <= 2:
continue
# Add points discarding start and end
nPoints = nPoints + len(section) - 2
# In order to avoid special directions we can modify line
# normal a little bit.
angle = 5
line.rotate(p0,Vector(1,0,0),angle)
line.rotate(p0,Vector(0,1,0),angle)
line.rotate(p0,Vector(0,0,1),angle)
nPoints2 = 0
for j in range(0,len(faces)):
if i == j:
continue
f2 = faces[j]
section = self.lineFaceSection(line, f2)
if len(section) <= 2:
continue
# Add points discarding start and end
nPoints2 = nPoints + len(section) - 2
# If the number of intersection points is pair, is a
# external face. So if we found an odd points intersection,
# face must be discarded.
if (nPoints % 2) or (nPoints2 % 2):
continue
result.append(f)
return result

View File

@ -25,6 +25,8 @@ import math
# FreeCAD modules
import FreeCAD as App
import FreeCADGui as Gui
from FreeCAD import Base, Vector
import Part
# Qt library
from PyQt4 import QtGui,QtCore
# Module
@ -37,10 +39,13 @@ class TaskPanel:
def __init__(self):
self.ui = Paths.modulePath() + "/shipHydrostatics/TaskPanel.ui"
self.ship = None
self.running = False
def accept(self):
if not self.ship:
return False
if self.running:
return
self.save()
draft = self.form.minDraft.value()
drafts = [draft]
@ -48,10 +53,45 @@ class TaskPanel:
for i in range(1,self.form.nDraft.value()):
draft = draft + dDraft
drafts.append(draft)
PlotAux.Plot(self.ship, self.form.trim.value(), drafts)
# Compute data
# Get external faces
self.loop=QtCore.QEventLoop()
self.timer=QtCore.QTimer()
self.timer.setSingleShot(True)
QtCore.QObject.connect(self.timer,QtCore.SIGNAL("timeout()"),self.loop,QtCore.SLOT("quit()"))
self.running = True
faces = self.externalFaces(self.ship.Shape)
if not self.running:
return False
if len(faces) == 0:
msg = QtGui.QApplication.translate("ship_console", "Can't detect external faces from ship object",
None,QtGui.QApplication.UnicodeUTF8)
App.Console.PrintError(msg + '\n')
return False
faces = Part.makeShell(faces)
# Get hydrostatics
msg = QtGui.QApplication.translate("ship_console", "Computing hydrostatics",
None,QtGui.QApplication.UnicodeUTF8)
App.Console.PrintMessage(msg + '...\n')
points = []
for i in range(0,len(drafts)):
App.Console.PrintMessage("\t%d / %d\n" % (i+1, len(drafts)))
draft = drafts[i]
point = Tools.Point(self.ship,faces,draft,self.form.trim.value())
points.append(point)
self.timer.start(0.0)
self.loop.exec_()
if(not self.running):
break
PlotAux.Plot(self.ship, self.form.trim.value(), points)
return True
def reject(self):
if not self.ship:
return False
if self.running:
self.running = False
return
return True
def clicked(self, index):
@ -235,6 +275,95 @@ class TaskPanel:
self.ship.addProperty("App::PropertyInteger","HydrostaticsNDraft","Ship", tooltip)
self.ship.HydrostaticsNDraft = self.form.nDraft.value()
def lineFaceSection(self,line,surface):
""" Returns the point of section of a line with a face
@param line Line object, that can be a curve.
@param surface Surface object (must be a Part::Shape)
@return Section points array, [] if line don't cut surface
"""
# Get initial data
result = []
vertexes = line.Vertexes
nVertex = len(vertexes)
# Perform the cut
section = line.cut(surface)
# Filter all old points
points = section.Vertexes
return points
def externalFaces(self, shape):
""" Returns detected external faces.
@param shape Shape where external faces wanted.
@return List of external faces detected.
"""
result = []
faces = shape.Faces
bbox = shape.BoundBox
L = bbox.XMax - bbox.XMin
B = bbox.YMax - bbox.YMin
T = bbox.ZMax - bbox.ZMin
dist = math.sqrt(L*L + B*B + T*T)
msg = QtGui.QApplication.translate("ship_console", "Computing external faces",
None,QtGui.QApplication.UnicodeUTF8)
App.Console.PrintMessage(msg + '...\n')
# Valid/unvalid faces detection loop
for i in range(0,len(faces)):
App.Console.PrintMessage("\t%d / %d\n" % (i+1, len(faces)))
f = faces[i]
# Create a line normal to surface at middle point
u = 0.0
v = 0.0
try:
surf = f.Surface
u = 0.5*(surf.getUKnots()[0]+surf.getUKnots()[-1])
v = 0.5*(surf.getVKnots()[0]+surf.getVKnots()[-1])
except:
cog = f.CenterOfMass
[u,v] = f.Surface.parameter(cog)
p0 = f.valueAt(u,v)
try:
n = f.normalAt(u,v).normalize()
except:
continue
p1 = p0 + n.multiply(1.5*dist)
line = Part.makeLine(p0, p1)
# Look for faces in front of this
nPoints = 0
for j in range(0,len(faces)):
f2 = faces[j]
section = self.lineFaceSection(line, f2)
if len(section) <= 2:
continue
# Add points discarding start and end
nPoints = nPoints + len(section) - 2
# In order to avoid special directions we can modify line
# normal a little bit.
angle = 5
line.rotate(p0,Vector(1,0,0),angle)
line.rotate(p0,Vector(0,1,0),angle)
line.rotate(p0,Vector(0,0,1),angle)
nPoints2 = 0
for j in range(0,len(faces)):
if i == j:
continue
f2 = faces[j]
section = self.lineFaceSection(line, f2)
if len(section) <= 2:
continue
# Add points discarding start and end
nPoints2 = nPoints + len(section) - 2
# If the number of intersection points is pair, is a
# external face. So if we found an odd points intersection,
# face must be discarded.
if (nPoints % 2) or (nPoints2 % 2):
continue
result.append(f)
self.timer.start(0.0)
self.loop.exec_()
if(not self.running):
break
return result
def createTask():
panel = TaskPanel()
Gui.Control.showDialog(panel)

View File

@ -39,10 +39,13 @@ class TaskPanel:
self.ui = Paths.modulePath() + "/tankGZ/TaskPanel.ui"
self.ship = None
self.tanks = {}
self.running = False
def accept(self):
if not self.ship:
return False
if self.running:
return
# Get general data
disp = self.computeDisplacement()
draft = self.computeDraft(disp[0], self.form.trim.value())
@ -57,16 +60,28 @@ class TaskPanel:
msg = QtGui.QApplication.translate("ship_console","Computing GZ",
None,QtGui.QApplication.UnicodeUTF8)
App.Console.PrintMessage(msg + "...\n")
loop=QtCore.QEventLoop()
timer=QtCore.QTimer()
timer.setSingleShot(True)
QtCore.QObject.connect(timer,QtCore.SIGNAL("timeout()"),loop,QtCore.SLOT("quit()"))
self.running = True
for i in range(0, nRoll):
App.Console.PrintMessage("\t%d/%d\n" % (i+1,nRoll))
roll.append(i*dRoll)
GZ.append(self.computeGZ(draft[0], trim, roll[-1]))
timer.start(0.0)
loop.exec_()
if(not self.running):
break
PlotAux.Plot(roll, GZ, disp[0]/1000.0, draft[0], trim)
return True
def reject(self):
if not self.ship:
return False
if self.running:
self.running = False
return
return True
def clicked(self, index):