diff --git a/data/tests/PadTest.fcstd b/data/tests/PadTest.fcstd
new file mode 100644
index 000000000..8a7223083
Binary files /dev/null and b/data/tests/PadTest.fcstd differ
diff --git a/data/tests/PocketTest.fcstd b/data/tests/PocketTest.fcstd
new file mode 100644
index 000000000..6acf91ba0
Binary files /dev/null and b/data/tests/PocketTest.fcstd differ
diff --git a/src/App/PropertyStandard.h b/src/App/PropertyStandard.h
index bff973cb2..fc2989379 100644
--- a/src/App/PropertyStandard.h
+++ b/src/App/PropertyStandard.h
@@ -394,9 +394,6 @@ protected:
const Constraints* _ConstStruct;
};
-
-
-
class AppExport PropertyFloatList: public PropertyLists
{
TYPESYSTEM_HEADER();
@@ -470,10 +467,11 @@ public:
*/
virtual ~PropertyString();
-
void setValue(const char* sString);
void setValue(const std::string &sString);
const char* getValue(void) const;
+ const std::string& getStrValue(void) const
+ { return _cValue; }
bool isEmpty(void){return _cValue.empty();}
virtual const char* getEditorName(void) const { return "Gui::PropertyEditor::PropertyStringItem"; }
diff --git a/src/Base/UnitsApi.cpp b/src/Base/UnitsApi.cpp
index ceb773473..91b71eba8 100644
--- a/src/Base/UnitsApi.cpp
+++ b/src/Base/UnitsApi.cpp
@@ -85,6 +85,7 @@ UnitsSchema *UnitsApi::UserPrefSystem = new UnitsSchemaInternal();
double UnitsApi::UserPrefFactor [50];
QString UnitsApi::UserPrefUnit [50];
+int UnitsApi::UserPrefDecimals = 2;
UnitsApi::UnitsApi(const char* filter)
{
@@ -196,6 +197,16 @@ const double UnitsApi::getPrefFactorOf(QuantityType t)
return UserPrefFactor[t];
}
+void UnitsApi::setDecimals(int prec)
+{
+ UserPrefDecimals = prec;
+}
+
+int UnitsApi::getDecimals()
+{
+ return UserPrefDecimals;
+}
+
void UnitsApi::setDefaults(void)
{
setPrefOf( Length ,"mm" );
diff --git a/src/Base/UnitsApi.h b/src/Base/UnitsApi.h
index e3beae5d5..1b2fdcd64 100644
--- a/src/Base/UnitsApi.h
+++ b/src/Base/UnitsApi.h
@@ -101,6 +101,10 @@ public:
static const QString getQuantityName(QuantityType t);
/// get the translation factor for the default unit of a quantity
static const double getPrefFactorOf(QuantityType t);
+ // set the number of decimals
+ static void setDecimals(int);
+ // fet the number of decimals
+ static int getDecimals();
/// set the application defaults
static void setDefaults(void);
//@}
@@ -119,6 +123,8 @@ protected:
static double UserPrefFactor [50] ;
/// name of the unit the user wants to use as quantities
static QString UserPrefUnit [50] ;
+ /// number of decimals for floats
+ static int UserPrefDecimals;
// do the real work
static double parse(const char*,bool &UsedUnit);
diff --git a/src/Gui/Application.cpp b/src/Gui/Application.cpp
index a4c3542b3..ad5663902 100644
--- a/src/Gui/Application.cpp
+++ b/src/Gui/Application.cpp
@@ -52,6 +52,7 @@
#include
#include
#include
+#include
#include
#include
@@ -328,6 +329,10 @@ Application::Application(bool GUIenabled)
Translator::instance()->activateLanguage(hPGrp->GetASCII("Language", (const char*)lang.toAscii()).c_str());
GetWidgetFactorySupplier();
+ ParameterGrp::handle hUnits = App::GetApplication().GetParameterGroupByPath
+ ("User parameter:BaseApp/Preferences/Units");
+ Base::UnitsApi::setDecimals(hUnits->GetInt("Decimals", Base::UnitsApi::getDecimals()));
+
// setting up Python binding
Base::PyGILStateLocker lock;
PyObject* module = Py_InitModule3("FreeCADGui", Application::Methods,
diff --git a/src/Gui/SelectionObject.h b/src/Gui/SelectionObject.h
index 784b89f27..5c871594c 100644
--- a/src/Gui/SelectionObject.h
+++ b/src/Gui/SelectionObject.h
@@ -55,11 +55,11 @@ public:
/// are there any SubNames selected
bool hasSubNames(void)const { return SubNames.size() != 0; }
/// get the name of the Document of this SelctionObject
- inline const char* getDocName(void) { return DocName.c_str(); }
+ inline const char* getDocName(void) const { return DocName.c_str(); }
/// get the name of the Document Object of this SelectionObject
- inline const char* getFeatName(void) { return FeatName.c_str(); }
+ inline const char* getFeatName(void) const { return FeatName.c_str(); }
/// get the Type of the selcted Object
- inline const char* getTypeName(void) { return TypeName.c_str(); }
+ inline const char* getTypeName(void) const { return TypeName.c_str(); }
/// returns the selected DocumentObject or NULL if the object is already deleted
const App::DocumentObject *getObject(void) const;
diff --git a/src/Gui/propertyeditor/PropertyItem.cpp b/src/Gui/propertyeditor/PropertyItem.cpp
index 3f0e5b08f..eab7c4c20 100644
--- a/src/Gui/propertyeditor/PropertyItem.cpp
+++ b/src/Gui/propertyeditor/PropertyItem.cpp
@@ -57,6 +57,7 @@ TYPESYSTEM_SOURCE(Gui::PropertyEditor::PropertyItem, Base::BaseClass);
PropertyItem::PropertyItem() : parentItem(0), readonly(false)
{
+ precision = Base::UnitsApi::getDecimals();
}
PropertyItem::~PropertyItem()
@@ -130,6 +131,16 @@ bool PropertyItem::isReadOnly() const
return readonly;
}
+void PropertyItem::setDecimals(int prec)
+{
+ precision = prec;
+}
+
+int PropertyItem::decimals() const
+{
+ return precision;
+}
+
QVariant PropertyItem::toolTip(const App::Property* prop) const
{
return QVariant(QString::fromUtf8(prop->getDocumentation()));
@@ -574,7 +585,7 @@ void PropertyFloatItem::setValue(const QVariant& value)
if (!value.canConvert(QVariant::Double))
return;
double val = value.toDouble();
- QString data = QString::fromAscii("%1").arg(val,0,'f',2);
+ QString data = QString::fromAscii("%1").arg(val,0,'f',decimals());
setPropertyValue(data);
}
@@ -582,6 +593,7 @@ QWidget* PropertyFloatItem::createEditor(QWidget* parent, const QObject* receive
{
QDoubleSpinBox *sb = new QDoubleSpinBox(parent);
sb->setFrame(false);
+ sb->setDecimals(decimals());
QObject::connect(sb, SIGNAL(valueChanged(double)), receiver, method);
return sb;
}
@@ -703,13 +715,14 @@ void PropertyFloatConstraintItem::setValue(const QVariant& value)
if (!value.canConvert(QVariant::Double))
return;
double val = value.toDouble();
- QString data = QString::fromAscii("%1").arg(val,0,'f',2);
+ QString data = QString::fromAscii("%1").arg(val,0,'f',decimals());
setPropertyValue(data);
}
QWidget* PropertyFloatConstraintItem::createEditor(QWidget* parent, const QObject* receiver, const char* method) const
{
QDoubleSpinBox *sb = new QDoubleSpinBox(parent);
+ sb->setDecimals(decimals());
sb->setFrame(false);
QObject::connect(sb, SIGNAL(valueChanged(double)), receiver, method);
return sb;
@@ -873,9 +886,9 @@ void PropertyVectorItem::setValue(const QVariant& value)
return;
const Base::Vector3f& val = value.value();
QString data = QString::fromAscii("(%1, %2, %3)")
- .arg(val.x,0,'f',2)
- .arg(val.y,0,'f',2)
- .arg(val.z,0,'f',2);
+ .arg(val.x,0,'f',decimals())
+ .arg(val.y,0,'f',decimals())
+ .arg(val.z,0,'f',decimals());
setPropertyValue(data);
}
@@ -976,9 +989,9 @@ void PropertyDoubleVectorItem::setValue(const QVariant& value)
return;
const Base::Vector3d& val = value.value();
QString data = QString::fromAscii("(%1, %2, %3)")
- .arg(val.x,0,'f',2)
- .arg(val.y,0,'f',2)
- .arg(val.z,0,'f',2);
+ .arg(val.x,0,'f',decimals())
+ .arg(val.y,0,'f',decimals())
+ .arg(val.z,0,'f',decimals());
setPropertyValue(data);
}
@@ -1503,9 +1516,9 @@ void PropertyColorItem::setValue(const QVariant& value)
val.g = (float)col.green()/255.0f;
val.b = (float)col.blue()/255.0f;
QString data = QString::fromAscii("(%1,%2,%3)")
- .arg(val.r,0,'f',2)
- .arg(val.g,0,'f',2)
- .arg(val.b,0,'f',2);
+ .arg(val.r,0,'f',decimals())
+ .arg(val.g,0,'f',decimals())
+ .arg(val.b,0,'f',decimals());
setPropertyValue(data);
}
diff --git a/src/Gui/propertyeditor/PropertyItem.h b/src/Gui/propertyeditor/PropertyItem.h
index d334d8ced..bc247966f 100644
--- a/src/Gui/propertyeditor/PropertyItem.h
+++ b/src/Gui/propertyeditor/PropertyItem.h
@@ -69,6 +69,8 @@ public:
void setReadOnly(bool);
bool isReadOnly() const;
+ void setDecimals(int);
+ int decimals() const;
PropertyItem *child(int row);
int childCount() const;
@@ -99,6 +101,7 @@ private:
PropertyItem *parentItem;
QList childItems;
bool readonly;
+ int precision;
};
/**
diff --git a/src/Mod/Arch/ArchAxis.py b/src/Mod/Arch/ArchAxis.py
index d165e69ea..a2ea31033 100644
--- a/src/Mod/Arch/ArchAxis.py
+++ b/src/Mod/Arch/ArchAxis.py
@@ -109,7 +109,8 @@ class _ViewProviderAxis:
vobj.LineColor = (0.13,0.15,0.37)
vobj.DrawStyle = "Dashdot"
- def getIcon(self):
+ def getIcon(self):
+ import Arch_rc
return ":/icons/Arch_Axis_Tree.svg"
def claimChildren(self):
diff --git a/src/Mod/Arch/ArchBuilding.py b/src/Mod/Arch/ArchBuilding.py
index 0d6d5cc40..968165527 100644
--- a/src/Mod/Arch/ArchBuilding.py
+++ b/src/Mod/Arch/ArchBuilding.py
@@ -86,6 +86,7 @@ class _ViewProviderBuilding(ArchFloor._ViewProviderFloor):
ArchFloor._ViewProviderFloor.__init__(self,vobj)
def getIcon(self):
+ import Arch_rc
return ":/icons/Arch_Building_Tree.svg"
FreeCADGui.addCommand('Arch_Building',_CommandBuilding())
diff --git a/src/Mod/Arch/ArchCell.py b/src/Mod/Arch/ArchCell.py
index 8783602cc..6c4527ce5 100644
--- a/src/Mod/Arch/ArchCell.py
+++ b/src/Mod/Arch/ArchCell.py
@@ -121,6 +121,7 @@ class _ViewProviderCell(ArchComponent.ViewProviderComponent):
self.Object = vobj.Object
def getIcon(self):
+ import Arch_rc
return ":/icons/Arch_Cell_Tree.svg"
def updateData(self,obj,prop):
diff --git a/src/Mod/Arch/ArchFloor.py b/src/Mod/Arch/ArchFloor.py
index f7ccab17a..be9956107 100644
--- a/src/Mod/Arch/ArchFloor.py
+++ b/src/Mod/Arch/ArchFloor.py
@@ -114,6 +114,7 @@ class _ViewProviderFloor:
vobj.Proxy = self
def getIcon(self):
+ import Arch_rc
return ":/icons/Arch_Floor_Tree.svg"
def attach(self,vobj):
diff --git a/src/Mod/Arch/ArchRoof.py b/src/Mod/Arch/ArchRoof.py
index 4c8d6964c..e85581e60 100644
--- a/src/Mod/Arch/ArchRoof.py
+++ b/src/Mod/Arch/ArchRoof.py
@@ -148,7 +148,8 @@ class _ViewProviderRoof(ArchComponent.ViewProviderComponent):
def __init__(self,vobj):
ArchComponent.ViewProviderComponent.__init__(self,vobj)
- def getIcon(self):
+ def getIcon(self):
+ import Arch_rc
return ":/icons/Arch_Roof_Tree.svg"
FreeCADGui.addCommand('Arch_Roof',_CommandRoof())
diff --git a/src/Mod/Arch/ArchSectionPlane.py b/src/Mod/Arch/ArchSectionPlane.py
index aa1d8bb99..460d3a7d1 100644
--- a/src/Mod/Arch/ArchSectionPlane.py
+++ b/src/Mod/Arch/ArchSectionPlane.py
@@ -123,6 +123,7 @@ class _ViewProviderSectionPlane(ArchComponent.ViewProviderComponent):
self.Object = vobj.Object
def getIcon(self):
+ import Arch_rc
return ":/icons/Arch_SectionPlane_Tree.svg"
def claimChildren(self):
diff --git a/src/Mod/Arch/ArchSite.py b/src/Mod/Arch/ArchSite.py
index 69cfda8ba..f6c6e9acb 100644
--- a/src/Mod/Arch/ArchSite.py
+++ b/src/Mod/Arch/ArchSite.py
@@ -89,6 +89,7 @@ class _ViewProviderSite(ArchFloor._ViewProviderFloor):
ArchFloor._ViewProviderFloor.__init__(self,vobj)
def getIcon(self):
+ import Arch_rc
return ":/icons/Arch_Site_Tree.svg"
diff --git a/src/Mod/Arch/ArchStructure.py b/src/Mod/Arch/ArchStructure.py
index d257c4d92..1a9f51c07 100644
--- a/src/Mod/Arch/ArchStructure.py
+++ b/src/Mod/Arch/ArchStructure.py
@@ -193,7 +193,8 @@ class _ViewProviderStructure(ArchComponent.ViewProviderComponent):
def __init__(self,vobj):
ArchComponent.ViewProviderComponent.__init__(self,vobj)
- def getIcon(self):
+ def getIcon(self):
+ import Arch_rc
return ":/icons/Arch_Structure_Tree.svg"
FreeCADGui.addCommand('Arch_Structure',_CommandStructure())
diff --git a/src/Mod/Arch/ArchWall.py b/src/Mod/Arch/ArchWall.py
index 1d6f8e5e0..e8236af3f 100644
--- a/src/Mod/Arch/ArchWall.py
+++ b/src/Mod/Arch/ArchWall.py
@@ -423,7 +423,8 @@ class _ViewProviderWall(ArchComponent.ViewProviderComponent):
def __init__(self,vobj):
ArchComponent.ViewProviderComponent.__init__(self,vobj)
- def getIcon(self):
+ def getIcon(self):
+ import Arch_rc
return ":/icons/Arch_Wall_Tree.svg"
def getDisplayModes(self,vobj):
diff --git a/src/Mod/Arch/ArchWindow.py b/src/Mod/Arch/ArchWindow.py
index 2f593257f..ad9d49369 100644
--- a/src/Mod/Arch/ArchWindow.py
+++ b/src/Mod/Arch/ArchWindow.py
@@ -179,7 +179,8 @@ class _ViewProviderWindow(ArchComponent.ViewProviderComponent):
def __init__(self,vobj):
ArchComponent.ViewProviderComponent.__init__(self,vobj)
- def getIcon(self):
+ def getIcon(self):
+ import Arch_rc
return ":/icons/Arch_Window_Tree.svg"
def setEdit(self,vobj,mode):
diff --git a/src/Mod/Part/App/AppPart.cpp b/src/Mod/Part/App/AppPart.cpp
index 716597e2b..4980b0be1 100644
--- a/src/Mod/Part/App/AppPart.cpp
+++ b/src/Mod/Part/App/AppPart.cpp
@@ -179,6 +179,7 @@ void PartExport initPart()
Part::Part2DObjectPython ::init();
Part::RuledSurface ::init();
Part::Loft ::init();
+ Part::Sweep ::init();
// Geometry types
Part::Geometry ::init();
diff --git a/src/Mod/Part/App/PartFeature.cpp b/src/Mod/Part/App/PartFeature.cpp
index ef43452df..45e0076e9 100644
--- a/src/Mod/Part/App/PartFeature.cpp
+++ b/src/Mod/Part/App/PartFeature.cpp
@@ -30,6 +30,10 @@
# include
# include
# include
+// includes for findAllFacesCutBy()
+# include
+# include
+# include // for Precision::Confusion()
#endif
@@ -139,22 +143,25 @@ ShapeHistory Feature::buildHistory(BRepBuilderAPI_MakeShape& mkShape, TopAbs_Sha
history.type = type;
TopTools_IndexedMapOfShape newM, oldM;
- TopExp::MapShapes(newS, type, newM);
- TopExp::MapShapes(oldS, type, oldM);
+ TopExp::MapShapes(newS, type, newM); // map containing all old objects of type "type"
+ TopExp::MapShapes(oldS, type, oldM); // map containing all new objects of type "type"
+ // Look at all objects in the old shape and try to find the modified object in the new shape
for (int i=1; i<=oldM.Extent(); i++) {
bool found = false;
TopTools_ListIteratorOfListOfShape it;
+ // Find all new objects that are a modification of the old object (e.g. a face was resized)
for (it.Initialize(mkShape.Modified(oldM(i))); it.More(); it.Next()) {
found = true;
- for (int j=1; j<=newM.Extent(); j++) {
+ for (int j=1; j<=newM.Extent(); j++) { // one old object might create several new ones!
if (newM(j).IsPartner(it.Value())) {
- history.shapeMap[i-1].push_back(j-1);
+ history.shapeMap[i-1].push_back(j-1); // adjust indices to start at zero
break;
}
}
}
+ // Find all new objects that were generated from an old object (e.g. a face generated from an edge)
for (it.Initialize(mkShape.Generated(oldM(i))); it.More(); it.Next()) {
found = true;
for (int j=1; j<=newM.Extent(); j++) {
@@ -166,10 +173,12 @@ ShapeHistory Feature::buildHistory(BRepBuilderAPI_MakeShape& mkShape, TopAbs_Sha
}
if (!found) {
+ // Find all old objects that don't exist any more (e.g. a face was completely cut away)
if (mkShape.IsDeleted(oldM(i))) {
history.shapeMap[i-1] = std::vector();
}
else {
+ // Mop up the rest (will this ever be reached?)
for (int j=1; j<=newM.Extent(); j++) {
if (newM(j).IsPartner(oldM(i))) {
history.shapeMap[i-1].push_back(j-1);
@@ -204,6 +213,15 @@ ShapeHistory Feature::joinHistory(const ShapeHistory& oldH, const ShapeHistory&
return join;
}
+const TopoDS_Shape Feature::findOriginOf(const TopoDS_Shape& reference) {
+/* Base::Console().Error("Looking for origin of face in %s\n", this->getName());
+ if (reference.ShapeType() == TopAbs_FACE) {
+ // Find index of reference in the history
+ }
+*/
+ return TopoDS_Shape();
+}
+
/// returns the type name of the ViewProvider
const char* Feature::getViewProviderName(void) const {
return "PartGui::ViewProviderPart";
@@ -253,3 +271,51 @@ template<> PyObject* Part::FeaturePython::getPyObject(void) {
template class PartExport FeaturePythonT;
}
+// ----------------------------------------------------------------
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+std::vector Part::findAllFacesCutBy(
+ const TopoDS_Shape& shape, const TopoDS_Shape& face, const gp_Dir& dir)
+{
+ // Find the centre of gravity of the face
+ GProp_GProps props;
+ BRepGProp::SurfaceProperties(face,props);
+ gp_Pnt cog = props.CentreOfMass();
+
+ // create a line through the centre of gravity
+ gp_Lin line = gce_MakeLin(cog, dir);
+
+ // Find intersection of line with all faces of the shape
+ std::vector result;
+ BRepIntCurveSurface_Inter mkSection;
+ // TODO: Less precision than Confusion() should be OK?
+
+ for (mkSection.Init(shape, line, Precision::Confusion()); mkSection.More(); mkSection.Next()) {
+ gp_Pnt iPnt = mkSection.Pnt();
+ double dsq = cog.SquareDistance(iPnt);
+
+ if (dsq < Precision::Confusion())
+ continue; // intersection with original face
+
+ // Find out which side of the original face the intersection is on
+ gce_MakeDir mkDir(cog, iPnt);
+ if (!mkDir.IsDone())
+ continue; // some error (appears highly unlikely to happen, though...)
+
+ if (mkDir.Value().IsOpposite(dir, Precision::Confusion()))
+ continue; // wrong side of face (opposite to extrusion direction)
+
+ cutFaces newF;
+ newF.face = mkSection.Face();
+ newF.distsq = dsq;
+ result.push_back(newF);
+ }
+
+ return result;
+}
diff --git a/src/Mod/Part/App/PartFeature.h b/src/Mod/Part/App/PartFeature.h
index 689736a42..9bb4bd49a 100644
--- a/src/Mod/Part/App/PartFeature.h
+++ b/src/Mod/Part/App/PartFeature.h
@@ -29,9 +29,16 @@
#include
#include
#include
+// includes for findAllFacesCutBy()
+#include
+class gp_Dir;
class BRepBuilderAPI_MakeShape;
+// includes for findAllFacesCutBy()
+#include
+class gp_Dir;
+
namespace Part
{
@@ -63,9 +70,22 @@ public:
virtual PyObject* getPyObject(void);
virtual std::vector getPySubObjects(const std::vector&) const;
+ /**
+ /* Find the origin of a reference, e.g. the vertex or edge in a sketch that
+ /* produced a face
+ */
+ const TopoDS_Shape findOriginOf(const TopoDS_Shape& reference);
+
protected:
void onChanged(const App::Property* prop);
TopLoc_Location getLocation() const;
+ /**
+ /* Build a history of changes
+ /* MakeShape: The operation that created the changes, e.g. BRepAlgoAPI_Common
+ /* type: The type of object we are interested in, e.g. TopAbs_FACE
+ /* newS: The new shape that was created by the operation
+ /* oldS: The original shape prior to the operation
+ */
ShapeHistory buildHistory(BRepBuilderAPI_MakeShape&, TopAbs_ShapeEnum type,
const TopoDS_Shape& newS, const TopoDS_Shape& oldS);
ShapeHistory joinHistory(const ShapeHistory&, const ShapeHistory&);
@@ -99,6 +119,20 @@ public:
}
};
+// Utility methods
+/**
+/* Find all faces cut by a line through the centre of gravity of a given face
+/* Useful for the "up to face" options to pocket or pad
+*/
+struct cutFaces {
+ TopoDS_Face face;
+ double distsq;
+};
+
+PartExport
+std::vector findAllFacesCutBy(const TopoDS_Shape& shape,
+ const TopoDS_Shape& face, const gp_Dir& dir);
+
} //namespace Part
diff --git a/src/Mod/Part/App/PartFeatures.cpp b/src/Mod/Part/App/PartFeatures.cpp
index 1f2088874..1bf2ce874 100644
--- a/src/Mod/Part/App/PartFeatures.cpp
+++ b/src/Mod/Part/App/PartFeatures.cpp
@@ -28,6 +28,8 @@
# include
# include
# include
+# include
+# include
#endif
@@ -196,3 +198,132 @@ App::DocumentObjectExecReturn *Loft::execute(void)
return new App::DocumentObjectExecReturn(e->GetMessageString());
}
}
+
+// ----------------------------------------------------------------------------
+
+const char* Part::Sweep::TransitionEnums[]= {"Transformed","Right corner", "Round corner",NULL};
+
+PROPERTY_SOURCE(Part::Sweep, Part::Feature)
+
+Sweep::Sweep()
+{
+ ADD_PROPERTY_TYPE(Sections,(0),"Sweep",App::Prop_None,"List of sections");
+ Sections.setSize(0);
+ ADD_PROPERTY_TYPE(Spine,(0),"Sweep",App::Prop_None,"Path to sweep along");
+ ADD_PROPERTY_TYPE(Solid,(false),"Sweep",App::Prop_None,"Create solid");
+ ADD_PROPERTY_TYPE(Frenet,(false),"Sweep",App::Prop_None,"Frenet");
+ ADD_PROPERTY_TYPE(Transition,(long(0)),"Sweep",App::Prop_None,"Transition mode");
+ Transition.setEnums(TransitionEnums);
+}
+
+short Sweep::mustExecute() const
+{
+ if (Sections.isTouched())
+ return 1;
+ if (Spine.isTouched())
+ return 1;
+ if (Solid.isTouched())
+ return 1;
+ if (Frenet.isTouched())
+ return 1;
+ if (Transition.isTouched())
+ return 1;
+ return 0;
+}
+
+void Sweep::onChanged(const App::Property* prop)
+{
+ Part::Feature::onChanged(prop);
+}
+
+App::DocumentObjectExecReturn *Sweep::execute(void)
+{
+ if (Sections.getSize() == 0)
+ return new App::DocumentObjectExecReturn("No sections linked.");
+ App::DocumentObject* spine = Spine.getValue();
+ if (!(spine && spine->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())))
+ return new App::DocumentObjectExecReturn("No spine linked.");
+ const std::vector& subedge = Spine.getSubValues();
+ if (subedge.size() != 1)
+ return new App::DocumentObjectExecReturn("Not exactly one sub-shape linked.");
+
+ TopoDS_Shape path;
+ const Part::TopoShape& shape = static_cast(spine)->Shape.getValue();
+ if (!shape._Shape.IsNull()) {
+ if (!subedge[0].empty()) {
+ path = shape.getSubShape(subedge[0].c_str());
+ }
+ else {
+ if (shape._Shape.ShapeType() == TopAbs_EDGE)
+ path = shape._Shape;
+ else if (shape._Shape.ShapeType() == TopAbs_WIRE)
+ path = shape._Shape;
+ else
+ return new App::DocumentObjectExecReturn("Spine is neither an edge nor a wire.");
+ }
+ }
+
+ try {
+ TopTools_ListOfShape profiles;
+ const std::vector& shapes = Sections.getValues();
+ std::vector::const_iterator it;
+ for (it = shapes.begin(); it != shapes.end(); ++it) {
+ if (!(*it)->isDerivedFrom(Part::Feature::getClassTypeId()))
+ return new App::DocumentObjectExecReturn("Linked object is not a shape.");
+ const TopoDS_Shape& shape = static_cast(*it)->Shape.getValue();
+ if (shape.IsNull())
+ return new App::DocumentObjectExecReturn("Linked shape is invalid.");
+ if (shape.ShapeType() == TopAbs_WIRE) {
+ profiles.Append(shape);
+ }
+ else if (shape.ShapeType() == TopAbs_EDGE) {
+ BRepBuilderAPI_MakeWire mkWire(TopoDS::Edge(shape));
+ profiles.Append(mkWire.Wire());
+ }
+ else if (shape.ShapeType() == TopAbs_VERTEX) {
+ profiles.Append(shape);
+ }
+ else {
+ return new App::DocumentObjectExecReturn("Linked shape is not a vertex, edge nor wire.");
+ }
+ }
+
+ Standard_Boolean isSolid = Solid.getValue() ? Standard_True : Standard_False;
+ Standard_Boolean isFrenet = Frenet.getValue() ? Standard_True : Standard_False;
+ BRepBuilderAPI_TransitionMode transMode;
+ switch (Transition.getValue()) {
+ case 1: transMode = BRepBuilderAPI_RightCorner;
+ break;
+ case 2: transMode = BRepBuilderAPI_RoundCorner;
+ break;
+ default: transMode = BRepBuilderAPI_Transformed;
+ break;
+ }
+
+ if (path.ShapeType() == TopAbs_EDGE) {
+ BRepBuilderAPI_MakeWire mkWire(TopoDS::Edge(path));
+ path = mkWire.Wire();
+ }
+
+ BRepOffsetAPI_MakePipeShell mkPipeShell(TopoDS::Wire(path));
+ mkPipeShell.SetMode(isFrenet);
+ mkPipeShell.SetTransitionMode(transMode);
+ TopTools_ListIteratorOfListOfShape iter;
+ for (iter.Initialize(profiles); iter.More(); iter.Next()) {
+ mkPipeShell.Add(TopoDS_Shape(iter.Value()));
+ }
+
+ if (!mkPipeShell.IsReady())
+ Standard_Failure::Raise("shape is not ready to build");
+ mkPipeShell.Build();
+ if (isSolid)
+ mkPipeShell.MakeSolid();
+
+ this->Shape.setValue(mkPipeShell.Shape());
+ return App::DocumentObject::StdReturn;
+ }
+ catch (Standard_Failure) {
+ Handle_Standard_Failure e = Standard_Failure::Caught();
+ return new App::DocumentObjectExecReturn(e->GetMessageString());
+ }
+}
diff --git a/src/Mod/Part/App/PartFeatures.h b/src/Mod/Part/App/PartFeatures.h
index f01fde575..ddaae9627 100644
--- a/src/Mod/Part/App/PartFeatures.h
+++ b/src/Mod/Part/App/PartFeatures.h
@@ -73,6 +73,33 @@ protected:
void onChanged (const App::Property* prop);
};
+class Sweep : public Part::Feature
+{
+ PROPERTY_HEADER(Part::Sweep);
+
+public:
+ Sweep();
+
+ App::PropertyLinkList Sections;
+ App::PropertyLinkSub Spine;
+ App::PropertyBool Solid;
+ App::PropertyBool Frenet;
+ App::PropertyEnumeration Transition;
+
+ /** @name methods override feature */
+ //@{
+ /// recalculate the feature
+ App::DocumentObjectExecReturn *execute(void);
+ short mustExecute() const;
+ //@}
+
+protected:
+ void onChanged (const App::Property* prop);
+
+private:
+ static const char* TransitionEnums[];
+};
+
} //namespace Part
diff --git a/src/Mod/Part/Gui/CMakeLists.txt b/src/Mod/Part/Gui/CMakeLists.txt
index d9ff99f95..ec068eb95 100644
--- a/src/Mod/Part/Gui/CMakeLists.txt
+++ b/src/Mod/Part/Gui/CMakeLists.txt
@@ -41,6 +41,7 @@ set(PartGui_MOC_HDRS
TaskFaceColors.h
TaskShapeBuilder.h
TaskLoft.h
+ TaskSweep.h
)
fc_wrap_cpp(PartGui_MOC_SRCS ${PartGui_MOC_HDRS})
SOURCE_GROUP("Moc" FILES ${PartGui_MOC_SRCS})
@@ -65,6 +66,7 @@ set(PartGui_UIC_SRCS
TaskFaceColors.ui
TaskShapeBuilder.ui
TaskLoft.ui
+ TaskSweep.ui
)
qt4_wrap_ui(PartGui_UIC_HDRS ${PartGui_UIC_SRCS})
@@ -155,6 +157,9 @@ SET(PartGui_SRCS
TaskLoft.cpp
TaskLoft.h
TaskLoft.ui
+ TaskSweep.cpp
+ TaskSweep.h
+ TaskSweep.ui
)
SET(PartGui_Scripts
diff --git a/src/Mod/Part/Gui/Command.cpp b/src/Mod/Part/Gui/Command.cpp
index 33cd008ee..5020e4872 100644
--- a/src/Mod/Part/Gui/Command.cpp
+++ b/src/Mod/Part/Gui/Command.cpp
@@ -61,6 +61,7 @@
#include "ViewProvider.h"
#include "TaskShapeBuilder.h"
#include "TaskLoft.h"
+#include "TaskSweep.h"
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -960,6 +961,31 @@ bool CmdPartLoft::isActive(void)
//--------------------------------------------------------------------------------------
+DEF_STD_CMD_A(CmdPartSweep);
+
+CmdPartSweep::CmdPartSweep()
+ : Command("Part_Sweep")
+{
+ sAppModule = "Part";
+ sGroup = QT_TR_NOOP("Part");
+ sMenuText = QT_TR_NOOP("Sweep...");
+ sToolTipText = QT_TR_NOOP("Advanced utility to sweep");
+ sWhatsThis = sToolTipText;
+ sStatusTip = sToolTipText;
+}
+
+void CmdPartSweep::activated(int iMsg)
+{
+ Gui::Control().showDialog(new PartGui::TaskSweep());
+}
+
+bool CmdPartSweep::isActive(void)
+{
+ return (hasActiveDocument() && !Gui::Control().activeDialog());
+}
+
+//--------------------------------------------------------------------------------------
+
DEF_STD_CMD_A(CmdShapeInfo);
CmdShapeInfo::CmdShapeInfo()
@@ -1194,5 +1220,6 @@ void CreatePartCommands(void)
rcCmdMgr.addCommand(new CmdPartRuledSurface());
rcCmdMgr.addCommand(new CmdPartBuilder());
rcCmdMgr.addCommand(new CmdPartLoft());
+ rcCmdMgr.addCommand(new CmdPartSweep());
}
diff --git a/src/Mod/Part/Gui/TaskSweep.cpp b/src/Mod/Part/Gui/TaskSweep.cpp
new file mode 100644
index 000000000..effd5c28b
--- /dev/null
+++ b/src/Mod/Part/Gui/TaskSweep.cpp
@@ -0,0 +1,255 @@
+/***************************************************************************
+ * Copyright (c) 2011 Werner Mayer *
+ * *
+ * 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
+# include
+#endif
+
+#include "ui_TaskSweep.h"
+#include "TaskSweep.h"
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+using namespace PartGui;
+
+class SweepWidget::Private
+{
+public:
+ Ui_TaskSweep ui;
+ std::string document;
+ Private()
+ {
+ }
+ ~Private()
+ {
+ }
+};
+
+/* TRANSLATOR PartGui::SweepWidget */
+
+SweepWidget::SweepWidget(QWidget* parent)
+ : d(new Private())
+{
+ Gui::Application::Instance->runPythonCode("from FreeCAD import Base");
+ Gui::Application::Instance->runPythonCode("import Part");
+
+ d->ui.setupUi(this);
+ d->ui.selector->setAvailableLabel(tr("Vertex/Wire"));
+ d->ui.selector->setSelectedLabel(tr("Sweep"));
+
+ connect(d->ui.selector->availableTreeWidget(), SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)),
+ this, SLOT(onCurrentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)));
+ connect(d->ui.selector->selectedTreeWidget(), SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)),
+ this, SLOT(onCurrentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)));
+
+ findShapes();
+}
+
+SweepWidget::~SweepWidget()
+{
+ delete d;
+}
+
+void SweepWidget::findShapes()
+{
+ App::Document* activeDoc = App::GetApplication().getActiveDocument();
+ Gui::Document* activeGui = Gui::Application::Instance->getDocument(activeDoc);
+ if (!activeGui) return;
+ d->document = activeDoc->getName();
+
+ std::vector objs = activeDoc->getObjectsOfType();
+
+ for (std::vector::iterator it = objs.begin(); it!=objs.end(); ++it) {
+ const TopoDS_Shape& shape = (*it)->Shape.getValue();
+ if (shape.IsNull()) continue;
+
+ if (shape.ShapeType() == TopAbs_WIRE ||
+ shape.ShapeType() == TopAbs_EDGE ||
+ shape.ShapeType() == TopAbs_VERTEX) {
+ QString label = QString::fromUtf8((*it)->Label.getValue());
+ QString name = QString::fromAscii((*it)->getNameInDocument());
+
+ QTreeWidgetItem* child = new QTreeWidgetItem();
+ child->setText(0, label);
+ child->setToolTip(0, label);
+ child->setData(0, Qt::UserRole, name);
+ Gui::ViewProvider* vp = activeGui->getViewProvider(*it);
+ if (vp) child->setIcon(0, vp->getIcon());
+ d->ui.selector->availableTreeWidget()->addTopLevelItem(child);
+ }
+ }
+}
+
+bool SweepWidget::accept()
+{
+ Gui::SelectionFilter edgeFilter ("SELECT Part::Feature SUBELEMENT Edge COUNT 1");
+ Gui::SelectionFilter partFilter ("SELECT Part::Feature COUNT 1");
+ bool matchEdge = edgeFilter.match();
+ bool matchPart = partFilter.match();
+ if (!matchEdge && !matchPart) {
+ QMessageBox::critical(this, tr("Sweep path"), tr("Select an edge or wire you want to sweep along."));
+ return false;
+ }
+
+ // get the selected object
+ std::string objectName, subShape;
+ if (matchEdge) {
+ const std::vector& result = edgeFilter.Result[0];
+ const std::vector& edges = result[0].getSubNames();
+ objectName = result.front().getFeatName();
+ subShape = edges.front();
+ }
+ else {
+ const std::vector& result = partFilter.Result[0];
+ objectName = result.front().getFeatName();
+ }
+
+ QString list, solid, frenet;
+ if (d->ui.checkSolid->isChecked())
+ solid = QString::fromAscii("True");
+ else
+ solid = QString::fromAscii("False");
+
+ if (d->ui.checkFrenet->isChecked())
+ frenet = QString::fromAscii("True");
+ else
+ frenet = QString::fromAscii("False");
+
+ QTextStream str(&list);
+
+ int count = d->ui.selector->selectedTreeWidget()->topLevelItemCount();
+ if (count < 1) {
+ QMessageBox::critical(this, tr("Too few elements"), tr("At least one edge or wire is required."));
+ return false;
+ }
+ for (int i=0; iui.selector->selectedTreeWidget()->topLevelItem(i);
+ QString name = child->data(0, Qt::UserRole).toString();
+ str << "App.getDocument('" << d->document.c_str() << "')." << name << ", ";
+ }
+
+ try {
+ QString cmd;
+ cmd = QString::fromAscii(
+ "App.getDocument('%6').addObject('Part::Sweep','Sweep')\n"
+ "App.getDocument('%6').ActiveObject.Sections=[%1]\n"
+ "App.getDocument('%6').ActiveObject.Spine=(FreeCAD.ActiveDocument.%2,['%3'])\n"
+ "App.getDocument('%6').ActiveObject.Solid=%4\n"
+ "App.getDocument('%6').ActiveObject.Frenet=%5\n"
+ )
+ .arg(list).arg(QLatin1String(objectName.c_str()))
+ .arg(QLatin1String(subShape.c_str()))
+ .arg(solid).arg(frenet).arg(QString::fromAscii(d->document.c_str()));
+
+ Gui::Document* doc = Gui::Application::Instance->getDocument(d->document.c_str());
+ if (!doc) throw Base::Exception("Document doesn't exist anymore");
+ doc->openCommand("Sweep");
+ Gui::Application::Instance->runPythonCode((const char*)cmd.toAscii(), false, false);
+ doc->commitCommand();
+ doc->getDocument()->recompute();
+ }
+ catch (const Base::Exception& e) {
+ Base::Console().Error("%s\n", e.what());
+ return false;
+ }
+
+ return true;
+}
+
+bool SweepWidget::reject()
+{
+ return true;
+}
+
+void SweepWidget::onCurrentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous)
+{
+ if (previous) {
+ Gui::Selection().rmvSelection(d->document.c_str(),
+ (const char*)previous->data(0,Qt::UserRole).toByteArray());
+ }
+ if (current) {
+ Gui::Selection().addSelection(d->document.c_str(),
+ (const char*)current->data(0,Qt::UserRole).toByteArray());
+ }
+}
+
+void SweepWidget::changeEvent(QEvent *e)
+{
+ QWidget::changeEvent(e);
+ if (e->type() == QEvent::LanguageChange) {
+ d->ui.retranslateUi(this);
+ d->ui.selector->setAvailableLabel(tr("Vertex/Wire"));
+ d->ui.selector->setSelectedLabel(tr("Sweep"));
+ }
+}
+
+
+/* TRANSLATOR PartGui::TaskSweep */
+
+TaskSweep::TaskSweep()
+{
+ widget = new SweepWidget();
+ taskbox = new Gui::TaskView::TaskBox(
+ QPixmap(), widget->windowTitle(), true, 0);
+ taskbox->groupLayout()->addWidget(widget);
+ Content.push_back(taskbox);
+}
+
+TaskSweep::~TaskSweep()
+{
+}
+
+void TaskSweep::open()
+{
+}
+
+void TaskSweep::clicked(int)
+{
+}
+
+bool TaskSweep::accept()
+{
+ return widget->accept();
+}
+
+bool TaskSweep::reject()
+{
+ return widget->reject();
+}
+
+#include "moc_TaskSweep.cpp"
diff --git a/src/Mod/Part/Gui/TaskSweep.h b/src/Mod/Part/Gui/TaskSweep.h
new file mode 100644
index 000000000..f0c6fc592
--- /dev/null
+++ b/src/Mod/Part/Gui/TaskSweep.h
@@ -0,0 +1,81 @@
+/***************************************************************************
+ * Copyright (c) 2011 Werner Mayer *
+ * *
+ * 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_TASKSWEEP_H
+#define PARTGUI_TASKSWEEP_H
+
+#include
+#include
+
+class QTreeWidgetItem;
+
+namespace PartGui {
+
+class SweepWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ SweepWidget(QWidget* parent = 0);
+ ~SweepWidget();
+
+ bool accept();
+ bool reject();
+
+private Q_SLOTS:
+ void onCurrentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*);
+
+private:
+ void changeEvent(QEvent *e);
+ void findShapes();
+
+private:
+ class Private;
+ Private* d;
+};
+
+class TaskSweep : public Gui::TaskView::TaskDialog
+{
+ Q_OBJECT
+
+public:
+ TaskSweep();
+ ~TaskSweep();
+
+public:
+ void open();
+ bool accept();
+ bool reject();
+ void clicked(int);
+
+ QDialogButtonBox::StandardButtons getStandardButtons() const
+ { return QDialogButtonBox::Ok|QDialogButtonBox::Cancel; }
+
+private:
+ SweepWidget* widget;
+ Gui::TaskView::TaskBox* taskbox;
+};
+
+} //namespace PartGui
+
+#endif // PARTGUI_TASKSWEEP_H
diff --git a/src/Mod/Part/Gui/TaskSweep.ui b/src/Mod/Part/Gui/TaskSweep.ui
new file mode 100644
index 000000000..6cfab459d
--- /dev/null
+++ b/src/Mod/Part/Gui/TaskSweep.ui
@@ -0,0 +1,68 @@
+
+
+ PartGui::TaskSweep
+
+
+
+ 0
+ 0
+ 336
+ 326
+
+
+
+ Sweep
+
+
+ -
+
+
+ -
+
+
+ Create solid
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 130
+ 20
+
+
+
+
+ -
+
+
+ Frenet
+
+
+
+ -
+
+
+ Select one or more profiles and select an edge or wire
+in the 3D view for the sweep path.
+
+
+
+
+
+
+
+ Gui::ActionSelector
+ QWidget
+
+
+
+
+
+
+
+
diff --git a/src/Mod/Part/Gui/Workbench.cpp b/src/Mod/Part/Gui/Workbench.cpp
index ea42cb9f3..9997750b2 100644
--- a/src/Mod/Part/Gui/Workbench.cpp
+++ b/src/Mod/Part/Gui/Workbench.cpp
@@ -72,7 +72,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const
<< "Part_RefineShape" << "Separator"
<< "Part_Boolean" << "Part_CrossSections" << "Part_Extrude"
<< "Part_Revolve" << "Part_Mirror" << "Part_Fillet" << "Part_Chamfer"
- << "Part_RuledSurface" << "Part_Loft"
+ << "Part_RuledSurface" << "Part_Loft" << "Part_Sweep"
<< "Part_Builder";
//Gui::MenuItem* partSimple = new Gui::MenuItem;
diff --git a/src/Mod/PartDesign/App/AppPartDesign.cpp b/src/Mod/PartDesign/App/AppPartDesign.cpp
index debb60f26..16620762f 100644
--- a/src/Mod/PartDesign/App/AppPartDesign.cpp
+++ b/src/Mod/PartDesign/App/AppPartDesign.cpp
@@ -34,6 +34,7 @@
#include "FeatureFillet.h"
#include "FeatureSketchBased.h"
#include "FeatureRevolution.h"
+#include "FeatureGroove.h"
#include "Body.h"
#include "FeatureDressUp.h"
#include "FeatureChamfer.h"
@@ -82,6 +83,7 @@ void PartDesignExport initPartDesign()
PartDesign::Pocket ::init();
PartDesign::Fillet ::init();
PartDesign::Revolution ::init();
+ PartDesign::Groove ::init();
PartDesign::Chamfer ::init();
PartDesign::Face ::init();
}
diff --git a/src/Mod/PartDesign/App/CMakeLists.txt b/src/Mod/PartDesign/App/CMakeLists.txt
index 49af69836..837189bb1 100644
--- a/src/Mod/PartDesign/App/CMakeLists.txt
+++ b/src/Mod/PartDesign/App/CMakeLists.txt
@@ -50,6 +50,8 @@ SET(FeaturesSketchBased_SRCS
FeaturePocket.h
FeatureRevolution.cpp
FeatureRevolution.h
+ FeatureGroove.cpp
+ FeatureGroove.h
FeatureAdditive.cpp
FeatureAdditive.h
FeatureSubtractive.h
diff --git a/src/Mod/PartDesign/App/FeatureGroove.cpp b/src/Mod/PartDesign/App/FeatureGroove.cpp
new file mode 100644
index 000000000..1cf17541d
--- /dev/null
+++ b/src/Mod/PartDesign/App/FeatureGroove.cpp
@@ -0,0 +1,208 @@
+/***************************************************************************
+ * Copyright (c) 2010 Juergen Riegel *
+ * *
+ * 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
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+#endif
+
+#include
+#include
+#include
+#include
+
+#include "FeatureGroove.h"
+
+
+using namespace PartDesign;
+
+namespace PartDesign {
+
+
+PROPERTY_SOURCE(PartDesign::Groove, PartDesign::SketchBased)
+
+Groove::Groove()
+{
+ ADD_PROPERTY_TYPE(Base,(Base::Vector3f(0.0f,0.0f,0.0f)),"Groove", App::Prop_ReadOnly, "Base");
+ ADD_PROPERTY_TYPE(Axis,(Base::Vector3f(0.0f,1.0f,0.0f)),"Groove", App::Prop_ReadOnly, "Axis");
+ ADD_PROPERTY_TYPE(Angle,(360.0),"Groove", App::Prop_None, "Angle");
+ ADD_PROPERTY_TYPE(ReferenceAxis,(0),"Groove",(App::PropertyType)(App::Prop_None),"Reference axis of Groove");
+ ADD_PROPERTY_TYPE(Midplane,(0),"Groove", App::Prop_None, "Mid plane");
+ ADD_PROPERTY_TYPE(Reversed, (0),"Groove", App::Prop_None, "Reversed");
+}
+
+short Groove::mustExecute() const
+{
+ if (Placement.isTouched() ||
+ Sketch.isTouched() ||
+ ReferenceAxis.isTouched() ||
+ Axis.isTouched() ||
+ Base.isTouched() ||
+ Angle.isTouched() ||
+ Midplane.isTouched() ||
+ Reversed.isTouched())
+ return 1;
+ return 0;
+}
+
+App::DocumentObjectExecReturn *Groove::execute(void)
+{
+ App::DocumentObject* link = Sketch.getValue();
+ if (!link)
+ return new App::DocumentObjectExecReturn("No sketch linked");
+ if (!link->getTypeId().isDerivedFrom(Part::Part2DObject::getClassTypeId()))
+ return new App::DocumentObjectExecReturn("Linked object is not a Sketch or Part2DObject");
+
+ Part::Part2DObject* pcSketch=static_cast(link);
+
+ TopoDS_Shape shape = pcSketch->Shape.getShape()._Shape;
+ if (shape.IsNull())
+ return new App::DocumentObjectExecReturn("Linked shape object is empty");
+
+ // this is a workaround for an obscure OCC bug which leads to empty tessellations
+ // for some faces. Making an explicit copy of the linked shape seems to fix it.
+ // The error only happens when re-computing the shape.
+ if (!this->Shape.getValue().IsNull()) {
+ BRepBuilderAPI_Copy copy(shape);
+ shape = copy.Shape();
+ if (shape.IsNull())
+ return new App::DocumentObjectExecReturn("Linked shape object is empty");
+ }
+
+ TopExp_Explorer ex;
+ std::vector wires;
+ for (ex.Init(shape, TopAbs_WIRE); ex.More(); ex.Next()) {
+ wires.push_back(TopoDS::Wire(ex.Current()));
+ }
+ if (wires.empty()) // there can be several wires
+ return new App::DocumentObjectExecReturn("Linked shape object is not a wire");
+
+ // get the Sketch plane
+ Base::Placement SketchPlm = pcSketch->Placement.getValue();
+
+ // get reference axis
+ App::DocumentObject *pcReferenceAxis = ReferenceAxis.getValue();
+ const std::vector &subReferenceAxis = ReferenceAxis.getSubValues();
+ if (pcReferenceAxis && pcReferenceAxis == pcSketch) {
+ bool hasValidAxis=false;
+ Base::Axis axis;
+ if (subReferenceAxis[0] == "V_Axis") {
+ hasValidAxis = true;
+ axis = pcSketch->getAxis(Part::Part2DObject::V_Axis);
+ }
+ else if (subReferenceAxis[0] == "H_Axis") {
+ hasValidAxis = true;
+ axis = pcSketch->getAxis(Part::Part2DObject::H_Axis);
+ }
+ else if (subReferenceAxis[0].size() > 4 && subReferenceAxis[0].substr(0,4) == "Axis") {
+ int AxId = std::atoi(subReferenceAxis[0].substr(4,4000).c_str());
+ if (AxId >= 0 && AxId < pcSketch->getAxisCount()) {
+ hasValidAxis = true;
+ axis = pcSketch->getAxis(AxId);
+ }
+ }
+ if (hasValidAxis) {
+ axis *= SketchPlm;
+ Base::Vector3d base=axis.getBase();
+ Base::Vector3d dir=axis.getDirection();
+ Base.setValue(base.x,base.y,base.z);
+ Axis.setValue(dir.x,dir.y,dir.z);
+ }
+ }
+
+ // get revolve axis
+ Base::Vector3f b = Base.getValue();
+ gp_Pnt pnt(b.x,b.y,b.z);
+ Base::Vector3f v = Axis.getValue();
+ gp_Dir dir(v.x,v.y,v.z);
+
+ // get the support of the Sketch if any
+ App::DocumentObject* pcSupport = pcSketch->Support.getValue();
+ Part::Feature *SupportObject = 0;
+ if (pcSupport && pcSupport->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId()))
+ SupportObject = static_cast(pcSupport);
+
+ TopoDS_Shape aFace = makeFace(wires);
+ if (aFace.IsNull())
+ return new App::DocumentObjectExecReturn("Creating a face from sketch failed");
+
+ // Rotate the face by half the angle to get Groove symmetric to sketch plane
+ if (Midplane.getValue()) {
+ gp_Trsf mov;
+ mov.SetRotation(gp_Ax1(pnt, dir), Base::toRadians(Angle.getValue()) * (-1.0) / 2.0);
+ TopLoc_Location loc(mov);
+ aFace.Move(loc);
+ }
+
+ this->positionBySketch();
+ TopLoc_Location invObjLoc = this->getLocation().Inverted();
+ pnt.Transform(invObjLoc.Transformation());
+ dir.Transform(invObjLoc.Transformation());
+
+ // Reverse angle if selected
+ double angle = Base::toRadians(Angle.getValue());
+ if (Reversed.getValue() && !Midplane.getValue())
+ angle *= (-1.0);
+
+ try {
+ // revolve the face to a solid
+ BRepPrimAPI_MakeRevol RevolMaker(aFace.Moved(invObjLoc), gp_Ax1(pnt, dir), angle);
+
+ if (RevolMaker.IsDone()) {
+ TopoDS_Shape result = RevolMaker.Shape();
+ // if the sketch has a support fuse them to get one result object (PAD!)
+ if (SupportObject) {
+ const TopoDS_Shape& support = SupportObject->Shape.getValue();
+ if (!support.IsNull() && support.ShapeType() == TopAbs_SOLID) {
+ // Let's call algorithm computing a fuse operation:
+ BRepAlgoAPI_Cut mkCut(support.Moved(invObjLoc), result);
+ // Let's check if the fusion has been successful
+ if (!mkCut.IsDone())
+ throw Base::Exception("Cut out of support failed");
+ result = mkCut.Shape();
+ }
+ }
+
+ this->Shape.setValue(result);
+ }
+ else
+ return new App::DocumentObjectExecReturn("Could not revolve the sketch!");
+
+ return App::DocumentObject::StdReturn;
+ }
+ catch (Standard_Failure) {
+ Handle_Standard_Failure e = Standard_Failure::Caught();
+ return new App::DocumentObjectExecReturn(e->GetMessageString());
+ }
+}
+
+}
diff --git a/src/Mod/PartDesign/App/FeatureGroove.h b/src/Mod/PartDesign/App/FeatureGroove.h
new file mode 100644
index 000000000..782e728cb
--- /dev/null
+++ b/src/Mod/PartDesign/App/FeatureGroove.h
@@ -0,0 +1,66 @@
+/***************************************************************************
+ * Copyright (c) 2010 Juergen Riegel *
+ * *
+ * 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 PARTDESIGN_Groove_H
+#define PARTDESIGN_Groove_H
+
+#include
+#include "FeatureSketchBased.h"
+
+namespace PartDesign
+{
+
+class Groove : public SketchBased
+{
+ PROPERTY_HEADER(PartDesign::Groove);
+
+public:
+ Groove();
+
+ App::PropertyVector Base;
+ App::PropertyVector Axis;
+ App::PropertyAngle Angle;
+ App::PropertyBool Midplane;
+ App::PropertyBool Reversed;
+
+ /** if this property is set to a valid link, both Axis and Base properties
+ * are calculated according to the linked line
+ */
+ App::PropertyLinkSub ReferenceAxis;
+
+ /** @name methods override feature */
+ //@{
+ /// recalculate the feature
+ App::DocumentObjectExecReturn *execute(void);
+ short mustExecute() const;
+ /// returns the type name of the view provider
+ const char* getViewProviderName(void) const {
+ return "PartDesignGui::ViewProviderGroove";
+ }
+ //@}
+};
+
+} //namespace PartDesign
+
+
+#endif // PART_Groove_H
diff --git a/src/Mod/PartDesign/App/FeaturePad.cpp b/src/Mod/PartDesign/App/FeaturePad.cpp
index 1a12c4556..8335668ae 100644
--- a/src/Mod/PartDesign/App/FeaturePad.cpp
+++ b/src/Mod/PartDesign/App/FeaturePad.cpp
@@ -23,14 +23,12 @@
#include "PreCompiled.h"
#ifndef _PreComp_
-//# include
-//# include
# include
+# include
# include
# include
# include
# include
-//# include
# include
# include
# include
@@ -39,23 +37,32 @@
# include
# include
# include
+# include
+# include
#endif
#include
#include
+#include
#include "FeaturePad.h"
using namespace PartDesign;
+const char* Pad::TypeEnums[]= {"Length","UpToLast","UpToFirst","UpToFace","TwoLengths",NULL};
+
PROPERTY_SOURCE(PartDesign::Pad, PartDesign::Additive)
Pad::Pad()
{
+ ADD_PROPERTY(Type,((long)0));
+ Type.setEnums(TypeEnums);
ADD_PROPERTY(Length,(100.0));
ADD_PROPERTY(Reversed,(0));
- ADD_PROPERTY(MirroredExtent,(0));
+ ADD_PROPERTY(Midplane,(0));
+ ADD_PROPERTY(Length2,(100.0));
+ ADD_PROPERTY(FaceName,(""));
}
short Pad::mustExecute() const
@@ -63,8 +70,10 @@ short Pad::mustExecute() const
if (Placement.isTouched() ||
Sketch.isTouched() ||
Length.isTouched() ||
- MirroredExtent.isTouched() ||
- Reversed.isTouched())
+ Midplane.isTouched() ||
+ Reversed.isTouched() ||
+ Length2.isTouched() ||
+ FaceName.isTouched())
return 1;
return 0;
}
@@ -74,6 +83,10 @@ App::DocumentObjectExecReturn *Pad::execute(void)
double L = Length.getValue();
if (L < Precision::Confusion())
return new App::DocumentObjectExecReturn("Length of pad too small");
+ double L2 = Length2.getValue();
+ if ((std::string(Type.getValueAsString()) == "TwoLengths") && (L < Precision::Confusion()))
+ return new App::DocumentObjectExecReturn("Second length of pad too small");
+
App::DocumentObject* link = Sketch.getValue();
if (!link)
return new App::DocumentObjectExecReturn("No sketch linked");
@@ -103,10 +116,8 @@ App::DocumentObjectExecReturn *Pad::execute(void)
// get the Sketch plane
Base::Placement SketchPos = static_cast(link)->Placement.getValue();
Base::Rotation SketchOrientation = SketchPos.getRotation();
- Base::Vector3d SketchOrientationVector(0,0,1);
- if (Reversed.getValue()) // negative direction
- SketchOrientationVector *= -1;
- SketchOrientation.multVec(SketchOrientationVector,SketchOrientationVector);
+ Base::Vector3d SketchVector(0,0,1);
+ SketchOrientation.multVec(SketchVector,SketchVector);
// get the support of the Sketch if any
App::DocumentObject* SupportLink = static_cast(link)->Support.getValue();
@@ -118,27 +129,159 @@ App::DocumentObjectExecReturn *Pad::execute(void)
if (aFace.IsNull())
return new App::DocumentObjectExecReturn("Creating a face from sketch failed");
- // lengthen the vector
- SketchOrientationVector *= L;
-
this->positionBySketch();
TopLoc_Location invObjLoc = this->getLocation().Inverted();
try {
// extrude the face to a solid
- gp_Vec vec(SketchOrientationVector.x,SketchOrientationVector.y,SketchOrientationVector.z);
- vec.Transform(invObjLoc.Transformation());
- BRepPrimAPI_MakePrism PrismMaker(aFace.Moved(invObjLoc),vec,0,1);
- if (PrismMaker.IsDone()) {
- // if the sketch has a support fuse them to get one result object (PAD!)
- if (SupportObject) {
- // At this point the prism can be a compound
- TopoDS_Shape result = PrismMaker.Shape();
- // set the additive shape property for later usage in e.g. pattern
- this->AddShape.setValue(result);
+ TopoDS_Shape prism;
+ bool isSolid = false; // support is a solid?
+ bool isSolidChecked = false; // not checked yet
+
+ if ((std::string(Type.getValueAsString()) == "UpToLast") ||
+ (std::string(Type.getValueAsString()) == "UpToFirst") ||
+ (std::string(Type.getValueAsString()) == "UpToFace"))
+ {
+ TopoDS_Face upToFace;
+ gp_Dir dir(SketchVector.x,SketchVector.y,SketchVector.z);
+
+ if ((std::string(Type.getValueAsString()) == "UpToLast") ||
+ (std::string(Type.getValueAsString()) == "UpToFirst"))
+ {
+ // Check for valid support object
+ if (!SupportObject)
+ return new App::DocumentObjectExecReturn("Cannot extrude up to face: No support in Sketch!");
const TopoDS_Shape& support = SupportObject->Shape.getValue();
- bool isSolid = false;
+ if (support.IsNull())
+ return new App::DocumentObjectExecReturn("Cannot extrude up to face: Support shape is invalid");
+ TopExp_Explorer xp (support, TopAbs_SOLID);
+ if (!xp.More())
+ return new App::DocumentObjectExecReturn("Cannot extrude up to face: Support shape is not a solid");
+ isSolid = true;
+ isSolidChecked = true;
+
+ TopoDS_Shape origFace = makeFace(wires); // original sketch face before moving one unit
+ std::vector cfaces = Part::findAllFacesCutBy(support, origFace, dir);
+ if (cfaces.empty())
+ return new App::DocumentObjectExecReturn("No faces found in this direction");
+
+ // Find nearest/furthest face
+ std::vector::const_iterator it, it_near, it_far;
+ it_near = it_far = cfaces.begin();
+ for (it = cfaces.begin(); it != cfaces.end(); it++)
+ if (it->distsq > it_far->distsq)
+ it_far = it;
+ else if (it->distsq < it_near->distsq)
+ it_near = it;
+ upToFace = (std::string(Type.getValueAsString()) == "UpToLast" ? it_far->face : it_near->face);
+ } else {
+ if (FaceName.isEmpty())
+ return new App::DocumentObjectExecReturn("Cannot extrude up to face: No face selected");
+
+ // Get active object, this is the object that the user referenced when he clicked on the face!
+ App::DocumentObject* baseLink = this->getDocument()->getActiveObject();
+
+ if (!baseLink)
+ return new App::DocumentObjectExecReturn("Cannot extrude up to face: No object linked");
+ if (!baseLink->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId()))
+ return new App::DocumentObjectExecReturn("Cannot extrude up to face: Linked object is not a Part object");
+ Part::Feature *base = static_cast(baseLink);
+ const Part::TopoShape& baseShape = base->Shape.getShape();
+ if (baseShape._Shape.IsNull())
+ return new App::DocumentObjectExecReturn("Cannot extrude up to face: Cannot work on invalid shape");
+
+ TopoDS_Shape sub = baseShape.getSubShape(FaceName.getValue());
+ if (!sub.IsNull() && sub.ShapeType() == TopAbs_FACE)
+ upToFace = TopoDS::Face(sub);
+ else
+ return new App::DocumentObjectExecReturn("Cannot extrude up to face: Selection is not a face");
+
+ // Validate face
+ // TODO: This would also exclude faces that are valid but not cut by the line
+ // So for now we trust to the intelligence of the user when picking the face
+ /*std::vector cfaces = findAllFacesCutBy(upToFace, origFace, dir);
+ if (cfaces.empty())
+ return new App::DocumentObjectExecReturn("No faces found in this direction");*/
+ }
+
+ // Create semi-infinite prism from sketch in direction dir
+ // Hack, because the two lines commented out below do NOT work!!!
+ SketchVector *= 1E6;
+ gp_Vec vec(SketchVector.x,SketchVector.y,SketchVector.z);
+ vec.Transform(invObjLoc.Transformation());
+ BRepPrimAPI_MakePrism PrismMaker(aFace.Moved(invObjLoc),vec,0,1); // very long, but finite prism
+ //dir.Transform(invObjLoc.Transformation());
+ //BRepPrimAPI_MakePrism PrismMaker(aFace.Moved(invObjLoc),dir,0,0,1);
+ if (!PrismMaker.IsDone())
+ return new App::DocumentObjectExecReturn("Cannot extrude up to face: Could not extrude the sketch!");
+
+ // Cut off the prism at the face we found
+ // Grab any point from the sketch
+ TopExp_Explorer exp;
+ exp.Init(aFace, TopAbs_VERTEX);
+ if (!exp.More())
+ return new App::DocumentObjectExecReturn("Cannot extrude up to face: Sketch without points?");
+ gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(exp.Current()));
+
+ // Create a halfspace from the face, extending in direction of sketch plane
+ BRepPrimAPI_MakeHalfSpace mkHalfSpace(upToFace, aPnt);
+ if (!mkHalfSpace.IsDone())
+ return new App::DocumentObjectExecReturn("Cannot extrude up to face: HalfSpace creation failed");
+
+ // Find common material between halfspace and prism
+ BRepAlgoAPI_Common mkCommon(PrismMaker.Shape(), mkHalfSpace.Solid().Moved(invObjLoc));
+ if (!mkCommon.IsDone())
+ return new App::DocumentObjectExecReturn("Cannot extrude up to face: Common creation failed");
+
+ prism = this->getSolid(mkCommon.Shape());
+ if (prism.IsNull())
+ return new App::DocumentObjectExecReturn("Cannot extrude up to face: Resulting shape is not a solid");
+ } else if ((std::string(Type.getValueAsString()) == "Length") ||
+ (std::string(Type.getValueAsString()) == "TwoLengths")) {
+ if (std::string(Type.getValueAsString()) == "Length") {
+ if (Midplane.getValue()) {
+ // Move face by half the extrusion distance to get pad symmetric to sketch plane
+ gp_Trsf mov;
+ mov.SetTranslation(gp_Vec(SketchVector.x,SketchVector.y,SketchVector.z) * (-1.0) * L/2.0);
+ TopLoc_Location loc(mov);
+ aFace.Move(loc);
+ } else if (Reversed.getValue()) { // negative direction
+ SketchVector *= -1.0;
+ }
+
+ // lengthen the vector
+ SketchVector *= L;
+ } else {
+ // Move face by the second length to get pad extending to both sides of sketch plane
+ gp_Trsf mov;
+ mov.SetTranslation(gp_Vec(SketchVector.x,SketchVector.y,SketchVector.z) * (-1.0) * L2);
+ TopLoc_Location loc(mov);
+ aFace.Move(loc);
+
+ // lengthen the vector
+ SketchVector *= (L + L2);
+ }
+
+ // create the extrusion
+ gp_Vec vec(SketchVector.x,SketchVector.y,SketchVector.z);
+ vec.Transform(invObjLoc.Transformation());
+ BRepPrimAPI_MakePrism PrismMaker(aFace.Moved(invObjLoc),vec,0,1); // finite prism
+ if (!PrismMaker.IsDone())
+ return new App::DocumentObjectExecReturn("Could not extrude the sketch!");
+ prism = PrismMaker.Shape();
+ } else {
+ return new App::DocumentObjectExecReturn("Internal error: Unknown type for Pad feature");
+ }
+
+ // if the sketch has a support fuse them to get one result object (PAD!)
+ if (SupportObject) {
+ // set the additive shape property for later usage in e.g. pattern
+ this->AddShape.setValue(prism);
+
+ const TopoDS_Shape& support = SupportObject->Shape.getValue();
+
+ if (!isSolidChecked) { // we haven't checked for solid, yet
if (!support.IsNull()) {
TopExp_Explorer xp;
xp.Init(support,TopAbs_SOLID);
@@ -147,32 +290,30 @@ App::DocumentObjectExecReturn *Pad::execute(void)
break;
}
}
- if (isSolid) {
- // Let's call algorithm computing a fuse operation:
- BRepAlgoAPI_Fuse mkFuse(support.Moved(invObjLoc), result);
- // Let's check if the fusion has been successful
- if (!mkFuse.IsDone())
- return new App::DocumentObjectExecReturn("Fusion with support failed");
- result = mkFuse.Shape();
- // we have to get the solids (fuse create seldomly compounds)
- TopoDS_Shape solRes = this->getSolid(result);
- // lets check if the result is a solid
- if (solRes.IsNull())
- return new App::DocumentObjectExecReturn("Resulting shape is not a solid");
- this->Shape.setValue(solRes);
- }
- else
+
+ if (!isSolid)
return new App::DocumentObjectExecReturn("Support is not a solid");
}
- else {
- TopoDS_Shape result = this->getSolid(PrismMaker.Shape());
- // set the additive shape property for later usage in e.g. pattern
- this->AddShape.setValue(result);
- this->Shape.setValue(result);
- }
+
+ // Let's call algorithm computing a fuse operation:
+ BRepAlgoAPI_Fuse mkFuse(support.Moved(invObjLoc), prism);
+ // Let's check if the fusion has been successful
+ if (!mkFuse.IsDone())
+ return new App::DocumentObjectExecReturn("Fusion with support failed");
+ TopoDS_Shape result = mkFuse.Shape();
+ // we have to get the solids (fuse create seldomly compounds)
+ TopoDS_Shape solRes = this->getSolid(result);
+ // lets check if the result is a solid
+ if (solRes.IsNull())
+ return new App::DocumentObjectExecReturn("Resulting shape is not a solid");
+ this->Shape.setValue(solRes);
+ }
+ else {
+ TopoDS_Shape result = this->getSolid(prism);
+ // set the additive shape property for later usage in e.g. pattern
+ this->AddShape.setValue(result);
+ this->Shape.setValue(result);
}
- else
- return new App::DocumentObjectExecReturn("Could not extrude the sketch!");
return App::DocumentObject::StdReturn;
}
diff --git a/src/Mod/PartDesign/App/FeaturePad.h b/src/Mod/PartDesign/App/FeaturePad.h
index c758c94f7..91bdeff59 100644
--- a/src/Mod/PartDesign/App/FeaturePad.h
+++ b/src/Mod/PartDesign/App/FeaturePad.h
@@ -38,10 +38,13 @@ class Pad : public Additive
public:
Pad();
- App::PropertyLength Length;
+ App::PropertyEnumeration Type;
+ App::PropertyLength Length;
//App::PropertyEnumeration Side;
- App::PropertyBool Reversed;
- App::PropertyBool MirroredExtent;
+ App::PropertyBool Reversed;
+ App::PropertyBool Midplane;
+ App::PropertyLength Length2;
+ App::PropertyString FaceName;
/** @name methods override feature */
//@{
@@ -54,7 +57,8 @@ public:
}
//@}
private:
- static const char* SideEnums[];
+ static const char* TypeEnums[];
+ //static const char* SideEnums[];
};
} //namespace PartDesign
diff --git a/src/Mod/PartDesign/App/FeaturePocket.cpp b/src/Mod/PartDesign/App/FeaturePocket.cpp
index c7f4fa8ac..a0ef1cdd4 100644
--- a/src/Mod/PartDesign/App/FeaturePocket.cpp
+++ b/src/Mod/PartDesign/App/FeaturePocket.cpp
@@ -27,6 +27,7 @@
# include
# include
# include
+# include
# include
# include
# include
@@ -40,17 +41,20 @@
# include
# include
# include
+# include
+# include
#endif
#include
#include
+#include
#include "FeaturePocket.h"
using namespace PartDesign;
-const char* Pocket::TypeEnums[]= {"Length","UpToLast","UpToFirst",NULL};
+const char* Pocket::TypeEnums[]= {"Length","UpToLast","UpToFirst","ThroughAll","UpToFace",NULL};
PROPERTY_SOURCE(PartDesign::Pocket, PartDesign::SketchBased)
@@ -59,13 +63,15 @@ Pocket::Pocket()
ADD_PROPERTY(Type,((long)0));
Type.setEnums(TypeEnums);
ADD_PROPERTY(Length,(100.0));
+ ADD_PROPERTY(FaceName,(""));
}
short Pocket::mustExecute() const
{
if (Placement.isTouched() ||
Sketch.isTouched() ||
- Length.isTouched())
+ Length.isTouched() ||
+ FaceName.isTouched())
return 1;
return 0;
}
@@ -113,13 +119,22 @@ App::DocumentObjectExecReturn *Pocket::execute(void)
if (!SupportObject)
return new App::DocumentObjectExecReturn("No support in Sketch!");
+ const TopoDS_Shape& support = SupportObject->Shape.getValue();
+ if (support.IsNull())
+ return new App::DocumentObjectExecReturn("Support shape is invalid");
+ TopExp_Explorer xp (support, TopAbs_SOLID);
+ if (!xp.More())
+ return new App::DocumentObjectExecReturn("Support shape is not a solid");
+
TopoDS_Shape aFace = makeFace(wires);
if (aFace.IsNull())
return new App::DocumentObjectExecReturn("Creating a face from sketch failed");
// This is a trick to avoid problems with the cut operation. Sometimes a cut doesn't
- // work as expected if faces or coincident. Thus, we move the face in normal direction
+ // work as expected if faces are coincident. Thus, we move the face in normal direction
// but make it longer by one unit in the opposite direction.
+ // TODO: Isn't one unit (one millimeter) a lot, assuming someone models a really tiny solid?
+ // What about using 2 * Precision::Confusion() ?
gp_Trsf mov;
mov.SetTranslation(gp_Vec(SketchVector.x,SketchVector.y,SketchVector.z));
TopLoc_Location loc(mov);
@@ -134,39 +149,133 @@ App::DocumentObjectExecReturn *Pocket::execute(void)
this->positionBySketch();
TopLoc_Location invObjLoc = this->getLocation().Inverted();
- // extrude the face to a solid
- gp_Vec vec(SketchVector.x,SketchVector.y,SketchVector.z);
- vec.Transform(invObjLoc.Transformation());
- BRepPrimAPI_MakePrism PrismMaker(aFace.Moved(invObjLoc),vec,0,1);
- if (PrismMaker.IsDone()) {
- // if the sketch has a support fuse them to get one result object (PAD!)
- if (SupportObject) {
- const TopoDS_Shape& support = SupportObject->Shape.getValue();
- if (support.IsNull())
- return new App::DocumentObjectExecReturn("Support shape is invalid");
- TopExp_Explorer xp (support, TopAbs_SOLID);
- if (!xp.More())
- return new App::DocumentObjectExecReturn("Support shape is not a solid");
- // Let's call algorithm computing a fuse operation:
- BRepAlgoAPI_Cut mkCut(support.Moved(invObjLoc), PrismMaker.Shape());
- // Let's check if the fusion has been successful
- if (!mkCut.IsDone())
- return new App::DocumentObjectExecReturn("Cut with support failed");
+ try {
+ // extrude the face to a solid
+ TopoDS_Shape prism;
- // we have to get the solids (fuse create seldomly compounds)
- TopoDS_Shape solRes = this->getSolid(mkCut.Shape());
- if (solRes.IsNull())
- return new App::DocumentObjectExecReturn("Resulting shape is not a solid");
+ if ((std::string(Type.getValueAsString()) == "UpToLast") ||
+ (std::string(Type.getValueAsString()) == "UpToFirst") ||
+ (std::string(Type.getValueAsString()) == "UpToFace"))
+ {
+ TopoDS_Face upToFace;
+ gp_Dir dir(SketchVector.x,SketchVector.y,SketchVector.z);
- this->Shape.setValue(solRes);
- }
- else {
- return new App::DocumentObjectExecReturn("Cannot create a tool out of sketch with no support");
+ if ((std::string(Type.getValueAsString()) == "UpToLast") ||
+ (std::string(Type.getValueAsString()) == "UpToFirst"))
+ {
+ TopoDS_Shape origFace = makeFace(wires); // original sketch face before moving one unit
+ std::vector cfaces = Part::findAllFacesCutBy(support, origFace, dir);
+ if (cfaces.empty())
+ return new App::DocumentObjectExecReturn("No faces found in this direction");
+
+ // Find nearest/furthest face
+ std::vector::const_iterator it, it_near, it_far;
+ it_near = it_far = cfaces.begin();
+ for (it = cfaces.begin(); it != cfaces.end(); it++)
+ if (it->distsq > it_far->distsq)
+ it_far = it;
+ else if (it->distsq < it_near->distsq)
+ it_near = it;
+ upToFace = (std::string(Type.getValueAsString()) == "UpToLast" ? it_far->face : it_near->face);
+ } else {
+ if (FaceName.getValue() == "")
+ return new App::DocumentObjectExecReturn("Cannot extrude up to face: No face selected");
+
+ // Get active object, this is the object that the user referenced when he clicked on the face!
+ App::DocumentObject* baseLink = this->getDocument()->getActiveObject();
+
+ if (!baseLink)
+ return new App::DocumentObjectExecReturn("Cannot extrude up to face: No object linked");
+ if (!baseLink->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId()))
+ return new App::DocumentObjectExecReturn("Cannot extrude up to face: Linked object is not a Part object");
+ Part::Feature *base = static_cast(baseLink);
+ const Part::TopoShape& baseShape = base->Shape.getShape();
+ if (baseShape._Shape.IsNull())
+ return new App::DocumentObjectExecReturn("Cannot extrude up to face: Cannot work on invalid shape");
+
+ TopoDS_Shape sub = baseShape.getSubShape(FaceName.getValue());
+ if (!sub.IsNull() && sub.ShapeType() == TopAbs_FACE)
+ upToFace = TopoDS::Face(sub);
+ else
+ return new App::DocumentObjectExecReturn("Cannot extrude up to face: Selection is not a face");
+
+ // Find the origin of this face (i.e. a vertex or a edge in a sketch)
+ TopoDS_Shape origin = base->findOriginOf(sub);
+
+ // Validate face
+ // TODO: This would also exclude faces that are valid but not cut by the line
+ // So for now we trust to the intelligence of the user when picking the face
+ /*std::vector cfaces = findAllFacesCutBy(upToFace, origFace, dir);
+ if (cfaces.empty())
+ return new App::DocumentObjectExecReturn("No faces found in this direction");*/
+ }
+
+ // Create semi-infinite prism from sketch in direction dir
+ dir.Transform(invObjLoc.Transformation());
+ BRepPrimAPI_MakePrism PrismMaker(aFace.Moved(invObjLoc),dir,0,0,1);
+ if (!PrismMaker.IsDone())
+ return new App::DocumentObjectExecReturn("Cannot extrude up to face: Could not extrude the sketch!");
+
+ // Cut off the prism at the face we found
+ // Grab any point from the sketch
+ TopExp_Explorer exp;
+ exp.Init(aFace, TopAbs_VERTEX);
+ if (!exp.More())
+ return new App::DocumentObjectExecReturn("Cannot extrude up to face: Sketch without points?");
+ gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(exp.Current()));
+
+ // Create a halfspace from the face, extending in direction of sketch plane
+ BRepPrimAPI_MakeHalfSpace mkHalfSpace(upToFace, aPnt);
+ if (!mkHalfSpace.IsDone())
+ return new App::DocumentObjectExecReturn("Cannot extrude up to face: HalfSpace creation failed");
+
+ // Find common material between halfspace and prism
+ BRepAlgoAPI_Common mkCommon(PrismMaker.Shape(), mkHalfSpace.Solid().Moved(invObjLoc));
+ if (!mkCommon.IsDone())
+ return new App::DocumentObjectExecReturn("Cannot extrude up to face: Common creation failed");
+
+ prism = this->getSolid(mkCommon.Shape());
+ if (prism.IsNull())
+ return new App::DocumentObjectExecReturn("Cannot extrude up to face: Resulting shape is not a solid");
+ } else if (std::string(Type.getValueAsString()) == "ThroughAll") {
+ gp_Dir dir(SketchVector.x,SketchVector.y,SketchVector.z);
+ dir.Transform(invObjLoc.Transformation());
+ BRepPrimAPI_MakePrism PrismMaker(aFace.Moved(invObjLoc),dir,1,0,1); // infinite prism (in both directions!)
+ if (!PrismMaker.IsDone())
+ return new App::DocumentObjectExecReturn("Could not extrude the sketch!");
+ prism = PrismMaker.Shape();
+ } else if (std::string(Type.getValueAsString()) == "Length") {
+ gp_Vec vec(SketchVector.x,SketchVector.y,SketchVector.z);
+ vec.Transform(invObjLoc.Transformation());
+ BRepPrimAPI_MakePrism PrismMaker(aFace.Moved(invObjLoc),vec,0,1); // finite prism
+ if (!PrismMaker.IsDone())
+ return new App::DocumentObjectExecReturn("Could not extrude the sketch!");
+ prism = PrismMaker.Shape();
+ } else {
+ return new App::DocumentObjectExecReturn("Internal error: Unknown type for Pocket feature");
}
+
+ // TODO: Set the subtractive shape property for later usage in e.g. pattern
+ //this->SubShape.setValue(prism); // This crashes with "Illegal storage access". Why?
+
+ // Cut out the pocket
+ BRepAlgoAPI_Cut mkCut(support.Moved(invObjLoc), prism);
+
+ // Let's check if the fusion has been successful
+ if (!mkCut.IsDone())
+ return new App::DocumentObjectExecReturn("Cut with support failed");
+
+ // we have to get the solids (fuse sometimes creates compounds)
+ TopoDS_Shape solRes = this->getSolid(mkCut.Shape());
+ if (solRes.IsNull())
+ return new App::DocumentObjectExecReturn("Resulting shape is not a solid");
+
+ this->Shape.setValue(solRes);
+
+ return App::DocumentObject::StdReturn;
+ } catch (Standard_Failure) {
+ Handle_Standard_Failure e = Standard_Failure::Caught();
+ return new App::DocumentObjectExecReturn(e->GetMessageString());
}
- else
- return new App::DocumentObjectExecReturn("Could not extrude the sketch!");
-
- return App::DocumentObject::StdReturn;
}
diff --git a/src/Mod/PartDesign/App/FeaturePocket.h b/src/Mod/PartDesign/App/FeaturePocket.h
index 7a7d57962..b9b47aa72 100644
--- a/src/Mod/PartDesign/App/FeaturePocket.h
+++ b/src/Mod/PartDesign/App/FeaturePocket.h
@@ -39,6 +39,7 @@ public:
App::PropertyEnumeration Type;
App::PropertyLength Length;
+ App::PropertyString FaceName;
/** @name methods override feature */
//@{
diff --git a/src/Mod/PartDesign/App/FeatureRevolution.cpp b/src/Mod/PartDesign/App/FeatureRevolution.cpp
index 317aa52d1..a31bebf43 100644
--- a/src/Mod/PartDesign/App/FeatureRevolution.cpp
+++ b/src/Mod/PartDesign/App/FeatureRevolution.cpp
@@ -52,10 +52,12 @@ PROPERTY_SOURCE(PartDesign::Revolution, PartDesign::SketchBased)
Revolution::Revolution()
{
- ADD_PROPERTY(Base,(Base::Vector3f(0.0f,0.0f,0.0f)));
- ADD_PROPERTY(Axis,(Base::Vector3f(0.0f,1.0f,0.0f)));
- ADD_PROPERTY(Angle,(360.0));
- ADD_PROPERTY_TYPE(ReferenceAxis,(0),"Revolution",(App::PropertyType)(App::Prop_None),"Reference axis of revolution");
+ ADD_PROPERTY_TYPE(Base,(Base::Vector3f(0.0f,0.0f,0.0f)),"Revolution", App::Prop_ReadOnly, "Base");
+ ADD_PROPERTY_TYPE(Axis,(Base::Vector3f(0.0f,1.0f,0.0f)),"Revolution", App::Prop_ReadOnly, "Axis");
+ ADD_PROPERTY_TYPE(Angle,(360.0),"Revolution", App::Prop_None, "Angle");
+ ADD_PROPERTY_TYPE(ReferenceAxis,(0),"Revolution",(App::Prop_None),"Reference axis of revolution");
+ ADD_PROPERTY_TYPE(Midplane,(0),"Revolution", App::Prop_None, "Mid plane");
+ ADD_PROPERTY_TYPE(Reversed, (0),"Revolution", App::Prop_None, "Reversed");
}
short Revolution::mustExecute() const
@@ -65,7 +67,9 @@ short Revolution::mustExecute() const
ReferenceAxis.isTouched() ||
Axis.isTouched() ||
Base.isTouched() ||
- Angle.isTouched())
+ Angle.isTouched() ||
+ Midplane.isTouched() ||
+ Reversed.isTouched())
return 1;
return 0;
}
@@ -151,35 +155,54 @@ App::DocumentObjectExecReturn *Revolution::execute(void)
if (aFace.IsNull())
return new App::DocumentObjectExecReturn("Creating a face from sketch failed");
+ // Rotate the face by half the angle to get revolution symmetric to sketch plane
+ if (Midplane.getValue()) {
+ gp_Trsf mov;
+ mov.SetRotation(gp_Ax1(pnt, dir), Base::toRadians(Angle.getValue()) * (-1.0) / 2.0);
+ TopLoc_Location loc(mov);
+ aFace.Move(loc);
+ }
+
this->positionBySketch();
TopLoc_Location invObjLoc = this->getLocation().Inverted();
pnt.Transform(invObjLoc.Transformation());
dir.Transform(invObjLoc.Transformation());
- // revolve the face to a solid
- BRepPrimAPI_MakeRevol RevolMaker(aFace.Moved(invObjLoc), gp_Ax1(pnt, dir), Base::toRadians(Angle.getValue()));
+ // Reverse angle if selected
+ double angle = Base::toRadians(Angle.getValue());
+ if (Reversed.getValue() && !Midplane.getValue())
+ angle *= (-1.0);
- if (RevolMaker.IsDone()) {
- TopoDS_Shape result = RevolMaker.Shape();
- // if the sketch has a support fuse them to get one result object (PAD!)
- if (SupportObject) {
- const TopoDS_Shape& support = SupportObject->Shape.getValue();
- if (!support.IsNull() && support.ShapeType() == TopAbs_SOLID) {
- // Let's call algorithm computing a fuse operation:
- BRepAlgoAPI_Fuse mkFuse(support.Moved(invObjLoc), result);
- // Let's check if the fusion has been successful
- if (!mkFuse.IsDone())
- throw Base::Exception("Fusion with support failed");
- result = mkFuse.Shape();
+ try {
+ // revolve the face to a solid
+ BRepPrimAPI_MakeRevol RevolMaker(aFace.Moved(invObjLoc), gp_Ax1(pnt, dir), angle);
+
+ if (RevolMaker.IsDone()) {
+ TopoDS_Shape result = RevolMaker.Shape();
+ // if the sketch has a support fuse them to get one result object (PAD!)
+ if (SupportObject) {
+ const TopoDS_Shape& support = SupportObject->Shape.getValue();
+ if (!support.IsNull() && support.ShapeType() == TopAbs_SOLID) {
+ // Let's call algorithm computing a fuse operation:
+ BRepAlgoAPI_Fuse mkFuse(support.Moved(invObjLoc), result);
+ // Let's check if the fusion has been successful
+ if (!mkFuse.IsDone())
+ throw Base::Exception("Fusion with support failed");
+ result = mkFuse.Shape();
+ }
}
+
+ this->Shape.setValue(result);
}
+ else
+ return new App::DocumentObjectExecReturn("Could not revolve the sketch!");
- this->Shape.setValue(result);
+ return App::DocumentObject::StdReturn;
+ }
+ catch (Standard_Failure) {
+ Handle_Standard_Failure e = Standard_Failure::Caught();
+ return new App::DocumentObjectExecReturn(e->GetMessageString());
}
- else
- return new App::DocumentObjectExecReturn("Could not revolve the sketch!");
-
- return App::DocumentObject::StdReturn;
}
}
diff --git a/src/Mod/PartDesign/App/FeatureRevolution.h b/src/Mod/PartDesign/App/FeatureRevolution.h
index 4d6677d54..ed11adc06 100644
--- a/src/Mod/PartDesign/App/FeatureRevolution.h
+++ b/src/Mod/PartDesign/App/FeatureRevolution.h
@@ -39,7 +39,9 @@ public:
App::PropertyVector Base;
App::PropertyVector Axis;
- App::PropertyAngle Angle;
+ App::PropertyAngle Angle;
+ App::PropertyBool Midplane;
+ App::PropertyBool Reversed;
/** if this property is set to a valid link, both Axis and Base properties
* are calculated according to the linked line
diff --git a/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp b/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp
index d86285fbe..32e718778 100644
--- a/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp
+++ b/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp
@@ -37,6 +37,7 @@
#include "ViewProviderChamfer.h"
#include "ViewProviderFillet.h"
#include "ViewProviderRevolution.h"
+#include "ViewProviderGroove.h"
//#include "resources/qrc_PartDesign.cpp"
@@ -83,6 +84,7 @@ void PartDesignGuiExport initPartDesignGui()
PartDesignGui::ViewProviderPocket ::init();
PartDesignGui::ViewProviderPad ::init();
PartDesignGui::ViewProviderRevolution::init();
+ PartDesignGui::ViewProviderGroove ::init();
PartDesignGui::ViewProviderChamfer ::init();
PartDesignGui::ViewProviderFillet ::init();
diff --git a/src/Mod/PartDesign/Gui/CMakeLists.txt b/src/Mod/PartDesign/Gui/CMakeLists.txt
index 8f6e26556..0aa1cb918 100644
--- a/src/Mod/PartDesign/Gui/CMakeLists.txt
+++ b/src/Mod/PartDesign/Gui/CMakeLists.txt
@@ -32,6 +32,7 @@ set(PartDesignGui_MOC_HDRS
TaskFilletParameters.h
TaskHoleParameters.h
TaskRevolutionParameters.h
+ TaskGrooveParameters.h
)
fc_wrap_cpp(PartDesignGui_MOC_SRCS ${PartDesignGui_MOC_HDRS})
SOURCE_GROUP("Moc" FILES ${PartDesignGui_MOC_SRCS})
@@ -46,6 +47,7 @@ set(PartDesignGui_UIC_SRCS
TaskFilletParameters.ui
TaskHoleParameters.ui
TaskRevolutionParameters.ui
+ TaskGrooveParameters.ui
)
qt4_wrap_ui(PartDesignGui_UIC_HDRS ${PartDesignGui_UIC_SRCS})
@@ -64,6 +66,8 @@ SET(PartDesignGuiViewProvider_SRCS
ViewProviderFillet.h
ViewProviderRevolution.cpp
ViewProviderRevolution.h
+ ViewProviderGroove.cpp
+ ViewProviderGroove.h
ViewProviderPatternRectangular.cpp
ViewProviderPatternRectangular.h
)
@@ -88,6 +92,9 @@ SET(PartDesignGuiTaskDlgs_SRCS
TaskRevolutionParameters.ui
TaskRevolutionParameters.cpp
TaskRevolutionParameters.h
+ TaskGrooveParameters.ui
+ TaskGrooveParameters.cpp
+ TaskGrooveParameters.h
TaskHoleParameters.ui
TaskHoleParameters.cpp
TaskHoleParameters.h
diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp
index 37e02dc6a..335d6d5dd 100644
--- a/src/Mod/PartDesign/Gui/Command.cpp
+++ b/src/Mod/PartDesign/Gui/Command.cpp
@@ -327,6 +327,82 @@ bool CmdPartDesignRevolution::isActive(void)
return hasActiveDocument();
}
+//===========================================================================
+// PartDesign_Groove
+//===========================================================================
+DEF_STD_CMD_A(CmdPartDesignGroove);
+
+CmdPartDesignGroove::CmdPartDesignGroove()
+ : Command("PartDesign_Groove")
+{
+ sAppModule = "PartDesign";
+ sGroup = QT_TR_NOOP("PartDesign");
+ sMenuText = QT_TR_NOOP("Groove");
+ sToolTipText = QT_TR_NOOP("Groove a selected sketch");
+ sWhatsThis = sToolTipText;
+ sStatusTip = sToolTipText;
+ sPixmap = "PartDesign_Groove";
+}
+
+void CmdPartDesignGroove::activated(int iMsg)
+{
+ unsigned int n = getSelection().countObjectsOfType(Part::Part2DObject::getClassTypeId());
+ if (n != 1) {
+ QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
+ QObject::tr("Select a sketch or 2D object."));
+ return;
+ }
+
+ std::string FeatName = getUniqueObjectName("Groove");
+
+ std::vector Sel = getSelection().getObjectsOfType(Part::Part2DObject::getClassTypeId());
+ Part::Part2DObject* sketch = static_cast(Sel.front());
+ const TopoDS_Shape& shape = sketch->Shape.getValue();
+ if (shape.IsNull()) {
+ QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
+ QObject::tr("The shape of the selected object is empty."));
+ return;
+ }
+
+ // count free wires
+ int ctWires=0;
+ TopExp_Explorer ex;
+ for (ex.Init(shape, TopAbs_WIRE); ex.More(); ex.Next()) {
+ ctWires++;
+ }
+ if (ctWires == 0) {
+ QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
+ QObject::tr("The shape of the selected object is not a wire."));
+ return;
+ }
+
+ App::DocumentObject* support = sketch->Support.getValue();
+
+ openCommand("Make Groove");
+ doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Groove\",\"%s\")",FeatName.c_str());
+ doCommand(Doc,"App.activeDocument().%s.Sketch = App.activeDocument().%s",FeatName.c_str(),sketch->getNameInDocument());
+ doCommand(Doc,"App.activeDocument().%s.ReferenceAxis = (App.activeDocument().%s,['V_Axis'])",
+ FeatName.c_str(), sketch->getNameInDocument());
+ doCommand(Doc,"App.activeDocument().%s.Angle = 360.0",FeatName.c_str());
+ updateActive();
+ if (isActiveObjectValid()) {
+ doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",sketch->getNameInDocument());
+ if (support)
+ doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",support->getNameInDocument());
+ }
+ doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str());
+
+ if (support) {
+ copyVisual(FeatName.c_str(), "ShapeColor", support->getNameInDocument());
+ copyVisual(FeatName.c_str(), "LineColor", support->getNameInDocument());
+ copyVisual(FeatName.c_str(), "PointColor", support->getNameInDocument());
+ }
+}
+
+bool CmdPartDesignGroove::isActive(void)
+{
+ return hasActiveDocument();
+}
//===========================================================================
// PartDesign_Fillet
//===========================================================================
@@ -628,6 +704,7 @@ void CreatePartDesignCommands(void)
rcCmdMgr.addCommand(new CmdPartDesignPad());
rcCmdMgr.addCommand(new CmdPartDesignPocket());
rcCmdMgr.addCommand(new CmdPartDesignRevolution());
+ rcCmdMgr.addCommand(new CmdPartDesignGroove());
rcCmdMgr.addCommand(new CmdPartDesignFillet());
//rcCmdMgr.addCommand(new CmdPartDesignNewSketch());
rcCmdMgr.addCommand(new CmdPartDesignChamfer());
diff --git a/src/Mod/PartDesign/Gui/Resources/Makefile.am b/src/Mod/PartDesign/Gui/Resources/Makefile.am
index 332007335..79bee0639 100644
--- a/src/Mod/PartDesign/Gui/Resources/Makefile.am
+++ b/src/Mod/PartDesign/Gui/Resources/Makefile.am
@@ -37,6 +37,7 @@ EXTRA_DIST = \
translations/PartDesign_uk.ts \
translations/PartDesign_zh.qm \
translations/PartDesign_zh.ts \
+ icons/PartDesign_Groove.svg \
icons/PartDesign_Pad.svg \
icons/PartDesign_Pocket.svg \
icons/PartDesign_Revolution.svg \
diff --git a/src/Mod/PartDesign/Gui/Resources/PartDesign.qrc b/src/Mod/PartDesign/Gui/Resources/PartDesign.qrc
index caff25cab..37804e403 100644
--- a/src/Mod/PartDesign/Gui/Resources/PartDesign.qrc
+++ b/src/Mod/PartDesign/Gui/Resources/PartDesign.qrc
@@ -1,5 +1,6 @@
+ icons/PartDesign_Groove.svg
icons/PartDesign_Pad.svg
icons/PartDesign_Pocket.svg
icons/PartDesign_Revolution.svg
diff --git a/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Groove.svg b/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Groove.svg
new file mode 100644
index 000000000..2c1ca60aa
--- /dev/null
+++ b/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Groove.svg
@@ -0,0 +1,144 @@
+
+
+
+
diff --git a/src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp b/src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp
new file mode 100644
index 000000000..79b0278fe
--- /dev/null
+++ b/src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp
@@ -0,0 +1,287 @@
+/***************************************************************************
+ * Copyright (c) 2011 Juergen Riegel *
+ * *
+ * 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_
+#endif
+
+#include "ui_TaskGrooveParameters.h"
+#include "TaskGrooveParameters.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+using namespace PartDesignGui;
+using namespace Gui;
+
+/* TRANSLATOR PartDesignGui::TaskGrooveParameters */
+
+TaskGrooveParameters::TaskGrooveParameters(ViewProviderGroove *GrooveView,QWidget *parent)
+ : TaskBox(Gui::BitmapFactory().pixmap("PartDesign_Groove"),tr("Groove parameters"),true, parent),GrooveView(GrooveView)
+{
+ // we need a separate container widget to add all controls to
+ proxy = new QWidget(this);
+ ui = new Ui_TaskGrooveParameters();
+ ui->setupUi(proxy);
+ QMetaObject::connectSlotsByName(this);
+
+ connect(ui->doubleSpinBox, SIGNAL(valueChanged(double)),
+ this, SLOT(onAngleChanged(double)));
+ connect(ui->axis, SIGNAL(activated(int)),
+ this, SLOT(onAxisChanged(int)));
+ connect(ui->checkBoxMidplane, SIGNAL(toggled(bool)),
+ this, SLOT(onMidplane(bool)));
+ connect(ui->checkBoxReversed, SIGNAL(toggled(bool)),
+ this, SLOT(onReversed(bool)));
+
+ this->groupLayout()->addWidget(proxy);
+
+ PartDesign::Groove* pcGroove = static_cast(GrooveView->getObject());
+ double l = pcGroove->Angle.getValue();
+ bool mirrored = pcGroove->Midplane.getValue();
+ bool reversed = pcGroove->Reversed.getValue();
+
+ ui->doubleSpinBox->setValue(l);
+
+ int count=pcGroove->getSketchAxisCount();
+
+ for (int i=ui->axis->count()-1; i >= count+2; i--)
+ ui->axis->removeItem(i);
+ for (int i=ui->axis->count(); i < count+2; i++)
+ ui->axis->addItem(QString::fromAscii("Sketch axis %1").arg(i-2));
+
+ int pos=-1;
+
+ App::DocumentObject *pcReferenceAxis = pcGroove->ReferenceAxis.getValue();
+ const std::vector &subReferenceAxis = pcGroove->ReferenceAxis.getSubValues();
+ if (pcReferenceAxis && pcReferenceAxis == pcGroove->Sketch.getValue()) {
+ assert(subReferenceAxis.size()==1);
+ if (subReferenceAxis[0] == "V_Axis")
+ pos = 0;
+ else if (subReferenceAxis[0] == "H_Axis")
+ pos = 1;
+ else if (subReferenceAxis[0].size() > 4 && subReferenceAxis[0].substr(0,4) == "Axis")
+ pos = 2 + std::atoi(subReferenceAxis[0].substr(4,4000).c_str());
+ }
+
+ if (pos < 0 || pos >= ui->axis->count()) {
+ ui->axis->addItem(QString::fromAscii("Undefined"));
+ pos = ui->axis->count()-1;
+ }
+
+ ui->axis->setCurrentIndex(pos);
+
+ ui->checkBoxMidplane->setChecked(mirrored);
+ ui->checkBoxReversed->setChecked(reversed);
+
+ setFocus ();
+}
+
+void TaskGrooveParameters::onAngleChanged(double len)
+{
+ PartDesign::Groove* pcGroove = static_cast(GrooveView->getObject());
+ pcGroove->Angle.setValue((float)len);
+ pcGroove->getDocument()->recomputeFeature(pcGroove);
+}
+
+void TaskGrooveParameters::onAxisChanged(int num)
+{
+ PartDesign::Groove* pcGroove = static_cast(GrooveView->getObject());
+ Sketcher::SketchObject *pcSketch = static_cast(pcGroove->Sketch.getValue());
+ if (pcSketch) {
+ int maxcount = pcSketch->getAxisCount()+2;
+ if (num == 0)
+ pcGroove->ReferenceAxis.setValue(pcSketch, std::vector(1,"V_Axis"));
+ else if (num == 1)
+ pcGroove->ReferenceAxis.setValue(pcSketch, std::vector(1,"H_Axis"));
+ else if (num >= 2 && num < maxcount) {
+ QString buf = QString::fromUtf8("Axis%1").arg(num-2);
+ std::string str = buf.toStdString();
+ pcGroove->ReferenceAxis.setValue(pcSketch, std::vector(1,str));
+ }
+ if (num < maxcount && ui->axis->count() > maxcount)
+ ui->axis->setMaxCount(maxcount);
+ }
+ pcGroove->getDocument()->recomputeFeature(pcGroove);
+}
+
+void TaskGrooveParameters::onMidplane(bool on)
+{
+ PartDesign::Groove* pcGroove = static_cast(GrooveView->getObject());
+ pcGroove->Midplane.setValue(on);
+ pcGroove->getDocument()->recomputeFeature(pcGroove);
+}
+
+void TaskGrooveParameters::onReversed(bool on)
+{
+ PartDesign::Groove* pcGroove = static_cast(GrooveView->getObject());
+ pcGroove->Reversed.setValue(on);
+ pcGroove->getDocument()->recomputeFeature(pcGroove);
+}
+
+
+double TaskGrooveParameters::getAngle(void) const
+{
+ return ui->doubleSpinBox->value();
+}
+
+QString TaskGrooveParameters::getReferenceAxis(void) const
+{
+ // get the support and Sketch
+ PartDesign::Groove* pcGroove = static_cast(GrooveView->getObject());
+ Sketcher::SketchObject *pcSketch = static_cast(pcGroove->Sketch.getValue());
+
+ QString buf;
+ if (pcSketch) {
+ buf = QString::fromUtf8("(App.ActiveDocument.%1,[%2])");
+ buf = buf.arg(QString::fromUtf8(pcSketch->getNameInDocument()));
+ if (ui->axis->currentIndex() == 0)
+ buf = buf.arg(QString::fromUtf8("'V_Axis'"));
+ else if (ui->axis->currentIndex() == 1)
+ buf = buf.arg(QString::fromUtf8("'H_Axis'"));
+ else if (ui->axis->currentIndex() >= 2) {
+ buf = buf.arg(QString::fromUtf8("'Axis%1'"));
+ buf = buf.arg(ui->axis->currentIndex()-2);
+ }
+ }
+ else
+ buf = QString::fromUtf8("''");
+
+ return buf;
+}
+
+bool TaskGrooveParameters::getMidplane(void) const
+{
+ return ui->checkBoxMidplane->isChecked();
+}
+
+bool TaskGrooveParameters::getReversed(void) const
+{
+ return ui->checkBoxReversed->isChecked();
+}
+
+TaskGrooveParameters::~TaskGrooveParameters()
+{
+ delete ui;
+}
+
+void TaskGrooveParameters::changeEvent(QEvent *e)
+{
+ TaskBox::changeEvent(e);
+ if (e->type() == QEvent::LanguageChange) {
+ ui->retranslateUi(proxy);
+ }
+}
+
+//**************************************************************************
+//**************************************************************************
+// TaskDialog
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+TaskDlgGrooveParameters::TaskDlgGrooveParameters(ViewProviderGroove *GrooveView)
+ : TaskDialog(),GrooveView(GrooveView)
+{
+ assert(GrooveView);
+ parameter = new TaskGrooveParameters(GrooveView);
+
+ Content.push_back(parameter);
+}
+
+TaskDlgGrooveParameters::~TaskDlgGrooveParameters()
+{
+
+}
+
+//==== calls from the TaskView ===============================================================
+
+
+void TaskDlgGrooveParameters::open()
+{
+
+}
+
+void TaskDlgGrooveParameters::clicked(int)
+{
+
+}
+
+bool TaskDlgGrooveParameters::accept()
+{
+ std::string name = GrooveView->getObject()->getNameInDocument();
+
+ //Gui::Command::openCommand("Groove changed");
+ Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Angle = %f",name.c_str(),parameter->getAngle());
+ std::string axis = parameter->getReferenceAxis().toStdString();
+ Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.ReferenceAxis = %s",name.c_str(),axis.c_str());
+ Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Midplane = %i",name.c_str(),parameter->getMidplane()?1:0);
+ Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %i",name.c_str(),parameter->getReversed()?1:0);
+ Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()");
+ Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()");
+ Gui::Command::commitCommand();
+
+ return true;
+}
+
+bool TaskDlgGrooveParameters::reject()
+{
+ // get the support and Sketch
+ PartDesign::Groove* pcGroove = static_cast(GrooveView->getObject());
+ Sketcher::SketchObject *pcSketch;
+ App::DocumentObject *pcSupport;
+ if (pcGroove->Sketch.getValue()) {
+ pcSketch = static_cast(pcGroove->Sketch.getValue());
+ pcSupport = pcSketch->Support.getValue();
+ }
+
+ // role back the done things
+ Gui::Command::abortCommand();
+ Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()");
+
+ // if abort command deleted the object the support is visible again
+ if (!Gui::Application::Instance->getViewProvider(pcGroove)) {
+ if (pcSketch && Gui::Application::Instance->getViewProvider(pcSketch))
+ Gui::Application::Instance->getViewProvider(pcSketch)->show();
+ if (pcSupport && Gui::Application::Instance->getViewProvider(pcSupport))
+ Gui::Application::Instance->getViewProvider(pcSupport)->show();
+ }
+
+ //Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()");
+ //Gui::Command::commitCommand();
+
+ return true;
+}
+
+
+
+#include "moc_TaskGrooveParameters.cpp"
diff --git a/src/Mod/PartDesign/Gui/TaskGrooveParameters.h b/src/Mod/PartDesign/Gui/TaskGrooveParameters.h
new file mode 100644
index 000000000..8b82f0187
--- /dev/null
+++ b/src/Mod/PartDesign/Gui/TaskGrooveParameters.h
@@ -0,0 +1,115 @@
+/***************************************************************************
+ * Copyright (c) 2011 Juergen Riegel *
+ * *
+ * 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 GUI_TASKVIEW_TaskGrooveParameters_H
+#define GUI_TASKVIEW_TaskGrooveParameters_H
+
+#include
+#include
+#include
+
+#include "ViewProviderGroove.h"
+
+class Ui_TaskGrooveParameters;
+
+namespace App {
+class Property;
+}
+
+namespace Gui {
+class ViewProvider;
+}
+
+namespace PartDesignGui {
+
+
+
+class TaskGrooveParameters : public Gui::TaskView::TaskBox
+{
+ Q_OBJECT
+
+public:
+ TaskGrooveParameters(ViewProviderGroove *GrooveView,QWidget *parent = 0);
+ ~TaskGrooveParameters();
+
+ QString getReferenceAxis(void) const;
+ double getAngle(void) const;
+ bool getMidplane(void) const;
+ bool getReversed(void) const;
+
+private Q_SLOTS:
+ void onAngleChanged(double);
+ void onAxisChanged(int);
+ void onMidplane(bool);
+ void onReversed(bool);
+
+protected:
+ void changeEvent(QEvent *e);
+
+private:
+
+private:
+ QWidget* proxy;
+ Ui_TaskGrooveParameters* ui;
+ ViewProviderGroove *GrooveView;
+};
+
+/// simulation dialog for the TaskView
+class TaskDlgGrooveParameters : public Gui::TaskView::TaskDialog
+{
+ Q_OBJECT
+
+public:
+ TaskDlgGrooveParameters(ViewProviderGroove *GrooveView);
+ ~TaskDlgGrooveParameters();
+
+ ViewProviderGroove* getGrooveView() const
+ { return GrooveView; }
+
+
+public:
+ /// is called the TaskView when the dialog is opened
+ virtual void open();
+ /// is called by the framework if an button is clicked which has no accept or reject role
+ virtual void clicked(int);
+ /// is called by the framework if the dialog is accepted (Ok)
+ virtual bool accept();
+ /// is called by the framework if the dialog is rejected (Cancel)
+ virtual bool reject();
+ /// is called by the framework if the user presses the help button
+ virtual bool isAllowedAlterDocument(void) const
+ { return false; }
+
+ /// returns for Close and Help button
+ virtual QDialogButtonBox::StandardButtons getStandardButtons(void) const
+ { return QDialogButtonBox::Ok|QDialogButtonBox::Cancel; }
+
+protected:
+ ViewProviderGroove *GrooveView;
+
+ TaskGrooveParameters *parameter;
+};
+
+} //namespace PartDesignGui
+
+#endif // GUI_TASKVIEW_TASKAPPERANCE_H
diff --git a/src/Mod/PartDesign/Gui/TaskGrooveParameters.ui b/src/Mod/PartDesign/Gui/TaskGrooveParameters.ui
new file mode 100644
index 000000000..d7a68d6c2
--- /dev/null
+++ b/src/Mod/PartDesign/Gui/TaskGrooveParameters.ui
@@ -0,0 +1,93 @@
+
+
+ PartDesignGui::TaskGrooveParameters
+
+
+
+ 0
+ 0
+ 278
+ 158
+
+
+
+ Form
+
+
+ -
+
+
-
+
+
+ Axis:
+
+
+
+ -
+
+
-
+
+ Vertical sketch axis
+
+
+ -
+
+ Horizontal sketch axis
+
+
+
+
+
+
+ -
+
+
-
+
+
+ Angle:
+
+
+
+ -
+
+
+ 1
+
+
+ 0.000000000000000
+
+
+ 360.000000000000000
+
+
+ 10.000000000000000
+
+
+ 360.000000000000000
+
+
+
+
+
+ -
+
+
+ true
+
+
+ Symmetric to plane
+
+
+
+ -
+
+
+ Reversed
+
+
+
+
+
+
+
+
diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp
index 8a902b2b9..d7c37b7b3 100644
--- a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp
+++ b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp
@@ -59,30 +59,106 @@ TaskPadParameters::TaskPadParameters(ViewProviderPad *PadView,QWidget *parent)
connect(ui->doubleSpinBox, SIGNAL(valueChanged(double)),
this, SLOT(onLengthChanged(double)));
- connect(ui->checkBoxMirrored, SIGNAL(toggled(bool)),
- this, SLOT(onMirrored(bool)));
+ connect(ui->checkBoxMidplane, SIGNAL(toggled(bool)),
+ this, SLOT(onMidplane(bool)));
connect(ui->checkBoxReversed, SIGNAL(toggled(bool)),
this, SLOT(onReversed(bool)));
+ connect(ui->doubleSpinBox2, SIGNAL(valueChanged(double)),
+ this, SLOT(onLength2Changed(double)));
+ connect(ui->changeMode, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(onModeChanged(int)));
+ connect(ui->lineFaceName, SIGNAL(textEdited(QString)),
+ this, SLOT(onFaceName(QString)));
this->groupLayout()->addWidget(proxy);
+ // Get the feature data
PartDesign::Pad* pcPad = static_cast(PadView->getObject());
double l = pcPad->Length.getValue();
- bool mirrored = pcPad->MirroredExtent.getValue();
+ bool midplane = pcPad->Midplane.getValue();
bool reversed = pcPad->Reversed.getValue();
+ double l2 = pcPad->Length2.getValue();
+ int index = pcPad->Type.getValue(); // must extract value here, clear() kills it!
+ const char* upToFace = pcPad->FaceName.getValue();
+ // Fill data into dialog elements
ui->doubleSpinBox->setMinimum(0);
+ ui->doubleSpinBox->setMaximum(INT_MAX);
ui->doubleSpinBox->setValue(l);
- ui->doubleSpinBox->selectAll();
- ui->checkBoxMirrored->setChecked(mirrored);
+ ui->doubleSpinBox2->setMinimum(0);
+ ui->doubleSpinBox2->setMaximum(INT_MAX);
+ ui->doubleSpinBox2->setValue(l2);
+ ui->checkBoxMidplane->setChecked(midplane);
// According to bug #0000521 the reversed option
// shouldn't be de-activated if the pad has a support face
ui->checkBoxReversed->setChecked(reversed);
+ ui->lineFaceName->setText(upToFace == "" ? tr("No face selected") : tr(upToFace));
+ ui->changeMode->clear();
+ ui->changeMode->insertItem(0, tr("Dimension"));
+ ui->changeMode->insertItem(1, tr("To last"));
+ ui->changeMode->insertItem(2, tr("To first"));
+ ui->changeMode->insertItem(3, tr("Up to face"));
+ ui->changeMode->insertItem(4, tr("Two dimensions"));
+ ui->changeMode->setCurrentIndex(index);
- // Make sure that the spin box has the focus to get key events
- // Calling setFocus() directly doesn't work because the spin box is not
- // yet visible.
- QMetaObject::invokeMethod(ui->doubleSpinBox, "setFocus", Qt::QueuedConnection);
+ // activate and de-activate dialog elements as appropriate
+ updateUI(index);
+}
+
+void TaskPadParameters::updateUI(int index)
+{
+ if (index == 0) { // dimension
+ ui->doubleSpinBox->setEnabled(true);
+ ui->doubleSpinBox->selectAll();
+ // Make sure that the spin box has the focus to get key events
+ // Calling setFocus() directly doesn't work because the spin box is not
+ // yet visible.
+ QMetaObject::invokeMethod(ui->doubleSpinBox, "setFocus", Qt::QueuedConnection);
+ ui->checkBoxMidplane->setEnabled(true);
+ ui->checkBoxReversed->setEnabled(true);
+ ui->doubleSpinBox2->setEnabled(false);
+ ui->lineFaceName->setEnabled(false);
+ } else if ((index == 1) || (index == 2)) { // up to first/last
+ ui->doubleSpinBox->setEnabled(false);
+ ui->checkBoxMidplane->setEnabled(false);
+ ui->checkBoxReversed->setEnabled(false);
+ ui->doubleSpinBox2->setEnabled(false);
+ ui->lineFaceName->setEnabled(false);
+ } else if (index == 3) { // up to face
+ ui->doubleSpinBox->setEnabled(false);
+ ui->checkBoxMidplane->setEnabled(false);
+ ui->checkBoxReversed->setEnabled(false);
+ ui->doubleSpinBox2->setEnabled(false);
+ ui->lineFaceName->setEnabled(true);
+ QMetaObject::invokeMethod(ui->lineFaceName, "setFocus", Qt::QueuedConnection);
+ } else { // two dimensions
+ ui->doubleSpinBox->setEnabled(true);
+ ui->doubleSpinBox->selectAll();
+ QMetaObject::invokeMethod(ui->doubleSpinBox, "setFocus", Qt::QueuedConnection);
+ ui->checkBoxMidplane->setEnabled(false);
+ ui->checkBoxReversed->setEnabled(false);
+ ui->doubleSpinBox2->setEnabled(true);
+ ui->lineFaceName->setEnabled(false);
+ }
+}
+
+void TaskPadParameters::onSelectionChanged(const Gui::SelectionChanges& msg)
+{
+ PartDesign::Pad* pcPad = static_cast(PadView->getObject());
+ if (pcPad->Type.getValue() != 3) // ignore user selections if mode is not upToFace
+ return;
+
+ if (!msg.pSubName || msg.pSubName[0] == '\0')
+ return;
+ std::string element(msg.pSubName);
+ if (element.substr(0,4) != "Face")
+ return;
+
+ if (msg.Type == Gui::SelectionChanges::AddSelection) {
+ pcPad->FaceName.setValue(element);
+ pcPad->getDocument()->recomputeFeature(pcPad);
+ ui->lineFaceName->setText(tr(element.c_str()));
+ }
}
void TaskPadParameters::onLengthChanged(double len)
@@ -92,10 +168,10 @@ void TaskPadParameters::onLengthChanged(double len)
pcPad->getDocument()->recomputeFeature(pcPad);
}
-void TaskPadParameters::onMirrored(bool on)
+void TaskPadParameters::onMidplane(bool on)
{
PartDesign::Pad* pcPad = static_cast(PadView->getObject());
- pcPad->MirroredExtent.setValue(on);
+ pcPad->Midplane.setValue(on);
pcPad->getDocument()->recomputeFeature(pcPad);
}
@@ -106,6 +182,40 @@ void TaskPadParameters::onReversed(bool on)
pcPad->getDocument()->recomputeFeature(pcPad);
}
+void TaskPadParameters::onLength2Changed(double len)
+{
+ PartDesign::Pad* pcPad = static_cast(PadView->getObject());
+ pcPad->Length2.setValue((float)len);
+ pcPad->getDocument()->recomputeFeature(pcPad);
+}
+
+void TaskPadParameters::onModeChanged(int index)
+{
+ PartDesign::Pad* pcPad = static_cast(PadView->getObject());
+
+ switch (index) {
+ case 0: pcPad->Type.setValue("Length"); break;
+ case 1: pcPad->Type.setValue("UpToLast"); break;
+ case 2: pcPad->Type.setValue("UpToFirst"); break;
+ case 3: pcPad->Type.setValue("UpToFace"); break;
+ default: pcPad->Type.setValue("TwoLengths");
+ }
+
+ updateUI(index);
+
+ pcPad->getDocument()->recomputeFeature(pcPad);
+}
+
+void TaskPadParameters::onFaceName(const QString& text)
+{
+ if (text.left(4) != tr("Face"))
+ return;
+
+ PartDesign::Pad* pcPad = static_cast(PadView->getObject());
+ pcPad->FaceName.setValue(text.toUtf8());
+ pcPad->getDocument()->recomputeFeature(pcPad);
+}
+
double TaskPadParameters::getLength(void) const
{
return ui->doubleSpinBox->value();
@@ -116,9 +226,24 @@ bool TaskPadParameters::getReversed(void) const
return ui->checkBoxReversed->isChecked();
}
-bool TaskPadParameters::getMirroredExtent(void) const
+bool TaskPadParameters::getMidplane(void) const
{
- return ui->checkBoxMirrored->isChecked();
+ return ui->checkBoxMidplane->isChecked();
+}
+
+double TaskPadParameters::getLength2(void) const
+{
+ return ui->doubleSpinBox2->value();
+}
+
+int TaskPadParameters::getMode(void) const
+{
+ return ui->changeMode->currentIndex();
+}
+
+const QString TaskPadParameters::getFaceName(void) const
+{
+ return ui->lineFaceName->text();
}
TaskPadParameters::~TaskPadParameters()
@@ -174,7 +299,10 @@ bool TaskDlgPadParameters::accept()
//Gui::Command::openCommand("Pad changed");
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Length = %f",name.c_str(),parameter->getLength());
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %i",name.c_str(),parameter->getReversed()?1:0);
- Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.MirroredExtent = %i",name.c_str(),parameter->getMirroredExtent()?1:0);
+ Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Midplane = %i",name.c_str(),parameter->getMidplane()?1:0);
+ Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Length2 = %f",name.c_str(),parameter->getLength2());
+ Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Type = %u",name.c_str(),parameter->getMode());
+ Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.FaceName = \"%s\"",name.c_str(),parameter->getFaceName().toAscii().data());
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()");
if (!PadView->getObject()->isValid())
throw Base::Exception(PadView->getObject()->getStatusString());
diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.h b/src/Mod/PartDesign/Gui/TaskPadParameters.h
index c16493cad..53afdacd0 100644
--- a/src/Mod/PartDesign/Gui/TaskPadParameters.h
+++ b/src/Mod/PartDesign/Gui/TaskPadParameters.h
@@ -44,7 +44,7 @@ namespace PartDesignGui {
-class TaskPadParameters : public Gui::TaskView::TaskBox
+class TaskPadParameters : public Gui::TaskView::TaskBox, public Gui::SelectionObserver
{
Q_OBJECT
@@ -52,19 +52,27 @@ public:
TaskPadParameters(ViewProviderPad *PadView,QWidget *parent = 0);
~TaskPadParameters();
+ int getMode(void) const;
double getLength(void) const;
+ double getLength2(void) const;
bool getReversed(void) const;
- bool getMirroredExtent(void) const;
+ bool getMidplane(void) const;
+ const QString getFaceName(void) const;
private Q_SLOTS:
void onLengthChanged(double);
- void onMirrored(bool);
+ void onMidplane(bool);
void onReversed(bool);
+ void onLength2Changed(double);
+ void onModeChanged(int);
+ void onFaceName(const QString& text);
protected:
void changeEvent(QEvent *e);
private:
+ void onSelectionChanged(const Gui::SelectionChanges& msg);
+ void updateUI(int index);
private:
QWidget* proxy;
diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.ui b/src/Mod/PartDesign/Gui/TaskPadParameters.ui
index d407bbf31..d1f2601cb 100644
--- a/src/Mod/PartDesign/Gui/TaskPadParameters.ui
+++ b/src/Mod/PartDesign/Gui/TaskPadParameters.ui
@@ -6,8 +6,8 @@
0
0
- 158
- 116
+ 272
+ 238
@@ -19,7 +19,7 @@
-
- Type:
+ Type
@@ -39,7 +39,7 @@
-
- Length:
+ Length
@@ -55,19 +55,19 @@
5.000000000000000
- 20.000000000000000
+ 10.000000000000000
-
-
+
- false
+ true
- Mirrored extent
+ Symmetric to plane
@@ -78,6 +78,47 @@
+ -
+
+
-
+
+
+ 2nd length
+
+
+
+ -
+
+
+ -999999999.000000000000000
+
+
+ 999999999.000000000000000
+
+
+ 5.000000000000000
+
+
+ 0.000000000000000
+
+
+
+
+
+ -
+
+
-
+
+
+ Face
+
+
+
+ -
+
+
+
+
diff --git a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp
index 30618f621..2122bafd1 100644
--- a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp
+++ b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp
@@ -58,16 +58,39 @@ TaskPocketParameters::TaskPocketParameters(ViewProviderPocket *PocketView,QWidge
connect(ui->doubleSpinBox, SIGNAL(valueChanged(double)),
this, SLOT(onLengthChanged(double)));
+ connect(ui->changeMode, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(onModeChanged(int)));
+ connect(ui->lineFaceName, SIGNAL(textEdited(QString)),
+ this, SLOT(onFaceName(QString)));
this->groupLayout()->addWidget(proxy);
PartDesign::Pocket* pcPocket = static_cast(PocketView->getObject());
double l = pcPocket->Length.getValue();
+ int index = pcPocket->Type.getValue(); // must extract value here, clear() kills it!
+ const char* upToFace = pcPocket->FaceName.getValue();
- ui->doubleSpinBox->setMaximum(INT_MAX);
- ui->doubleSpinBox->setValue(l);
- ui->doubleSpinBox->selectAll();
- QMetaObject::invokeMethod(ui->doubleSpinBox, "setFocus", Qt::QueuedConnection);
+ ui->changeMode->clear();
+ ui->changeMode->insertItem(0, tr("Dimension"));
+ ui->changeMode->insertItem(1, tr("To last"));
+ ui->changeMode->insertItem(2, tr("To first"));
+ ui->changeMode->insertItem(3, tr("Through all"));
+ ui->changeMode->insertItem(4, tr("Up to face"));
+ ui->changeMode->setCurrentIndex(index);
+
+ if (index == 0) { // Only this option requires a numeric value
+ ui->doubleSpinBox->setMaximum(INT_MAX);
+ ui->doubleSpinBox->setValue(l);
+ ui->doubleSpinBox->selectAll();
+ QMetaObject::invokeMethod(ui->doubleSpinBox, "setFocus", Qt::QueuedConnection);
+ ui->lineFaceName->setEnabled(false);
+ } else if (index == 4) { // Only this option requires to select a face
+ ui->doubleSpinBox->setEnabled(false);
+ ui->lineFaceName->setText(upToFace == "" ? tr("No face selected") : tr(upToFace));
+ } else { // Neither value nor face required
+ ui->doubleSpinBox->setEnabled(false);
+ ui->lineFaceName->setEnabled(false);
+ }
//// check if the sketch has support
//Sketcher::SketchObject *pcSketch;
@@ -81,6 +104,25 @@ TaskPocketParameters::TaskPocketParameters(ViewProviderPocket *PocketView,QWidge
//}
}
+void TaskPocketParameters::onSelectionChanged(const Gui::SelectionChanges& msg)
+{
+ PartDesign::Pocket* pcPocket = static_cast(PocketView->getObject());
+ if (pcPocket->Type.getValue() != 4) // ignore user selections if mode is not upToFace
+ return;
+
+ if (!msg.pSubName || msg.pSubName[0] == '\0')
+ return;
+ std::string element(msg.pSubName);
+ if (element.substr(0,4) != "Face")
+ return;
+
+ if (msg.Type == Gui::SelectionChanges::AddSelection) {
+ pcPocket->FaceName.setValue(element);
+ pcPocket->getDocument()->recomputeFeature(pcPocket);
+ ui->lineFaceName->setText(tr(element.c_str()));
+ }
+}
+
void TaskPocketParameters::onLengthChanged(double len)
{
PartDesign::Pocket* pcPocket = static_cast(PocketView->getObject());
@@ -88,11 +130,59 @@ void TaskPocketParameters::onLengthChanged(double len)
pcPocket->getDocument()->recomputeFeature(pcPocket);
}
+void TaskPocketParameters::onModeChanged(int index)
+{
+ PartDesign::Pocket* pcPocket = static_cast(PocketView->getObject());
+
+ switch (index) {
+ case 0: pcPocket->Type.setValue("Length"); break;
+ case 1: pcPocket->Type.setValue("UpToLast"); break;
+ case 2: pcPocket->Type.setValue("UpToFirst"); break;
+ case 3: pcPocket->Type.setValue("ThroughAll"); break;
+ case 4: pcPocket->Type.setValue("UpToFace"); break;
+ default: pcPocket->Type.setValue("Length");
+ }
+
+ if (index == 0) {
+ ui->doubleSpinBox->setEnabled(true);
+ ui->lineFaceName->setEnabled(false);
+ ui->doubleSpinBox->setValue(pcPocket->Length.getValue());
+ } else if (index == 4) {
+ ui->lineFaceName->setEnabled(true);
+ ui->doubleSpinBox->setEnabled(false);
+ ui->lineFaceName->setText(tr(pcPocket->FaceName.getValue()));
+ } else {
+ ui->doubleSpinBox->setEnabled(false);
+ ui->lineFaceName->setEnabled(false);
+ }
+
+ pcPocket->getDocument()->recomputeFeature(pcPocket);
+}
+
+void TaskPocketParameters::onFaceName(const QString& text)
+{
+ if (text.left(4) != tr("Face"))
+ return;
+
+ PartDesign::Pocket* pcPocket = static_cast(PocketView->getObject());
+ pcPocket->FaceName.setValue(text.toUtf8());
+ pcPocket->getDocument()->recomputeFeature(pcPocket);
+}
+
double TaskPocketParameters::getLength(void) const
{
return ui->doubleSpinBox->value();
}
+int TaskPocketParameters::getMode(void) const
+{
+ return ui->changeMode->currentIndex();
+}
+
+const QString TaskPocketParameters::getFaceName(void) const
+{
+ return ui->lineFaceName->text();
+}
TaskPocketParameters::~TaskPocketParameters()
{
@@ -145,6 +235,8 @@ bool TaskDlgPocketParameters::accept()
//Gui::Command::openCommand("Pocket changed");
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Length = %f",name.c_str(),parameter->getLength());
+ Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Type = %u",name.c_str(),parameter->getMode());
+ Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.FaceName = \"%s\"",name.c_str(),parameter->getFaceName().toAscii().data());
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()");
Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()");
Gui::Command::commitCommand();
@@ -163,7 +255,7 @@ bool TaskDlgPocketParameters::reject()
pcSupport = pcSketch->Support.getValue();
}
- // role back the done things
+ // roll back the done things
Gui::Command::abortCommand();
Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()");
diff --git a/src/Mod/PartDesign/Gui/TaskPocketParameters.h b/src/Mod/PartDesign/Gui/TaskPocketParameters.h
index 077a9ef0c..bbb6bbb3f 100644
--- a/src/Mod/PartDesign/Gui/TaskPocketParameters.h
+++ b/src/Mod/PartDesign/Gui/TaskPocketParameters.h
@@ -44,7 +44,7 @@ namespace PartDesignGui {
-class TaskPocketParameters : public Gui::TaskView::TaskBox
+class TaskPocketParameters : public Gui::TaskView::TaskBox, public Gui::SelectionObserver
{
Q_OBJECT
@@ -53,14 +53,19 @@ public:
~TaskPocketParameters();
double getLength(void) const;
+ int getMode(void) const;
+ const QString getFaceName(void) const;
private Q_SLOTS:
void onLengthChanged(double);
+ void onModeChanged(int);
+ void onFaceName(const QString& text);
protected:
void changeEvent(QEvent *e);
private:
+ void onSelectionChanged(const Gui::SelectionChanges& msg);
private:
QWidget* proxy;
diff --git a/src/Mod/PartDesign/Gui/TaskPocketParameters.ui b/src/Mod/PartDesign/Gui/TaskPocketParameters.ui
index 34c8979a1..4f313be76 100644
--- a/src/Mod/PartDesign/Gui/TaskPocketParameters.ui
+++ b/src/Mod/PartDesign/Gui/TaskPocketParameters.ui
@@ -6,49 +6,97 @@
0
0
- 137
- 68
+ 241
+ 134
+
+
+ 0
+ 0
+
+
+
+
+ 233
+ 134
+
+
Form
-
- -
-
-
-
-
+
+
+
+ 10
+ 10
+ 211
+ 34
+
+
+
+
-
+
+
+ Type
+
+
+
+ -
+
+
-
- Type:
+ Dimension
-
-
- -
-
-
-
-
- Dimension
-
-
-
-
-
-
- -
-
-
-
-
-
- Length
-
-
-
- -
-
-
-
-
-
+
+
+
+
+
+
+
+
+ 10
+ 90
+ 211
+ 34
+
+
+
+ -
+
+
+ Face
+
+
+
+ -
+
+
+
+
+
+
+
+ 10
+ 50
+ 211
+ 34
+
+
+
+ -
+
+
+ Length
+
+
+
+ -
+
+
+
+
diff --git a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp
index 05b01058f..f78134b74 100644
--- a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp
+++ b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp
@@ -60,11 +60,18 @@ TaskRevolutionParameters::TaskRevolutionParameters(ViewProviderRevolution *Revol
this, SLOT(onAngleChanged(double)));
connect(ui->axis, SIGNAL(activated(int)),
this, SLOT(onAxisChanged(int)));
+ connect(ui->checkBoxMidplane, SIGNAL(toggled(bool)),
+ this, SLOT(onMidplane(bool)));
+ connect(ui->checkBoxReversed, SIGNAL(toggled(bool)),
+ this, SLOT(onReversed(bool)));
this->groupLayout()->addWidget(proxy);
PartDesign::Revolution* pcRevolution = static_cast(RevolutionView->getObject());
double l = pcRevolution->Angle.getValue();
+ bool mirrored = pcRevolution->Midplane.getValue();
+ bool reversed = pcRevolution->Reversed.getValue();
+
ui->doubleSpinBox->setValue(l);
int count=pcRevolution->getSketchAxisCount();
@@ -95,6 +102,9 @@ TaskRevolutionParameters::TaskRevolutionParameters(ViewProviderRevolution *Revol
ui->axis->setCurrentIndex(pos);
+ ui->checkBoxMidplane->setChecked(mirrored);
+ ui->checkBoxReversed->setChecked(reversed);
+
setFocus ();
}
@@ -126,6 +136,19 @@ void TaskRevolutionParameters::onAxisChanged(int num)
pcRevolution->getDocument()->recomputeFeature(pcRevolution);
}
+void TaskRevolutionParameters::onMidplane(bool on)
+{
+ PartDesign::Revolution* pcRevolution = static_cast(RevolutionView->getObject());
+ pcRevolution->Midplane.setValue(on);
+ pcRevolution->getDocument()->recomputeFeature(pcRevolution);
+}
+
+void TaskRevolutionParameters::onReversed(bool on)
+{
+ PartDesign::Revolution* pcRevolution = static_cast(RevolutionView->getObject());
+ pcRevolution->Reversed.setValue(on);
+ pcRevolution->getDocument()->recomputeFeature(pcRevolution);
+}
double TaskRevolutionParameters::getAngle(void) const
{
@@ -157,6 +180,16 @@ QString TaskRevolutionParameters::getReferenceAxis(void) const
return buf;
}
+bool TaskRevolutionParameters::getMidplane(void) const
+{
+ return ui->checkBoxMidplane->isChecked();
+}
+
+bool TaskRevolutionParameters::getReversed(void) const
+{
+ return ui->checkBoxReversed->isChecked();
+}
+
TaskRevolutionParameters::~TaskRevolutionParameters()
{
delete ui;
@@ -210,6 +243,8 @@ bool TaskDlgRevolutionParameters::accept()
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Angle = %f",name.c_str(),parameter->getAngle());
std::string axis = parameter->getReferenceAxis().toStdString();
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.ReferenceAxis = %s",name.c_str(),axis.c_str());
+ Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Midplane = %i",name.c_str(),parameter->getMidplane()?1:0);
+ Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %i",name.c_str(),parameter->getReversed()?1:0);
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()");
Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()");
Gui::Command::commitCommand();
diff --git a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h
index dcafbd618..1d9eb71a8 100644
--- a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h
+++ b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h
@@ -54,10 +54,14 @@ public:
QString getReferenceAxis(void) const;
double getAngle(void) const;
+ bool getMidplane(void) const;
+ bool getReversed(void) const;
private Q_SLOTS:
void onAngleChanged(double);
void onAxisChanged(int);
+ void onMidplane(bool);
+ void onReversed(bool);
protected:
void changeEvent(QEvent *e);
diff --git a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.ui b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.ui
index a80c300fe..dac292f99 100644
--- a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.ui
+++ b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.ui
@@ -6,8 +6,8 @@
0
0
- 182
- 68
+ 278
+ 158
@@ -54,7 +54,7 @@
1
- -360.000000000000000
+ 0.000000000000000
360.000000000000000
@@ -69,6 +69,23 @@
+ -
+
+
+ true
+
+
+ Symmetric to plane
+
+
+
+ -
+
+
+ Reversed
+
+
+
diff --git a/src/Mod/PartDesign/Gui/ViewProviderGroove.cpp b/src/Mod/PartDesign/Gui/ViewProviderGroove.cpp
new file mode 100644
index 000000000..af7a24854
--- /dev/null
+++ b/src/Mod/PartDesign/Gui/ViewProviderGroove.cpp
@@ -0,0 +1,141 @@
+/***************************************************************************
+ * Copyright (c) 2011 Juergen Riegel *
+ * *
+ * 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_
+#endif
+
+#include
+#include
+#include
+#include
+#include
+
+#include "ViewProviderGroove.h"
+#include "TaskGrooveParameters.h"
+
+using namespace PartDesignGui;
+
+PROPERTY_SOURCE(PartDesignGui::ViewProviderGroove,PartDesignGui::ViewProvider)
+
+ViewProviderGroove::ViewProviderGroove()
+{
+}
+
+ViewProviderGroove::~ViewProviderGroove()
+{
+}
+
+std::vector ViewProviderGroove::claimChildren(void)const
+{
+ std::vector temp;
+ temp.push_back(static_cast(getObject())->Sketch.getValue());
+
+ return temp;
+}
+
+void ViewProviderGroove::setupContextMenu(QMenu* menu, QObject* receiver, const char* member)
+{
+ QAction* act;
+ act = menu->addAction(QObject::tr("Edit Groove"), receiver, member);
+ act->setData(QVariant((int)ViewProvider::Default));
+ PartGui::ViewProviderPart::setupContextMenu(menu, receiver, member);
+}
+
+bool ViewProviderGroove::setEdit(int ModNum)
+{
+ if (ModNum == ViewProvider::Default ) {
+ // When double-clicking on the item for this pad the
+ // object unsets and sets its edit mode without closing
+ // the task panel
+ Gui::TaskView::TaskDialog *dlg = Gui::Control().activeDialog();
+ TaskDlgGrooveParameters *padDlg = qobject_cast(dlg);
+ if (padDlg && padDlg->getGrooveView() != this)
+ padDlg = 0; // another pad left open its task panel
+ if (dlg && !padDlg) {
+ QMessageBox msgBox;
+ msgBox.setText(QObject::tr("A dialog is already open in the task panel"));
+ msgBox.setInformativeText(QObject::tr("Do you want to close this dialog?"));
+ msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
+ msgBox.setDefaultButton(QMessageBox::Yes);
+ int ret = msgBox.exec();
+ if (ret == QMessageBox::Yes)
+ Gui::Control().closeDialog();
+ else
+ return false;
+ }
+
+ // clear the selection (convenience)
+ Gui::Selection().clearSelection();
+ //if (ModNum == 1)
+ // Gui::Command::openCommand("Change Groove parameters");
+
+ // start the edit dialog
+ if (padDlg)
+ Gui::Control().showDialog(padDlg);
+ else
+ Gui::Control().showDialog(new TaskDlgGrooveParameters(this));
+
+ return true;
+ }
+ else {
+ return PartGui::ViewProviderPart::setEdit(ModNum);
+ }
+}
+
+void ViewProviderGroove::unsetEdit(int ModNum)
+{
+ if (ModNum == ViewProvider::Default) {
+ // and update the pad
+ //getSketchObject()->getDocument()->recompute();
+
+ // when pressing ESC make sure to close the dialog
+ Gui::Control().closeDialog();
+ }
+ else {
+ PartGui::ViewProviderPart::unsetEdit(ModNum);
+ }
+}
+
+bool ViewProviderGroove::onDelete(const std::vector &)
+{
+ // get the support and Sketch
+ PartDesign::Groove* pcGroove = static_cast(getObject());
+ Sketcher::SketchObject *pcSketch;
+ App::DocumentObject *pcSupport;
+ if (pcGroove->Sketch.getValue()){
+ pcSketch = static_cast(pcGroove->Sketch.getValue());
+ pcSupport = pcSketch->Support.getValue();
+ }
+
+ // if abort command deleted the object the support is visible again
+ if (pcSketch && Gui::Application::Instance->getViewProvider(pcSketch))
+ Gui::Application::Instance->getViewProvider(pcSketch)->show();
+ if (pcSupport && Gui::Application::Instance->getViewProvider(pcSupport))
+ Gui::Application::Instance->getViewProvider(pcSupport)->show();
+
+ return true;
+}
+
+
diff --git a/src/Mod/PartDesign/Gui/ViewProviderGroove.h b/src/Mod/PartDesign/Gui/ViewProviderGroove.h
new file mode 100644
index 000000000..51b1adca4
--- /dev/null
+++ b/src/Mod/PartDesign/Gui/ViewProviderGroove.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+ * Copyright (c) 2011 Juergen Riegel *
+ * *
+ * 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_ViewProviderGroove_H
+#define PARTGUI_ViewProviderGroove_H
+
+#include "ViewProvider.h"
+
+
+namespace PartDesignGui {
+
+class PartDesignGuiExport ViewProviderGroove : public ViewProvider
+{
+ PROPERTY_HEADER(PartGui::ViewProviderGroove);
+
+public:
+ /// constructor
+ ViewProviderGroove();
+ /// destructor
+ virtual ~ViewProviderGroove();
+
+ /// grouping handling
+ std::vector claimChildren(void)const;
+
+ void setupContextMenu(QMenu*, QObject*, const char*);
+
+ virtual bool onDelete(const std::vector &);
+
+protected:
+ virtual bool setEdit(int ModNum);
+ virtual void unsetEdit(int ModNum);
+
+};
+
+
+} // namespace PartDesignGui
+
+
+#endif // PARTGUI_ViewProviderGroove_H
diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp
index 50f9f9adf..961393e70 100644
--- a/src/Mod/PartDesign/Gui/Workbench.cpp
+++ b/src/Mod/PartDesign/Gui/Workbench.cpp
@@ -86,6 +86,7 @@ void Workbench::activated()
"PartDesign_Pad",
"PartDesign_Pocket",
"PartDesign_Revolution",
+ "PartDesign_Groove",
0};
Watcher.push_back(new Gui::TaskView::TaskWatcherCommands(
"SELECT Sketcher::SketchObject COUNT 1",
@@ -169,6 +170,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const
<< "PartDesign_Pad"
<< "PartDesign_Pocket"
<< "PartDesign_Revolution"
+ << "PartDesign_Groove"
<< "PartDesign_Fillet"
<< "PartDesign_Chamfer";
@@ -186,6 +188,7 @@ Gui::ToolBarItem* Workbench::setupToolBars() const
<< "PartDesign_Pad"
<< "PartDesign_Pocket"
<< "PartDesign_Revolution"
+ << "PartDesign_Groove"
<< "PartDesign_Fillet"
<< "PartDesign_Chamfer";