From 6235385c5ac5c486c06774adc7e5ad09dcd7fb28 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Tue, 2 Apr 2013 20:51:31 +0430 Subject: [PATCH] Create Base property for SketchBased features and changed Pad to use it --- src/Mod/PartDesign/App/Body.cpp | 16 ++++++++ src/Mod/PartDesign/App/Body.h | 8 ++++ src/Mod/PartDesign/App/FeaturePad.cpp | 31 ++++++++++++-- src/Mod/PartDesign/App/FeatureSketchBased.cpp | 21 ++++++++++ src/Mod/PartDesign/App/FeatureSketchBased.h | 7 +++- src/Mod/PartDesign/Gui/Command.cpp | 40 ++++++++++--------- 6 files changed, 100 insertions(+), 23 deletions(-) diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index 40e33035d..a6fb49143 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -86,6 +86,22 @@ const Part::TopoShape Body::getPreviousSolid(const PartDesign::Feature* f) return static_cast(*it)->Shape.getShape(); } +App::DocumentObject* Body::getTipSolidFeature() +{ + std::vector features = Model.getValues(); + if (features.empty()) return NULL; + std::vector::const_iterator it = std::find(features.begin(), features.end(), Tip.getValue()); + + // Skip sketches + while (!(*it)->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId())) { + if (it == features.begin()) + return NULL; + it--; + } + + return *it; +} + const bool Body::hasFeature(const App::DocumentObject* f) { std::vector features = Model.getValues(); diff --git a/src/Mod/PartDesign/App/Body.h b/src/Mod/PartDesign/App/Body.h index b72a183cc..8fc28d5c9 100644 --- a/src/Mod/PartDesign/App/Body.h +++ b/src/Mod/PartDesign/App/Body.h @@ -58,6 +58,14 @@ public: /// Get the tip shape 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 + */ + App::DocumentObject *getTipSolidFeature(); + /// Return the shape of the feature preceding this feature const Part::TopoShape getPreviousSolid(const PartDesign::Feature* f); diff --git a/src/Mod/PartDesign/App/FeaturePad.cpp b/src/Mod/PartDesign/App/FeaturePad.cpp index 0a1e262b9..b1d053edb 100644 --- a/src/Mod/PartDesign/App/FeaturePad.cpp +++ b/src/Mod/PartDesign/App/FeaturePad.cpp @@ -96,7 +96,20 @@ App::DocumentObjectExecReturn *Pad::execute(void) return new App::DocumentObjectExecReturn(e.what()); } + TopoDS_Shape support; + try { + support = getSupportShape(); + } catch (const Base::Exception&) { + // ignore, because support isn't mandatory + support = TopoDS_Shape(); + } + +/* // Find Body feature which owns this Pad and get the shape of the feature preceding this one for fusing + // This method was rejected in favour of the Base property because it makes the feature atomic (independent of the + // Body object). See + // https://sourceforge.net/apps/phpbb/free-cad/viewtopic.php?f=19&t=3831 + // https://sourceforge.net/apps/phpbb/free-cad/viewtopic.php?f=19&t=3855 PartDesign::Body* body = getBody(); if (body == NULL) { return new App::DocumentObjectExecReturn( @@ -113,6 +126,7 @@ App::DocumentObjectExecReturn *Pad::execute(void) support = TopoDS_Shape(); else support = prevShape._Shape; +*/ // get the Sketch plane Base::Placement SketchPos = sketch->Placement.getValue(); @@ -184,13 +198,22 @@ App::DocumentObjectExecReturn *Pad::execute(void) prism = refineShapeIfActive(prism); this->AddShape.setValue(prism); - // if the sketch has a support fuse them to get one result object - if (!support.IsNull()) { + // if the Base property has a valid shape, fuse the prism into it + TopoDS_Shape base; + try { + base = getBaseShape(); + base.Move(invObjLoc); + } catch (const Base::Exception&) { + // fall back to support (for legacy features) + base = support; + } + + if (!base.IsNull()) { // Let's call algorithm computing a fuse operation: - BRepAlgoAPI_Fuse mkFuse(support, prism); + BRepAlgoAPI_Fuse mkFuse(base, prism); // Let's check if the fusion has been successful if (!mkFuse.IsDone()) - return new App::DocumentObjectExecReturn("Pad: Fusion with support failed"); + return new App::DocumentObjectExecReturn("Pad: Fusion with base feature failed"); TopoDS_Shape result = mkFuse.Shape(); // we have to get the solids (fuse sometimes creates compounds) TopoDS_Shape solRes = this->getSolid(result); diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.cpp b/src/Mod/PartDesign/App/FeatureSketchBased.cpp index 147e8fb20..52b58c084 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.cpp +++ b/src/Mod/PartDesign/App/FeatureSketchBased.cpp @@ -98,6 +98,7 @@ PROPERTY_SOURCE(PartDesign::SketchBased, PartDesign::Feature) SketchBased::SketchBased() { + ADD_PROPERTY(Base,(0)); ADD_PROPERTY_TYPE(Sketch,(0),"SketchBased", App::Prop_None, "Reference to sketch"); ADD_PROPERTY_TYPE(Midplane,(0),"SketchBased", App::Prop_None, "Extrude symmetric to sketch face"); ADD_PROPERTY_TYPE(Reversed, (0),"SketchBased", App::Prop_None, "Reverse extrusion direction"); @@ -231,6 +232,26 @@ const TopoDS_Shape& SketchBased::getSupportShape() const { return result; } +const TopoDS_Shape& SketchBased::getBaseShape() const { + App::DocumentObject* BaseLink = Base.getValue(); + if (BaseLink == NULL) throw Base::Exception("Base property not set"); + Part::Feature* BaseObject = NULL; + if (BaseLink->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) + BaseObject = static_cast(BaseLink); + + if (BaseObject == NULL) + throw Base::Exception("No base feature linked"); + + const TopoDS_Shape& result = BaseObject->Shape.getValue(); + if (result.IsNull()) + throw Base::Exception("Base feature's shape is invalid"); + TopExp_Explorer xp (result, TopAbs_SOLID); + if (!xp.More()) + throw Base::Exception("Base feature's shape is not a solid"); + + return result; +} + int SketchBased::getSketchAxisCount(void) const { Part::Part2DObject *sketch = static_cast(Sketch.getValue()); diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.h b/src/Mod/PartDesign/App/FeatureSketchBased.h index abb034e80..84269ef9f 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.h +++ b/src/Mod/PartDesign/App/FeatureSketchBased.h @@ -44,7 +44,10 @@ class PartDesignExport SketchBased : public PartDesign::Feature public: SketchBased(); - /// Common properties for all sketch based features + // Common properties for all sketch based features + /// Base feature which this feature will be fused into or cut out of + App::PropertyLink Base; + /// Sketch used to create this feature App::PropertyLink Sketch; /// Reverse extrusion direction App::PropertyBool Reversed; @@ -72,6 +75,8 @@ public: Part::Feature* getSupport() const; /// Returns the sketch support shape (if any) const TopoDS_Shape& getSupportShape() const; + /// Returns the base property's shape (if any) + const TopoDS_Shape& getBaseShape() const; /// retrieves the number of axes in the linked sketch (defined as construction lines) int getSketchAxisCount(void) const; diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 6f46c38ea..31be55b6f 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -300,7 +300,7 @@ void CmdPartDesignNewSketch::activated(int iMsg) doCommand(Gui,"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]); 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.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); } } @@ -382,11 +382,10 @@ bool CmdPartDesignNewSketch::isActive(void) } void prepareSketchBased(Gui::Command* cmd, const std::string& which, - Part::Part2DObject*& sketch, std::string& FeatName, App::DocumentObject*& prevTip) + Part::Part2DObject*& sketch, std::string& FeatName, App::DocumentObject*& prevSolidFeature) { PartDesign::Body *pcActiveBody = getBody(); if (!pcActiveBody) return; - prevTip = pcActiveBody->Tip.getValue(); // Get a valid sketch from the user // First check selections @@ -415,17 +414,22 @@ 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(); 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) + cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Base = App.activeDocument().%s",FeatName.c_str(),prevSolidFeature->getNameInDocument()); 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().%s.Sketch = App.activeDocument().%s",FeatName.c_str(),sketch->getNameInDocument()); } void finishSketchBased(const Gui::Command* cmd, - const Part::Part2DObject* sketch, const std::string& FeatName, const App::DocumentObject* prevTip) + const Part::Part2DObject* sketch, const std::string& FeatName, const App::DocumentObject* prevSolidFeature) { App::DocumentObjectGroup* grp = sketch->getGroup(); if (grp) { @@ -438,8 +442,8 @@ void finishSketchBased(const Gui::Command* cmd, cmd->updateActive(); if (cmd->isActiveObjectValid()) { cmd->doCommand(cmd->Gui,"Gui.activeDocument().hide(\"%s\")", sketch->getNameInDocument()); - if (prevTip != NULL) - cmd->doCommand(cmd->Gui,"Gui.activeDocument().hide(\"%s\")", prevTip->getNameInDocument()); + 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 @@ -474,14 +478,14 @@ void CmdPartDesignPad::activated(int iMsg) { Part::Part2DObject* sketch; std::string FeatName; - App::DocumentObject* prevTip; - prepareSketchBased(this, "Pad", sketch, FeatName, prevTip); + App::DocumentObject* prevSolidFeature; + prepareSketchBased(this, "Pad", sketch, FeatName, prevSolidFeature); if (FeatName.empty()) return; // specific parameters for Pad doCommand(Doc,"App.activeDocument().%s.Length = 10.0",FeatName.c_str()); - finishSketchBased(this, sketch, FeatName, prevTip); + finishSketchBased(this, sketch, FeatName, prevSolidFeature); adjustCameraPosition(); } @@ -511,13 +515,13 @@ void CmdPartDesignPocket::activated(int iMsg) { Part::Part2DObject* sketch; std::string FeatName; - App::DocumentObject* prevTip; - prepareSketchBased(this, "Pocket", sketch, FeatName, prevTip); + App::DocumentObject* prevSolidFeature; + prepareSketchBased(this, "Pocket", sketch, FeatName, prevSolidFeature); if (FeatName.empty()) return; doCommand(Doc,"App.activeDocument().%s.Length = 5.0",FeatName.c_str()); - finishSketchBased(this, sketch, FeatName, prevTip); + finishSketchBased(this, sketch, FeatName, prevSolidFeature); adjustCameraPosition(); } @@ -547,8 +551,8 @@ void CmdPartDesignRevolution::activated(int iMsg) { Part::Part2DObject* sketch; std::string FeatName; - App::DocumentObject* prevTip; - prepareSketchBased(this, "Revolution", sketch, FeatName, prevTip); + App::DocumentObject* prevSolidFeature; + prepareSketchBased(this, "Revolution", sketch, FeatName, prevSolidFeature); if (FeatName.empty()) return; doCommand(Doc,"App.activeDocument().%s.ReferenceAxis = (App.activeDocument().%s,['V_Axis'])", @@ -558,7 +562,7 @@ void CmdPartDesignRevolution::activated(int iMsg) if (pcRevolution && pcRevolution->suggestReversed()) doCommand(Doc,"App.activeDocument().%s.Reversed = 1",FeatName.c_str()); - finishSketchBased(this, sketch, FeatName, prevTip); + finishSketchBased(this, sketch, FeatName, prevSolidFeature); adjustCameraPosition(); } @@ -588,8 +592,8 @@ void CmdPartDesignGroove::activated(int iMsg) { Part::Part2DObject* sketch; std::string FeatName; - App::DocumentObject* prevTip; - prepareSketchBased(this, "Groove", sketch, FeatName, prevTip); + App::DocumentObject* prevSolidFeature; + prepareSketchBased(this, "Groove", sketch, FeatName, prevSolidFeature); if (FeatName.empty()) return; doCommand(Doc,"App.activeDocument().%s.ReferenceAxis = (App.activeDocument().%s,['V_Axis'])", @@ -599,7 +603,7 @@ void CmdPartDesignGroove::activated(int iMsg) if (pcGroove && pcGroove->suggestReversed()) doCommand(Doc,"App.activeDocument().%s.Reversed = 1",FeatName.c_str()); - finishSketchBased(this, sketch, FeatName, prevTip); + finishSketchBased(this, sketch, FeatName, prevSolidFeature); adjustCameraPosition(); }