From cf31d43e54063f20ab40710c328f288048e80e4b Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 8 Jun 2012 15:19:53 +0200 Subject: [PATCH 01/13] Add support of number of decimals to unit system --- src/Base/UnitsApi.cpp | 11 ++++++++ src/Base/UnitsApi.h | 6 +++++ src/Gui/Application.cpp | 5 ++++ src/Gui/propertyeditor/PropertyItem.cpp | 35 +++++++++++++++++-------- src/Gui/propertyeditor/PropertyItem.h | 3 +++ 5 files changed, 49 insertions(+), 11 deletions(-) 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/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; }; /** From 33ecf9e76844c755bf947f9e6001d2fd8798e6c4 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Fri, 8 Jun 2012 19:11:09 +0430 Subject: [PATCH 02/13] Groove feature (code is 99% identical to Revolution feature) --- src/Mod/PartDesign/App/AppPartDesign.cpp | 2 + src/Mod/PartDesign/App/CMakeLists.txt | 2 + src/Mod/PartDesign/App/FeatureGroove.cpp | 207 +++++++++++++ src/Mod/PartDesign/App/FeatureGroove.h | 66 ++++ src/Mod/PartDesign/Gui/AppPartDesignGui.cpp | 2 + src/Mod/PartDesign/Gui/CMakeLists.txt | 7 + src/Mod/PartDesign/Gui/Command.cpp | 77 +++++ .../PartDesign/Gui/TaskGrooveParameters.cpp | 287 ++++++++++++++++++ src/Mod/PartDesign/Gui/TaskGrooveParameters.h | 115 +++++++ .../PartDesign/Gui/TaskGrooveParameters.ui | 93 ++++++ src/Mod/PartDesign/Gui/ViewProviderGroove.cpp | 141 +++++++++ src/Mod/PartDesign/Gui/ViewProviderGroove.h | 59 ++++ src/Mod/PartDesign/Gui/Workbench.cpp | 3 + 13 files changed, 1061 insertions(+) create mode 100644 src/Mod/PartDesign/App/FeatureGroove.cpp create mode 100644 src/Mod/PartDesign/App/FeatureGroove.h create mode 100644 src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp create mode 100644 src/Mod/PartDesign/Gui/TaskGrooveParameters.h create mode 100644 src/Mod/PartDesign/Gui/TaskGrooveParameters.ui create mode 100644 src/Mod/PartDesign/Gui/ViewProviderGroove.cpp create mode 100644 src/Mod/PartDesign/Gui/ViewProviderGroove.h 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..1e7f7d660 --- /dev/null +++ b/src/Mod/PartDesign/App/FeatureGroove.cpp @@ -0,0 +1,207 @@ +/*************************************************************************** + * 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(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),"Groove",(App::PropertyType)(App::Prop_None),"Reference axis of Groove"); + ADD_PROPERTY(Midplane,(0)); + ADD_PROPERTY(Reversed, (0)); +} + +short Groove::mustExecute() const +{ + if (Placement.isTouched() || + Sketch.isTouched() || + ReferenceAxis.isTouched() || + Axis.isTouched() || + Base.isTouched() || + Angle.isTouched() || + Midplane.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/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..d671fbe46 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("Revolve 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/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/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"; From d5c7c1ea45f68ffd96758d81a317ec4d5b4605c3 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Fri, 8 Jun 2012 19:51:53 +0430 Subject: [PATCH 03/13] Pad feature: Midplane, two-sided dimensions, up to first/last/face options --- data/tests/PadTest.fcstd | Bin 0 -> 14782 bytes src/Mod/Part/App/PartFeature.cpp | 74 +++++- src/Mod/Part/App/PartFeature.h | 32 +++ src/Mod/PartDesign/App/FeaturePad.cpp | 231 +++++++++++++++---- src/Mod/PartDesign/App/FeaturePad.h | 12 +- src/Mod/PartDesign/Gui/TaskPadParameters.cpp | 156 +++++++++++-- src/Mod/PartDesign/Gui/TaskPadParameters.h | 14 +- src/Mod/PartDesign/Gui/TaskPadParameters.ui | 57 ++++- 8 files changed, 499 insertions(+), 77 deletions(-) create mode 100644 data/tests/PadTest.fcstd diff --git a/data/tests/PadTest.fcstd b/data/tests/PadTest.fcstd new file mode 100644 index 0000000000000000000000000000000000000000..8a7223083d43f88af19d30fa4f4f7e9512152815 GIT binary patch literal 14782 zcmbW8V~`-*)8^Z@ZQHiHr)}G|ZBN_wv~AnAIo&;NyL;!}ci;WrI~%*Pv8O&%L`D57 zPMpefG9&Xz`ES4=C;$Ke5CC!+{Q{3a%P<7M0RZOs0RUirKNYbva*bSg2M$7`9s*WN~nL)OIRA#mIOd~MJM8O;M|cIcP> z07;1F^Et0}ZJM~BIRCVmeUe0DJrU4yLtB6S?nTrQOw=kwJwra~u;&;;IY}~c zn@-Z#YE8k?f;S4~C*yw)*0o|*Q^LHXg`CSpB9OX0T#Vl3u$tp)9UrB3Sm1VACB(xk z(qh%>)1fOzHrBAg`CvdhXH-*i1N$0~iv6r77XhZUss}1uQ`cc*VxFrnb?$Zn3n#7D zha%JWC1ZV$XcxaNzV2RtiL4^rUVd5zXRtDz;2qd9@2q&#r-gWg?J6wk=!+C4Mg)pf zyqabhlHdPe@to6_wA@TTYn{ypf{3? zdLxBt4gljZVm$KNl4*U_UgCg zLyRW#z*i4m$*OSo;wIE*`J5=}jmkg&&01)4S-38C#Ahss`Fw#IiQ|bb4H5r-Dk=p7JTO5~+q&vo!%WbJR!;k61<}ZL@_avBmIm^`LY+;6vTPy#JUFHhJEdL`{h|bG@O{CVn0N;b(x*1Nd2_EwR<+Renufmx>AN(^kg zpffXh%JDinuVk2CgVwUg+wQZ5p7TgMQAh{S>}r!fn~huh$&y%SQPf%h)Kx8@GH(zR z{BRjDjr|IhblS5;8UVq5GjOz{yi;^ZD!D)&5Cu5P*ttDP%&NvhfKuwe!C2XG^WtcrtZIgF!6`<|tfV=q{{=4cP!=XL zLD{$WQ-HIMoIDprtBzCjo!XIM%Kisyc&oE z7zY*zoRboGELre6{EdM^g1fLN2{6lITu@`j^wX#LtsOn^nk zK^r1{_rRODls7v47eU;5p|3~I z-LON?47;0lJ>kkQ6Rc%MguG+dgZ=q5{!hPp5XQ43ghOmh5Sf_-+)Df-MX5x|Rj8BE ztWEJ3^Avl1%&-_#vL20BjhF^+2PvW_j0`1!XLu5UXq`-~hj*>XB9V(P)Qz1E*HeyJ zxIz?Vw2Y`Ar@UnXk11p zAvCOC!i0(^NfYt{J*6WA`uT(U-2z_<5<)-P%+E#fCHh$&$_D_7bOn@Z8f)dRGLm9Q z;du3)G^4jozgZ(1XxJ=gf&f>-*Z? z`!x=xLlt(+N7M((ACBp{XK=y3xKcwM@34;RQe*9Cm3oM(0{r$xxO{3dTc)~m76-I8!@MsOKWyfcS=c&|Y> zroqZDVAp1+0!+)W-iO!HJ%6e<@Ln$FxR%kdx=kNgGb<7f!f#y!PVfNxb)1MpxN;QIFu;Ufc|+l@xI>Ao)h`&KKQ$W+AUTf+e(RzUKmeDW&$r`GXx@-| z^zW4c8bBiTMS4l39)F4?d(g=Myv-kV2fuCYN zH^;+g^SK`jmyH$h*KOO+%w1VYpdhH;3^-KCu`VoRUMK!&yPXt@QEYCMSVr|yMtB~W ziUmf47@hspxkFSTQiV*loh)+6K0FUKlrZQD z@+UjF3JgxncSBnyDM{@3G>!!rPW{k28O#O4N5Nn+JUBTyKUA-BTOJ5$DdD!>RtDPF zUIrfPuax!mT`YXxWQO{%R`qFti0e4q%K)ftpicTBf`J&!<9r#QFQQ(EW@K^_5V9Ck z*a`{{M!YWZ1tXNkA;@DJ`xK6&1dp@!K_gtosce`%yFnG|OM+eVrmpm zqM)LPNtmcq+j`Cj?W`(1wB zKX!axh0)J|KiEGzK3{wsKgr>D^ze4^diUYydht59pP|!t;XDpFRz@=N=|T0P-}8xC zH9~IxGQij@oX?L_tWhjepewA2lWMo#lx^#>t&n8uaikgs>q9z{%C zTw1LB7OWlJmmW-OVWv~R8hxtvI0_!4q`o89G-`g@O1SD_BxZ%61qL4GymwC2EVghp zWuEl}XNw!eCfmE|f3#L;p4FhM6mRWdw|U~t0NDO~f`j=>qfAS@!C?+b5XaV_B2~t# zIn?pg_%)P`o;`Tuh}~MC3Zw7HriDk7)%iY#!Ex?1v93>(m+LGM4-uYDy`Oj4W^~kM zueo)WBP3NzXuy(v+)iC+^UU12Rx^{Ogb)Oznp-SLKC`doI~X=PYcXVSsyHz3x!_xU z>M8bm=O&nK>P{?}XE+}Sf?5q?toY#u`mx*6Y@M{T2-PJX>}8#;3DjjQO}+yZeM_(y z%PK`rpOI?#HmEItt(z3I*_dFEhwqzxt;1Ya1ra{n90;$bmG^8AB(b|rqF~L9hQX5A z7+!3p>EZDqM+ za3OUW?&{%$%IpNQKiE)WD9{rypw*2dIdNGIjN2eiKXh;fd8NEd*5Xnth&ia)L!KZJ z)=Qag7MDn>T8&5@`0bvfJ?EE)a7#y@wHg|Kf$s}+G3quWlKxGx!Xo^yCGtXEWF8$* zzq_#{H1eeD#X_9+6}{XqFZU?*nk~!9 z+`wpeO&bG>s~>j@_3x*|vJj;7S(b)q-3byL%~KyGrseU6ZeG=t*zp>4nQ~3AEA2om zGeMQyQ5no4_S+m}gFq9!%?URWKdo7o4}ml4sAw;g8s~xp^5%trU>BPut-$ZXX3v_> zc~}Y8oX6iW2Y=FO6t;8n?pQLlkRFe*+TM<;YME$lcHh9T6(4i^Z%dHEz9Pp`-VI-D zrPN;qTu(*33?rKlzQcmKGViN2pKV`0Q*m>jooAifiWTY!ake?vGxgZ+4wE2CVS;+jOrsPV`Z<>q zroMtk0gH_I`>2mC1aW{3;20UiB7=B;=@OVc&N8o-Vi6}@-=)(SeeZrd0|fUJVOoKE zm`6gP>|hHdN~{JBY2?P5P0JT}WZ6Z@EUN_-t;++Wx}#x}B2fqhWnX4tL8il?bCnG* z3r^cYqjd95gn^ECZe57;|4CGYAek1I!pamaY3yxCVr*Cz7hqwcFP4$e5tUR(s#p9N zsON^B?u^S+v^Cb`0|tsqe7X@xmLOh6;kxKARt=l2kGS?Nc7R1NNDh4#fdVQ}EiZli zQ1T~4dQm$JtaN-Gr7;s#k!i?OFqF7iu&h4vFcdb1dZ_RSyjO%Vxv68INXT=iev#oo~pCbdG`CxNoH4pOt>L;hME|^Y+?l3_@32PD%5xHiWh`b^Yh5J_gB{TZrrN&RwP1Vh` zeB)^sLWD75Udd4m^0VJ&|0FY3cEHA7X7@z?l7XXks>gv$O zB*+j}$Sbsbh&Ld4%A`C(8EStJtY_XXFCd8cVxVxUGGq;L8Y;l`tfC@rFH!+=QyH(| zV)}97v_@Ms5ecM5+Pc!;-!>cy;)%}AI^f8W6xkDmf!#{40VKI`L4vYE3T2KlLsNhv zHJ4a`A_xfe>o1We@{cQ`_O~a%6xgML_AfH&s$xpuR0DD*f^?3ny$|_D_;Jf?C_^l; zXs%@_SC!xrn+<~y%}f7Xo&e%I1roGyVH$9A$aHYhH$8PFU4noDR%nvYP?joyjJ&G0^~dw$>D|Ie=~GWMe;I#_pZn9uja>)*4EIg#Tm9S1 zz(iQ7+<;#0_C@z@YO2DTAnd`p_!PZ3XAjyED_<^jFZv=INMZ8hGzDd`56ZZjq9$!J zW)qf6fO5U)_d=`?tfQ-oKGl8YgXP^|_TY6-Ohb8vinwJf$at+mfwBm+gR?{TMu^n9mPSg-5Lm|#g|(khW^JN-mRK;;$lO?rDIee_6^_3G$@-AV}-v+G+bnOrj&F@sqd_+*6~Es ztJvTK4T{_Z=k0pXL|@ptyLm;cl*`XnnN)CjGE=-_RUOYyx&wTw5mqC>J3!@%{L=(_ zf|$M!pN{K__vU5L%*p7?E>sppTiq`*{Aw)7rNnC2J)ZYDsfd!QNqGu?4i1!+qejbE z*UM+NSikY-`>EwdMx9K@YB*Am*TPkfGE1e~;}sugl&jG`4)@nhC?Tv%zL zT_*dl_Ec%+mOa60wX4VVyIGKrC2m|`OResKa8HvZ}UZj?+y^+?nrd zKs((_b8c$Lz2%qzL7>0iwt0#IJTY_`Au!*L|0{H)4$gF2%>z@gG@k)n*I((Jb4DFy zZX1HCdp-?LET!%9xQL;c?&Yn&*G?{9JI39(1Z&Wc_Z9efM_>0n&sm-d0$NtKyYJ{* zc(K8L?zoaho=Eb0mUMidUcXI0%xVE0XBIy|jCiS^QB|q?v@)!kD((c&C1s=kIA==kNpKi|o9;iVK-y z)4w;~<>Q|7=d@^HYa7oF7E=rAF(s?*xI`tM8TVzduQ4w3_DPV+(F_cZBzJ_ACB0v-~ttH$2=fSs=`>9rU$lP>mcL&o+A_J)K;w|5`K8vwPtzcCU5NR)WM6wbj zy)Wpw1$_KnA4d;Mkw~LWDir#8ZF+Trk=8uJOO<8KAODcV3#wjAROPC8TLGK>={yqGYF>l=VkgMy6|Jz+sq@?OdUp>9-r zu}^ZKs9IE3MT_#BCDMlP6tH+Vkl3B`E$vR+S#x7A(|b`@5!_kc-MeNmE3tsE(^AZZ#WgGf^r>#!0tRi%pyNPUZuX_C+IWtOrB|^h;87VTD5PRPPDFB-zjLqH0%I)IzU_ zvW!9x8tD{!D(H&8D@ef8iK9?lyFo*b4MimhACgP(nxcb!O$MtFG03N}q3w;IXEZ>L zP}EJ*O-62=k8{Kq(`sWBsrs?s*t(U+GGQ9z2XZIY@r!DFXjp2$VTnoOK?M{809 ziKH~E%TU}ml<1u zZ$wko)%mLg({5irBrq;lbD<-; zw}>sV?a5@PFdCECa=HiXPXtSDwuHnxgV zABH*a%;z?LAbuxN90xQx0&8WaL2;c%&`O6(LlYjuayU^pB6q6V#X z`^lo$KJ*joNpEDZ&>OcM?VR<48=JY6`AkpeD@BL1<*{|!hq}5SgFH~dZ>xO5$EyQ< z<+2rE5OPr?z$E8uwNoX~M!N$f${q)%g9-qnJE292mMrVJPJcx9m>pS6wE)FtZy%=N z5Vcqmx`Te=lopM-6S2!L_5MTU& zics_pYKkAE3pBSGuo{LHf~X4w@5{Ft7xLnOkv74q;qieUnLNpfS?ok`a%#Ca@%sIKs z8@&T}4=ah=1U_mX*PhZKZ4HDLU4{t+M79R62mGQ3mt{3~#{%1x;13!N07afN{lx!w zsL4rV8Y2h@0ATSu>-?{LA@g6MX0k$`Z9fA{*BiC>rv8ufV7AkE1=~zE*uhvOFw6?& zrZP~nPhVN^M1SNNg+mID8G6^7XEZi^(KEkyGgQ+ZUt|EXgEeDqX@_m=jB*Wp`#yO0 zmd+8g9-A(z_vNdJYHLe(%M@Q~$uKMoj=E*@Wev-;a4|uL(Br(j!u^H@L!s6X|6hvN zin|3sMEU!J#wk@3GCA`SXI8mH&{*+Dv`Esf7knowZc^OFZ7RbgNt!lHFIMnDp-4o{ zDR;<4x-cnm;~$afGL^2x&4YnFj(bf%;Lb|eLXtRt(m!<4`gCopjL;!Zx?ZH}g`OP! zg8TUaz|B$%(JL4qva0A(U#w6XF*jW|k?k+o35XB{YlzY747z&v2@@1e-cCA+bOF<` z7{@{<=k#2P2m?E8JIdz&ghXID_HIxX!U2FGR;Bmv#m099xNQLj05JTW+yB>Mv-};` ztIF76vmyXZVkbN<&F$W$$bdfkc{Y`QN#icFd1`;e){a#lWM#Xs>99VNnt-; zCg60l-0b&!P4xG*p!QzTl!S|Fjo&2lWqHDYaU=tKd}xvYs7ksPGp_Luv9 zm9LhZaG2^#4JpudWyN}ft<>R5QkAD+zWdxu2S_Py8iYRmAdzEz+Ci!c^sL2mv=q^V z8k5}gOdPz#ndHt*trB6`B1n3zkYnas+)Z@JM@`)uPhgY}d0#XyBeM+sX7MDx1g?+K zClp6sTRxcIlw}auDw*!7-)CK$@zH^AP#s zBXb^G7xS@L@oi>L$B>^v8Se!nWmdv^tabq#>cxNvxUrg^?2sE?wrN7#H!Qr+ zgB~suP2L*n#ZPxyUSnWy;g6jJQqi4=_~d2Aw{;b87Q4tv&*cW#1YWld*%yRbf`aay zUm`hadzD1>MpaS!0mfADgzxu>En(e*lT}sAYW^!NQs1w+l)5E zlUG@uoHj?z|UbRUA*`P1G>-HC$OnZK@SPM(L2Zcm0@9GNl9fHmmvy{#_u#};S(Yl~lKZzN#1Ao?7uT{AK=E4Aw3 z;f{HXR}rOtq^+-FYp76FeXGyD-8pte=4zdA+=Rd)vAkIZC|e);&McjNEu z!PedWuzy;}gtx=nzW98e%aBLwW>;Yu{WAElK;C5!?`)k@f}VoA?;)P{9#)txT}C# z#!us&$?@!KxT3!Zw(7f0C&0I%#2cdO{?lLYYBq~wrF4y#XnMXd?WWb2SdG7=>)FV5 zqqm-mAZ6fayC?aysf$%buaGOJxhS5|zH9C9Pqo>1+(FF989Zfcc9f}|n4J)lRB@TL{5H{%Muw*e98%z59^omyXYr4b zbKzR94dcLvv9mWqGOTgTssuL$uR;b?6BY59JFRKWnjqP}pK%Kx2sE&4$O2{_RP0vv zApJc2^G^#uGpb7q3k(Fst*Ef}%aYy5H1UIk&g-5(D`{XX6Q<`#ONHb)xivjUd?6<0 zhU0kLBbMYR^gZmQ4p$~CDQKDT z>T?nU`L9|*9+Snp?SY_&;hN1`J1?i)iqA$ul|D$nMhmtyZ=MZYLyCDTf>c-SQ!;uG z6YJo0pl2NPn|E*Gz{pZt7r=5R$|;jvTwo-~s&?%5b}Pps^}8<0zDdjA<~mN&756j>$QZr#(N1cW z9MptK!RP_a5WQBa&llM3>!X-&c_yF36Uc_hD(rwP4e$+lzp>8Ol8|2JtVz6_SJ}>0 znGfqM3ZDG%GaVfn_qtGwHPD}d@ip^il!mi^S7d}8X9~r63Ih%yfrHUQu z1tj$qcn2<`6@_*s6d%>=S%E%#)!kZ2tnSVJgrfv@8D`zKg8;#RB9T`!NQ)ti8dbza zz$4x^=Udn!0*8tqQuX%->tblnj zBCJ)f&};O(}FfFwOwNb$2Wqi379GLqEfv@ zI2$_{8;1}FyLKu+?IaeOy2_uj6mF}Lw}hKQqJ-^n+^vV)D%g2==4>#$^ZGoQdmLpt z&%G9K-g!Ad>j&6PW!YM};rF%3+SWLLn)u(4obkD`?PGZ-6q7XoHkxhA`3#I?`H49QVyq7?KvoKP1)dodzGf}i=8{Ez zvMmSLoVD@VqFe|$M&nmWo}8GR%K(NYpMiSkGx+(rzuldMxjmA~!Y1{6Jzh>c*(tPY2~CO?EwVs4fi7qft`f#-EtMPcHws3T7M4bH5^8dCD~fcIy#8XDUSNuNp4iDqtBY;y8yClpe(nWoyWT_QGD;6gXc z@uf|_quc5Oyq4PQCCnQsSa0vVmsJI^HPh|MPf_Zy5Hhb)bCmAcswT5ZlP6OA6mX|G z->0PyxS8_SLNuh$wK+fTEaru0wZSFzzoy$j_Fy;8s>S7HLJTmaS zi9P-{5bo3jMaUCbivc$b6rQZ@{8SG|u?Mw} zr=c*J<{6i@Y1N~VJGmF#zDhDufrhdMu2e=@!0T9EHaBzpTYdNBN^1T6&z6=f7HM=` z*xTLdH43!u_3}9!=xun@(hsyHgKP2>H0qT+r9&a7Sxjp%8I;F)QA;OcRgfpyQ^P$S z(*o^W@Fu4aENBsn4HE-pwTDRWB#kP}Sq$Zyb1>*}g{zlpg4g})Ql;I_ zOC|);0Rm;nM?-h1Q>=_IRS_J#7)Sa-eb_x8jGJKIn#F=N$;1w9qA4YWzAOfRpgI#e zI3k(Jv0U`UacJ#o%1@6`)ou}1P^^HF5nSxmBLy_E7}LbOzh{|WpQ9E)d_sj|T9;?Z zM_1!ED&;jGg_vL{UWV7tC3;Cp^VFI5v1>vi6cwVz8%WeT7bi~z}xi1wl3IT}}YBUEn1Sb3gialA+!kk0#5jN0L{d zA4QOf)P{IMhgBORHoD-6g$Nl6z(^g#lP*VKku^7uIEBna`kF5jsx+NLB?5v0#AlyW z2%jp)n&|I72X~Vq8C&eLD71qehUjsk#na^JFE58GBA^vFmyM%VT}LTL5^ijhr$~Y! zbk?RL*!&VD&}=@Ki_@ZQlp|EF854dyZxA+a(9Sx?H)bS{<5PHhzbej zJrn_Yx|9IaQ+&?dX4p17w`*%Y?ysGxY+biYa)5_Hl#d_sNyy*`ra4H+fUqCsa6f+K z>ASMf(Gg_EP+X8VB+0|xCwYZQ?)8le$x1;sYf;Tvr`J?>3;11Bt)U$hYD5jje|PtY zgg~8jS(Y6WA67j7o?&#bw87${WX7`2!*~1#BUzS0qvJ16VD8W`VytrDgO7#%%J@mt zkLB-C@HX%7DAfq`qXNMDs6DT=;7pEQul2ljGRGTF_9*dfe6`D8G~zoc@M`n*X+aQM zi&g#v&m;)7E|Q}xKiqkaeaU@7b;F7+Hwl2IU5IJpsltr1*OK58zMJ_{f?^^;5Ym=W zhHX^R4A3AG;)a;$b(U9(rm33H%YWjip$d|E|6I^xZmQECy>bUt3Uu!cNOw;&p~@Nb znc`vtSC%_XSj<2U-d9#;aiqKKhR*AqE4th${UkBZANnnYe^KF{)?dI&Dy+FErvw>N zE)z`>Ue($N5}6{=HmB2(QlC>w{URo4A-Czg~qA&_TjuqMYB5udY5C4Y4VqMaJy({44lKn;D9y&9dn{EL> z*&Ropfdpt$zQp2nT7G%Z2^JYke?TZWIjEz!Ln6c`nM_{Fv7<2vWKcZfVj3hw{ty7D zGYkD>;<*8$BD2!GJQ*VM7IS|(bMFZy`#~x74s$Vl;{~QkY?Mh05*G9NBK%_Tx1$hm&=F+7+(C%<(sUA1E6Kt61$YfEaBWF z*vX;W1lVq@NCBdoNWtDuk%BEA&%9)dGre`P`ES+iffNN`@=l!vBSJw$qh_+YE^4(w z?AYP48wfIlo#sH8b-Xs_GbS8ApDZ_ikcC89$3O?EixPcTQ+4O=Ai+*^<^p zCyA2W?HjGj!)RsP}

PRq*>42O03P1^v|#P$@HIIK6?4UliZ_|#7K$qdn3G;9~A0F zD0_!zIH6~4Re1-^I;CZ1GsZcllr}Kcl_TzeT(SF%Vu*h8Vbk0>7EiB5l=Ou#d|f-& z+1#vc#Qv9S%$1&ic2K!A@XGVzSV~P4>;^Ry3sZIM1fMhl=C)u6Z$hEmJlojxtDiaU z`GGf0moI(K`>U^K4&Hkqd_0)3U!neG8<5sJfGFw=*Ia~fI`CEJ`HFqB7y5;jF>(5+=o2VBRSIc*Acae{@BZevMCN<_eIS%iwfbKgh zfuWJFAzL~pK<6|}9GeB??})YDq95HEF2BWY&KjDv1-@>ig{bT4VReDxqXHCG2a&J5 zE*X-dAF7L2u7-wtN*6n=Z9CoLD{Z}8{O$mpJwU=}_46-oagd?2GeV-?RQ5=7_9`Fb zLgsMkgOKQPhe;&Yl)vEpUQL|8HuC)5Zk+IcA=CYsUKfEKVe_dt;Iuge<7yy>09w42 z*|Bh;LGL~kGHWoQ%z;px;2G7mY2t$GY_XZSyKn`l!R zO&V>Q?7iJ!^9~}zK4OEo+w85+$2k+>c+h|re*Fp# # 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..ed3de3737 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,18 @@ 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; +}; +std::vector findAllFacesCutBy(const TopoDS_Shape& shape, + const TopoDS_Shape& face, const gp_Dir& dir); + } //namespace Part diff --git a/src/Mod/PartDesign/App/FeaturePad.cpp b/src/Mod/PartDesign/App/FeaturePad.cpp index 1a12c4556..c7742c1f4 100644 --- a/src/Mod/PartDesign/App/FeaturePad.cpp +++ b/src/Mod/PartDesign/App/FeaturePad.cpp @@ -39,23 +39,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 +72,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 +85,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 +118,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 +131,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.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"); + + // 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 +292,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/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 + + + + + + + + From 3e5c374a9bb84434c129f8d7bc1b721bb3978144 Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 8 Jun 2012 18:02:35 +0200 Subject: [PATCH 04/13] Fix build errors on Windows, fix a couple of bugs --- src/Mod/Part/App/PartFeature.cpp | 2 +- src/Mod/Part/App/PartFeature.h | 2 ++ src/Mod/PartDesign/App/FeaturePad.cpp | 5 +++-- src/Mod/PartDesign/App/FeaturePocket.cpp | 1 + src/Mod/PartDesign/Gui/Command.cpp | 5 +++-- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/Mod/Part/App/PartFeature.cpp b/src/Mod/Part/App/PartFeature.cpp index ed936a46b..45e0076e9 100644 --- a/src/Mod/Part/App/PartFeature.cpp +++ b/src/Mod/Part/App/PartFeature.cpp @@ -272,6 +272,7 @@ template class PartExport FeaturePythonT; } // ---------------------------------------------------------------- + #include #include #include @@ -318,4 +319,3 @@ std::vector Part::findAllFacesCutBy( return result; } -// -------------------------------------------------------------------- diff --git a/src/Mod/Part/App/PartFeature.h b/src/Mod/Part/App/PartFeature.h index ed3de3737..9bb4bd49a 100644 --- a/src/Mod/Part/App/PartFeature.h +++ b/src/Mod/Part/App/PartFeature.h @@ -128,6 +128,8 @@ struct cutFaces { TopoDS_Face face; double distsq; }; + +PartExport std::vector findAllFacesCutBy(const TopoDS_Shape& shape, const TopoDS_Shape& face, const gp_Dir& dir); diff --git a/src/Mod/PartDesign/App/FeaturePad.cpp b/src/Mod/PartDesign/App/FeaturePad.cpp index c7742c1f4..c5791abcd 100644 --- a/src/Mod/PartDesign/App/FeaturePad.cpp +++ b/src/Mod/PartDesign/App/FeaturePad.cpp @@ -26,6 +26,7 @@ //# include //# include # include +# include # include # include # include @@ -87,7 +88,7 @@ App::DocumentObjectExecReturn *Pad::execute(void) 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"); + return new App::DocumentObjectExecReturn("Second length of pad too small"); App::DocumentObject* link = Sketch.getValue(); if (!link) @@ -178,7 +179,7 @@ App::DocumentObjectExecReturn *Pad::execute(void) it_near = it; upToFace = (std::string(Type.getValueAsString()) == "UpToLast" ? it_far->face : it_near->face); } else { - if (FaceName.getValue() == "") + 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! diff --git a/src/Mod/PartDesign/App/FeaturePocket.cpp b/src/Mod/PartDesign/App/FeaturePocket.cpp index c7f4fa8ac..b6aec7dcd 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 diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index d671fbe46..c69df762f 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -338,10 +338,11 @@ CmdPartDesignGroove::CmdPartDesignGroove() sAppModule = "PartDesign"; sGroup = QT_TR_NOOP("PartDesign"); sMenuText = QT_TR_NOOP("Groove"); - sToolTipText = QT_TR_NOOP("Revolve a selected sketch"); + sToolTipText = QT_TR_NOOP("Groove a selected sketch"); sWhatsThis = sToolTipText; sStatusTip = sToolTipText; - sPixmap = "PartDesign_Groove"; + //sPixmap = "PartDesign_Groove"; + sPixmap = "PartDesign_Revolution"; } void CmdPartDesignGroove::activated(int iMsg) From 85342cd8ae1eae7673717a3295948178a869038e Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Fri, 8 Jun 2012 20:00:44 +0430 Subject: [PATCH 05/13] Pocket Feature: up to first/last/face and through all options --- data/tests/PocketTest.fcstd | Bin 0 -> 13766 bytes src/Mod/PartDesign/App/FeaturePocket.cpp | 174 ++++++++++++++---- src/Mod/PartDesign/App/FeaturePocket.h | 1 + .../PartDesign/Gui/TaskPocketParameters.cpp | 102 +++++++++- src/Mod/PartDesign/Gui/TaskPocketParameters.h | 7 +- .../PartDesign/Gui/TaskPocketParameters.ui | 120 ++++++++---- 6 files changed, 329 insertions(+), 75 deletions(-) create mode 100644 data/tests/PocketTest.fcstd diff --git a/data/tests/PocketTest.fcstd b/data/tests/PocketTest.fcstd new file mode 100644 index 0000000000000000000000000000000000000000..6acf91ba055c2b8fd6614aecde44c161b3f5d616 GIT binary patch literal 13766 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ᦼ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 B3F80& literal 0 HcmV?d00001 diff --git a/src/Mod/PartDesign/App/FeaturePocket.cpp b/src/Mod/PartDesign/App/FeaturePocket.cpp index b6aec7dcd..a0ef1cdd4 100644 --- a/src/Mod/PartDesign/App/FeaturePocket.cpp +++ b/src/Mod/PartDesign/App/FeaturePocket.cpp @@ -41,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) @@ -60,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; } @@ -114,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); @@ -135,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/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 + + + + + + + + From 58a02d24ae2ad93a6d8a7321d44a37fc88c105b7 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Fri, 8 Jun 2012 20:07:18 +0430 Subject: [PATCH 06/13] Revolution feature: Midplane and Reversed options --- src/Mod/PartDesign/App/FeatureRevolution.cpp | 62 +++++++++++++------ src/Mod/PartDesign/App/FeatureRevolution.h | 4 +- .../Gui/TaskRevolutionParameters.cpp | 35 +++++++++++ .../PartDesign/Gui/TaskRevolutionParameters.h | 4 ++ .../Gui/TaskRevolutionParameters.ui | 23 ++++++- 5 files changed, 104 insertions(+), 24 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureRevolution.cpp b/src/Mod/PartDesign/App/FeatureRevolution.cpp index 317aa52d1..1a14783ae 100644 --- a/src/Mod/PartDesign/App/FeatureRevolution.cpp +++ b/src/Mod/PartDesign/App/FeatureRevolution.cpp @@ -56,6 +56,8 @@ Revolution::Revolution() 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(Midplane,(0)); + ADD_PROPERTY(Reversed, (0)); } short Revolution::mustExecute() const @@ -65,7 +67,8 @@ short Revolution::mustExecute() const ReferenceAxis.isTouched() || Axis.isTouched() || Base.isTouched() || - Angle.isTouched()) + Angle.isTouched() || + Midplane.isTouched()) return 1; return 0; } @@ -151,35 +154,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/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 + + + From 2e89e0015d0fc426cd264234d4243679d348d783 Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 8 Jun 2012 21:33:37 +0200 Subject: [PATCH 07/13] Cleanup, add method getStrValue() --- src/App/PropertyStandard.h | 6 ++---- src/Mod/PartDesign/App/FeaturePad.cpp | 3 --- 2 files changed, 2 insertions(+), 7 deletions(-) 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/Mod/PartDesign/App/FeaturePad.cpp b/src/Mod/PartDesign/App/FeaturePad.cpp index c5791abcd..8335668ae 100644 --- a/src/Mod/PartDesign/App/FeaturePad.cpp +++ b/src/Mod/PartDesign/App/FeaturePad.cpp @@ -23,15 +23,12 @@ #include "PreCompiled.h" #ifndef _PreComp_ -//# include -//# include # include # include # include # include # include # include -//# include # include # include # include From 7144890c93c084fae8eedc4e7c595ce5bc0d05b5 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 9 Jun 2012 11:21:56 +0200 Subject: [PATCH 08/13] Add groove icon --- src/Mod/PartDesign/Gui/Command.cpp | 3 +- src/Mod/PartDesign/Gui/Resources/Makefile.am | 1 + .../PartDesign/Gui/Resources/PartDesign.qrc | 1 + .../Gui/Resources/icons/PartDesign_Groove.svg | 144 ++++++++++++++++++ 4 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Groove.svg diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index c69df762f..335d6d5dd 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -341,8 +341,7 @@ CmdPartDesignGroove::CmdPartDesignGroove() sToolTipText = QT_TR_NOOP("Groove a selected sketch"); sWhatsThis = sToolTipText; sStatusTip = sToolTipText; - //sPixmap = "PartDesign_Groove"; - sPixmap = "PartDesign_Revolution"; + sPixmap = "PartDesign_Groove"; } void CmdPartDesignGroove::activated(int iMsg) 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + From 0bf33b646694e28c3604d4dc118cfc7c6d09a267 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 9 Jun 2012 11:50:02 +0200 Subject: [PATCH 09/13] 0000740: work bench initiation from in fcstd file --- src/Mod/Arch/ArchAxis.py | 3 ++- src/Mod/Arch/ArchBuilding.py | 1 + src/Mod/Arch/ArchCell.py | 1 + src/Mod/Arch/ArchFloor.py | 1 + src/Mod/Arch/ArchRoof.py | 3 ++- src/Mod/Arch/ArchSectionPlane.py | 1 + src/Mod/Arch/ArchSite.py | 1 + src/Mod/Arch/ArchStructure.py | 3 ++- src/Mod/Arch/ArchWall.py | 3 ++- src/Mod/Arch/ArchWindow.py | 3 ++- 10 files changed, 15 insertions(+), 5 deletions(-) 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): From 245cae03ef6c1f30a2a1c89d955c0a383fd22f29 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 9 Jun 2012 13:50:33 +0200 Subject: [PATCH 10/13] 0000144: Add several tools to Part module --- src/Gui/SelectionObject.h | 6 +- src/Mod/Part/App/AppPart.cpp | 1 + src/Mod/Part/App/PartFeatures.cpp | 95 ++++++++++++ src/Mod/Part/App/PartFeatures.h | 23 +++ src/Mod/Part/Gui/CMakeLists.txt | 5 + src/Mod/Part/Gui/Command.cpp | 27 ++++ src/Mod/Part/Gui/TaskSweep.cpp | 243 ++++++++++++++++++++++++++++++ src/Mod/Part/Gui/TaskSweep.h | 81 ++++++++++ src/Mod/Part/Gui/TaskSweep.ui | 60 ++++++++ src/Mod/Part/Gui/Workbench.cpp | 2 +- 10 files changed, 539 insertions(+), 4 deletions(-) create mode 100644 src/Mod/Part/Gui/TaskSweep.cpp create mode 100644 src/Mod/Part/Gui/TaskSweep.h create mode 100644 src/Mod/Part/Gui/TaskSweep.ui 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/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/PartFeatures.cpp b/src/Mod/Part/App/PartFeatures.cpp index 1f2088874..c50c854bb 100644 --- a/src/Mod/Part/App/PartFeatures.cpp +++ b/src/Mod/Part/App/PartFeatures.cpp @@ -196,3 +196,98 @@ App::DocumentObjectExecReturn *Loft::execute(void) return new App::DocumentObjectExecReturn(e->GetMessageString()); } } + +// ---------------------------------------------------------------------------- + +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(Fresnet,(false),"Sweep",App::Prop_None,"Fresnet"); +} + +short Sweep::mustExecute() const +{ + if (Sections.isTouched()) + return 1; + if (Spine.isTouched()) + return 1; + if (Solid.isTouched()) + return 1; + if (Fresnet.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 shape linked."); + const std::vector& subedge = Spine.getSubValues(); + if (subedge.size() != 1) + return new App::DocumentObjectExecReturn("Not exactly one sub-shape linked."); + + TopoDS_Shape edge; + const Part::TopoShape& shape = static_cast(spine)->Shape.getValue(); + if (!shape._Shape.IsNull()) { + if (!subedge[0].empty()) { + edge = shape.getSubShape(subedge[0].c_str()); + } + else { + if (shape._Shape.ShapeType() == TopAbs_EDGE) + edge = shape._Shape; + else if (shape._Shape.ShapeType() == TopAbs_WIRE) + edge = shape._Shape; + } + } + + 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 isFresnet = Fresnet.getValue() ? Standard_True : Standard_False; + + BRepBuilderAPI_MakeWire mkWire(TopoDS::Edge(edge)); + TopoShape myShape(mkWire.Wire()); + this->Shape.setValue(myShape.makePipeShell(profiles, isSolid, isFresnet)); + 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..25d2050a5 100644 --- a/src/Mod/Part/App/PartFeatures.h +++ b/src/Mod/Part/App/PartFeatures.h @@ -73,6 +73,29 @@ 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 Fresnet; + + /** @name methods override feature */ + //@{ + /// recalculate the feature + App::DocumentObjectExecReturn *execute(void); + short mustExecute() const; + //@} + +protected: + void onChanged (const App::Property* prop); +}; + } //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..0639c28a2 --- /dev/null +++ b/src/Mod/Part/Gui/TaskSweep.cpp @@ -0,0 +1,243 @@ +/*************************************************************************** + * 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"); + if (!edgeFilter.match()) { + QMessageBox::critical(this, tr("Sweep path"), tr("Select an edge you want to sweep along.")); + return false; + } + + // get the selected object + const std::vector& result = edgeFilter.Result[0]; + const std::vector& edges = result[0].getSubNames(); + + QString list, solid, fresnet; + if (d->ui.checkSolid->isChecked()) + solid = QString::fromAscii("True"); + else + solid = QString::fromAscii("False"); + + if (d->ui.checkFresnet->isChecked()) + fresnet = QString::fromAscii("True"); + else + fresnet = 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.Fresnet=%5\n" + ) + .arg(list).arg(QLatin1String(result.front().getFeatName())) + .arg(QLatin1String(edges.front().c_str())) + .arg(solid).arg(fresnet).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..f91e754f5 --- /dev/null +++ b/src/Mod/Part/Gui/TaskSweep.ui @@ -0,0 +1,60 @@ + + + PartGui::TaskSweep + + + + 0 + 0 + 336 + 326 + + + + Sweep + + + + + + + + + Create solid + + + + + + + Qt::Horizontal + + + + 130 + 20 + + + + + + + + Fresnet + + + + + + + + Gui::ActionSelector + QWidget +

