From 8c5d514b18eefdb41c37b5c98b3415cbc1d7eb6c Mon Sep 17 00:00:00 2001 From: Alexander Golubev Date: Thu, 6 Aug 2015 20:46:26 +0300 Subject: [PATCH] PartDesign: Body rework - add BaseFeature property and make Tip always point to solid --- src/Mod/Part/App/BodyBase.cpp | 66 +++-- src/Mod/Part/App/BodyBase.h | 60 ++-- src/Mod/Part/App/PartFeature.h | 2 +- src/Mod/Part/Gui/ViewProvider.cpp | 4 +- src/Mod/PartDesign/App/Body.cpp | 266 ++++++++++-------- src/Mod/PartDesign/App/Body.h | 46 +-- src/Mod/PartDesign/App/FeatureBoolean.cpp | 2 +- src/Mod/PartDesign/App/FeatureDressUp.h | 2 +- src/Mod/PartDesign/Gui/Command.cpp | 222 ++++++++------- src/Mod/PartDesign/Gui/CommandPrimitive.cpp | 100 +++---- .../PartDesign/Gui/TaskDatumParameters.cpp | 11 - .../Gui/TaskSketchBasedParameters.cpp | 22 +- src/Mod/PartDesign/Gui/ViewProviderBody.cpp | 34 ++- src/Mod/PartDesign/Gui/ViewProviderBody.h | 14 +- src/Mod/PartDesign/Gui/ViewProviderDatum.cpp | 14 - src/Mod/PartDesign/Gui/Workbench.cpp | 14 +- src/Mod/Sketcher/Gui/CommandCreateGeo.cpp | 7 +- 17 files changed, 470 insertions(+), 416 deletions(-) diff --git a/src/Mod/Part/App/BodyBase.cpp b/src/Mod/Part/App/BodyBase.cpp index 3722b0f0c..7c14273fb 100644 --- a/src/Mod/Part/App/BodyBase.cpp +++ b/src/Mod/Part/App/BodyBase.cpp @@ -39,28 +39,15 @@ PROPERTY_SOURCE(Part::BodyBase, Part::Feature) BodyBase::BodyBase() { - ADD_PROPERTY(Model,(0)); - ADD_PROPERTY(Tip ,(0)); -} - -short BodyBase::mustExecute() const -{ - //if (Sketch.isTouched() || - // Length.isTouched()) - // return 1; - return 0; -} - -App::DocumentObjectExecReturn *BodyBase::execute(void) -{ - - return App::DocumentObject::StdReturn; + ADD_PROPERTY(Model , (0) ); + ADD_PROPERTY(Tip , (0) ); + ADD_PROPERTY(BaseFeature , (0) ); } const bool BodyBase::hasFeature(const App::DocumentObject* f) const { - const std::vector features = Model.getValues(); - return std::find(features.begin(), features.end(), f) != features.end(); + const std::vector &features = Model.getValues(); + return f == BaseFeature.getValue() || std::find(features.begin(), features.end(), f) != features.end(); } BodyBase* BodyBase::findBodyOf(const App::DocumentObject* f) @@ -78,15 +65,42 @@ BodyBase* BodyBase::findBodyOf(const App::DocumentObject* f) return NULL; } -const bool BodyBase::isAfterTip(const App::DocumentObject *f) const { - App::DocumentObject* tipFeature = Tip.getValue(); - if (tipFeature == NULL) - return true; +const bool BodyBase::isAfter(const App::DocumentObject *feature, const App::DocumentObject* target) const { + assert (feature); - std::vector features = Model.getValues(); - std::vector::const_iterator it = std::find(features.begin(), features.end(), f); - std::vector::const_iterator tip = std::find(features.begin(), features.end(), tipFeature); - return (it > tip); + if (feature == target) { + return false; + } + + if (!target || target == BaseFeature.getValue() ) { + return hasFeature (feature); + } + + const std::vector & features = Model.getValues(); + auto featureIt = std::find(features.begin(), features.end(), feature); + auto targetIt = std::find(features.begin(), features.end(), target); + + if (featureIt == features.end()) { + return false; + } else { + return featureIt > targetIt; + } } +void BodyBase::onBeforeChange (const App::Property* prop) { + // If we are changing the base feature and tip point to it reset it + if ( prop == &BaseFeature && BaseFeature.getValue() == Tip.getValue() && BaseFeature.getValue() ) { + Tip.setValue( nullptr ); + } + Part::Feature::onBeforeChange ( prop ); } + +void BodyBase::onChanged (const App::Property* prop) { + // If the tip is zero and we are adding a base feature to the body set it to be the tip + if ( prop == &BaseFeature && !Tip.getValue() && BaseFeature.getValue() ) { + Tip.setValue( BaseFeature.getValue () ); + } + Part::Feature::onChanged ( prop ); +} + +} /* Part */ diff --git a/src/Mod/Part/App/BodyBase.h b/src/Mod/Part/App/BodyBase.h index 49cfff1e5..139fb5e49 100644 --- a/src/Mod/Part/App/BodyBase.h +++ b/src/Mod/Part/App/BodyBase.h @@ -31,11 +31,11 @@ namespace Part { /** Base class of all body objects in FreeCAD - * A body is used, e.g. in PartDesign, to agregate - * some modeling features to one shape. As long as not - * in edit or active on a workbench, the body shows only the - * resulting shape to the outside (Tip link). - */ + * A body is used, e.g. in PartDesign, to agregate + * some modeling features to one shape. As long as not + * in edit or active on a workbench, the body shows only the + * resulting shape to the outside (Tip link). + */ class PartExport BodyBase : public Part::Feature { PROPERTY_HEADER(Part::BodyBase); @@ -43,41 +43,47 @@ class PartExport BodyBase : public Part::Feature public: BodyBase(); + /// The list of features App::PropertyLinkList Model; + + /** + * The final feature of the body it is associated with. + * Note: tip may either point to the BaseFeature or to some feature inside the Model list. + * in case it points to the model the PartDesign::Body guaranties that it is a solid. + */ App::PropertyLink Tip; - /** @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::ViewProviderBodyBase"; - //} - //@} + /** + * A base object of the body, serves as a base object for the first feature of the body. + * A Part::Feature link to make bodies be able based upon non-PartDesign Features. + */ + App::PropertyLink BaseFeature; // These methods are located here to avoid a dependency of ViewProviderSketchObject on PartDesign /// Remove the feature from the body virtual void removeFeature(App::DocumentObject* feature){} - /// Return true if the feature belongs to this body + /// Return true if the feature belongs to this body or either the body is based on the feature const bool hasFeature(const App::DocumentObject *f) const; + /// Return true if the feature belongs to the body and is located after the target + const bool isAfter(const App::DocumentObject *feature, const App::DocumentObject *target) const; + /** - * 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 - */ - virtual App::DocumentObject *getPrevSolidFeature(App::DocumentObject *start = NULL, const bool inclusive = true) - { return NULL; } - - /// Return true if the feature is located after the current Tip feature - const bool isAfterTip(const App::DocumentObject *f) const; - - /// Return the body which this feature belongs too, or NULL + * Return the body which this feature belongs too, or NULL. + * Note: Normally each PartDesign feature belongs to a single body, + * But if a body is based on the feature it also will be return... + * But there are could be more features based on the same body. + * TODO introduce a findBodiesOf() if needed (2015-08-04, Fat-Zer) + */ static BodyBase* findBodyOf(const App::DocumentObject* f); +protected: + /// If BaseFeature is getting changed and Tip points to it resets the Tip + virtual void onBeforeChange (const App::Property* prop); + /// If BaseFeature is setted and Tip is null sets the Tip to it + virtual void onChanged (const App::Property* prop); + }; } //namespace Part diff --git a/src/Mod/Part/App/PartFeature.h b/src/Mod/Part/App/PartFeature.h index f984bdc08..cd386eabd 100644 --- a/src/Mod/Part/App/PartFeature.h +++ b/src/Mod/Part/App/PartFeature.h @@ -71,7 +71,7 @@ public: TopLoc_Location getLocation() const; protected: - void onChanged(const App::Property* prop); + virtual void onChanged(const App::Property* prop); /** * Build a history of changes * MakeShape: The operation that created the changes, e.g. BRepAlgoAPI_Common diff --git a/src/Mod/Part/Gui/ViewProvider.cpp b/src/Mod/Part/Gui/ViewProvider.cpp index e819feea6..f89a62a72 100644 --- a/src/Mod/Part/Gui/ViewProvider.cpp +++ b/src/Mod/Part/Gui/ViewProvider.cpp @@ -127,17 +127,15 @@ bool ViewProviderPart::doubleClicked(void) bool ViewProviderPart::onDelete(const std::vector &) { + // TODO Why the heck it's here? (2015-08-05, Fat-Zer) // Body feature housekeeping Part::BodyBase* body = Part::BodyBase::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(); if (tip != NULL) { Gui::Application::Instance->getViewProvider(tip)->show(); - if ((tip != prev) && (prev != NULL)) - Gui::Application::Instance->getViewProvider(prev)->show(); } } diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index 1477c5679..1e4246052 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -110,23 +110,10 @@ void Body::onChanged(const App::Property *prop) short Body::mustExecute() const { - if (Tip.isTouched() ) + if ( Tip.isTouched() || + BaseFeature.isTouched() ) return 1; - return 0; -} - -const Part::TopoShape Body::getTipShape() -{ - // TODO right selection for Body - App::DocumentObject* link = Tip.getValue(); - if (!link) - return Part::TopoShape(); - - if (!link->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) - //return new App::DocumentObjectExecReturn("Linked object is not a PartDesign object"); - return Part::TopoShape(); - // get the shape of the tip - return static_cast(link)->Shape.getShape(); + return Part::BodyBase::mustExecute(); } App::DocumentObject* Body::getPrevFeature(App::DocumentObject *start) const @@ -144,54 +131,85 @@ App::DocumentObject* Body::getPrevFeature(App::DocumentObject *start) const return *it; } -App::DocumentObject* Body::getPrevSolidFeature(App::DocumentObject *start, const bool inclusive) +App::DocumentObject* Body::getPrevSolidFeature(App::DocumentObject *start) { - std::vector features = Model.getValues(); - if (features.empty()) return NULL; - App::DocumentObject* st = (start == NULL ? Tip.getValue() : start); - if (st == NULL) - return st; // Tip is NULL + App::DocumentObject* baseFeature = BaseFeature.getValue(); - if (inclusive && isSolidFeature(st)) - return st; + if ( !start ) { // default to tip + start = Tip.getValue(); + } - std::vector::iterator it = std::find(features.begin(), features.end(), st); - if (it == features.end()) return NULL; // Invalid start object + if ( !start ) { // No Tip + return nullptr; + } else if ( start == baseFeature ) { // The base feature always considered as the first solid + return nullptr; + } - // Skip sketches and datum features - do { - if (it == features.begin()) - return NULL; - it--; - } while (!isSolidFeature(*it)); + assert ( hasFeature ( start ) ); - return *it; + const std::vector & features = Model.getValues(); + + auto startIt = std::find ( features.rbegin(), features.rend(), start ); + assert ( startIt != features.rend() ); + auto rvIt = std::find_if ( startIt + 1, features.rend(), isSolidFeature ); + + if (rvIt != features.rend()) { // the solid found in model list + return *rvIt; + } else { // if solid is not present in the list the previous one is baseFeature + return baseFeature; // return it either it's set or nullptr + } } -App::DocumentObject* Body::getNextSolidFeature(App::DocumentObject *start, const bool inclusive) +App::DocumentObject* Body::getNextSolidFeature(App::DocumentObject *start) { - std::vector features = Model.getValues(); - if (features.empty()) return NULL; - App::DocumentObject* st = (start == NULL ? Tip.getValue() : start); + App::DocumentObject* baseFeature = BaseFeature.getValue(); - if (inclusive && isSolidFeature(st)) - return st; + if ( !start ) { // default to tip + start = Tip.getValue(); + } - std::vector::iterator it; - if (st == NULL) - it = features.begin(); // Tip is NULL - else - it = std::find(features.begin(), features.end(), st); - if (it == features.end()) return NULL; // Invalid start object + if ( !start ) { // no tip + return nullptr; + } - // Skip sketches and datum features - do { - it++; - if (it == features.end()) - return NULL; - } while (!isSolidFeature(*it)); + assert ( hasFeature ( start ) ); - return *it; + const std::vector & features = Model.getValues(); + std::vector::const_iterator startIt; + + if ( start == baseFeature ) { + // Handle the base feature, it's always considered to be solid + startIt = features.begin(); + } else { + startIt = std::find ( features.begin(), features.end(), start ); + assert ( startIt != features.end() ); + startIt++; + } + + if (startIt == features.end() ) { // features list is empty + return nullptr; + } + + auto rvIt = std::find_if ( startIt, features.end(), isSolidFeature ); + + if (rvIt != features.end()) { // the solid found in model list + return *rvIt; + } else { + return nullptr; + } +} + +bool Body::isAfterInsertPoint(App::DocumentObject* feature) { + App::DocumentObject *nextSolid = getNextSolidFeature (); + assert (feature); + + if (feature == nextSolid) { + return true; + } else if (!nextSolid) { // the tip is last solid, we can't be plased after it + return false; + } else { + return isAfter ( feature, nextSolid ); + } } const bool Body::isMemberOfMultiTransform(const App::DocumentObject* f) @@ -240,18 +258,28 @@ Body* Body::findBodyOf(const App::DocumentObject* feature) void Body::addFeature(App::DocumentObject *feature) { - insertFeature (feature, Tip.getValue(), /*after = */ true); - - // Move the Tip - Tip.setValue (feature); + insertFeature (feature, getNextSolidFeature (), /*after = */ false); + // Move the Tip if we added a solid + if (isSolidFeature(feature)) { + Tip.setValue (feature); + } } void Body::insertFeature(App::DocumentObject* feature, App::DocumentObject* target, bool after) { - // Check if the after feature belongs to the body - if (target && !hasFeature (target)) { - throw Base::Exception("Body: the feature we should insert relative to is not part of that body"); + if (target) { + if (target == BaseFeature.getValue()) { + // Handle the insertion relative to the base feature in a special way + if (after) { + target = nullptr; + } else { + throw Base::Exception("Body: impossible to insert before the base object"); + } + } else if (!hasFeature (target)) { + // Check if the target feature belongs to the body + throw Base::Exception("Body: the feature we should insert relative to is not part of that body"); + } } std::vector model = Model.getValues(); @@ -282,14 +310,16 @@ void Body::insertFeature(App::DocumentObject* feature, App::DocumentObject* targ // Set the BaseFeature property if (Body::isSolidFeature(feature)) { // Set BaseFeature property to previous feature (this might be the Tip feature) - App::DocumentObject* prevSolidFeature = getPrevSolidFeature(feature, false); + App::DocumentObject* prevSolidFeature = getPrevSolidFeature(feature); // NULL is ok here, it just means we made the current one fiature the base solid static_cast(feature)->BaseFeature.setValue(prevSolidFeature); // Reroute the next solid feature's BaseFeature property to this feature - App::DocumentObject* nextSolidFeature = getNextSolidFeature(feature, false); - if (nextSolidFeature) + App::DocumentObject* nextSolidFeature = getNextSolidFeature(feature); + if (nextSolidFeature) { + assert ( nextSolidFeature->isDerivedFrom ( PartDesign::Feature::getClassTypeId () ) ); static_cast(nextSolidFeature)->BaseFeature.setValue(feature); + } } } @@ -297,15 +327,15 @@ void Body::insertFeature(App::DocumentObject* feature, App::DocumentObject* targ void Body::removeFeature(App::DocumentObject* feature) { + App::DocumentObject* nextSolidFeature = getNextSolidFeature(feature); + App::DocumentObject* prevSolidFeature = getPrevSolidFeature(feature); // This method must be called BEFORE the feature is removed from the Document! - 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) { - App::DocumentObject* prevSolidFeature = getPrevSolidFeature(feature, false); - // Note: It's ok to remove the first solid feature, that just mean the next feature become the base one + assert ( nextSolidFeature->isDerivedFrom ( PartDesign::Feature::getClassTypeId () ) ); + // Note: It's ok to remove the first solid feature, that just mean the next feature become the base one static_cast(nextSolidFeature)->BaseFeature.setValue(prevSolidFeature); } } @@ -314,28 +344,11 @@ void Body::removeFeature(App::DocumentObject* feature) std::vector::iterator it = std::find(model.begin(), model.end(), feature); // Adjust Tip feature if it is pointing to the deleted object - App::DocumentObject* tipFeature = Tip.getValue(); - 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; - if (it != model.begin()) { - prev--; - next++; - - if (prev != model.end()) { - Tip.setValue(*prev); - } else { - if (next != model.end()) - Tip.setValue(*next); - else - Tip.setValue(NULL); - } + if (Tip.getValue()== feature) { + if (prevSolidFeature) { + Tip.setValue(prevSolidFeature); } else { - next++; - if (next != model.end()) - Tip.setValue(*next); - else - Tip.setValue(NULL); + Tip.setValue(nextSolidFeature); } } @@ -365,36 +378,51 @@ App::DocumentObjectExecReturn *Body::execute(void) } */ - const Part::TopoShape& TipShape = getTipShape(); + App::DocumentObject* tip = Tip.getValue(); - if (TipShape._Shape.IsNull()) - //return new App::DocumentObjectExecReturn("empty shape"); - return App::DocumentObject::StdReturn; + Part::TopoShape tipShape; + if ( tip ) { + if ( !tip->getTypeId().isDerivedFrom ( PartDesign::Feature::getClassTypeId() ) + && tip != BaseFeature.getValue () ) { + return new App::DocumentObjectExecReturn ( "Linked object is not a PartDesign feature" ); + } - Shape.setValue(TipShape); + App::DocumentObject* link = Tip.getValue(); + // get the shape of the tip + tipShape = static_cast(tip)->Shape.getShape(); + + if ( tipShape._Shape.IsNull () ) { + return new App::DocumentObjectExecReturn ( "Tip shape is empty" ); + } + + // We should hide here the transformation of the baseFeature + tipShape.transformShape (tipShape.getTransform(), true ); + + } else { + tipShape = Part::TopoShape(); + } + + Shape.setValue ( tipShape ); return App::DocumentObject::StdReturn; + } Base::BoundBox3d Body::getBoundBox() { Base::BoundBox3d result; - Part::Feature* tipSolid = static_cast(getPrevSolidFeature()); - if (tipSolid != NULL) { - if (tipSolid->Shape.getValue().IsNull()) - // This can happen when a new feature is added without having its Shape property set yet - tipSolid = static_cast(getPrevSolidFeature(NULL, false)); - - if (tipSolid != NULL) { - if (tipSolid->Shape.getValue().IsNull()) - tipSolid = NULL; - else - result = tipSolid->Shape.getShape().getBoundBox(); - } + Part::Feature* tipSolid = static_cast(Tip.getValue()); + if (tipSolid && tipSolid->Shape.getValue().IsNull()) { + // This can happen when a new feature is added without having its Shape property set yet + tipSolid = static_cast(getPrevSolidFeature()); } - if (tipSolid == NULL) + + if (!tipSolid || tipSolid->Shape.getValue().IsNull()) { result = App::Plane::getBoundBox(); + } else { + result = tipSolid->Shape.getShape().getBoundBox(); + } std::vector model = Model.getValues(); // TODO: In DatumLine and DatumPlane, recalculate the Base point to be as near as possible to the origin (0,0,0) @@ -427,22 +455,38 @@ PyObject *Body::getPyObject(void) } void Body::onSettingDocument() { - + if(connection.connected()) connection.disconnect(); - + getDocument()->signalDeletedObject.connect(boost::bind(&Body::onDelete, this, _1)); - App::DocumentObject::onSettingDocument(); + + Part::BodyBase::onSettingDocument(); } void Body::onDelete(const App::DocumentObject& obj) { - - if(&obj == this) { + // TODO Handle this in view provider rather here (2015-08-06, Fat-Zer) + if(&obj == this) { //delete all child objects if needed std::vector grp = Model.getValues(); - for (auto obj : grp) + for (auto obj : grp) this->getDocument()->remObject(obj->getNameInDocument(), true); } } +void Body::onChanged (const App::Property* prop) { + if ( prop == &BaseFeature ) { + App::DocumentObject *baseFeature = BaseFeature.getValue(); + App::DocumentObject *nextSolid = getNextSolidFeature ( baseFeature ); + if ( nextSolid ) { + assert ( nextSolid->isDerivedFrom ( PartDesign::Feature::getClassTypeId () ) ); + static_cast(nextSolid)->BaseFeature.setValue( baseFeature ); + } + + } + + Part::BodyBase::onChanged ( prop ); } + + +} /* PartDesign */ diff --git a/src/Mod/PartDesign/App/Body.h b/src/Mod/PartDesign/App/Body.h index 364872efe..88a07f27c 100644 --- a/src/Mod/PartDesign/App/Body.h +++ b/src/Mod/PartDesign/App/Body.h @@ -56,30 +56,16 @@ public: } //@} - /// Get the tip shape - const Part::TopoShape getTipShape(); - /// Return the previous feature App::DocumentObject* getPrevFeature(App::DocumentObject *start = NULL) const; - /** - * 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 *getPrevSolidFeature(App::DocumentObject *start = NULL, const bool inclusive = true); - - /** - * 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* start = NULL, const bool inclusive = true); - // Return the shape of the feature preceding this feature //const Part::TopoShape getPreviousSolid(const PartDesign::Feature* f); - /// Add the feature into the body at the current insert point (Tip feature) + /** + * Add the feature into the body at the current insert point. + * The insertion poin is the before next solid after the Tip feature + */ void addFeature(App::DocumentObject* feature); /** @@ -98,8 +84,11 @@ public: /// Remove the feature from the body void removeFeature(App::DocumentObject* feature); - /// Checks if the given document object is a feaure of this body - bool isFeature(App::DocumentObject* feature); + /** + * Checks if the given document object lays after the current insert point + * (place before next solid after the Tip) + */ + bool isAfterInsertPoint(App::DocumentObject* feature); /// Return true if the given feature is member of a MultiTransform feature static const bool isMemberOfMultiTransform(const App::DocumentObject* f); @@ -130,7 +119,22 @@ public: protected: virtual void onSettingDocument(); - + + /// Adjusts the first solid's feature's base on on BaseFeature getting setted + virtual void onChanged (const App::Property* prop); + + /** + * Return the solid feature before the given feature, or before the Tip feature + * That is, sketches and datum features are skipped + */ + App::DocumentObject *getPrevSolidFeature(App::DocumentObject *start = NULL); + + /** + * Return the next solid feature after the given feature, or after the Tip feature + * That is, sketches and datum features are skipped + */ + App::DocumentObject *getNextSolidFeature(App::DocumentObject* start = NULL); + private: App::DocumentObject* rememberTip; boost::signals::scoped_connection connection; diff --git a/src/Mod/PartDesign/App/FeatureBoolean.cpp b/src/Mod/PartDesign/App/FeatureBoolean.cpp index 5f8531b3a..04debba34 100644 --- a/src/Mod/PartDesign/App/FeatureBoolean.cpp +++ b/src/Mod/PartDesign/App/FeatureBoolean.cpp @@ -128,7 +128,7 @@ App::DocumentObjectExecReturn *Boolean::execute(void) if(!part->hasObject(body)) return new App::DocumentObjectExecReturn("Cannot do boolean on bodies of different parts"); - TopoDS_Shape shape = body->getTipShape()._Shape; + TopoDS_Shape shape = body->Shape.getValue(); // Move the shape to the location of the base shape in the other body Base::Placement pl = body->Placement.getValue(); diff --git a/src/Mod/PartDesign/App/FeatureDressUp.h b/src/Mod/PartDesign/App/FeatureDressUp.h index 735ed06fd..1af808373 100644 --- a/src/Mod/PartDesign/App/FeatureDressUp.h +++ b/src/Mod/PartDesign/App/FeatureDressUp.h @@ -60,7 +60,7 @@ public: void getContiniusEdges(Part::TopoShape, std::vector< std::string >&); protected: - void onChanged(const App::Property* prop); + virtual void onChanged(const App::Property* prop); }; } //namespace PartDesign diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index acfd5eef4..40d1ff085 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -139,37 +139,49 @@ CmdPartDesignBody::CmdPartDesignBody() void CmdPartDesignBody::activated(int iMsg) { - openCommand("Add a body"); - std::string FeatName = getUniqueObjectName("Body"); + std::vector features = + getSelection().getObjectsOfType(Part::Feature::getClassTypeId()); + App::DocumentObject* baseFeature = nullptr; + + if (!features.empty()) { + if (features.size() == 1) { + baseFeature = features[0]; + // TODO Check if the feature belongs to another body and may be some other sanity checks (2015-08-04, Fat-Zer) + } else { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Body may be based no more than on one feature.")); + return; + } + } // first check if Part is already created: - App::Part *actPart = getDocument()->Tip.getValue(); + App::Part *actPart = getDocument()->Tip.getValue(); std::string PartName; if(!actPart){ - // if not, creating a part and set it up by calling the appropiated function in Workbench - //if we create a new part we automaticly get a new body, there is no need to create a second one - PartName = getUniqueObjectName("Part"); - doCommand(Doc,"App.activeDocument().Tip = App.activeDocument().addObject('App::Part','%s')",PartName.c_str()); - doCommand(Doc,"App.activeDocument().ActiveObject.Label = '%s'", QObject::tr(PartName.c_str()).toStdString().c_str()); - PartDesignGui::Workbench::setUpPart(dynamic_cast(getDocument()->getObject(PartName.c_str()))); - doCommand(Gui::Command::Gui, "Gui.activeView().setActiveObject('%s', App.activeDocument().%s)", PARTKEY, PartName.c_str()); - - } else { - PartName = actPart->getNameInDocument(); - // 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.Model = []",FeatName.c_str()); - //doCommand(Doc,"App.activeDocument().%s.Tip = None",FeatName.c_str()); - addModule(Gui,"PartDesignGui"); // import the Gui module only once a session - doCommand(Gui::Command::Gui, "Gui.activeView().setActiveObject('%s', App.activeDocument().%s)", PDBODYKEY, FeatName.c_str()); - - // Make the "Create sketch" prompt appear in the task panel - doCommand(Gui,"Gui.Selection.clearSelection()"); - doCommand(Gui,"Gui.Selection.addSelection(App.ActiveDocument.%s)", FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.addObject(App.ActiveDocument.%s)",PartName.c_str(),FeatName.c_str()); + Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager(); + rcCmdMgr.runCommandByName("PartDesign_Part"); + actPart = getDocument()->Tip.getValue(); } + openCommand("Add a body"); + std::string FeatName = getUniqueObjectName("Body"); + + PartName = actPart->getNameInDocument(); + // add the Body feature itself, and make it active + doCommand(Doc,"App.activeDocument().addObject('PartDesign::Body','%s')", FeatName.c_str()); + if (baseFeature) { + doCommand(Doc,"App.activeDocument().%s.BaseFeature = App.activeDocument().%s", + FeatName.c_str(), baseFeature->getNameInDocument()); + } + addModule(Gui,"PartDesignGui"); // import the Gui module only once a session + doCommand(Gui::Command::Gui, "Gui.activeView().setActiveObject('%s', App.activeDocument().%s)", PDBODYKEY, FeatName.c_str()); + + // Make the "Create sketch" prompt appear in the task panel + doCommand(Gui,"Gui.Selection.clearSelection()"); + doCommand(Gui,"Gui.Selection.addSelection(App.ActiveDocument.%s)", FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.addObject(App.ActiveDocument.%s)",PartName.c_str(),FeatName.c_str()); + updateActive(); } @@ -188,8 +200,8 @@ CmdPartDesignMoveTip::CmdPartDesignMoveTip() { sAppModule = "PartDesign"; sGroup = QT_TR_NOOP("PartDesign"); - sMenuText = QT_TR_NOOP("Insert here"); - sToolTipText = QT_TR_NOOP("Move insert point to selected feature"); + sMenuText = QT_TR_NOOP("Set tip"); + sToolTipText = QT_TR_NOOP("Move the tip of the body"); sWhatsThis = sToolTipText; sStatusTip = sToolTipText; sPixmap = "PartDesign_MoveTip"; @@ -197,51 +209,47 @@ CmdPartDesignMoveTip::CmdPartDesignMoveTip() void CmdPartDesignMoveTip::activated(int iMsg) { - PartDesign::Body *pcActiveBody = PartDesignGui::getBody(/*messageIfNot = */true); - if(!pcActiveBody) return; - - std::vector features = getSelection().getObjectsOfType(Part::Feature::getClassTypeId()); + std::vector features = getSelection().getObjectsOfType( + Part::Feature::getClassTypeId() ); App::DocumentObject* selFeature; + PartDesign::Body* body= nullptr; - if (features.empty()) { - // Insert at the beginning of this body - selFeature = NULL; - } else { + if ( features.size() == 1 ) { selFeature = features.front(); - if (selFeature->getTypeId().isDerivedFrom(PartDesign::Body::getClassTypeId())) { - // Insert at the beginning of this body - selFeature = NULL; - } else if (!pcActiveBody->hasFeature(selFeature)) { - // Switch to other body - pcActiveBody = static_cast(Part::BodyBase::findBodyOf(selFeature)); - if (pcActiveBody != NULL) - Gui::Command::doCommand(Gui::Command::Gui, "Gui.activeView().setActiveObject('%s',App.activeDocument().%s)", - PDBODYKEY, pcActiveBody->getNameInDocument()); - else - return; + if ( selFeature->getTypeId().isDerivedFrom ( PartDesign::Body::getClassTypeId() ) ) { + body = static_cast ( selFeature ); + } else { + body = PartDesignGui::getBodyFor ( selFeature, /* messageIfNot =*/ false ); } + } else { + selFeature = nullptr; + } + // TODO Refuse to set tip to nonsolid features (2015-08-05, Fat-Zer) + + if (!selFeature || !body ) { + QMessageBox::warning (0, QObject::tr( "Selection error" ), + QObject::tr( "Select exactly one PartDesign feature or a body." ) ); + return; + } else if (!body) { + QMessageBox::warning (0, QObject::tr( "Selection error" ), + QObject::tr( "Couldn't determin a body for selected feature." ) ); + return; } openCommand("Move insert point to selected feature"); - App::DocumentObject* oldTip = pcActiveBody->Tip.getValue(); - if (oldTip != NULL) { - if (!oldTip->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", oldTip->getNameInDocument()); - App::DocumentObject* prevSolidFeature = pcActiveBody->getPrevSolidFeature(); - if (prevSolidFeature != NULL) - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", prevSolidFeature->getNameInDocument()); + App::DocumentObject* oldTip = body->Tip.getValue(); + if (oldTip) { + doCommand(Gui, "Gui.activeDocument().hide(\"%s\")", oldTip->getNameInDocument() ); } - if (selFeature == NULL) { - doCommand(Doc,"App.activeDocument().%s.Tip = None", pcActiveBody->getNameInDocument()); + if (selFeature == body) { + doCommand(Doc,"App.activeDocument().%s.Tip = None", body->getNameInDocument()); } else { - doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(), selFeature->getNameInDocument()); + doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",body->getNameInDocument(), + selFeature->getNameInDocument()); - // Adjust visibility to show only the Tip feature and (if the Tip feature is not solid) the solid feature prior to the Tip + // Adjust visibility to show only the Tip feature doCommand(Gui,"Gui.activeDocument().show(\"%s\")", selFeature->getNameInDocument()); - App::DocumentObject* prevSolidFeature = pcActiveBody->getPrevSolidFeature(); - if ((prevSolidFeature != NULL) && !PartDesign::Body::isSolidFeature(selFeature)) - doCommand(Gui,"Gui.activeDocument().show(\"%s\")", prevSolidFeature->getNameInDocument()); } // TOOD: Hide all datum features after the Tip feature? But the user might have already hidden some and wants to see @@ -271,8 +279,8 @@ CmdPartDesignDuplicateSelection::CmdPartDesignDuplicateSelection() sPixmap = ""; } -void CmdPartDesignDuplicateSelection::activated(int iMsg) -{ +void CmdPartDesignDuplicateSelection::activated(int iMsg) { + // TODO Review the function (2015-08-05, Fat-Zer) PartDesign::Body *pcActiveBody = PartDesignGui::getBody(/*messageIfNot = */true); if(!pcActiveBody) return; @@ -314,9 +322,6 @@ void CmdPartDesignDuplicateSelection::activated(int iMsg) // Adjust visibility of features doCommand(Gui,"Gui.activeDocument().show(\"%s\")", newFeatures.back()->getNameInDocument()); - App::DocumentObject* prevSolidFeature = pcActiveBody->getPrevSolidFeature(); - if ((prevSolidFeature != NULL) && !PartDesign::Body::isSolidFeature(selFeature)) - doCommand(Gui,"Gui.activeDocument().show(\"%s\")", prevSolidFeature->getNameInDocument()); } bool CmdPartDesignDuplicateSelection::isActive(void) @@ -375,17 +380,19 @@ void CmdPartDesignMoveFeature::activated(int iMsg) for (std::vector::const_iterator f = features.begin(); f != features.end(); f++) { // Find body of this feature Part::BodyBase* source = PartDesign::Body::findBodyOf(*f); - bool featureIsTip = false; + bool featureWasTip = false; if (source == target) continue; // Remove from the source body if the feature belonged to a body if (source) { - featureIsTip = (source->Tip.getValue() == *f); + featureWasTip = (source->Tip.getValue() == *f); doCommand(Doc,"App.activeDocument().%s.removeFeature(App.activeDocument().%s)", source->getNameInDocument(), (*f)->getNameInDocument()); } + App::DocumentObject* targetOldTip = target->Tip.getValue(); + // Add to target body (always at the Tip) doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", target->getNameInDocument(), (*f)->getNameInDocument()); @@ -393,20 +400,26 @@ void CmdPartDesignMoveFeature::activated(int iMsg) doCommand(Gui,"App.activeDocument().recompute()"); // Adjust visibility of features - if (PartDesign::Body::isSolidFeature(*f)) { - // If we removed the tip of the source body, make the new tip visible - if (featureIsTip) { - App::DocumentObject* prevSolidFeature = source->getPrevSolidFeature(); - if (prevSolidFeature) { - doCommand(Gui,"Gui.activeDocument().show(\"%s\")", prevSolidFeature->getNameInDocument()); - } - } + // TODO: May be something can be done in view provider (2015-08-05, Fat-Zer) + // If we removed the tip of the source body, make the new tip visible + if (featureWasTip ) { + App::DocumentObject * sourceNewTip = source->Tip.getValue(); + doCommand(Gui,"Gui.activeDocument().show(\"%s\")", sourceNewTip->getNameInDocument()); + } - // Hide old tip and show new tip (the moved feature) of the target body - App::DocumentObject* prevSolidFeature = target->getPrevSolidFeature(); - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", prevSolidFeature->getNameInDocument()); - doCommand(Gui,"Gui.activeDocument().show(\"%s\")", (*f)->getNameInDocument()); - } else if ((*f)->getTypeId().isDerivedFrom(Sketcher::SketchObject::getClassTypeId())) { + // Hide old tip and show new tip (the moved feature) of the target body + App::DocumentObject* targetNewTip = target->Tip.getValue(); + if ( targetOldTip != targetNewTip ) { + if ( targetOldTip ) { + doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", targetOldTip->getNameInDocument()); + } + if (targetNewTip) { + doCommand(Gui,"Gui.activeDocument().show(\"%s\")", targetNewTip->getNameInDocument()); + } + } + + // Fix sketch support + if ((*f)->getTypeId().isDerivedFrom(Sketcher::SketchObject::getClassTypeId())) { Sketcher::SketchObject *sketch = static_cast(*f); try { PartDesignGui::Workbench::fixSketchSupport(sketch); @@ -421,10 +434,7 @@ void CmdPartDesignMoveFeature::activated(int iMsg) bool CmdPartDesignMoveFeature::isActive(void) { - if (getActiveGuiDocument()) - return true; - else - return false; + return hasActiveDocument (); } DEF_STD_CMD_A(CmdPartDesignMoveFeatureInTree); @@ -699,7 +709,7 @@ void CmdPartDesignNewSketch::activated(int iMsg) Part::Feature* feat = static_cast(obj); const std::vector &sub = FaceFilter.Result[0][0].getSubNames(); - if (sub.size() > 1){ + if (sub.size() > 1) { // No assert for wrong user input! QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Several sub-elements selected"), QObject::tr("You have to select a single face as support for a sketch!")); @@ -710,7 +720,7 @@ void CmdPartDesignNewSketch::activated(int iMsg) const Part::TopoShape &shape = feat->Shape.getValue(); TopoDS_Shape sh = shape.getSubShape(sub[0].c_str()); const TopoDS_Face& face = TopoDS::Face(sh); - if (face.IsNull()){ + if (face.IsNull()) { // No assert for wrong user input! QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No support face selected"), QObject::tr("You have to select a face as support for a sketch!")); @@ -747,10 +757,10 @@ void CmdPartDesignNewSketch::activated(int iMsg) return; } } else if (!obj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId()) - && pcActiveBody->getNextSolidFeature() != obj) { - // TOOD: checkme why it's forbidden!? + && pcActiveBody->Tip.getValue () != obj) { + // TODO checkme why it's forbidden!? (2015-08-05, Fat-Zer) QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Selection from inactive feature"), - QObject::tr("You can only use the last solid feature as sketch support")); + QObject::tr("You can only use the Tip as sketch support")); return; } @@ -789,7 +799,7 @@ void CmdPartDesignNewSketch::activated(int iMsg) status.push_back(PartDesignGui::TaskFeaturePick::basePlane); else status.push_back(PartDesignGui::TaskFeaturePick::invalidShape); - + if (firstValidPlane == planes.end()) firstValidPlane = p; validPlanes++; @@ -804,12 +814,12 @@ void CmdPartDesignNewSketch::activated(int iMsg) if (!pcActiveBody->hasFeature(*p)) { if(pcActivePart->hasObject(*p, true)) status.push_back(PartDesignGui::TaskFeaturePick::otherBody); - else + else status.push_back(PartDesignGui::TaskFeaturePick::otherPart); - + continue; } else { - if (pcActiveBody->isAfterTip(*p)){ + if (pcActiveBody->isAfterInsertPoint(*p)) { status.push_back(PartDesignGui::TaskFeaturePick::afterTip); continue; } @@ -908,7 +918,7 @@ void finishFeature(const Gui::Command* cmd, const std::string& FeatName, } if (pcActiveBody) { - App::DocumentObject* lastSolidFeature = pcActiveBody->getPrevSolidFeature(NULL, true); + App::DocumentObject* lastSolidFeature = pcActiveBody->Tip.getValue(); if (!prevSolidFeature || prevSolidFeature == lastSolidFeature) { // If the previous feature not given or is the Tip add Feature after it. cmd->doCommand(cmd->Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", @@ -916,7 +926,7 @@ void finishFeature(const Gui::Command* cmd, const std::string& FeatName, prevSolidFeature = lastSolidFeature; } else { // Insert the feature into the body after the given one. - cmd->doCommand(cmd->Doc, + cmd->doCommand(cmd->Doc, "App.activeDocument().%s.insertFeature(App.activeDocument().%s, App.activeDocument().%s, True)", pcActiveBody->getNameInDocument(), FeatName.c_str(), prevSolidFeature->getNameInDocument()); } @@ -999,7 +1009,7 @@ const unsigned validateSketches(std::vector& sketches, continue; } - if (pcActiveBody && pcActiveBody->isAfterTip(*s)){ + if (pcActiveBody && pcActiveBody->isAfterInsertPoint(*s)){ status.push_back(PartDesignGui::TaskFeaturePick::afterTip); continue; } @@ -1409,19 +1419,19 @@ CmdPartDesignAdditiveLoft::CmdPartDesignAdditiveLoft() } void CmdPartDesignAdditiveLoft::activated(int iMsg) -{ +{ Gui::Command* cmd = this; auto worker = [cmd](Part::Part2DObject* sketch, std::string FeatName) { - + if (FeatName.empty()) return; - + // specific parameters for pipe Gui::Command::updateActive(); finishSketchBased(cmd, sketch, FeatName); cmd->adjustCameraPosition(); }; - + prepareSketchBased(this, "AdditiveLoft", worker); } @@ -1449,19 +1459,19 @@ CmdPartDesignSubtractiveLoft::CmdPartDesignSubtractiveLoft() } void CmdPartDesignSubtractiveLoft::activated(int iMsg) -{ +{ Gui::Command* cmd = this; auto worker = [cmd](Part::Part2DObject* sketch, std::string FeatName) { - + if (FeatName.empty()) return; - + // specific parameters for pipe Gui::Command::updateActive(); finishSketchBased(cmd, sketch, FeatName); cmd->adjustCameraPosition(); }; - + prepareSketchBased(this, "SubtractiveLoft", worker); } @@ -1749,7 +1759,7 @@ void prepareTransformed(Gui::Command* cmd, const std::string& which, // Exception (Thu Sep 6 11:52:01 2012): 'App.Document' object has no attribute 'Mirrored' Gui::Command::updateActive(); // Helps to ensure that the object already exists when the next command comes up Gui::Command::doCommand(Gui::Command::Doc, str.str().c_str()); - + // TODO Wjat that function supposed to do? (2015-08-05, Fat-Zer) func(FeatName, features); }; @@ -2069,9 +2079,7 @@ void CmdPartDesignMultiTransform::activated(int iMsg) return; // Make sure the user isn't presented with an empty screen because no transformations are defined yet... - App::DocumentObject* prevSolid = 0; - if (pcActiveBody) - pcActiveBody->getPrevSolidFeature(NULL, true); + App::DocumentObject* prevSolid = pcActiveBody->Tip.getValue(); if (prevSolid != NULL) { Part::Feature* feat = static_cast(prevSolid); doCommand(Doc,"App.activeDocument().%s.Shape = App.activeDocument().%s.Shape", diff --git a/src/Mod/PartDesign/Gui/CommandPrimitive.cpp b/src/Mod/PartDesign/Gui/CommandPrimitive.cpp index eb7488c30..e08ad8109 100644 --- a/src/Mod/PartDesign/Gui/CommandPrimitive.cpp +++ b/src/Mod/PartDesign/Gui/CommandPrimitive.cpp @@ -56,78 +56,78 @@ CmdPrimtiveCompAdditive::CmdPrimtiveCompAdditive() void CmdPrimtiveCompAdditive::activated(int iMsg) { - + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(/*messageIfNot = */true); if (!pcActiveBody) return; - + std::string FeatName; std::string CSName = getUniqueObjectName("CoordinateSystem");; if(iMsg == 0) { - + FeatName = getUniqueObjectName("Box"); - + Gui::Command::openCommand("Make additive box"); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.addObject(\'PartDesign::AdditiveBox\',\'%s\')", FeatName.c_str()); } else if(iMsg == 1) { - + FeatName = getUniqueObjectName("Cylinder"); - + Gui::Command::openCommand("Make additive cylinder"); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.addObject(\'PartDesign::AdditiveCylinder\',\'%s\')", FeatName.c_str()); } else if(iMsg == 2) { - + FeatName = getUniqueObjectName("Sphere"); - + Gui::Command::openCommand("Make additive sphere"); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.addObject(\'PartDesign::AdditiveSphere\',\'%s\')", FeatName.c_str()); } else if(iMsg == 3) { - + FeatName = getUniqueObjectName("Cone"); - + Gui::Command::openCommand("Make additive cone"); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.addObject(\'PartDesign::AdditiveCone\',\'%s\')", FeatName.c_str()); } else if(iMsg == 4) { - + FeatName = getUniqueObjectName("Ellipsoid"); - + Gui::Command::openCommand("Make additive ellipsoid"); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.addObject(\'PartDesign::AdditiveEllipsoid\',\'%s\')", FeatName.c_str()); } else if(iMsg == 5) { - + FeatName = getUniqueObjectName("Torus"); - + Gui::Command::openCommand("Make additive torus"); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.addObject(\'PartDesign::AdditiveTorus\',\'%s\')", FeatName.c_str()); } else if(iMsg == 6) { - + FeatName = getUniqueObjectName("Prism"); - + Gui::Command::openCommand("Make additive prism"); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.addObject(\'PartDesign::AdditivePrism\',\'%s\')", FeatName.c_str()); } else if(iMsg == 7) { - + FeatName = getUniqueObjectName("Wedge"); - + Gui::Command::openCommand("Make additive wedge"); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.addObject(\'PartDesign::AdditiveWedge\',\'%s\')", FeatName.c_str()); } - - + + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addFeature(App.activeDocument().%s)" ,pcActiveBody->getNameInDocument(), FeatName.c_str()); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.addObject(\'PartDesign::CoordinateSystem\',\'%s\')", @@ -137,13 +137,13 @@ void CmdPrimtiveCompAdditive::activated(int iMsg) Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.CoordinateSystem=(App.ActiveDocument.%s)", FeatName.c_str(), CSName.c_str()); Gui::Command::updateActive(); - + auto* prm = static_cast(getDocument()->getObject(FeatName.c_str())); if (prm->BaseFeature.getValue()) doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", prm->BaseFeature.getValue()->getNameInDocument()); Gui::Command::doCommand(Gui, "Gui.activeDocument().hide(\'%s\')", CSName.c_str()); - Gui::Command::doCommand(Gui, "Gui.activeDocument().setEdit(\'%s\')", FeatName.c_str()); + Gui::Command::doCommand(Gui, "Gui.activeDocument().setEdit(\'%s\')", FeatName.c_str()); } Gui::Action * CmdPrimtiveCompAdditive::createAction(void) @@ -245,85 +245,86 @@ CmdPrimtiveCompSubtractive::CmdPrimtiveCompSubtractive() } void CmdPrimtiveCompSubtractive::activated(int iMsg) -{ +{ PartDesign::Body *pcActiveBody = PartDesignGui::getBody(/*messageIfNot = */true); if (!pcActiveBody) return; - - //check if we already have a feature as subtractive ones work only if we have + + //check if we already have a feature as subtractive ones work only if we have //something to subtract from. - if(!pcActiveBody->getPrevSolidFeature()) { + App::DocumentObject *prevSolid = pcActiveBody->Tip.getValue(); + if(!prevSolid) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No previous feature found"), QObject::tr("It is not possible to create a subtractive feature without a base feature available")); return; } - + std::string FeatName; std::string CSName = getUniqueObjectName("CoordinateSystem"); if(iMsg == 0) { - + FeatName = getUniqueObjectName("Box"); - + Gui::Command::openCommand("Make subtractive box"); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.addObject(\'PartDesign::SubtractiveBox\',\'%s\')", FeatName.c_str()); } else if(iMsg == 1) { - + FeatName = getUniqueObjectName("Cylinder"); - + Gui::Command::openCommand("Make subtractive cylinder"); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.addObject(\'PartDesign::SubtractiveCylinder\',\'%s\')", FeatName.c_str()); } else if(iMsg == 2) { - + FeatName = getUniqueObjectName("Sphere"); - + Gui::Command::openCommand("Make subtractive sphere"); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.addObject(\'PartDesign::SubtractiveSphere\',\'%s\')", FeatName.c_str()); } else if(iMsg == 3) { - + FeatName = getUniqueObjectName("Cone"); - + Gui::Command::openCommand("Make subtractive cone"); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.addObject(\'PartDesign::SubtractiveCone\',\'%s\')", FeatName.c_str()); } else if(iMsg == 4) { - + FeatName = getUniqueObjectName("Ellipsoid"); - + Gui::Command::openCommand("Make subtractive ellipsoid"); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.addObject(\'PartDesign::SubtractiveEllipsoid\',\'%s\')", FeatName.c_str()); } else if(iMsg == 5) { - + FeatName = getUniqueObjectName("Torus"); - + Gui::Command::openCommand("Make subtractive torus"); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.addObject(\'PartDesign::SubtractiveTorus\',\'%s\')", FeatName.c_str()); } else if(iMsg == 6) { - + FeatName = getUniqueObjectName("Prism"); - + Gui::Command::openCommand("Make subtractive prism"); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.addObject(\'PartDesign::SubtractivePrism\',\'%s\')", FeatName.c_str()); } else if(iMsg == 7) { - + FeatName = getUniqueObjectName("Wedge"); - + Gui::Command::openCommand("Make subtractive wedge"); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.addObject(\'PartDesign::SubtractiveWedge\',\'%s\')", FeatName.c_str()); } - + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addFeature(App.activeDocument().%s)" ,pcActiveBody->getNameInDocument(), FeatName.c_str()); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.addObject(\'PartDesign::CoordinateSystem\',\'%s\')", @@ -333,15 +334,16 @@ void CmdPrimtiveCompSubtractive::activated(int iMsg) Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.CoordinateSystem=(App.ActiveDocument.%s)", FeatName.c_str(), CSName.c_str()); Gui::Command::updateActive(); - + if (isActiveObjectValid() && (pcActiveBody != NULL)) { - App::DocumentObject* prevSolidFeature = pcActiveBody->getPrevSolidFeature(NULL, false); - if (prevSolidFeature != NULL && strcmp(prevSolidFeature->getNameInDocument(), FeatName.c_str())!=0) - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", prevSolidFeature->getNameInDocument()); + // TODO (2015-08-05, Fat-Zer) + if (prevSolid) { + doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", prevSolid->getNameInDocument()); + } } Gui::Command::doCommand(Gui, "Gui.activeDocument().hide(\'%s\')", CSName.c_str()); - Gui::Command::doCommand(Gui, "Gui.activeDocument().setEdit(\'%s\')", FeatName.c_str()); + Gui::Command::doCommand(Gui, "Gui.activeDocument().setEdit(\'%s\')", FeatName.c_str()); } Gui::Action * CmdPrimtiveCompSubtractive::createAction(void) diff --git a/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp b/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp index e7c188392..7eede73cb 100644 --- a/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp @@ -917,17 +917,6 @@ bool TaskDlgDatumParameters::reject() Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); PartDesign::Body* activeBody = Gui::Application::Instance->activeView()->getActiveObject(PDBODYKEY); - // Body housekeeping - if (activeBody != NULL) { - // Make the new Tip and the previous solid feature visible again - App::DocumentObject* tip = activeBody->Tip.getValue(); - App::DocumentObject* prev = activeBody->getPrevSolidFeature(); - if (tip != NULL) { - Gui::Application::Instance->getViewProvider(tip)->show(); - if ((tip != prev) && (prev != NULL)) - Gui::Application::Instance->getViewProvider(prev)->show(); - } - } return true; } diff --git a/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp b/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp index 1b6a4f3c6..2555b1bc7 100644 --- a/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp @@ -97,24 +97,14 @@ void TaskSketchBasedParameters::onSelectReference(const bool pressed, const bool PartDesign::SketchBased* pcSketchBased = static_cast(vp->getObject()); PartDesign::Body* activeBody = Gui::Application::Instance->activeView()->getActiveObject(PDBODYKEY); - App::DocumentObject* curSolid = 0;//the last solid of the body, the one that is likely visible, but can't be used for up-to-face - if (activeBody) - curSolid = activeBody->getPrevSolidFeature(); - else - curSolid = pcSketchBased; - - App::DocumentObject* prevSolid = 0;//the solid this feature will be fused to - try { - prevSolid = pcSketchBased->getBaseObject(); - } catch (Base::Exception) { - //this feature is a starting feature - } + // The solid this feature will be fused to + App::DocumentObject* prevSolid = pcSketchBased->getBaseObject( /* silent =*/ true ); if (pressed) { Gui::Document* doc = Gui::Application::Instance->activeDocument(); if (doc) { - if (curSolid) - doc->setHide(curSolid->getNameInDocument()); + if (pcSketchBased) + doc->setHide(pcSketchBased->getNameInDocument()); if (prevSolid) doc->setShow(prevSolid->getNameInDocument()); } @@ -125,8 +115,8 @@ void TaskSketchBasedParameters::onSelectReference(const bool pressed, const bool Gui::Selection().rmvSelectionGate(); Gui::Document* doc = Gui::Application::Instance->activeDocument(); if (doc) { - if (curSolid) - doc->setShow(curSolid->getNameInDocument()); + if (pcSketchBased) + doc->setShow(pcSketchBased->getNameInDocument()); if (prevSolid) doc->setHide(prevSolid->getNameInDocument()); } diff --git a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp index a6b904a1c..513473c52 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp @@ -70,7 +70,7 @@ void ViewProviderBody::attach(App::DocumentObject *pcFeat) // call parent attach method ViewProviderPart::attach(pcFeat); - + // TODO fixup the "Body" display mode (2015-08-07, Fat-Zer) // putting all together with the switch addDisplayMaskMode(pcBodyTip, "Body"); addDisplayMaskMode(pcBodyChildren, "Through"); @@ -106,12 +106,12 @@ bool ViewProviderBody::doubleClicked(void) { // assure the PartDesign workbench Gui::Command::assureWorkbench("PartDesignWorkbench"); - + //and set correct active objects auto* part = PartDesignGui::getPartFor(getObject(), false); if(part!=Gui::Application::Instance->activeView()->getActiveObject(PARTKEY)) Gui::Command::doCommand(Gui::Command::Gui, "Gui.activeView().setActiveObject('%s', App.activeDocument().%s)", PARTKEY, part->getNameInDocument()); - + Gui::Command::doCommand(Gui::Command::Gui, "Gui.activeView().setActiveObject('%s', App.activeDocument().%s)", PDBODYKEY, this->getObject()->getNameInDocument()); return true; @@ -119,7 +119,8 @@ bool ViewProviderBody::doubleClicked(void) std::vector ViewProviderBody::claimChildren(void)const { - std::vector Model = static_cast(getObject())->Model.getValues(); + PartDesign::Body* bodyObj = static_cast(getObject()); + const std::vector &Model = bodyObj->Model.getValues(); std::set OutSet; // search for objects handled (claimed) by the features @@ -136,23 +137,34 @@ std::vector ViewProviderBody::claimChildren(void)const // remove the otherwise handled objects, preserving their order so the order in the TreeWidget is correct std::vector Result; + + // Clame for the base feature first + if (bodyObj->BaseFeature.getValue()) { + Result.push_back (bodyObj->BaseFeature.getValue()); + } + + // return the rest as claim set of the Body for (std::vector::const_iterator it = Model.begin();it!=Model.end();++it) { if (OutSet.find(*it) == OutSet.end()) Result.push_back(*it); } - // return the rest as claim set of the Body return Result; } std::vector ViewProviderBody::claimChildren3D(void)const { - //std::vector children = static_cast(getObject())->Model.getValues(); - //Base::Console().Error("Body 3D claimed children:\n"); - //for (std::vector::const_iterator o = children.begin(); o != children.end(); o++) - // Base::Console().Error("%s\n", (*o)->getNameInDocument()); - return static_cast(getObject())->Model.getValues(); + PartDesign::Body* body = static_cast(getObject()); + + const std::vector & features = body->Model.getValues(); + + std::vector rv; + + rv.push_back( body->BaseFeature.getValue() ); + rv.insert( rv.end(), features.begin(), features.end()); + // TODO Check what will happen if BaseFature will be shared by severral bodies (2015-08-04, Fat-Zer) + return rv; } @@ -164,7 +176,7 @@ std::vector ViewProviderBody::claimChildren3D(void)const // //Base::Console().Error("ViewProviderBody::updateTree()\n"); // PartDesign::Body* body = static_cast(getObject()); // bool active = body->IsActive.getValue(); -// //Base::Console().Error("Body is %s\n", active ? "active" : "inactive"); +// //Base::Console().Error("Body is %s\n", active ? "active" : "inactive"); // ActiveGuiDoc->signalHighlightObject(*this, Gui::Blue, active); // std::vector features = body->Model.getValues(); // bool highlight = true; diff --git a/src/Mod/PartDesign/Gui/ViewProviderBody.h b/src/Mod/PartDesign/Gui/ViewProviderBody.h index 301028aa2..9163efee1 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderBody.h +++ b/src/Mod/PartDesign/Gui/ViewProviderBody.h @@ -30,9 +30,9 @@ namespace PartDesignGui { /** ViewProvider of the Body feature - * This class manage the visual apperance of the features in the - * Body feature. That mean while editing only the tip feature is - * visible. If the Body is not active it shows only the result shape (tip). + * This class manage the visual apperance of the features in the + * Body feature. That mean while editing only the tip feature is + * visible. If the Body is not active it shows only the result shape (tip). * \author jriegel */ class PartDesignGuiExport ViewProviderBody : public PartGui::ViewProviderPart @@ -44,21 +44,21 @@ public: ViewProviderBody(); /// destructor virtual ~ViewProviderBody(); - + virtual void attach(App::DocumentObject *); virtual void setDisplayMode(const char* ModeName); /// returns a list of all possible modes virtual std::vector getDisplayModes(void) const; virtual bool doubleClicked(void); - std::vector claimChildren(void)const; + virtual std::vector claimChildren(void)const; // returns the root node where the children gets collected(3D) virtual SoGroup* getChildRoot(void) const {return pcBodyChildren;} - std::vector claimChildren3D(void)const; + virtual std::vector claimChildren3D(void)const; /// Update the children's highlighting when triggered - void updateData(const App::Property* prop); + void updateData(const App::Property* prop); private: /// group used to store children collected by claimChildren3D() diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp b/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp index b7497a4e7..07b484b6f 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp @@ -120,20 +120,6 @@ void ViewProviderDatum::attach(App::DocumentObject *obj) bool ViewProviderDatum::onDelete(const std::vector &) { - // Body feature housekeeping - Part::BodyBase* body = Part::BodyBase::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(); - if (tip != NULL) { - Gui::Application::Instance->getViewProvider(tip)->show(); - if ((tip != prev) && (prev != NULL)) - 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 diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index e9e605c32..d3639e904 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -172,16 +172,16 @@ PartDesign::Body *Workbench::setUpPart(const App::Part *part) Gui::ViewProviderPart::setUpPart(part); // check for Bodies - std::vector bodies = part->getObjectsOfType(PartDesign::Body::getClassTypeId()); - assert(bodies.size() == 0); + // std::vector bodies = part->getObjectsOfType(PartDesign::Body::getClassTypeId()); + // assert(bodies.size() == 0); - std::string PartName = part->getNameInDocument(); - std::string BodyName = part->getDocument()->getUniqueObjectName("MainBody"); + // std::string PartName = part->getNameInDocument(); + // std::string BodyName = part->getDocument()->getUniqueObjectName("MainBody"); Gui::Command::addModule(Gui::Command::Doc, "PartDesign"); - Gui::Command::doCommand(Gui::Command::Doc, "App.activeDocument().addObject('PartDesign::Body','%s')", BodyName.c_str()); - Gui::Command::doCommand(Gui::Command::Doc, "App.activeDocument().%s.addObject(App.activeDocument().ActiveObject)", part->getNameInDocument()); - Gui::Command::doCommand(Gui::Command::Gui, "Gui.activeView().setActiveObject('%s', App.activeDocument().%s)", PDBODYKEY, BodyName.c_str()); + // Gui::Command::doCommand(Gui::Command::Doc, "App.activeDocument().addObject('PartDesign::Body','%s')", BodyName.c_str()); + // Gui::Command::doCommand(Gui::Command::Doc, "App.activeDocument().%s.addObject(App.activeDocument().ActiveObject)", part->getNameInDocument()); + // Gui::Command::doCommand(Gui::Command::Gui, "Gui.activeView().setActiveObject('%s', App.activeDocument().%s)", PDBODYKEY, BodyName.c_str()); Gui::Command::updateActive(); return NULL; diff --git a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp index 75714e31d..a78f61547 100644 --- a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp +++ b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp @@ -4480,9 +4480,10 @@ namespace SketcherGui { // Note: its better to search the support of the sketch in case the sketch support is a base plane Part::BodyBase* body = Part::BodyBase::findBodyOf(sketch); - if ((body != NULL) && (Part::BodyBase::findBodyOf(pObj) == body) && body->isAfterTip(pObj)) - // Don't allow selection after the Tip feature in the same body + if ((body != NULL) && (Part::BodyBase::findBodyOf(pObj) == body) && body->isAfter(pObj, sketch)) { + // Don't allow selection after the sketch in the same body return false; + } if (!sSubName || sSubName[0] == '\0') return false; @@ -4491,7 +4492,7 @@ namespace SketcherGui { (element.size() > 6 && element.substr(0,6) == "Vertex") || (element.size() > 4 && element.substr(0,4) == "Face")) { return true; - } + } if (pObj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId()) || pObj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) return true;