From 70184ba59d88c7e19cfa56e2b174662a3dbf8755 Mon Sep 17 00:00:00 2001 From: Florian Foinant-Willig Date: Mon, 2 Dec 2024 17:57:30 +0100 Subject: [PATCH] PartDesign: decouple refine and other geometric computation (#17008) --- src/Mod/PartDesign/App/Feature.cpp | 4 ++-- src/Mod/PartDesign/App/Feature.h | 4 ++-- src/Mod/PartDesign/App/FeatureAddSub.cpp | 23 ++++++++++++++++++ src/Mod/PartDesign/App/FeatureAddSub.h | 5 ++++ src/Mod/PartDesign/App/FeatureChamfer.cpp | 9 +++++++ src/Mod/PartDesign/App/FeatureExtrude.cpp | 25 +++++++++++++++++++- src/Mod/PartDesign/App/FeatureFillet.cpp | 8 +++++++ src/Mod/PartDesign/App/FeatureGroove.cpp | 8 +++++++ src/Mod/PartDesign/App/FeatureHelix.cpp | 13 ++++++++++ src/Mod/PartDesign/App/FeatureLoft.cpp | 8 +++++++ src/Mod/PartDesign/App/FeaturePipe.cpp | 12 ++++++++++ src/Mod/PartDesign/App/FeaturePrimitive.cpp | 9 +++++++ src/Mod/PartDesign/App/FeatureRevolution.cpp | 10 ++++++++ src/Mod/PartDesign/App/FeatureThickness.cpp | 8 +++++++ 14 files changed, 141 insertions(+), 5 deletions(-) diff --git a/src/Mod/PartDesign/App/Feature.cpp b/src/Mod/PartDesign/App/Feature.cpp index a1992db815..fd15a8645f 100644 --- a/src/Mod/PartDesign/App/Feature.cpp +++ b/src/Mod/PartDesign/App/Feature.cpp @@ -150,7 +150,7 @@ short Feature::mustExecute() const return Part::Feature::mustExecute(); } -TopoShape Feature::getSolid(const TopoShape& shape) +TopoShape Feature::getSolid(const TopoShape& shape) const { if (shape.isNull()) { throw Part::NullShapeException("Null shape"); @@ -226,7 +226,7 @@ bool Feature::isSingleSolidRuleSatisfied(const TopoDS_Shape& shape, TopAbs_Shape } -Feature::SingleSolidRuleMode Feature::singleSolidRuleMode() +Feature::SingleSolidRuleMode Feature::singleSolidRuleMode() const { auto body = getFeatureBody(); diff --git a/src/Mod/PartDesign/App/Feature.h b/src/Mod/PartDesign/App/Feature.h index 05b8744af6..cda66bcd30 100644 --- a/src/Mod/PartDesign/App/Feature.h +++ b/src/Mod/PartDesign/App/Feature.h @@ -99,14 +99,14 @@ protected: /** * Get a solid of the given shape. If no solid is found an exception is raised. */ - TopoShape getSolid(const TopoShape&); + TopoShape getSolid(const TopoShape&) const; static int countSolids(const TopoDS_Shape&, TopAbs_ShapeEnum type = TopAbs_SOLID); /** * Checks if the single-solid body rule is fulfilled. */ bool isSingleSolidRuleSatisfied(const TopoDS_Shape&, TopAbs_ShapeEnum type = TopAbs_SOLID); - SingleSolidRuleMode singleSolidRuleMode(); + SingleSolidRuleMode singleSolidRuleMode() const; void updateSuppressedShape(); diff --git a/src/Mod/PartDesign/App/FeatureAddSub.cpp b/src/Mod/PartDesign/App/FeatureAddSub.cpp index 9cb955657f..3a2bf63e06 100644 --- a/src/Mod/PartDesign/App/FeatureAddSub.cpp +++ b/src/Mod/PartDesign/App/FeatureAddSub.cpp @@ -60,6 +60,29 @@ short FeatureAddSub::mustExecute() const return PartDesign::Feature::mustExecute(); } + +bool FeatureAddSub::onlyHasToRefine() const +{ + if( ! Refine.isTouched()){ + return false; + } + if (rawShape.isNull()){ + return false; + } + std::vector propList; + getPropertyList(propList); + for (auto prop : propList){ + if (prop != &Refine + /*&& prop != &SuppressedShape*/ + && prop->isTouched()){ + return false; + } + } + return true; +} + + + TopoShape FeatureAddSub::refineShapeIfActive(const TopoShape& oldShape, const RefineErrorPolicy onError) const { if (this->Refine.getValue()) { diff --git a/src/Mod/PartDesign/App/FeatureAddSub.h b/src/Mod/PartDesign/App/FeatureAddSub.h index 0b12326f24..b7948bf952 100644 --- a/src/Mod/PartDesign/App/FeatureAddSub.h +++ b/src/Mod/PartDesign/App/FeatureAddSub.h @@ -56,9 +56,14 @@ public: Part::PropertyPartShape AddSubShape; App::PropertyBool Refine; + protected: Type addSubType{Additive}; + //store the shape before refinement + TopoShape rawShape; + + bool onlyHasToRefine() const; TopoShape refineShapeIfActive(const TopoShape& oldShape, const RefineErrorPolicy onError = RefineErrorPolicy::Raise) const; }; diff --git a/src/Mod/PartDesign/App/FeatureChamfer.cpp b/src/Mod/PartDesign/App/FeatureChamfer.cpp index 1833b68172..406e094d4a 100644 --- a/src/Mod/PartDesign/App/FeatureChamfer.cpp +++ b/src/Mod/PartDesign/App/FeatureChamfer.cpp @@ -104,6 +104,12 @@ short Chamfer::mustExecute() const App::DocumentObjectExecReturn *Chamfer::execute() { + if (onlyHasToRefine()){ + TopoShape result = refineShapeIfActive(rawShape); + Shape.setValue(result); + return App::DocumentObject::StdReturn; + } + // NOTE: Normally the Base property and the BaseFeature property should point to the same object. // The only difference is that the Base property also stores the edges that are to be chamfered Part::TopoShape TopShape; @@ -164,6 +170,9 @@ App::DocumentObjectExecReturn *Chamfer::execute() TopAbs_SHAPE); } if (!failed) { + + // store shape before refinement + this->rawShape = shape; shape = refineShapeIfActive(shape); shape = getSolid(shape); } diff --git a/src/Mod/PartDesign/App/FeatureExtrude.cpp b/src/Mod/PartDesign/App/FeatureExtrude.cpp index 97f3ae3fec..6d0e4938e0 100644 --- a/src/Mod/PartDesign/App/FeatureExtrude.cpp +++ b/src/Mod/PartDesign/App/FeatureExtrude.cpp @@ -463,6 +463,12 @@ void FeatureExtrude::setupObject() App::DocumentObjectExecReturn* FeatureExtrude::buildExtrusion(ExtrudeOptions options) { + if (onlyHasToRefine()){ + TopoShape result = refineShapeIfActive(rawShape); + Shape.setValue(result); + return App::DocumentObject::StdReturn; + } + bool makeface = options.testFlag(ExtrudeOption::MakeFace); bool fuse = options.testFlag(ExtrudeOption::MakeFuse); bool legacyPocket = options.testFlag(ExtrudeOption::LegacyPocket); @@ -660,6 +666,9 @@ App::DocumentObjectExecReturn* FeatureExtrude::buildExtrusion(ExtrudeOptions opt else { result.makeElementCut({base, prism}); } + + // store shape before refinement + this->rawShape = result; result = refineShapeIfActive(result); this->AddSubShape.setValue(result); } @@ -672,6 +681,9 @@ App::DocumentObjectExecReturn* FeatureExtrude::buildExtrusion(ExtrudeOptions opt prism = base.makeElementFuse(this->AddSubShape.getShape()); } else { + + // store shape before refinement + this->rawShape = prism; prism = refineShapeIfActive(prism); } @@ -750,8 +762,10 @@ App::DocumentObjectExecReturn* FeatureExtrude::buildExtrusion(ExtrudeOptions opt } } - // set the additive shape property for later usage in e.g. pattern + // store shape before refinement + this->rawShape = prism; prism = refineShapeIfActive(prism); + // set the additive shape property for later usage in e.g. pattern this->AddSubShape.setValue(prism); if (base.shapeType(true) <= TopAbs_SOLID && fuse) { @@ -781,7 +795,11 @@ App::DocumentObjectExecReturn* FeatureExtrude::buildExtrusion(ExtrudeOptions opt return new App::DocumentObjectExecReturn( QT_TRANSLATE_NOOP("Exception", "Resulting shape is not a solid")); } + + // store shape before refinement + this->rawShape = result; solRes = refineShapeIfActive(solRes); + if (!isSingleSolidRuleSatisfied(solRes.getShape())) { return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Result has multiple solids: that is not currently supported.")); } @@ -791,6 +809,9 @@ App::DocumentObjectExecReturn* FeatureExtrude::buildExtrusion(ExtrudeOptions opt if (prism.countSubShapes(TopAbs_SOLID) > 1) { prism.makeElementFuse(prism.getSubTopoShapes(TopAbs_SOLID)); } + + // store shape before refinement + this->rawShape = prism; prism = refineShapeIfActive(prism); prism = getSolid(prism); if (!isSingleSolidRuleSatisfied(prism.getShape())) { @@ -799,6 +820,8 @@ App::DocumentObjectExecReturn* FeatureExtrude::buildExtrusion(ExtrudeOptions opt this->Shape.setValue(prism); } else { + // store shape before refinement + this->rawShape = prism; prism = refineShapeIfActive(prism); if (!isSingleSolidRuleSatisfied(prism.getShape())) { return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Result has multiple solids: that is not currently supported.")); diff --git a/src/Mod/PartDesign/App/FeatureFillet.cpp b/src/Mod/PartDesign/App/FeatureFillet.cpp index cad29c6f4f..9524cd6bb6 100644 --- a/src/Mod/PartDesign/App/FeatureFillet.cpp +++ b/src/Mod/PartDesign/App/FeatureFillet.cpp @@ -65,6 +65,12 @@ short Fillet::mustExecute() const App::DocumentObjectExecReturn *Fillet::execute() { + if (onlyHasToRefine()){ + TopoShape result = refineShapeIfActive(rawShape); + Shape.setValue(result); + return App::DocumentObject::StdReturn; + } + Part::TopoShape baseShape; try { baseShape = getBaseTopoShape(); @@ -110,6 +116,8 @@ App::DocumentObjectExecReturn *Fillet::execute() } if (!failed) { + // store shape before refinement + this->rawShape = shape; shape = refineShapeIfActive(shape); shape = getSolid(shape); } diff --git a/src/Mod/PartDesign/App/FeatureGroove.cpp b/src/Mod/PartDesign/App/FeatureGroove.cpp index 6d0a8677da..24e3fa6e57 100644 --- a/src/Mod/PartDesign/App/FeatureGroove.cpp +++ b/src/Mod/PartDesign/App/FeatureGroove.cpp @@ -81,6 +81,12 @@ short Groove::mustExecute() const App::DocumentObjectExecReturn *Groove::execute() { + if (onlyHasToRefine()){ + TopoShape result = refineShapeIfActive(rawShape); + Shape.setValue(result); + return App::DocumentObject::StdReturn; + } + // Validate parameters double angle = Angle.getValue(); if (angle > 360.0) @@ -187,6 +193,8 @@ App::DocumentObjectExecReturn *Groove::execute() if (boolOp.isNull()) return new App::DocumentObjectExecReturn("Resulting shape is not a solid"); + // store shape before refinement + this->rawShape = boolOp; boolOp = refineShapeIfActive(boolOp); boolOp = getSolid(boolOp); if (!isSingleSolidRuleSatisfied(boolOp.getShape())) { diff --git a/src/Mod/PartDesign/App/FeatureHelix.cpp b/src/Mod/PartDesign/App/FeatureHelix.cpp index 6739db60b7..f3f3a94245 100644 --- a/src/Mod/PartDesign/App/FeatureHelix.cpp +++ b/src/Mod/PartDesign/App/FeatureHelix.cpp @@ -126,6 +126,13 @@ short Helix::mustExecute() const App::DocumentObjectExecReturn* Helix::execute() { + + if (onlyHasToRefine()){ + TopoShape result = refineShapeIfActive(rawShape, RefineErrorPolicy::Warn); + Shape.setValue(result); + return App::DocumentObject::StdReturn; + } + // Validate and normalize parameters HelixMode mode = static_cast(Mode.getValue()); if (mode == HelixMode::pitch_height_angle) { @@ -268,6 +275,8 @@ App::DocumentObjectExecReturn* Helix::execute() return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Error: Result has multiple solids")); } + // store shape before refinement + this->rawShape = result; Shape.setValue(getSolid(result)); return App::DocumentObject::StdReturn; } @@ -290,6 +299,8 @@ App::DocumentObjectExecReturn* Helix::execute() return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Error: Result has multiple solids")); } + // store shape before refinement + this->rawShape = boolOp; boolOp = refineShapeIfActive(boolOp, RefineErrorPolicy::Warn); Shape.setValue(getSolid(boolOp)); } @@ -319,6 +330,8 @@ App::DocumentObjectExecReturn* Helix::execute() return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Error: Result has multiple solids")); } + // store shape before refinement + this->rawShape = boolOp; boolOp = refineShapeIfActive(boolOp, RefineErrorPolicy::Warn); Shape.setValue(getSolid(boolOp)); } diff --git a/src/Mod/PartDesign/App/FeatureLoft.cpp b/src/Mod/PartDesign/App/FeatureLoft.cpp index 5fc9e2e67a..70a7de5f19 100644 --- a/src/Mod/PartDesign/App/FeatureLoft.cpp +++ b/src/Mod/PartDesign/App/FeatureLoft.cpp @@ -112,6 +112,12 @@ Loft::getSectionShape(const char *name, App::DocumentObjectExecReturn *Loft::execute() { + if (onlyHasToRefine()){ + TopoShape result = refineShapeIfActive(rawShape); + Shape.setValue(result); + return App::DocumentObject::StdReturn; + } + std::vector wires; try { wires = getSectionShape("Profile", Profile.getValue(), Profile.getSubValues()); @@ -257,6 +263,8 @@ App::DocumentObjectExecReturn *Loft::execute() if (boolOp.isNull()) return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Resulting shape is not a solid")); + // store shape before refinement + this->rawShape = boolOp; boolOp = refineShapeIfActive(boolOp); boolOp = getSolid(boolOp); if (!isSingleSolidRuleSatisfied(boolOp.getShape())) { diff --git a/src/Mod/PartDesign/App/FeaturePipe.cpp b/src/Mod/PartDesign/App/FeaturePipe.cpp index 215317b94b..6d7642f31e 100644 --- a/src/Mod/PartDesign/App/FeaturePipe.cpp +++ b/src/Mod/PartDesign/App/FeaturePipe.cpp @@ -104,6 +104,12 @@ short Pipe::mustExecute() const App::DocumentObjectExecReturn *Pipe::execute() { + if (onlyHasToRefine()){ + TopoShape result = refineShapeIfActive(rawShape); + Shape.setValue(result); + return App::DocumentObject::StdReturn; + } + auto getSectionShape = [](App::DocumentObject* feature, const std::vector& subs) -> TopoDS_Shape { if (!feature || !feature->isDerivedFrom(Part::Feature::getClassTypeId())) @@ -380,6 +386,8 @@ App::DocumentObjectExecReturn *Pipe::execute() return new App::DocumentObjectExecReturn( QT_TRANSLATE_NOOP("Exception", "Pipe: There is nothing to subtract from")); + // store shape before refinement + this->rawShape = result; auto ts_result = refineShapeIfActive(result); Shape.setValue(getSolid(ts_result)); return App::DocumentObject::StdReturn; @@ -402,6 +410,8 @@ App::DocumentObjectExecReturn *Pipe::execute() "Result has multiple solids: that is not currently supported.")); } + // store shape before refinement + this->rawShape = boolOp; boolOp = refineShapeIfActive(boolOp); Shape.setValue(getSolid(boolOp)); } @@ -422,6 +432,8 @@ App::DocumentObjectExecReturn *Pipe::execute() "Result has multiple solids: that is not currently supported.")); } + // store shape before refinement + this->rawShape = boolOp; boolOp = refineShapeIfActive(boolOp); Shape.setValue(getSolid(boolOp)); } diff --git a/src/Mod/PartDesign/App/FeaturePrimitive.cpp b/src/Mod/PartDesign/App/FeaturePrimitive.cpp index a5fd544dc3..e7a52f76b2 100644 --- a/src/Mod/PartDesign/App/FeaturePrimitive.cpp +++ b/src/Mod/PartDesign/App/FeaturePrimitive.cpp @@ -68,6 +68,12 @@ FeaturePrimitive::FeaturePrimitive() App::DocumentObjectExecReturn* FeaturePrimitive::execute(const TopoDS_Shape& primitive) { + if (onlyHasToRefine()){ + TopoShape result = refineShapeIfActive(rawShape); + Shape.setValue(result); + return App::DocumentObject::StdReturn; + } + try { //transform the primitive in the correct coordinance FeatureAddSub::execute(); @@ -126,6 +132,9 @@ App::DocumentObjectExecReturn* FeaturePrimitive::execute(const TopoDS_Shape& pri return new App::DocumentObjectExecReturn( QT_TRANSLATE_NOOP("Exception", "Resulting shape is not a solid")); } + // store shape before refinement + this->rawShape = boolOp; + if (solidBoolOp == base){ //solidBoolOp is misplaced but boolOp is ok Shape.setValue(boolOp); diff --git a/src/Mod/PartDesign/App/FeatureRevolution.cpp b/src/Mod/PartDesign/App/FeatureRevolution.cpp index a3aba83360..0f9cca70cb 100644 --- a/src/Mod/PartDesign/App/FeatureRevolution.cpp +++ b/src/Mod/PartDesign/App/FeatureRevolution.cpp @@ -80,6 +80,12 @@ short Revolution::mustExecute() const App::DocumentObjectExecReturn* Revolution::execute() { + if (onlyHasToRefine()){ + TopoShape result = refineShapeIfActive(rawShape); + Shape.setValue(result); + return App::DocumentObject::StdReturn; + } + // Validate parameters // All angles are in radians unless explicitly stated double angleDeg = Angle.getValue(); @@ -213,12 +219,16 @@ App::DocumentObjectExecReturn* Revolution::execute() } if (!result.isNull()) { + // store shape before refinement + this->rawShape = result; result = refineShapeIfActive(result); // set the additive shape property for later usage in e.g. pattern this->AddSubShape.setValue(result); if (!base.isNull()) { result = result.makeElementFuse(base); + // store shape before refinement + this->rawShape = result; result = refineShapeIfActive(result); } this->Shape.setValue(getSolid(result)); diff --git a/src/Mod/PartDesign/App/FeatureThickness.cpp b/src/Mod/PartDesign/App/FeatureThickness.cpp index d890ca189d..002fcf0700 100644 --- a/src/Mod/PartDesign/App/FeatureThickness.cpp +++ b/src/Mod/PartDesign/App/FeatureThickness.cpp @@ -65,6 +65,12 @@ int16_t Thickness::mustExecute() const { } App::DocumentObjectExecReturn *Thickness::execute() { + if (onlyHasToRefine()){ + TopoShape result = refineShapeIfActive(rawShape); + Shape.setValue(result); + return App::DocumentObject::StdReturn; + } + // Base shape Part::TopoShape TopShape; try { @@ -164,6 +170,8 @@ App::DocumentObjectExecReturn *Thickness::execute() { } else { result = shapes.front(); } + // store shape before refinement + this->rawShape = result; result = refineShapeIfActive(result); this->Shape.setValue(getSolid(result)); return App::DocumentObject::StdReturn;