Gui/Widgets.h
+ + + + + + + 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; From 2a7e6f3e96995bb1a7871b4574a96979f93f3a8b Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 9 Jun 2012 15:55:11 +0200 Subject: [PATCH 11/13] 0000144: Add several tools to Part module --- src/Mod/Part/App/PartFeatures.cpp | 58 +++++++++++++++++++++++++------ src/Mod/Part/App/PartFeatures.h | 6 +++- src/Mod/Part/Gui/TaskSweep.cpp | 36 ++++++++++++------- src/Mod/Part/Gui/TaskSweep.ui | 4 +-- 4 files changed, 78 insertions(+), 26 deletions(-) diff --git a/src/Mod/Part/App/PartFeatures.cpp b/src/Mod/Part/App/PartFeatures.cpp index c50c854bb..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 @@ -199,6 +201,8 @@ App::DocumentObjectExecReturn *Loft::execute(void) // ---------------------------------------------------------------------------- +const char* Part::Sweep::TransitionEnums[]= {"Transformed","Right corner", "Round corner",NULL}; + PROPERTY_SOURCE(Part::Sweep, Part::Feature) Sweep::Sweep() @@ -207,7 +211,9 @@ Sweep::Sweep() 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(Fresnet,(false),"Sweep",App::Prop_None,"Fresnet"); + 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 @@ -218,7 +224,9 @@ short Sweep::mustExecute() const return 1; if (Solid.isTouched()) return 1; - if (Fresnet.isTouched()) + if (Frenet.isTouched()) + return 1; + if (Transition.isTouched()) return 1; return 0; } @@ -234,22 +242,24 @@ App::DocumentObjectExecReturn *Sweep::execute(void) 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 shape linked."); + 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 edge; + TopoDS_Shape path; const Part::TopoShape& shape = static_cast(spine)->Shape.getValue(); if (!shape._Shape.IsNull()) { if (!subedge[0].empty()) { - edge = shape.getSubShape(subedge[0].c_str()); + path = shape.getSubShape(subedge[0].c_str()); } else { if (shape._Shape.ShapeType() == TopAbs_EDGE) - edge = shape._Shape; + path = shape._Shape; else if (shape._Shape.ShapeType() == TopAbs_WIRE) - edge = shape._Shape; + path = shape._Shape; + else + return new App::DocumentObjectExecReturn("Spine is neither an edge nor a wire."); } } @@ -279,11 +289,37 @@ App::DocumentObjectExecReturn *Sweep::execute(void) } Standard_Boolean isSolid = Solid.getValue() ? Standard_True : Standard_False; - Standard_Boolean isFresnet = Fresnet.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; + } - BRepBuilderAPI_MakeWire mkWire(TopoDS::Edge(edge)); - TopoShape myShape(mkWire.Wire()); - this->Shape.setValue(myShape.makePipeShell(profiles, isSolid, isFresnet)); + 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) { diff --git a/src/Mod/Part/App/PartFeatures.h b/src/Mod/Part/App/PartFeatures.h index 25d2050a5..ddaae9627 100644 --- a/src/Mod/Part/App/PartFeatures.h +++ b/src/Mod/Part/App/PartFeatures.h @@ -83,7 +83,8 @@ public: App::PropertyLinkList Sections; App::PropertyLinkSub Spine; App::PropertyBool Solid; - App::PropertyBool Fresnet; + App::PropertyBool Frenet; + App::PropertyEnumeration Transition; /** @name methods override feature */ //@{ @@ -94,6 +95,9 @@ public: protected: void onChanged (const App::Property* prop); + +private: + static const char* TransitionEnums[]; }; } //namespace Part diff --git a/src/Mod/Part/Gui/TaskSweep.cpp b/src/Mod/Part/Gui/TaskSweep.cpp index 0639c28a2..effd5c28b 100644 --- a/src/Mod/Part/Gui/TaskSweep.cpp +++ b/src/Mod/Part/Gui/TaskSweep.cpp @@ -118,25 +118,37 @@ void SweepWidget::findShapes() bool SweepWidget::accept() { Gui::SelectionFilter edgeFilter ("SELECT Part::Feature SUBELEMENT Edge COUNT 1"); - if (!edgeFilter.match()) { - QMessageBox::critical(this, tr("Sweep path"), tr("Select an edge you want to sweep along.")); + 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 - const std::vector& result = edgeFilter.Result[0]; - const std::vector& edges = result[0].getSubNames(); + 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, fresnet; + QString list, solid, frenet; if (d->ui.checkSolid->isChecked()) solid = QString::fromAscii("True"); else solid = QString::fromAscii("False"); - if (d->ui.checkFresnet->isChecked()) - fresnet = QString::fromAscii("True"); + if (d->ui.checkFrenet->isChecked()) + frenet = QString::fromAscii("True"); else - fresnet = QString::fromAscii("False"); + frenet = QString::fromAscii("False"); QTextStream str(&list); @@ -158,11 +170,11 @@ bool SweepWidget::accept() "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.Fresnet=%5\n" + "App.getDocument('%6').ActiveObject.Frenet=%5\n" ) - .arg(list).arg(QLatin1String(result.front().getFeatName())) - .arg(QLatin1String(edges.front().c_str())) - .arg(solid).arg(fresnet).arg(QString::fromAscii(d->document.c_str())); + .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"); diff --git a/src/Mod/Part/Gui/TaskSweep.ui b/src/Mod/Part/Gui/TaskSweep.ui index f91e754f5..898596365 100644 --- a/src/Mod/Part/Gui/TaskSweep.ui +++ b/src/Mod/Part/Gui/TaskSweep.ui @@ -38,9 +38,9 @@ - + - Fresnet + Frenet From 6a2a72627635d9b72d24fa90312586e7967e6f8c Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 9 Jun 2012 16:37:06 +0200 Subject: [PATCH 12/13] Fix bugs in Groove and Revolution --- src/Mod/PartDesign/App/FeatureGroove.cpp | 13 +++++++------ src/Mod/PartDesign/App/FeatureRevolution.cpp | 15 ++++++++------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureGroove.cpp b/src/Mod/PartDesign/App/FeatureGroove.cpp index 1e7f7d660..1cf17541d 100644 --- a/src/Mod/PartDesign/App/FeatureGroove.cpp +++ b/src/Mod/PartDesign/App/FeatureGroove.cpp @@ -52,12 +52,12 @@ PROPERTY_SOURCE(PartDesign::Groove, PartDesign::SketchBased) Groove::Groove() { - 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(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(Midplane,(0)); - ADD_PROPERTY(Reversed, (0)); + 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 @@ -68,7 +68,8 @@ short Groove::mustExecute() const Axis.isTouched() || Base.isTouched() || Angle.isTouched() || - Midplane.isTouched()) + Midplane.isTouched() || + Reversed.isTouched()) return 1; return 0; } diff --git a/src/Mod/PartDesign/App/FeatureRevolution.cpp b/src/Mod/PartDesign/App/FeatureRevolution.cpp index 1a14783ae..a31bebf43 100644 --- a/src/Mod/PartDesign/App/FeatureRevolution.cpp +++ b/src/Mod/PartDesign/App/FeatureRevolution.cpp @@ -52,12 +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(Midplane,(0)); - ADD_PROPERTY(Reversed, (0)); + 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 @@ -68,7 +68,8 @@ short Revolution::mustExecute() const Axis.isTouched() || Base.isTouched() || Angle.isTouched() || - Midplane.isTouched()) + Midplane.isTouched() || + Reversed.isTouched()) return 1; return 0; } From 55a205062a9660f7c9bef116505a2e7a8c342d00 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 9 Jun 2012 17:16:41 +0200 Subject: [PATCH 13/13] Show some help text in sweep panel --- src/Mod/Part/Gui/TaskSweep.ui | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/Mod/Part/Gui/TaskSweep.ui b/src/Mod/Part/Gui/TaskSweep.ui index 898596365..6cfab459d 100644 --- a/src/Mod/Part/Gui/TaskSweep.ui +++ b/src/Mod/Part/Gui/TaskSweep.ui @@ -14,17 +14,17 @@ Sweep - + - + Create solid - + Qt::Horizontal @@ -37,13 +37,21 @@ - + Frenet + + + + Select one or more profiles and select an edge or wire +in the 3D view for the sweep path. + + +