From 7ffddb6f7dcffae11b3843141d8d08c8a5cd9950 Mon Sep 17 00:00:00 2001 From: Florian Foinant-Willig Date: Sun, 26 May 2024 21:41:22 +0200 Subject: [PATCH] PD Extrude up to multiple faces or shape --- src/Mod/Part/App/TopoShapeExpansion.cpp | 2 +- src/Mod/PartDesign/App/FeatureExtrude.cpp | 42 ++++++++++----- src/Mod/PartDesign/App/FeaturePad.cpp | 1 + src/Mod/PartDesign/App/FeaturePocket.cpp | 3 +- src/Mod/PartDesign/App/FeatureSketchBased.cpp | 53 +++++++++++++++++++ src/Mod/PartDesign/App/FeatureSketchBased.h | 6 +++ 6 files changed, 93 insertions(+), 14 deletions(-) diff --git a/src/Mod/Part/App/TopoShapeExpansion.cpp b/src/Mod/Part/App/TopoShapeExpansion.cpp index f5c8d4bd7b..f77f528d71 100644 --- a/src/Mod/Part/App/TopoShapeExpansion.cpp +++ b/src/Mod/Part/App/TopoShapeExpansion.cpp @@ -4279,7 +4279,7 @@ TopoShape& TopoShape::makeElementPrismUntil(const TopoShape& _base, // Check whether the face has limits or not. Unlimited faces have no wire // Note: Datum planes are always unlimited - if (checkLimits && uptoface.hasSubShape(TopAbs_WIRE)) { + if (checkLimits && _uptoface.shapeType(true) == TopAbs_FACE && uptoface.hasSubShape(TopAbs_WIRE)) { TopoDS_Face face = TopoDS::Face(uptoface.getShape()); bool remove_limits = false; // Remove the limits of the upToFace so that the extrusion works even if profile is larger diff --git a/src/Mod/PartDesign/App/FeatureExtrude.cpp b/src/Mod/PartDesign/App/FeatureExtrude.cpp index e93cce5107..bba40c1425 100644 --- a/src/Mod/PartDesign/App/FeatureExtrude.cpp +++ b/src/Mod/PartDesign/App/FeatureExtrude.cpp @@ -375,6 +375,7 @@ void FeatureExtrude::updateProperties(const std::string &method) bool isMidplaneEnabled = false; bool isReversedEnabled = false; bool isUpToFaceEnabled = false; + bool isUpToShapeEnabled = false; bool isTaperVisible = false; bool isTaper2Visible = false; if (method == "Length") { @@ -409,6 +410,7 @@ void FeatureExtrude::updateProperties(const std::string &method) } else if (method == "UpToShape") { isReversedEnabled = true; + isUpToShapeEnabled = true; } Length.setReadOnly(!isLengthEnabled); @@ -420,6 +422,7 @@ void FeatureExtrude::updateProperties(const std::string &method) Midplane.setReadOnly(!isMidplaneEnabled); Reversed.setReadOnly(!isReversedEnabled); UpToFace.setReadOnly(!isUpToFaceEnabled); + UpToShape.setReadOnly(!isUpToShapeEnabled); } void FeatureExtrude::setupObject() @@ -558,7 +561,7 @@ App::DocumentObjectExecReturn* FeatureExtrude::buildExtrusion(ExtrudeOptions opt TopoShape prism(0, getDocument()->getStringHasher()); - if (method == "UpToFirst" || method == "UpToLast" || method == "UpToFace") { + if (method == "UpToFirst" || method == "UpToLast" || method == "UpToFace" || method == "UpToShape") { // Note: This will return an unlimited planar face if support is a datum plane TopoShape supportface = getTopoShapeSupportFace(); supportface.move(invObjLoc); @@ -567,18 +570,33 @@ App::DocumentObjectExecReturn* FeatureExtrude::buildExtrusion(ExtrudeOptions opt dir.Reverse(); } - // Find a valid face or datum plane to extrude up to - TopoShape upToFace; - - if (method != "UpToShape") { - if (method == "UpToFace") { - getUpToFaceFromLinkSub(upToFace, UpToFace); - upToFace.move(invObjLoc); + TopoShape upToShape; + int faceCount = 1; + // Find a valid shape, face or datum plane to extrude up to + if (method == "UpToFace") { + getUpToFaceFromLinkSub(upToShape, UpToFace); + upToShape.move(invObjLoc); + faceCount = 1; + } + else if (method == "UpToShape") { + try { + faceCount = getUpToShapeFromLinkSubList(upToShape, UpToShape); + upToShape.move(invObjLoc); + } + catch (Base::ValueError&){ + //no shape selected use the base + upToShape = base; + faceCount = 0; } - getUpToFace(upToFace, base, supportface, sketchshape, method, dir); - addOffsetToFace(upToFace, dir, Offset.getValue()); } + if (faceCount == 1) { + getUpToFace(upToShape, base, supportface, sketchshape, method, dir); + addOffsetToFace(upToShape, dir, Offset.getValue()); + } + else if (fabs(Offset.getValue()) > Precision::Confusion()){ + return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Extrude: Can only offset one face")); + } if (!supportface.hasSubShape(TopAbs_WIRE)) { supportface = TopoShape(); @@ -588,7 +606,7 @@ App::DocumentObjectExecReturn* FeatureExtrude::buildExtrusion(ExtrudeOptions opt base.isNull() ? TopoShape::PrismMode::None : TopoShape::PrismMode::CutFromBase; prism = base.makeElementPrismUntil(sketchshape, supportface, - upToFace, + upToShape, dir, mode, false /*CheckUpToFaceLimits.getValue()*/); @@ -630,7 +648,7 @@ App::DocumentObjectExecReturn* FeatureExtrude::buildExtrusion(ExtrudeOptions opt prism.makeElementPrismUntil(base, sketchshape, supportface, - upToFace, + upToShape, dir, TopoShape::PrismMode::None, true /*CheckUpToFaceLimits.getValue()*/); diff --git a/src/Mod/PartDesign/App/FeaturePad.cpp b/src/Mod/PartDesign/App/FeaturePad.cpp index 4a9d29bb0d..7220fff488 100644 --- a/src/Mod/PartDesign/App/FeaturePad.cpp +++ b/src/Mod/PartDesign/App/FeaturePad.cpp @@ -55,6 +55,7 @@ Pad::Pad() ADD_PROPERTY_TYPE(ReferenceAxis, (nullptr), "Pad", App::Prop_None, "Reference axis of direction"); ADD_PROPERTY_TYPE(AlongSketchNormal, (true), "Pad", App::Prop_None, "Measure pad length along the sketch normal direction"); ADD_PROPERTY_TYPE(UpToFace, (nullptr), "Pad", App::Prop_None, "Face where pad will end"); + ADD_PROPERTY_TYPE(UpToShape, (nullptr), "Pad", App::Prop_None, "Faces or shape(s) where pad will end"); ADD_PROPERTY_TYPE(Offset, (0.0), "Pad", App::Prop_None, "Offset from face in which pad will end"); Offset.setConstraints(&signedLengthConstraint); ADD_PROPERTY_TYPE(TaperAngle, (0.0), "Pad", App::Prop_None, "Taper angle"); diff --git a/src/Mod/PartDesign/App/FeaturePocket.cpp b/src/Mod/PartDesign/App/FeaturePocket.cpp index 9183fe9551..54e4005152 100644 --- a/src/Mod/PartDesign/App/FeaturePocket.cpp +++ b/src/Mod/PartDesign/App/FeaturePocket.cpp @@ -39,7 +39,7 @@ using namespace PartDesign; /* TRANSLATOR PartDesign::Pocket */ -const char* Pocket::TypeEnums[]= {"Length", "ThroughAll", "UpToFirst", "UpToFace", "TwoLengths", nullptr}; +const char* Pocket::TypeEnums[]= {"Length", "ThroughAll", "UpToFirst", "UpToFace", "TwoLengths", "UpToShape", nullptr}; PROPERTY_SOURCE(PartDesign::Pocket, PartDesign::FeatureExtrude) @@ -56,6 +56,7 @@ Pocket::Pocket() ADD_PROPERTY_TYPE(ReferenceAxis, (nullptr), "Pocket", App::Prop_None, "Reference axis of direction"); ADD_PROPERTY_TYPE(AlongSketchNormal, (true), "Pocket", App::Prop_None, "Measure pocket length along the sketch normal direction"); ADD_PROPERTY_TYPE(UpToFace, (nullptr), "Pocket", App::Prop_None, "Face where pocket will end"); + ADD_PROPERTY_TYPE(UpToShape, (nullptr), "Pocket", App::Prop_None, "Face(s) or shape(s) where pocket will end"); ADD_PROPERTY_TYPE(Offset, (0.0), "Pocket", App::Prop_None, "Offset from face in which pocket will end"); Offset.setConstraints(&signedLengthConstraint); ADD_PROPERTY_TYPE(TaperAngle, (0.0), "Pocket", App::Prop_None, "Taper angle"); diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.cpp b/src/Mod/PartDesign/App/FeatureSketchBased.cpp index 141bc95f22..522edc0529 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.cpp +++ b/src/Mod/PartDesign/App/FeatureSketchBased.cpp @@ -75,6 +75,7 @@ ProfileBased::ProfileBased() 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"); ADD_PROPERTY_TYPE(UpToFace, (nullptr), "SketchBased", (App::PropertyType)(App::Prop_None), "Face where feature will end"); + ADD_PROPERTY_TYPE(UpToShape, (nullptr), "SketchBased", (App::PropertyType)(App::Prop_None), "Shape where feature will end"); ADD_PROPERTY_TYPE(AllowMultiFace, (false), "SketchBased", App::Prop_None, "Allow multiple faces in profile"); } @@ -682,6 +683,58 @@ void ProfileBased::getUpToFaceFromLinkSub(TopoShape& upToFace, const App::Proper } } +int ProfileBased::getUpToShapeFromLinkSubList(TopoShape& upToShape, const App::PropertyLinkSubList& refShape) +{ + int ret = 0; + + auto subSets = refShape.getSubListValues(); + + std::vector faceList; + for (auto &subSet : subSets){ + auto ref = subSet.first; + if (ref->isDerivedFrom()) { + faceList.push_back(makeTopoShapeFromPlane(ref)); + ret ++; + } else { + if (!ref->isDerivedFrom()) + throw Base::TypeError("SketchBased: Must be face of a feature"); + + auto subStrings = subSet.second; + if (subStrings.empty() || subStrings[0].empty()) { + TopoShape baseShape = Part::Feature::getTopoShape(ref, nullptr, true); + for (auto face : baseShape.getSubTopoShapes(TopAbs_FACE)){ + faceList.push_back(face); + ret ++; + } + } + else { + for (auto &subString : subStrings){ + auto shape = Part::Feature::getTopoShape(ref, subString.c_str(), true); + TopoShape face = shape; + face = face.makeElementFace(); + if (face.isNull()) { + throw Base::ValueError("SketchBased: Failed to extract face"); + } + faceList.push_back(face); + ret ++; + } + } + } + } + if (ret == 0){ + throw Base::ValueError("SketchBased: No face selected"); + } + + upToShape = faceList[0]; + + if (ret == 1){ + return 1; + } + + // create a unique shell with all selected faces + upToShape = upToShape.makeElementCompound(faceList); + return ret; +} void ProfileBased::getFaceFromLinkSub(TopoDS_Face& upToFace, const App::PropertyLinkSub& refFace) { diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.h b/src/Mod/PartDesign/App/FeatureSketchBased.h index 0c1ceab95a..04a293a670 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.h +++ b/src/Mod/PartDesign/App/FeatureSketchBased.h @@ -57,6 +57,8 @@ public: App::PropertyBool Midplane; /// Face to extrude up to App::PropertyLinkSub UpToFace; + /// Shape to extrude up to + App::PropertyLinkSubList UpToShape; App::PropertyBool AllowMultiFace; @@ -164,6 +166,10 @@ protected: /// Extract a face from a given LinkSub static void getUpToFaceFromLinkSub(TopoShape& upToFace, const App::PropertyLinkSub& refFace); + /// Create a shape with shapes and faces from a given LinkSubList + /// return 0 if almost one full shape is selected else the face count + int getUpToShapeFromLinkSubList(TopoShape& upToShape, const App::PropertyLinkSubList& refShape); // TODO static + /// Find a valid face to extrude up to static void getUpToFace(TopoShape& upToFace, const TopoShape& support,