diff --git a/src/Mod/PartDesign/App/Feature.cpp b/src/Mod/PartDesign/App/Feature.cpp index fe5c0ce07..2b56be6fb 100644 --- a/src/Mod/PartDesign/App/Feature.cpp +++ b/src/Mod/PartDesign/App/Feature.cpp @@ -116,7 +116,7 @@ bool Feature::isDatum(const App::DocumentObject* feature) feature->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId()); } -TopoDS_Shape Feature::makeShapeFromPlane(const App::DocumentObject* obj) +gp_Pln Feature::makePlnFromPlane(const App::DocumentObject* obj) { const App::Plane* plane = static_cast(obj); if (plane == NULL) @@ -125,7 +125,12 @@ TopoDS_Shape Feature::makeShapeFromPlane(const App::DocumentObject* obj) Base::Rotation rot = plane->Placement.getValue().getRotation(); Base::Vector3d normal(0,0,1); rot.multVec(normal, normal); - BRepBuilderAPI_MakeFace builder(gp_Pln(gp_Pnt(0,0,0), gp_Dir(normal.x,normal.y,normal.z))); + return gp_Pln(gp_Pnt(0,0,0), gp_Dir(normal.x,normal.y,normal.z)); +} + +TopoDS_Shape Feature::makeShapeFromPlane(const App::DocumentObject* obj) +{ + BRepBuilderAPI_MakeFace builder(makePlnFromPlane(obj)); if (!builder.IsDone()) throw Base::Exception("Feature: Could not create shape from base plane"); diff --git a/src/Mod/PartDesign/App/Feature.h b/src/Mod/PartDesign/App/Feature.h index daa024c45..adba54e43 100644 --- a/src/Mod/PartDesign/App/Feature.h +++ b/src/Mod/PartDesign/App/Feature.h @@ -28,6 +28,7 @@ #include class gp_Pnt; +class gp_Pln; /// Base class of all additive features in PartDesign @@ -67,6 +68,7 @@ protected: /// Grab any point from the given face static const gp_Pnt getPointFromFace(const TopoDS_Face& f); /// Make a shape from a base plane (convenience method) + static gp_Pln makePlnFromPlane(const App::DocumentObject* obj); static TopoDS_Shape makeShapeFromPlane(const App::DocumentObject* obj); }; diff --git a/src/Mod/PartDesign/App/FeatureDraft.cpp b/src/Mod/PartDesign/App/FeatureDraft.cpp index eda4e4bf2..f3e8a686f 100644 --- a/src/Mod/PartDesign/App/FeatureDraft.cpp +++ b/src/Mod/PartDesign/App/FeatureDraft.cpp @@ -47,10 +47,13 @@ # include #endif +#include #include #include #include "FeatureDraft.h" +#include "DatumLine.h" +#include "DatumPlane.h" #include @@ -110,29 +113,35 @@ App::DocumentObjectExecReturn *Draft::execute(void) // Pull direction gp_Dir pullDirection; - App::DocumentObject* refDirection = PullDirection.getValue(); + App::DocumentObject* refDirection = PullDirection.getValue(); if (refDirection != NULL) { - if (!refDirection->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) - throw Base::Exception("Pull direction reference must be an edge of a feature"); - std::vector subStrings = PullDirection.getSubValues(); - if (subStrings.empty() || subStrings[0].empty()) - throw Base::Exception("No pull direction reference specified"); + if (refDirection->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId())) { + PartDesign::Line* line = static_cast(refDirection); + Base::Vector3d d = line->getDirection(); + pullDirection = gp_Dir(d.x, d.y, d.z); + } else if (refDirection->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { + std::vector subStrings = PullDirection.getSubValues(); + if (subStrings.empty() || subStrings[0].empty()) + throw Base::Exception("No pull direction reference specified"); - Part::Feature* refFeature = static_cast(refDirection); - Part::TopoShape refShape = refFeature->Shape.getShape(); - TopoDS_Shape ref = refShape.getSubShape(subStrings[0].c_str()); + Part::Feature* refFeature = static_cast(refDirection); + Part::TopoShape refShape = refFeature->Shape.getShape(); + TopoDS_Shape ref = refShape.getSubShape(subStrings[0].c_str()); - if (ref.ShapeType() == TopAbs_EDGE) { - TopoDS_Edge refEdge = TopoDS::Edge(ref); - if (refEdge.IsNull()) - throw Base::Exception("Failed to extract pull direction reference edge"); - BRepAdaptor_Curve adapt(refEdge); - if (adapt.GetType() != GeomAbs_Line) - throw Base::Exception("Pull direction reference edge must be linear"); + if (ref.ShapeType() == TopAbs_EDGE) { + TopoDS_Edge refEdge = TopoDS::Edge(ref); + if (refEdge.IsNull()) + throw Base::Exception("Failed to extract pull direction reference edge"); + BRepAdaptor_Curve adapt(refEdge); + if (adapt.GetType() != GeomAbs_Line) + throw Base::Exception("Pull direction reference edge must be linear"); - pullDirection = adapt.Line().Direction(); + pullDirection = adapt.Line().Direction(); + } else { + throw Base::Exception("Pull direction reference must be an edge or a datum line"); + } } else { - throw Base::Exception("Pull direction reference must be an edge"); + throw Base::Exception("Pull direction reference must be an edge of a feature or a datum line"); } TopLoc_Location invObjLoc = this->getLocation().Inverted(); @@ -188,43 +197,52 @@ App::DocumentObjectExecReturn *Draft::execute(void) if (!found) throw Base::Exception("No neutral plane specified and none can be guessed"); } else { - if (!refPlane->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) - throw Base::Exception("Neutral plane reference must be face of a feature"); - std::vector subStrings = NeutralPlane.getSubValues(); - if (subStrings.empty() || subStrings[0].empty()) - throw Base::Exception("No neutral plane reference specified"); + if (refPlane->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { + PartDesign::Plane* plane = static_cast(refPlane); + Base::Vector3d b = plane->getBasePoint(); + Base::Vector3d n = plane->getNormal(); + neutralPlane = gp_Pln(gp_Pnt(b.x, b.y, b.z), gp_Dir(n.x, n.y, n.z)); + } else if (refPlane->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { + neutralPlane = Feature::makePlnFromPlane(refPlane); + } else if (refPlane->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { + std::vector subStrings = NeutralPlane.getSubValues(); + if (subStrings.empty() || subStrings[0].empty()) + throw Base::Exception("No neutral plane reference specified"); - Part::Feature* refFeature = static_cast(refPlane); - Part::TopoShape refShape = refFeature->Shape.getShape(); - TopoDS_Shape ref = refShape.getSubShape(subStrings[0].c_str()); + Part::Feature* refFeature = static_cast(refPlane); + Part::TopoShape refShape = refFeature->Shape.getShape(); + TopoDS_Shape ref = refShape.getSubShape(subStrings[0].c_str()); - if (ref.ShapeType() == TopAbs_FACE) { - TopoDS_Face refFace = TopoDS::Face(ref); - if (refFace.IsNull()) - throw Base::Exception("Failed to extract neutral plane reference face"); - BRepAdaptor_Surface adapt(refFace); - if (adapt.GetType() != GeomAbs_Plane) - throw Base::Exception("Neutral plane reference face must be planar"); + if (ref.ShapeType() == TopAbs_FACE) { + TopoDS_Face refFace = TopoDS::Face(ref); + if (refFace.IsNull()) + throw Base::Exception("Failed to extract neutral plane reference face"); + BRepAdaptor_Surface adapt(refFace); + if (adapt.GetType() != GeomAbs_Plane) + throw Base::Exception("Neutral plane reference face must be planar"); - neutralPlane = adapt.Plane(); - } else if (ref.ShapeType() == TopAbs_EDGE) { - if (refDirection != NULL) { - // Create neutral plane through edge normal to pull direction - TopoDS_Edge refEdge = TopoDS::Edge(ref); - if (refEdge.IsNull()) - throw Base::Exception("Failed to extract neutral plane reference edge"); - BRepAdaptor_Curve c(refEdge); + neutralPlane = adapt.Plane(); + } else if (ref.ShapeType() == TopAbs_EDGE) { + if (refDirection != NULL) { + // Create neutral plane through edge normal to pull direction + TopoDS_Edge refEdge = TopoDS::Edge(ref); + if (refEdge.IsNull()) + throw Base::Exception("Failed to extract neutral plane reference edge"); + BRepAdaptor_Curve c(refEdge); if (c.GetType() != GeomAbs_Line) - throw Base::Exception("Neutral plane reference edge must be linear"); - double a = c.Line().Angle(gp_Lin(c.Value(c.FirstParameter()), pullDirection)); - if (std::fabs(a - M_PI_2) > Precision::Confusion()) - throw Base::Exception("Neutral plane reference edge must be normal to pull direction"); - neutralPlane = gp_Pln(c.Value(c.FirstParameter()), pullDirection); + throw Base::Exception("Neutral plane reference edge must be linear"); + double a = c.Line().Angle(gp_Lin(c.Value(c.FirstParameter()), pullDirection)); + if (std::fabs(a - M_PI_2) > Precision::Confusion()) + throw Base::Exception("Neutral plane reference edge must be normal to pull direction"); + neutralPlane = gp_Pln(c.Value(c.FirstParameter()), pullDirection); + } else { + throw Base::Exception("Neutral plane reference can only be an edge if pull direction is defined"); + } } else { - throw Base::Exception("Neutral plane reference can only be an edge if pull direction is defined"); + throw Base::Exception("Neutral plane reference must be a face"); } } else { - throw Base::Exception("Neutral plane reference must be a face"); + throw Base::Exception("Neutral plane reference must be face of a feature or a datum plane"); } TopLoc_Location invObjLoc = this->getLocation().Inverted(); diff --git a/src/Mod/PartDesign/Gui/ReferenceSelection.cpp b/src/Mod/PartDesign/Gui/ReferenceSelection.cpp index eb33af112..ef943f762 100644 --- a/src/Mod/PartDesign/Gui/ReferenceSelection.cpp +++ b/src/Mod/PartDesign/Gui/ReferenceSelection.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -111,3 +112,31 @@ bool ReferenceSelection::allow(App::Document* pDoc, App::DocumentObject* pObj, c } return false; } + +namespace PartDesignGui +{ + +const QString getRefStr(const App::DocumentObject* obj, const std::vector& sub) +{ + if (obj == NULL) + return QString::fromAscii(""); + + if (PartDesign::Feature::isDatum(obj)) + return QString::fromAscii(obj->getNameInDocument()); + else + return QString::fromAscii(obj->getNameInDocument()) + QString::fromAscii(":") + + QString::fromAscii(sub.front().c_str()); +} + +const std::string getPythonStr(const App::DocumentObject* obj, const std::vector& sub) +{ + if (obj == NULL) + return ""; + + if (PartDesign::Feature::isDatum(obj)) + return std::string("(App.ActiveDocument.") + obj->getNameInDocument() + ", [\"\"])"; + else + return std::string("(App.ActiveDocument.") + obj->getNameInDocument() + ", [\"" + sub.front() + "\"])"; +} + +} diff --git a/src/Mod/PartDesign/Gui/ReferenceSelection.h b/src/Mod/PartDesign/Gui/ReferenceSelection.h index efdf62422..0055d65fa 100644 --- a/src/Mod/PartDesign/Gui/ReferenceSelection.h +++ b/src/Mod/PartDesign/Gui/ReferenceSelection.h @@ -47,6 +47,12 @@ public: bool allow(App::Document* pDoc, App::DocumentObject* pObj, const char* sSubName); }; +// Convenience methods +/// Return reference as string for UI elements (format : +const QString getRefStr(const App::DocumentObject* obj, const std::vector& sub); +/// Return reference as string for python (format (, [""]) ) +const std::string getPythonStr(const App::DocumentObject* obj, const std::vector& sub); + } //namespace PartDesignGui #endif // GUI_ReferenceSelection_H diff --git a/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp b/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp index de55ef332..c220b4683 100644 --- a/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp @@ -101,13 +101,30 @@ TaskDraftParameters::TaskDraftParameters(ViewProviderDraft *DraftView,QWidget *p connect(action, SIGNAL(triggered()), this, SLOT(onFaceDeleted())); ui->listWidgetFaces->setContextMenuPolicy(Qt::ActionsContextMenu); + App::DocumentObject* ref = pcDraft->NeutralPlane.getValue(); strings = pcDraft->NeutralPlane.getSubValues(); - std::string neutralPlane = (strings.empty() ? "" : strings[0]); - ui->linePlane->setText(QString::fromStdString(neutralPlane)); + ui->linePlane->setText(getRefStr(ref, strings)); + ref = pcDraft->PullDirection.getValue(); strings = pcDraft->PullDirection.getSubValues(); - std::string pullDirection = (strings.empty() ? "" : strings[0]); - ui->lineLine->setText(QString::fromStdString(pullDirection)); + ui->lineLine->setText(getRefStr(ref, strings)); +} + +void TaskDraftParameters::getReferencedSelection(const Gui::SelectionChanges& msg, + App::DocumentObject*& selObj, std::vector& selSub) +{ + PartDesign::DressUp* pcDressup = static_cast(DraftView->getObject()); + selObj = pcDressup->getDocument()->getObject(msg.pObjectName); + if (selObj == pcDressup) + return; + std::string subname = msg.pSubName; + + // Remove subname for planes and datum features + if (PartDesign::Feature::isDatum(selObj)) { + subname = ""; + } + + selSub = std::vector(1,subname); } void TaskDraftParameters::onSelectionChanged(const Gui::SelectionChanges& msg) @@ -162,27 +179,22 @@ void TaskDraftParameters::onSelectionChanged(const Gui::SelectionChanges& msg) ui->buttonFaceRemove->setChecked(false); exitSelectionMode(); } - } else if ((selectionMode == plane) && (subName.size() > 4) && - ((subName.substr(0,4) == "Face") || (subName.substr(0,4) == "Edge"))) { - - if (strcmp(msg.pObjectName, fname) != 0) - return; - - std::vector planes(1,subName); - pcDraft->NeutralPlane.setValue(base, planes); - ui->linePlane->setText(QString::fromStdString(subName)); + } else if ((selectionMode == plane)) { + std::vector planes; + App::DocumentObject* selObj; + getReferencedSelection(msg, selObj, planes); + pcDraft->NeutralPlane.setValue(selObj, planes); + ui->linePlane->setText(getRefStr(selObj, planes)); pcDraft->getDocument()->recomputeFeature(pcDraft); ui->buttonPlane->setChecked(false); exitSelectionMode(); } else if ((selectionMode == line) && (subName.size() > 4 && subName.substr(0,4) == "Edge")) { - - if (strcmp(msg.pObjectName, fname) != 0) - return; - - std::vector edges(1,subName); - pcDraft->PullDirection.setValue(base, edges); - ui->lineLine->setText(QString::fromStdString(subName)); + std::vector edges; + App::DocumentObject* selObj; + getReferencedSelection(msg, selObj, edges); + pcDraft->PullDirection.setValue(selObj, edges); + ui->lineLine->setText(getRefStr(selObj, edges)); pcDraft->getDocument()->recomputeFeature(pcDraft); ui->buttonLine->setChecked(false); @@ -258,14 +270,22 @@ void TaskDraftParameters::onFaceDeleted(void) pcDraft->getDocument()->recomputeFeature(pcDraft); } -const std::string TaskDraftParameters::getPlane(void) const +void TaskDraftParameters::getPlane(App::DocumentObject*& obj, std::vector& sub) const { - return ui->linePlane->text().toStdString(); + sub = std::vector(1,""); + QStringList parts = ui->linePlane->text().split(QChar::fromAscii(':')); + obj = DraftView->getObject()->getDocument()->getObject(parts[0].toStdString().c_str()); + if (parts.size() > 1) + sub[0] = parts[1].toStdString(); } -const std::string TaskDraftParameters::getLine(void) const +void TaskDraftParameters::getLine(App::DocumentObject*& obj, std::vector& sub) const { - return ui->lineLine->text().toStdString(); + sub = std::vector(1,""); + QStringList parts = ui->lineLine->text().split(QChar::fromAscii(':')); + obj = DraftView->getObject()->getDocument()->getObject(parts[0].toStdString().c_str()); + if (parts.size() > 1) + sub[0] = parts[1].toStdString(); } void TaskDraftParameters::hideObject() @@ -379,7 +399,11 @@ bool TaskDlgDraftParameters::accept() parameter->showObject(); // Force the user to select a neutral plane - if (parameter->getPlane().empty()) { + std::vector strings; + App::DocumentObject* obj; + parameter->getPlane(obj, strings); + std::string neutralPlane = getPythonStr(obj, strings); + if (neutralPlane.empty()) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Missing neutral plane"), QObject::tr("Please select a plane or an edge plus a pull direction")); return false; @@ -403,20 +427,14 @@ bool TaskDlgDraftParameters::accept() QMessageBox::warning(parameter, tr("Input error"), QString::fromLatin1(e.what())); return false; } - std::string neutralPlane = parameter->getPlane(); if (!neutralPlane.empty()) { - QString buf = QString::fromUtf8("(App.ActiveDocument.%1,[\"%2\"])"); - buf = buf.arg(QString::fromUtf8(parameter->getBase()->getNameInDocument())); - buf = buf.arg(QString::fromUtf8(neutralPlane.c_str())); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.NeutralPlane = %s", name.c_str(), buf.toStdString().c_str()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.NeutralPlane = %s", name.c_str(), neutralPlane.c_str()); } else Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.NeutralPlane = None", name.c_str()); - std::string pullDirection = parameter->getLine(); + parameter->getLine(obj, strings); + std::string pullDirection = getPythonStr(obj, strings); if (!pullDirection.empty()) { - QString buf = QString::fromUtf8("(App.ActiveDocument.%1,[\"%2\"])"); - buf = buf.arg(QString::fromUtf8(parameter->getBase()->getNameInDocument())); - buf = buf.arg(QString::fromUtf8(pullDirection.c_str())); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.PullDirection = %s", name.c_str(), buf.toStdString().c_str()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.PullDirection = %s", name.c_str(), pullDirection.c_str()); } else Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.PullDirection = None", name.c_str()); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); diff --git a/src/Mod/PartDesign/Gui/TaskDraftParameters.h b/src/Mod/PartDesign/Gui/TaskDraftParameters.h index 7a19fef51..3d93f389e 100644 --- a/src/Mod/PartDesign/Gui/TaskDraftParameters.h +++ b/src/Mod/PartDesign/Gui/TaskDraftParameters.h @@ -54,8 +54,8 @@ public: const double getAngle(void) const; const bool getReversed(void) const; const std::vector getFaces(void) const; - const std::string getPlane(void) const; - const std::string getLine(void) const; + void getPlane(App::DocumentObject*& obj, std::vector& sub) const; + void getLine(App::DocumentObject*& obj, std::vector& sub) const; App::DocumentObject *getBase(void) const; void hideObject(); @@ -84,6 +84,9 @@ private: enum selectionModes { none, faceAdd, faceRemove, plane, line }; selectionModes selectionMode; + + void getReferencedSelection(const Gui::SelectionChanges& msg, + App::DocumentObject*& selObj, std::vector& selSub); }; /// simulation dialog for the TaskView diff --git a/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp b/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp index ce5f7f5a8..1c80e5ff1 100644 --- a/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp @@ -245,30 +245,6 @@ void TaskTransformedParameters::getReferencedSelection(const Gui::SelectionChang selSub = std::vector(1,subname); } -const QString TaskTransformedParameters::getRefStr(const App::DocumentObject* obj, const std::vector& sub) -{ - if (obj == NULL) - return QString::fromAscii(""); - - if (PartDesign::Feature::isDatum(obj)) - return QString::fromAscii(obj->getNameInDocument()); - else - return QString::fromAscii(obj->getNameInDocument()) + QString::fromAscii(":") + - QString::fromAscii(sub.front().c_str()); -} - -const std::string TaskTransformedParameters::getPythonStr(const App::DocumentObject* obj, const std::vector& sub) -{ - if (obj == NULL) - return ""; - - if (PartDesign::Feature::isDatum(obj)) - return std::string("(App.ActiveDocument.") + obj->getNameInDocument() + ", [\"\"])"; - else - return std::string("(App.ActiveDocument.") + obj->getNameInDocument() + ", [\"" + sub.front() + "\"])"; -} - - //************************************************************************** //************************************************************************** // TaskDialog diff --git a/src/Mod/PartDesign/Gui/TaskTransformedParameters.h b/src/Mod/PartDesign/Gui/TaskTransformedParameters.h index 30209268a..ebcb0d47d 100644 --- a/src/Mod/PartDesign/Gui/TaskTransformedParameters.h +++ b/src/Mod/PartDesign/Gui/TaskTransformedParameters.h @@ -62,10 +62,7 @@ public: /// Get the support object either of the object associated with this feature or with the parent feature (MultiTransform mode) App::DocumentObject* getSupportObject() const; /// Get the sketch object of the first original either of the object associated with this feature or with the parent feature (MultiTransform mode) - App::DocumentObject* getSketchObject() const; - - /// Return reference as string for python (format (, [""]) ) - const std::string getPythonStr(const App::DocumentObject* selObj, const std::vector& selSub); + App::DocumentObject* getSketchObject() const; void exitSelectionMode(); @@ -93,8 +90,6 @@ protected: /// Extract reference from Selection (convenience method) void getReferencedSelection(const Gui::SelectionChanges& msg, App::DocumentObject*& selObj, std::vector& selSub); - /// Return reference as string for UI elements (format : - const QString getRefStr(const App::DocumentObject* selObj, const std::vector& selSub); bool isViewUpdated() const; int getUpdateViewTimeout() const;