Merge pull request #23770 from PaddleStroke/patch-59

PartDesign: FeatureExtrude fix symmetric + custom dir
This commit is contained in:
Chris Hennes
2025-09-30 08:55:18 -05:00
committed by GitHub

View File

@@ -309,10 +309,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")) {
@@ -455,52 +458,167 @@ 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 : 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);
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));
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(),
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();
bool noTaper = std::fabs(taper1) < Precision::Angular()
&& std::fabs(taper2) < Precision::Angular();
bool method1LengthBased = method == "Length" || method == "ThroughAll";
bool method2LengthBased = method2 == "Length" || method2 == "ThroughAll";
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 (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 prism = generateSingleExtrusionSide(moved_sketch,
method,
L + L2,
0.0,
UpToFace,
UpToShape,
dir,
offset1,
makeface,
base);
if (!prism.isNull() && !prism.getShape().IsNull()) {
prisms.push_back(prism);
}
}
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);
}
}
}