From 1ec99c5d3280709d8cc222713d45ab9548bb9ac4 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Wed, 10 Apr 2013 17:41:26 +0430 Subject: [PATCH] Work on inserting, removing, hiding and showing features in the body --- src/Gui/Tree.cpp | 6 + src/Gui/Tree.h | 3 +- src/Mod/Assembly/App/AppAssemblyPy.cpp | 31 ++-- src/Mod/Part/App/Part2DObject.cpp | 2 + src/Mod/PartDesign/App/Body.cpp | 185 ++++++++++++++++--- src/Mod/PartDesign/App/Body.h | 44 +++-- src/Mod/PartDesign/App/BodyPy.xml | 10 + src/Mod/PartDesign/App/BodyPyImp.cpp | 46 +++++ src/Mod/PartDesign/Gui/Command.cpp | 166 +++++++---------- src/Mod/PartDesign/Gui/FeaturePickDialog.cpp | 2 + src/Mod/PartDesign/Gui/FeaturePickDialog.h | 3 +- src/Mod/PartDesign/Gui/ViewProvider.cpp | 25 +++ src/Mod/PartDesign/Gui/ViewProvider.h | 2 + 13 files changed, 365 insertions(+), 160 deletions(-) diff --git a/src/Gui/Tree.cpp b/src/Gui/Tree.cpp index 37d290162..b267fd12b 100644 --- a/src/Gui/Tree.cpp +++ b/src/Gui/Tree.cpp @@ -1032,6 +1032,12 @@ void DocumentItem::slotHighlightObject (const Gui::ViewProviderDocumentObject& o else jt->second->setData(0, Qt::BackgroundColorRole,QVariant()); break; + case Gui::LightBlue: + if(set) + jt->second->setBackgroundColor(0,QColor(230,230,255)); + else + jt->second->setData(0, Qt::BackgroundColorRole,QVariant()); + break; default: break; } diff --git a/src/Gui/Tree.h b/src/Gui/Tree.h index 2a8fa840e..fb3e3f3db 100644 --- a/src/Gui/Tree.h +++ b/src/Gui/Tree.h @@ -44,7 +44,8 @@ enum HighlightMode { Underlined, Italic , Overlined , Bold , - Blue + Blue , + LightBlue }; /// highlight modes for the tree items diff --git a/src/Mod/Assembly/App/AppAssemblyPy.cpp b/src/Mod/Assembly/App/AppAssemblyPy.cpp index 7c0997d49..812d2cdec 100644 --- a/src/Mod/Assembly/App/AppAssemblyPy.cpp +++ b/src/Mod/Assembly/App/AppAssemblyPy.cpp @@ -31,11 +31,12 @@ #include #include -#include #include #include +#include "ViewProviderBody.h" + namespace PartDesignGui { // pointer to the active assembly object @@ -48,35 +49,25 @@ Gui::ViewProviderDocumentObject *ActiveVp =0; static PyObject * setActivePart(PyObject *self, PyObject *args) { - if(PartDesignGui::ActivePartObject){ - // check if the document not already closed - std::vector docs = App::GetApplication().getDocuments(); - for(std::vector::const_iterator it=docs.begin();it!=docs.end();++it) - if(*it == PartDesignGui::ActiveAppDoc){ - PartDesignGui::ActiveGuiDoc->signalHighlightObject(*PartDesignGui::ActiveVp,Gui::Underlined,false); - break; - } - - PartDesignGui::ActivePartObject->IsActive.setValue(false); - PartDesignGui::ActivePartObject = 0; - PartDesignGui::ActiveGuiDoc =0; - PartDesignGui::ActiveAppDoc =0; - PartDesignGui::ActiveVp =0; - } - PyObject *object=0; if (PyArg_ParseTuple(args,"|O!",&(PartDesign::BodyPy::Type), &object)&& object) { PartDesign::Body* Item = static_cast(object)->getBodyPtr(); // Should be set! assert(Item); - Item->IsActive.setValue(true); + if (PartDesignGui::ActivePartObject != NULL) + PartDesignGui::ActivePartObject->IsActive.setValue(false); PartDesignGui::ActivePartObject = Item; PartDesignGui::ActiveAppDoc = Item->getDocument(); PartDesignGui::ActiveGuiDoc = Gui::Application::Instance->getDocument(PartDesignGui::ActiveAppDoc); PartDesignGui::ActiveVp = dynamic_cast (PartDesignGui::ActiveGuiDoc->getViewProvider(Item)) ; - PartDesignGui::ActiveGuiDoc->signalHighlightObject(*PartDesignGui::ActiveVp,Gui::Underlined,true); - + Item->IsActive.setValue(true); + } else { + // This handles the case of deactivating the workbench + PartDesignGui::ActivePartObject = 0; + PartDesignGui::ActiveGuiDoc =0; + PartDesignGui::ActiveAppDoc =0; + PartDesignGui::ActiveVp =0; } Py_Return; diff --git a/src/Mod/Part/App/Part2DObject.cpp b/src/Mod/Part/App/Part2DObject.cpp index 46f063541..2a68c0018 100644 --- a/src/Mod/Part/App/Part2DObject.cpp +++ b/src/Mod/Part/App/Part2DObject.cpp @@ -80,6 +80,8 @@ void Part2DObject::positionBySupport(void) bool Reverse = false; gp_Pln plane; App::DocumentObject* support = Support.getValue(); + if (support == NULL) + throw Base::Exception("Sketch support has been deleted"); if (support->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { Place = static_cast(support)->Placement.getValue(); diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index d6b4b9489..6c58a58f4 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -28,10 +28,14 @@ #include #include "Feature.h" +#include "DatumFeature.h" #include "Body.h" #include "BodyPy.h" +#include +#include #include +#include "FeatureSketchBased.h" using namespace PartDesign; @@ -46,6 +50,26 @@ Body::Body() ADD_PROPERTY(IsActive,(0)); } +void Body::onChanged(const App::Property *prop) +{ + Base::Console().Error("Checking Body '%s' for sanity\n", getNameInDocument()); + App::DocumentObject* tip = Tip.getValue(); + Base::Console().Error(" Tip: %s\n", (tip == NULL) ? "None" : tip->getNameInDocument()); + std::vector model = Model.getValues(); + Base::Console().Error(" Model:\n"); + for (std::vector::const_iterator m = model.begin(); m != model.end(); m++) { + Base::Console().Error(" %s", (*m)->getNameInDocument()); + if ((*m)->getTypeId().isDerivedFrom(PartDesign::SketchBased::getClassTypeId())) { + App::DocumentObject* baseFeature = static_cast(*m)->BaseFeature.getValue(); + Base::Console().Error(", Base: %s\n", baseFeature == NULL ? "None" : baseFeature->getNameInDocument()); + } else { + Base::Console().Error("\n"); + } + } + + return Part::Feature::onChanged(prop); +} + short Body::mustExecute() const { if (Tip.isTouched() ) @@ -66,7 +90,7 @@ const Part::TopoShape Body::getTipShape() // get the shape of the tip return static_cast(link)->Shape.getShape(); } - +/* const Part::TopoShape Body::getPreviousSolid(const PartDesign::Feature* f) { std::vector features = Model.getValues(); @@ -76,8 +100,9 @@ const Part::TopoShape Body::getPreviousSolid(const PartDesign::Feature* f) return Part::TopoShape(); // move to previous feature it--; - // Skip sketches - while (!(*it)->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId())) { + // Skip sketches and datum features + while ((*it)->getTypeId().isDerivedFrom(PartDesign::Datum::getClassTypeId()) || + (*it)->getTypeId().isDerivedFrom(Part::Part2DObject::getClassTypeId())) { if (it == features.begin()) return Part::TopoShape(); it--; @@ -85,38 +110,47 @@ const Part::TopoShape Body::getPreviousSolid(const PartDesign::Feature* f) return static_cast(*it)->Shape.getShape(); } - -App::DocumentObject* Body::getTipSolidFeature() +*/ +App::DocumentObject* Body::getPrevSolidFeature(App::DocumentObject *start, const bool inclusive) { std::vector features = Model.getValues(); if (features.empty()) return NULL; - std::vector::const_iterator it = std::find(features.begin(), features.end(), Tip.getValue()); + App::DocumentObject* st = (start == NULL ? Tip.getValue() : start); - // Skip sketches - while (!(*it)->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId())) { + if (inclusive && isSolidFeature(st)) + return st; + + std::vector::iterator it = std::find(features.begin(), features.end(), st); + if (it == features.end()) return NULL; // Invalid start object + + // Skip sketches and datum features + do { if (it == features.begin()) return NULL; it--; - } + } while (!isSolidFeature(*it)); return *it; } -App::DocumentObject* Body::getNextSolidFeature() +App::DocumentObject* Body::getNextSolidFeature(App::DocumentObject *start, const bool inclusive) { std::vector features = Model.getValues(); if (features.empty()) return NULL; - if (Tip.getValue() == features.back()) return NULL; + App::DocumentObject* st = (start == NULL ? Tip.getValue() : start); - std::vector::const_iterator it = std::find(features.begin(), features.end(), Tip.getValue()); - it++; // Move beyond the Tip + if (inclusive && isSolidFeature(st)) + return st; - // Skip sketches - while (!(*it)->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId())) { + std::vector::iterator it = std::find(features.begin(), features.end(), st); + if (it == features.end()) return NULL; // Invalid start object + + // Skip sketches and datum features + do { it++; if (it == features.end()) return NULL; - } + } while (!isSolidFeature(*it)); return *it; } @@ -127,19 +161,122 @@ const bool Body::hasFeature(const App::DocumentObject* f) return std::find(features.begin(), features.end(), f) != features.end(); } -const bool Body::insertMode() { +const bool Body::isAfterTip(const App::DocumentObject *f) { std::vector features = Model.getValues(); - if (features.empty()) return false; - return Tip.getValue() != features.back(); + std::vector::const_iterator it = std::find(features.begin(), features.end(), f); + std::vector::const_iterator tip = std::find(features.begin(), features.end(), Tip.getValue()); + return (it > tip); +} + +const bool Body::isSolidFeature(const App::DocumentObject* f) +{ + return (!f->getTypeId().isDerivedFrom(PartDesign::Datum::getClassTypeId()) && + !f->getTypeId().isDerivedFrom(Part::Part2DObject::getClassTypeId())); +} + +Body* Body::findBodyOf(const App::DocumentObject* f) +{ + App::Document* doc = App::GetApplication().getActiveDocument(); + if (doc != NULL) { + std::vector bodies = doc->getObjectsOfType(PartDesign::Body::getClassTypeId()); + for (std::vector::const_iterator b = bodies.begin(); b != bodies.end(); b++) { + PartDesign::Body* body = static_cast(*b); + if (body->hasFeature(f)) + return body; + } + } + + return NULL; +} + +void Body::insertFeature(App::DocumentObject *feature) +{ + // Set the BaseFeature property + // Note: This is not strictly necessary for Datum features + if (feature->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId())) { + App::DocumentObject* prevSolidFeature = getPrevSolidFeature(NULL, true); + if (prevSolidFeature != NULL) + // Set BaseFeature property to previous feature (this might be the Tip feature) + static_cast(feature)->BaseFeature.setValue(prevSolidFeature); + } + + if (Body::isSolidFeature(feature)) { + // Reroute the next solid feature's BaseFeature property to this feature + App::DocumentObject* nextSolidFeature = getNextSolidFeature(NULL, false); + if (nextSolidFeature != NULL) + static_cast(nextSolidFeature)->BaseFeature.setValue(feature); + } + + // Insert the new feature after the current Tip feature + App::DocumentObject* tipFeature = Tip.getValue(); + std::vector model = Model.getValues(); + if (tipFeature == NULL) { + if (model.empty()) + // First feature in the body + model.push_back(feature); + else + throw Base::Exception("Body has features, but Tip is not valid"); + } else { + // Insert after Tip + std::vector::iterator it = std::find(model.begin(), model.end(), tipFeature); + if (it == model.end()) + throw Base::Exception("Body: Tip is not contained in model"); + + it++; + if (it == model.end()) + model.push_back(feature); + else + model.insert(it, feature); + } + Model.setValues(model); + + // Move the Tip + Tip.setValue(feature); +} + +void Body::removeFeature(App::DocumentObject* feature) +{ + if (isSolidFeature(feature)) { + // This is a solid feature + // If the next feature is solid, reroute its BaseFeature property to the previous solid feature + App::DocumentObject* nextSolidFeature = getNextSolidFeature(feature, false); + if (nextSolidFeature != NULL) { + App::DocumentObject* prevSolidFeature = getPrevSolidFeature(feature, false); + PartDesign::Feature* nextFeature = static_cast(nextSolidFeature); + if ((prevSolidFeature == NULL) && (nextFeature->BaseFeature.getValue() != NULL)) + // sanity check + throw Base::Exception((std::string("Body: Base feature of ") + nextFeature->getNameInDocument() + " was removed!").c_str()); + nextFeature->BaseFeature.setValue(prevSolidFeature); + } + } + + // Adjust Tip feature if it is pointing to the deleted object + App::DocumentObject* tipFeature = Tip.getValue(); + std::vector model = Model.getValues(); + std::vector::iterator it = std::find(model.begin(), model.end(), feature); + if (tipFeature == feature) { + // Set the Tip to the previous feature if possible, otherwise to the next feature + std::vector::const_iterator prev = it, next = it; + prev--; + next++; + + if (prev != model.end()) { + Tip.setValue(*prev); + } else { + if (next != model.end()) + Tip.setValue(*next); + else + Tip.setValue(NULL); + } + } + + // Erase feature from Model + model.erase(it); + Model.setValues(model); } App::DocumentObjectExecReturn *Body::execute(void) { - std::vector children = Model.getValues(); - //Base::Console().Error("Body exec children:\n"); - //for (std::vector::const_iterator o = children.begin(); o != children.end(); o++) - // Base::Console().Error("%s\n", (*o)->getNameInDocument()); - const Part::TopoShape& TipShape = getTipShape(); if (TipShape._Shape.IsNull()) diff --git a/src/Mod/PartDesign/App/Body.h b/src/Mod/PartDesign/App/Body.h index 49f22d4be..26391ba17 100644 --- a/src/Mod/PartDesign/App/Body.h +++ b/src/Mod/PartDesign/App/Body.h @@ -49,6 +49,8 @@ public: /// recalculate the feature App::DocumentObjectExecReturn *execute(void); short mustExecute() const; + /// Just for debugging, remove when Body functionality is stable + void onChanged(const App::Property* prop); /// returns the type name of the view provider const char* getViewProviderName(void) const { return "PartDesignGui::ViewProviderBody"; @@ -59,28 +61,44 @@ public: const Part::TopoShape getTipShape(); /** - * Return Tip feature if it is a solid. Otherwise, go backwards in the Model and - * find the first feature that is a solid (i.e. Sketches are skipped) - * This is used by SketchBased features to determine the shape they should fuse with or cut out off - * NOTE: Currently only PartDesign features are accepted as TipSolidFeatures + * Return the solid feature before the given feature, or before the Tip feature + * That is, sketches and datum features are skipped + * If inclusive is true, start or the Tip is returned if it is a solid feature */ - App::DocumentObject *getTipSolidFeature(); + App::DocumentObject *getPrevSolidFeature(App::DocumentObject *start = NULL, const bool inclusive = true); /** - * Return the next solid feature after the Tip feature (so this only makes sense in insert mode) - * This is used by Sketchbased features in insert mode to re-route the Base property - * NOTE: Currently only PartDesign features are accepted as nextSolidFeatures + * Return the next solid feature after the given feature, or after the Tip feature + * That is, sketches and datum features are skipped + * If inclusive is true, start or the Tip is returned if it is a solid feature */ - App::DocumentObject *getNextSolidFeature(); + App::DocumentObject *getNextSolidFeature(App::DocumentObject* start = NULL, const bool inclusive = true); - /// Return the shape of the feature preceding this feature - const Part::TopoShape getPreviousSolid(const PartDesign::Feature* f); + // Return the shape of the feature preceding this feature + //const Part::TopoShape getPreviousSolid(const PartDesign::Feature* f); /// Return true if the feature belongs to this body const bool hasFeature(const App::DocumentObject *f); - /// Returns true if we are inserting into the feature tree instead of appending at the end - const bool insertMode(); + /// Return true if the feature is located after the current Tip feature + const bool isAfterTip(const App::DocumentObject *f); + + /// Insert the feature into the body at the current insert point (Tip feature) + void insertFeature(App::DocumentObject* feature); + + /// Remove the feature from the body + void removeFeature(App::DocumentObject* feature); + + + /** + * Return true if the given feature is a solid feature allowed in a Body. Currently this is only valid + * for features derived from PartDesign::Feature with the exception of PartDesign::Datum features + * Return false if the given feature is a Sketch or a PartDesign::Datum feature + */ + static const bool isSolidFeature(const App::DocumentObject* f); + + /// Return the body which this feature belongs too, or NULL + static Body* findBodyOf(const App::DocumentObject* f); PyObject *getPyObject(void); diff --git a/src/Mod/PartDesign/App/BodyPy.xml b/src/Mod/PartDesign/App/BodyPy.xml index ab251ac73..2903e2a58 100644 --- a/src/Mod/PartDesign/App/BodyPy.xml +++ b/src/Mod/PartDesign/App/BodyPy.xml @@ -13,5 +13,15 @@ PartDesign body class + + + insertFeature(feat) - Insert the given feature after the current Tip feature + + + + + removeFeature(feat) - Remove the given feature from the Body + + diff --git a/src/Mod/PartDesign/App/BodyPyImp.cpp b/src/Mod/PartDesign/App/BodyPyImp.cpp index aa592537a..cce3db236 100644 --- a/src/Mod/PartDesign/App/BodyPyImp.cpp +++ b/src/Mod/PartDesign/App/BodyPyImp.cpp @@ -1,7 +1,9 @@ #include "PreCompiled.h" +#include "Mod/Part/App/Part2DObject.h" #include "Mod/PartDesign/App/Body.h" +#include "Mod/PartDesign/App/DatumFeature.h" // inclusion of the generated files (generated out of ItemPy.xml) #include "BodyPy.h" @@ -27,4 +29,48 @@ int BodyPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/) return 0; } +PyObject* BodyPy::insertFeature(PyObject *args) +{ + PyObject* featurePy; + if (!PyArg_ParseTuple(args, "O!", &(Part::PartFeaturePy::Type), &featurePy)) + return 0; + + Part::Feature* feature = static_cast(featurePy)->getFeaturePtr(); + + if (!feature->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId()) && + !feature->getTypeId().isDerivedFrom(Part::Part2DObject::getClassTypeId())) { + PyErr_SetString(PyExc_SystemError, "Only PartDesign features and sketches can be inserted into a Body"); + return 0; + } + Body* body = this->getBodyPtr(); + + try { + body->insertFeature(feature); + } catch (Base::Exception& e) { + PyErr_SetString(PyExc_SystemError, e.what()); + return 0; + } + + Py_Return; +} + +PyObject* BodyPy::removeFeature(PyObject *args) +{ + PyObject* featurePy; + if (!PyArg_ParseTuple(args, "O!", &(Part::PartFeaturePy::Type), &featurePy)) + return 0; + + Part::Feature* feature = static_cast(featurePy)->getFeaturePtr(); + Body* body = this->getBodyPtr(); + + try { + body->removeFeature(feature); + } catch (Base::Exception& e) { + PyErr_SetString(PyExc_SystemError, e.what()); + return 0; + } + + Py_Return; +} + diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 4ae302fff..21c15d917 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -56,6 +56,7 @@ #include #include +#include #include #include #include @@ -125,6 +126,7 @@ void CmdPartDesignBody::activated(int iMsg) // add the Body feature itself, and make it active doCommand(Doc,"App.activeDocument().addObject('PartDesign::Body','%s')",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Tip = None",FeatName.c_str()); doCommand(Doc,"import PartDesignGui"); doCommand(Gui,"PartDesignGui.setActivePart(App.ActiveDocument.ActiveObject)"); // Make the "Create sketch" prompt appear in the task panel @@ -163,25 +165,30 @@ void CmdPartDesignMoveTip::activated(int iMsg) std::vector features = getSelection().getObjectsOfType(Part::Feature::getClassTypeId()); if (features.empty()) return; - Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(pcActiveBody); - std::vector bodyChildren = vp->claimChildren(); + App::DocumentObject* selFeature = features.front(); - App::DocumentObject* tipFeature = pcActiveBody->Tip.getValue(); - const Gui::ViewProviderDocumentObject* vpFeature = dynamic_cast(Gui::Application::Instance->getViewProvider(tipFeature)); - PartDesignGui::ActiveGuiDoc->signalHighlightObject(*vpFeature, Gui::Blue, false); + if (!pcActiveBody->hasFeature(selFeature)) { + // Switch to other body + pcActiveBody = PartDesign::Body::findBodyOf(selFeature); + if (pcActiveBody != NULL) + Gui::Command::doCommand(Gui::Command::Gui,"PartDesignGui.setActivePart(App.activeDocument().%s)", + pcActiveBody->getNameInDocument()); + } + + App::DocumentObject* oldTip = pcActiveBody->Tip.getValue(); + doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", oldTip->getNameInDocument()); + App::DocumentObject* prevSolidFeature = pcActiveBody->getPrevSolidFeature(); + if (prevSolidFeature != NULL) + doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", prevSolidFeature->getNameInDocument()); openCommand("Move insert point to selected feature"); - doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),features.front()->getNameInDocument()); + doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(), selFeature->getNameInDocument()); - // Adjust visibility - for (std::vector::const_iterator f = bodyChildren.begin(); f != bodyChildren.end(); f++) { - if ((*f) == pcActiveBody->Tip.getValue()) { - doCommand(Gui,"Gui.activeDocument().show(\"%s\")", (*f)->getNameInDocument()); - vpFeature = dynamic_cast(Gui::Application::Instance->getViewProvider(*f)); - PartDesignGui::ActiveGuiDoc->signalHighlightObject(*vpFeature,Gui::Blue,true); - } else - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", (*f)->getNameInDocument()); - } + // Adjust visibility to show only the Tip feature and (if the Tip feature is not solid) the solid feature prior to the Tip + doCommand(Gui,"Gui.activeDocument().show(\"%s\")", selFeature->getNameInDocument()); + prevSolidFeature = pcActiveBody->getPrevSolidFeature(); + if ((prevSolidFeature != NULL) && !PartDesign::Body::isSolidFeature(selFeature)) + doCommand(Gui,"Gui.activeDocument().show(\"%s\")", prevSolidFeature->getNameInDocument()); } bool CmdPartDesignMoveTip::isActive(void) @@ -218,19 +225,22 @@ void CmdPartDesignNewSketch::activated(int iMsg) Gui::SelectionFilter SketchFilter("SELECT Sketcher::SketchObject COUNT 1"); Gui::SelectionFilter FaceFilter ("SELECT Part::Feature SUBELEMENT Face COUNT 1"); - Gui::SelectionFilter PlaneFilter ("SELECT App::Plane COUNT 1"); + Gui::SelectionFilter PlaneFilter1 ("SELECT App::Plane COUNT 1"); + Gui::SelectionFilter PlaneFilter2 ("SELECT PartDesign::Plane COUNT 1"); if (SketchFilter.match()) { Sketcher::SketchObject *Sketch = static_cast(SketchFilter.Result[0][0].getObject()); openCommand("Edit Sketch"); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",Sketch->getNameInDocument()); } - else if (FaceFilter.match() || PlaneFilter.match()) { + else if (FaceFilter.match() || PlaneFilter1.match() || PlaneFilter2.match()) { // get the selected object std::string supportString; if (FaceFilter.match()) { Part::Feature *part = static_cast(FaceFilter.Result[0][0].getObject()); + // FIXME: Reject or warn about feature that is outside of active body, and feature + // that comes after the current insert point (Tip) const std::vector &sub = FaceFilter.Result[0][0].getSubNames(); if (sub.size() > 1){ // No assert for wrong user input! @@ -258,32 +268,20 @@ void CmdPartDesignNewSketch::activated(int iMsg) supportString = FaceFilter.Result[0][0].getAsPropertyLinkSubString(); } else { - supportString = PlaneFilter.Result[0][0].getAsPropertyLinkSubString(); + if (PlaneFilter1.match()) + supportString = PlaneFilter1.Result[0][0].getAsPropertyLinkSubString(); + else + supportString = PlaneFilter2.Result[0][0].getAsPropertyLinkSubString(); } // create Sketch on Face std::string FeatName = getUniqueObjectName("Sketch"); - App::DocumentObject* nextSolidFeature = pcActiveBody->getNextSolidFeature(); openCommand("Create a Sketch on Face"); - doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str()); - if (nextSolidFeature != NULL) { - // Insert mode - doCommand(Doc,"m = App.activeDocument().%s.Model; " - "m.insert(m.index(App.activeDocument().%s.Tip) + 1, App.activeDocument().%s);" - "App.activeDocument().%s.Model = m", - pcActiveBody->getNameInDocument(), - pcActiveBody->getNameInDocument(),FeatName.c_str(), - pcActiveBody->getNameInDocument()); - } else { - doCommand(Doc,"App.activeDocument().%s.Model = " - "App.activeDocument().%s.Model + [App.activeDocument().%s]", - pcActiveBody->getNameInDocument(), - pcActiveBody->getNameInDocument(),FeatName.c_str()); - } - doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s", - pcActiveBody->getNameInDocument(),FeatName.c_str()); - doCommand(Gui,"App.activeDocument().%s.Support = %s",FeatName.c_str(),supportString.c_str()); + doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Support = %s",FeatName.c_str(),supportString.c_str()); + doCommand(Doc,"App.activeDocument().%s.insertFeature(App.activeDocument().%s)", + pcActiveBody->getNameInDocument(), FeatName.c_str()); doCommand(Gui,"App.activeDocument().recompute()"); // recompute the sketch placement based on its support //doCommand(Gui,"Gui.activeDocument().activeView().setCamera('%s')",cam.c_str()); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); @@ -292,6 +290,8 @@ void CmdPartDesignNewSketch::activated(int iMsg) // Get a valid plane from the user std::vector status; std::vector planes = getDocument()->getObjectsOfType(App::Plane::getClassTypeId()); + std::vector planestmp = getDocument()->getObjectsOfType(PartDesign::Plane::getClassTypeId()); + planes.insert(planes.end(), planestmp.begin(), planestmp.end()); unsigned validPlanes = 0; std::vector::const_iterator firstValidPlane = planes.end(); @@ -316,6 +316,10 @@ void CmdPartDesignNewSketch::activated(int iMsg) if (!body->hasFeature(*p)) { status.push_back(PartDesignGui::FeaturePickDialog::otherBody); continue; + } else { + if (body->isAfterTip(*p)) + status.push_back(PartDesignGui::FeaturePickDialog::afterTip); + continue; } // All checks passed - found a valid plane @@ -345,27 +349,14 @@ void CmdPartDesignNewSketch::activated(int iMsg) std::string FeatName = getUniqueObjectName("Sketch"); std::string supportString = std::string("(App.activeDocument().") + plane->getNameInDocument() + ", [])"; - App::DocumentObject* nextSolidFeature = pcActiveBody->getNextSolidFeature(); openCommand("Create a new Sketch"); doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Support = %s",FeatName.c_str(),supportString.c_str()); doCommand(Doc,"App.activeDocument().%s.Placement = App.Placement(App.Vector(%f,%f,%f),App.Rotation(%f,%f,%f,%f))",FeatName.c_str(),p.x,p.y,p.z,r[0],r[1],r[2],r[3]); - if (nextSolidFeature != NULL) { - // Insert mode - doCommand(Doc,"m = App.activeDocument().%s.Model; " - "m.insert(m.index(App.activeDocument().%s.Tip) + 1, App.activeDocument().%s);" - "App.activeDocument().%s.Model = m", - pcActiveBody->getNameInDocument(), - pcActiveBody->getNameInDocument(),FeatName.c_str(), - pcActiveBody->getNameInDocument()); - } else { - doCommand(Doc,"App.activeDocument().%s.Model = " - "App.activeDocument().%s.Model + [App.activeDocument().%s]", - pcActiveBody->getNameInDocument(), - pcActiveBody->getNameInDocument(),FeatName.c_str()); - } - doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.insertFeature(App.activeDocument().%s)", + pcActiveBody->getNameInDocument(), FeatName.c_str()); + //doCommand(Gui,"Gui.activeDocument().activeView().setCamera('%s')",cam.c_str()); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); } } @@ -447,8 +438,7 @@ bool CmdPartDesignNewSketch::isActive(void) return validSketches; } -void prepareSketchBased(Gui::Command* cmd, const std::string& which, - Part::Part2DObject*& sketch, std::string& FeatName, App::DocumentObject*& prevSolidFeature) +void prepareSketchBased(Gui::Command* cmd, const std::string& which, Part::Part2DObject*& sketch, std::string& FeatName) { PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); if (!pcActiveBody) return; @@ -481,43 +471,18 @@ void prepareSketchBased(Gui::Command* cmd, const std::string& which, sketch = static_cast(*firstValidSketch); - // Find valid Body feature to set as the base feature - prevSolidFeature = pcActiveBody->getTipSolidFeature(); - App::DocumentObject* nextSolidFeature = pcActiveBody->getNextSolidFeature(); FeatName = cmd->getUniqueObjectName(which.c_str()); cmd->openCommand((std::string("Make ") + which).c_str()); - cmd->doCommand(cmd->Doc,"App.activeDocument().addObject(\"PartDesign::%s\",\"%s\")",which.c_str(), FeatName.c_str()); - if (prevSolidFeature != NULL) - // Set BaseFeature property to previous feature - cmd->doCommand(cmd->Doc,"App.activeDocument().%s.BaseFeature = App.activeDocument().%s", - FeatName.c_str(),prevSolidFeature->getNameInDocument()); - if (nextSolidFeature != NULL) { - // Insert mode - cmd->doCommand(cmd->Doc,"m = App.activeDocument().%s.Model; " - "m.insert(m.index(App.activeDocument().%s.Tip) + 1, App.activeDocument().%s);" - "App.activeDocument().%s.Model = m", - pcActiveBody->getNameInDocument(), - pcActiveBody->getNameInDocument(),FeatName.c_str(), - pcActiveBody->getNameInDocument()); - // Reroute BaseFeature property of the next feature to this feature - cmd->doCommand(cmd->Doc,"App.activeDocument().%s.BaseFeature = App.activeDocument().%s", - nextSolidFeature->getNameInDocument(), FeatName.c_str()); - } else { - cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Model = " - "App.activeDocument().%s.Model + [App.activeDocument().%s]", - pcActiveBody->getNameInDocument(), - pcActiveBody->getNameInDocument(),FeatName.c_str()); - } - cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s", - pcActiveBody->getNameInDocument(),FeatName.c_str()); - + cmd->doCommand(cmd->Doc,"App.activeDocument().addObject(\"PartDesign::%s\",\"%s\")", + which.c_str(), FeatName.c_str()); cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Sketch = App.activeDocument().%s", - FeatName.c_str(),sketch->getNameInDocument()); + FeatName.c_str(), sketch->getNameInDocument()); + cmd->doCommand(cmd->Doc,"App.activeDocument().%s.insertFeature(App.activeDocument().%s)", + pcActiveBody->getNameInDocument(), FeatName.c_str()); } -void finishSketchBased(const Gui::Command* cmd, - const Part::Part2DObject* sketch, const std::string& FeatName, const App::DocumentObject* prevSolidFeature) +void finishSketchBased(const Gui::Command* cmd, const Part::Part2DObject* sketch, const std::string& FeatName) { App::DocumentObjectGroup* grp = sketch->getGroup(); if (grp) { @@ -528,10 +493,14 @@ void finishSketchBased(const Gui::Command* cmd, } cmd->updateActive(); + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); if (cmd->isActiveObjectValid()) { cmd->doCommand(cmd->Gui,"Gui.activeDocument().hide(\"%s\")", sketch->getNameInDocument()); - if (prevSolidFeature != NULL) - cmd->doCommand(cmd->Gui,"Gui.activeDocument().hide(\"%s\")", prevSolidFeature->getNameInDocument()); + if (pcActiveBody != NULL) { + App::DocumentObject* prevSolidFeature = pcActiveBody->getPrevSolidFeature(NULL, false); + if (prevSolidFeature != NULL) + cmd->doCommand(cmd->Gui,"Gui.activeDocument().hide(\"%s\")", prevSolidFeature->getNameInDocument()); + } } // #0001721: use '0' as edit value to avoid switching off selection in // ViewProviderGeometryObject::setEditViewer @@ -539,7 +508,6 @@ void finishSketchBased(const Gui::Command* cmd, cmd->doCommand(cmd->Gui,"Gui.Selection.clearSelection()"); cmd->doCommand(cmd->Gui,"Gui.Selection.addSelection(App.ActiveDocument.ActiveObject)"); - PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); if (pcActiveBody) { cmd->copyVisual(FeatName.c_str(), "ShapeColor", pcActiveBody->getNameInDocument()); cmd->copyVisual(FeatName.c_str(), "LineColor", pcActiveBody->getNameInDocument()); @@ -568,14 +536,13 @@ void CmdPartDesignPad::activated(int iMsg) { Part::Part2DObject* sketch; std::string FeatName; - App::DocumentObject* prevSolidFeature; - prepareSketchBased(this, "Pad", sketch, FeatName, prevSolidFeature); + prepareSketchBased(this, "Pad", sketch, FeatName); if (FeatName.empty()) return; // specific parameters for Pad doCommand(Doc,"App.activeDocument().%s.Length = 10.0",FeatName.c_str()); - finishSketchBased(this, sketch, FeatName, prevSolidFeature); + finishSketchBased(this, sketch, FeatName); adjustCameraPosition(); } @@ -605,13 +572,12 @@ void CmdPartDesignPocket::activated(int iMsg) { Part::Part2DObject* sketch; std::string FeatName; - App::DocumentObject* prevSolidFeature; - prepareSketchBased(this, "Pocket", sketch, FeatName, prevSolidFeature); + prepareSketchBased(this, "Pocket", sketch, FeatName); if (FeatName.empty()) return; doCommand(Doc,"App.activeDocument().%s.Length = 5.0",FeatName.c_str()); - finishSketchBased(this, sketch, FeatName, prevSolidFeature); + finishSketchBased(this, sketch, FeatName); adjustCameraPosition(); } @@ -641,8 +607,7 @@ void CmdPartDesignRevolution::activated(int iMsg) { Part::Part2DObject* sketch; std::string FeatName; - App::DocumentObject* prevSolidFeature; - prepareSketchBased(this, "Revolution", sketch, FeatName, prevSolidFeature); + prepareSketchBased(this, "Revolution", sketch, FeatName); if (FeatName.empty()) return; doCommand(Doc,"App.activeDocument().%s.ReferenceAxis = (App.activeDocument().%s,['V_Axis'])", @@ -652,7 +617,7 @@ void CmdPartDesignRevolution::activated(int iMsg) if (pcRevolution && pcRevolution->suggestReversed()) doCommand(Doc,"App.activeDocument().%s.Reversed = 1",FeatName.c_str()); - finishSketchBased(this, sketch, FeatName, prevSolidFeature); + finishSketchBased(this, sketch, FeatName); adjustCameraPosition(); } @@ -682,8 +647,7 @@ void CmdPartDesignGroove::activated(int iMsg) { Part::Part2DObject* sketch; std::string FeatName; - App::DocumentObject* prevSolidFeature; - prepareSketchBased(this, "Groove", sketch, FeatName, prevSolidFeature); + prepareSketchBased(this, "Groove", sketch, FeatName); if (FeatName.empty()) return; doCommand(Doc,"App.activeDocument().%s.ReferenceAxis = (App.activeDocument().%s,['V_Axis'])", @@ -693,7 +657,7 @@ void CmdPartDesignGroove::activated(int iMsg) if (pcGroove && pcGroove->suggestReversed()) doCommand(Doc,"App.activeDocument().%s.Reversed = 1",FeatName.c_str()); - finishSketchBased(this, sketch, FeatName, prevSolidFeature); + finishSketchBased(this, sketch, FeatName); adjustCameraPosition(); } diff --git a/src/Mod/PartDesign/Gui/FeaturePickDialog.cpp b/src/Mod/PartDesign/Gui/FeaturePickDialog.cpp index a2003b666..dc53a3f0c 100644 --- a/src/Mod/PartDesign/Gui/FeaturePickDialog.cpp +++ b/src/Mod/PartDesign/Gui/FeaturePickDialog.cpp @@ -48,6 +48,7 @@ const QString FeaturePickDialog::getFeatureStatusString(const featureStatus st) case isUsed: return tr("Sketch already used by other feature"); case otherBody: return tr("Sketch belongs to another Body feature"); case basePlane: return tr("Base plane"); + case afterTip: return tr("Feature is located after the Tip feature"); } return tr(""); @@ -106,6 +107,7 @@ void FeaturePickDialog::updateList() case isUsed: item->setFlags(ui->checkOtherFeature->isChecked() ? Qt::ItemIsSelectable | Qt::ItemIsEnabled : Qt::NoItemFlags); break; case otherBody: item->setFlags(ui->checkOtherBody->isChecked() ? Qt::ItemIsSelectable | Qt::ItemIsEnabled : Qt::NoItemFlags); break; case basePlane: item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); break; + case afterTip: item->setFlags(Qt::NoItemFlags); break; } index++; diff --git a/src/Mod/PartDesign/Gui/FeaturePickDialog.h b/src/Mod/PartDesign/Gui/FeaturePickDialog.h index e70c04229..87f0140a6 100644 --- a/src/Mod/PartDesign/Gui/FeaturePickDialog.h +++ b/src/Mod/PartDesign/Gui/FeaturePickDialog.h @@ -41,7 +41,8 @@ public: noWire, isUsed, otherBody, - basePlane + basePlane, + afterTip }; FeaturePickDialog(std::vector &objects, const std::vector &status); diff --git a/src/Mod/PartDesign/Gui/ViewProvider.cpp b/src/Mod/PartDesign/Gui/ViewProvider.cpp index 6f16333e9..076a11c85 100644 --- a/src/Mod/PartDesign/Gui/ViewProvider.cpp +++ b/src/Mod/PartDesign/Gui/ViewProvider.cpp @@ -27,8 +27,11 @@ #endif #include "ViewProvider.h" +#include "Workbench.h" +#include #include #include +#include #include using namespace PartDesignGui; @@ -69,3 +72,25 @@ void ViewProvider::updateData(const App::Property* prop) } inherited::updateData(prop); } + +bool ViewProvider::onDelete(const std::vector &) +{ + // Body feature housekeeping + PartDesign::Body* body = PartDesign::Body::findBodyOf(getObject()); + if (body != NULL) { + body->removeFeature(getObject()); + // Make the new Tip and the previous solid feature visible again + App::DocumentObject* tip = body->Tip.getValue(); + App::DocumentObject* prev = body->getPrevSolidFeature(); + Gui::Application::Instance->getViewProvider(tip)->show(); + if (tip != prev) + Gui::Application::Instance->getViewProvider(prev)->show(); + } + + // TODO: Ask user what to do about dependent objects, e.g. Sketches that have this feature as their support + // 1. Delete + // 2. Suppress + // 3. Re-route + + return true; +} diff --git a/src/Mod/PartDesign/Gui/ViewProvider.h b/src/Mod/PartDesign/Gui/ViewProvider.h index 792b300df..955910b2a 100644 --- a/src/Mod/PartDesign/Gui/ViewProvider.h +++ b/src/Mod/PartDesign/Gui/ViewProvider.h @@ -41,6 +41,8 @@ public: virtual bool doubleClicked(void); void updateData(const App::Property*); + + virtual bool onDelete(const std::vector &); };