From 02479a152836fdd3ebd94389e724fb3e642e12a8 Mon Sep 17 00:00:00 2001 From: PaddleStroke Date: Tue, 9 Sep 2025 15:25:00 +0200 Subject: [PATCH 1/4] PartDesign: FeatureExtrude fix symmetric + custom dir --- src/Mod/PartDesign/App/FeatureExtrude.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureExtrude.cpp b/src/Mod/PartDesign/App/FeatureExtrude.cpp index 38c649f4f3..38bf1479ef 100644 --- a/src/Mod/PartDesign/App/FeatureExtrude.cpp +++ b/src/Mod/PartDesign/App/FeatureExtrude.cpp @@ -465,12 +465,16 @@ App::DocumentObjectExecReturn* FeatureExtrude::buildExtrusion(ExtrudeOptions opt dir, offset1, makeface, base); prisms.push_back(prism1); - // Prism 2 : Make a symmetric of prism1 - Base::Vector3d base = sketchshape.getBoundBox().GetCenter(); - gp_Ax2 axe(gp_Pnt(base.x, base.y, base.z), dir); - TopoShape prism2 = prism1.makeElementMirror(axe); - prisms.push_back(prism2); + // Prism 2: Mirror prism1 across the sketch plane. + // The mirror plane's normal must be the sketch normal, not the extrusion direction. + gp_Dir sketchNormalDir(SketchVector.x, SketchVector.y, SketchVector.z); + sketchNormalDir.Transform(invTrsf); // Transform to global CS, like 'dir' was. + Base::Vector3d sketchCenter = sketchshape.getBoundBox().GetCenter(); + gp_Ax2 mirrorPlane(gp_Pnt(sketchCenter.x, sketchCenter.y, sketchCenter.z), + sketchNormalDir); + TopoShape prism2 = prism1.makeElementMirror(mirrorPlane); + prisms.push_back(prism2); } else if (Sidemethod == "Two sides") { TopoShape prism1 = generateSingleExtrusionSide(sketchshape.makeElementCopy(), From c384a52fa573bb7e58c3f8c97b69a2c58f5d50e7 Mon Sep 17 00:00:00 2001 From: PaddleStroke Date: Wed, 24 Sep 2025 09:22:05 +0200 Subject: [PATCH 2/4] Feature Extrude: Make Length mode act as it did before. --- src/Mod/PartDesign/App/FeatureExtrude.cpp | 93 +++++++++++++++++++---- 1 file changed, 79 insertions(+), 14 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureExtrude.cpp b/src/Mod/PartDesign/App/FeatureExtrude.cpp index 38bf1479ef..d968efa0a0 100644 --- a/src/Mod/PartDesign/App/FeatureExtrude.cpp +++ b/src/Mod/PartDesign/App/FeatureExtrude.cpp @@ -459,22 +459,87 @@ App::DocumentObjectExecReturn* FeatureExtrude::buildExtrusion(ExtrudeOptions opt prisms.push_back(prism1); } else if (Sidemethod == "Symmetric") { - L /= 2.0; - TopoShape prism1 = generateSingleExtrusionSide(sketchshape, - method, L, taper1, UpToFace, UpToShape, - dir, offset1, makeface, base); - prisms.push_back(prism1); + // For Length mode, we are not doing a mirror, but we extrude along the same axis + // in both directions as it is what users expect. + if (method == "Length") { + if (std::fabs(taper1) > Precision::Angular()) { + // TAPERED case: We must create two separate prisms and fuse them + // to ensure the taper originates correctly from the sketch plane in both + // directions. + L /= 2.0; + TopoShape prism1 = generateSingleExtrusionSide(sketchshape.makeElementCopy(), + method, + L, + taper1, + UpToFace, + UpToShape, + dir, + offset1, + makeface, + base); + if (!prism1.isNull() && !prism1.getShape().IsNull()) { + prisms.push_back(prism1); + } - // Prism 2: Mirror prism1 across the sketch plane. - // The mirror plane's normal must be the sketch normal, not the extrusion direction. - gp_Dir sketchNormalDir(SketchVector.x, SketchVector.y, SketchVector.z); - sketchNormalDir.Transform(invTrsf); // Transform to global CS, like 'dir' was. + gp_Dir dir2 = dir; + dir2.Reverse(); + TopoShape prism2 = generateSingleExtrusionSide(sketchshape.makeElementCopy(), + method, + L, + taper1, + UpToFace, + UpToShape, + dir2, + offset1, + makeface, + base); + if (!prism2.isNull() && !prism2.getShape().IsNull()) { + prisms.push_back(prism2); + } + } + else { + // NON-TAPERED case: We can optimize by creating a single prism. + // Translate the sketch to the start position (-L/2) and extrude by the full + // length L. + gp_Trsf start_transform; + start_transform.SetTranslation(gp_Vec(dir).Reversed() * (L / 2.0)); - Base::Vector3d sketchCenter = sketchshape.getBoundBox().GetCenter(); - gp_Ax2 mirrorPlane(gp_Pnt(sketchCenter.x, sketchCenter.y, sketchCenter.z), - sketchNormalDir); - TopoShape prism2 = prism1.makeElementMirror(mirrorPlane); - prisms.push_back(prism2); + TopoShape moved_sketch = sketchshape.makeElementCopy(); + moved_sketch.move(start_transform); + + TopoShape prism1 = generateSingleExtrusionSide(moved_sketch, + method, + L, + taper1, + UpToFace, + UpToShape, + dir, + offset1, + makeface, + base); + if (!prism1.isNull() && !prism1.getShape().IsNull()) { + prisms.push_back(prism1); + } + } + } + else { + // For "UpToFace", "UpToShape", etc., mirror the result. + TopoShape prism1 = generateSingleExtrusionSide(sketchshape, + method, L, taper1, UpToFace, UpToShape, + dir, offset1, makeface, base); + prisms.push_back(prism1); + + // Prism 2: Mirror prism1 across the sketch plane. + // The mirror plane's normal must be the sketch normal, not the extrusion direction. + gp_Dir sketchNormalDir(SketchVector.x, SketchVector.y, SketchVector.z); + sketchNormalDir.Transform(invTrsf); // Transform to global CS, like 'dir' was. + + Base::Vector3d sketchCenter = sketchshape.getBoundBox().GetCenter(); + gp_Ax2 mirrorPlane(gp_Pnt(sketchCenter.x, sketchCenter.y, sketchCenter.z), + sketchNormalDir); + TopoShape prism2 = prism1.makeElementMirror(mirrorPlane); + prisms.push_back(prism2); + } } else if (Sidemethod == "Two sides") { TopoShape prism1 = generateSingleExtrusionSide(sketchshape.makeElementCopy(), From a01cab21cc16341bd834a14c747dcb3f29d2ccb3 Mon Sep 17 00:00:00 2001 From: PaddleStroke Date: Mon, 29 Sep 2025 09:33:53 +0200 Subject: [PATCH 3/4] PartDesign: FeatureExtrude: Make single prism if both modes are length and no taper --- src/Mod/PartDesign/App/FeatureExtrude.cpp | 78 +++++++++++++++-------- 1 file changed, 51 insertions(+), 27 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureExtrude.cpp b/src/Mod/PartDesign/App/FeatureExtrude.cpp index d968efa0a0..b41bc6592b 100644 --- a/src/Mod/PartDesign/App/FeatureExtrude.cpp +++ b/src/Mod/PartDesign/App/FeatureExtrude.cpp @@ -542,38 +542,62 @@ App::DocumentObjectExecReturn* FeatureExtrude::buildExtrusion(ExtrudeOptions opt } } else if (Sidemethod == "Two sides") { - TopoShape prism1 = generateSingleExtrusionSide(sketchshape.makeElementCopy(), - method, - L, - taper1, - UpToFace, - UpToShape, - dir, - offset1, - makeface, - base); - if (!prism1.isNull() && !prism1.getShape().IsNull()) { - prisms.push_back(prism1); - } - - // Side 2 double taper2 = TaperAngle2.getValue(); double offset2 = Offset2.getValue(); gp_Dir dir2 = dir; dir2.Reverse(); - TopoShape prism2 = generateSingleExtrusionSide(sketchshape.makeElementCopy(), - method2, - L2, - taper2, - UpToFace2, - UpToShape2, - dir2, - offset2, - makeface, - base); - if (!prism2.isNull() && !prism2.getShape().IsNull()) { - prisms.push_back(prism2); + if (method == "Length" && method2 == "Length" + && std::fabs(taper1) < Precision::Angular() + && std::fabs(taper2) < Precision::Angular()) { + gp_Trsf start_transform; + start_transform.SetTranslation(gp_Vec(dir).Reversed() * L2); + + TopoShape moved_sketch = sketchshape.makeElementCopy(); + moved_sketch.move(start_transform); + TopoShape prism1 = generateSingleExtrusionSide(moved_sketch, + method, + L + L2, + 0.0, + UpToFace, + UpToShape, + dir, + offset1, + makeface, + base); + if (!prism1.isNull() && !prism1.getShape().IsNull()) { + prisms.push_back(prism1); + } + } + else { + TopoShape prism1 = generateSingleExtrusionSide(sketchshape.makeElementCopy(), + method, + L, + taper1, + UpToFace, + UpToShape, + dir, + offset1, + makeface, + base); + if (!prism1.isNull() && !prism1.getShape().IsNull()) { + prisms.push_back(prism1); + } + + // Side 2 + TopoShape prism2 = generateSingleExtrusionSide(sketchshape.makeElementCopy(), + method2, + L2, + taper2, + UpToFace2, + UpToShape2, + dir2, + offset2, + makeface, + base); + if (!prism2.isNull() && !prism2.getShape().IsNull()) { + prisms.push_back(prism2); + } } } From 94750baa6b87b323808a0b77647b70a4721ed9af Mon Sep 17 00:00:00 2001 From: PaddleStroke Date: Mon, 29 Sep 2025 13:24:55 +0200 Subject: [PATCH 4/4] PartDesign: FeatureExtrude: single prism for modes that can --- src/Mod/PartDesign/App/FeatureExtrude.cpp | 45 ++++++++++++++++++----- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureExtrude.cpp b/src/Mod/PartDesign/App/FeatureExtrude.cpp index b41bc6592b..afca5c1248 100644 --- a/src/Mod/PartDesign/App/FeatureExtrude.cpp +++ b/src/Mod/PartDesign/App/FeatureExtrude.cpp @@ -313,10 +313,13 @@ App::DocumentObjectExecReturn* FeatureExtrude::buildExtrusion(ExtrudeOptions opt std::string method2(Type2.getValueAsString()); // Validate parameters - double L = method == "ThroughAll" ? getThroughAllLength() : Length.getValue(); - double L2 = Sidemethod == "Two sides" - ? method2 == "ThroughAll" ? getThroughAllLength() : Length2.getValue() - : 0; + double L = method == "ThroughAll" ? getThroughAllLength() + : method == "Length" ? Length.getValue() + : 0.0; + double L2 = Sidemethod == "Two sides" ? method2 == "ThroughAll" ? getThroughAllLength() + : method2 == "Length" ? Length2.getValue() + : 0.0 + : 0.0; if ((Sidemethod == "One side" && method == "Length") || (Sidemethod == "Two sides" && method == "Length" && method2 == "Length")) { @@ -546,16 +549,38 @@ App::DocumentObjectExecReturn* FeatureExtrude::buildExtrusion(ExtrudeOptions opt double offset2 = Offset2.getValue(); gp_Dir dir2 = dir; dir2.Reverse(); + bool noTaper = std::fabs(taper1) < Precision::Angular() + && std::fabs(taper2) < Precision::Angular(); + bool method1LengthBased = method == "Length" || method == "ThroughAll"; + bool method2LengthBased = method2 == "Length" || method2 == "ThroughAll"; - if (method == "Length" && method2 == "Length" - && std::fabs(taper1) < Precision::Angular() - && std::fabs(taper2) < Precision::Angular()) { + if (method1LengthBased && method2 != "UpToFirst" && noTaper) { + gp_Trsf start_transform; + start_transform.SetTranslation(gp_Vec(dir) * L); + + TopoShape moved_sketch = sketchshape.makeElementCopy(); + moved_sketch.move(start_transform); + TopoShape prism = generateSingleExtrusionSide(moved_sketch, + method2, + L + L2, + 0.0, + UpToFace2, + UpToShape2, + dir2, + offset2, + makeface, + base); + if (!prism.isNull() && !prism.getShape().IsNull()) { + prisms.push_back(prism); + } + } + else if (method2LengthBased && method != "UpToFirst" && noTaper) { gp_Trsf start_transform; start_transform.SetTranslation(gp_Vec(dir).Reversed() * L2); TopoShape moved_sketch = sketchshape.makeElementCopy(); moved_sketch.move(start_transform); - TopoShape prism1 = generateSingleExtrusionSide(moved_sketch, + TopoShape prism = generateSingleExtrusionSide(moved_sketch, method, L + L2, 0.0, @@ -565,8 +590,8 @@ App::DocumentObjectExecReturn* FeatureExtrude::buildExtrusion(ExtrudeOptions opt offset1, makeface, base); - if (!prism1.isNull() && !prism1.getShape().IsNull()) { - prisms.push_back(prism1); + if (!prism.isNull() && !prism.getShape().IsNull()) { + prisms.push_back(prism); } } else {