Part: Fix Part_Extrude taper angle regression for internal faces (#26781)
* Part: Fix Part_Extrude taper angle regression for internal faces The taper angle for holes (inner wires) in `Part_Extrude` was not being negated after the toponaming refactor, causing internal faces to taper in the wrong direction compared to v0.21.2. The original makeDraft function correctly handled inner wires by: - Negating taper for all inner wires in Part_Extrude - Negating taper only for multi-edge inner wires in PartDesign This logic was controlled via an isPartDesign function parameter. When makeElementDraft was introduced for toponaming support, it was designed to use innerTaperAngleFwd/innerTaperAngleRev fields that were never ported from realthunder's branch. The cleanup (commit 709eab3018) removed references to these non-existent fields, leaving makeElementDraft with no inner wire taper handling at all. So, this fix ports the makeDraft inner wire logic to makeElementDraft by adding the flag, and counting wires and then triggering proper angle flip depending on the flag/wire situation. --------- Co-authored-by: Chris Hennes <chennes@pioneerlibrarysystem.org>
This commit is contained in:
@@ -615,13 +615,24 @@ void ExtrusionHelper::makeElementDraft(
|
||||
Standard_Failure::Raise("Failed to make drafted extrusion");
|
||||
}
|
||||
std::vector<TopoShape> inner;
|
||||
TopoShape innerWires(0);
|
||||
innerWires.makeElementCompound(
|
||||
wires,
|
||||
"",
|
||||
TopoShape::SingleShapeCompoundCreationPolicy::returnShape
|
||||
);
|
||||
makeElementDraft(params, innerWires, inner, hasher);
|
||||
// process each inner wire individually to check edge count
|
||||
// Inner wires (holes) need negated taper angles
|
||||
for (auto& innerWire : wires) {
|
||||
ExtrusionParameters innerParams = params;
|
||||
|
||||
int numEdges = 0;
|
||||
TopExp_Explorer xp(innerWire.getShape(), TopAbs_EDGE);
|
||||
while (xp.More()) {
|
||||
numEdges++;
|
||||
xp.Next();
|
||||
}
|
||||
|
||||
if (numEdges > 1 || params.innerWireTaper == InnerWireTaper::Inverted) {
|
||||
innerParams.taperAngleFwd = -params.taperAngleFwd;
|
||||
innerParams.taperAngleRev = -params.taperAngleRev;
|
||||
}
|
||||
makeElementDraft(innerParams, innerWire, inner, hasher);
|
||||
}
|
||||
if (inner.empty()) {
|
||||
Standard_Failure::Raise("Failed to make drafted extrusion with inner hole");
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#ifndef PART_EXTRUSIONHELPER_H
|
||||
#define PART_EXTRUSIONHELPER_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <gp_Dir.hxx>
|
||||
@@ -39,6 +40,15 @@ namespace Part
|
||||
|
||||
class TopoShape;
|
||||
|
||||
/**
|
||||
* @brief Controls how taper is applied to inner wires (holes) during extrusion.
|
||||
*/
|
||||
enum class InnerWireTaper : std::uint8_t
|
||||
{
|
||||
Inverted,
|
||||
SameAsOuter,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The ExtrusionParameters struct is supposed to be filled with final
|
||||
* extrusion parameters, after resolving links, applying mode logic,
|
||||
@@ -53,6 +63,7 @@ struct ExtrusionParameters
|
||||
double taperAngleFwd {0}; // in radians
|
||||
double taperAngleRev {0};
|
||||
std::string faceMakerClass;
|
||||
InnerWireTaper innerWireTaper {InnerWireTaper::Inverted};
|
||||
};
|
||||
|
||||
class PartExport ExtrusionHelper
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
|
||||
#include <App/Document.h>
|
||||
#include <Base/Exception.h>
|
||||
#include <Base/ProgramVersion.h>
|
||||
#include <Base/Tools.h>
|
||||
|
||||
#include "FeatureExtrusion.h"
|
||||
@@ -53,6 +54,7 @@ using namespace Part;
|
||||
PROPERTY_SOURCE(Part::Extrusion, Part::Feature)
|
||||
|
||||
const char* Extrusion::eDirModeStrings[] = {"Custom", "Edge", "Normal", nullptr};
|
||||
const char* Extrusion::eInnerWireTaperStrings[] = {"Inverted", "SameAsOuter", nullptr};
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -136,6 +138,9 @@ Extrusion::Extrusion()
|
||||
ADD_PROPERTY_TYPE(FaceMakerMode, (3L), "Extrude", App::Prop_None,
|
||||
"If Solid is true, this sets the facemaker class to use when converting wires to faces. Otherwise, ignored.");
|
||||
FaceMakerMode.setEnums(MakerEnums);
|
||||
ADD_PROPERTY_TYPE(InnerWireTaper, (static_cast<long>(InnerWireTaper::Inverted)), "Compatibility", App::Prop_Hidden,
|
||||
"Controls taper direction for inner wires (holes).");
|
||||
InnerWireTaper.setEnums(eInnerWireTaperStrings);
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
@@ -144,7 +149,7 @@ short Extrusion::mustExecute() const
|
||||
if (Base.isTouched() || Dir.isTouched() || DirMode.isTouched() || DirLink.isTouched()
|
||||
|| LengthFwd.isTouched() || LengthRev.isTouched() || Solid.isTouched()
|
||||
|| Reversed.isTouched() || Symmetric.isTouched() || TaperAngle.isTouched()
|
||||
|| TaperAngleRev.isTouched() || FaceMakerClass.isTouched()) {
|
||||
|| TaperAngleRev.isTouched() || FaceMakerClass.isTouched() || InnerWireTaper.isTouched()) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@@ -267,6 +272,7 @@ ExtrusionParameters Extrusion::computeFinalParameters()
|
||||
}
|
||||
|
||||
result.faceMakerClass = this->FaceMakerClass.getValue();
|
||||
result.innerWireTaper = static_cast<Part::InnerWireTaper>(this->InnerWireTaper.getValue());
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -495,6 +501,16 @@ void Extrusion::onDocumentRestored()
|
||||
restoreFaceMakerMode(this);
|
||||
}
|
||||
|
||||
void Extrusion::Restore(Base::XMLReader& reader)
|
||||
{
|
||||
Part::Feature::Restore(reader);
|
||||
|
||||
// for 1.0 the inner wire taper was not inverted due to a bug
|
||||
if (Base::getVersion(reader.ProgramVersion) == Base::Version::v1_0) {
|
||||
InnerWireTaper.setValue(static_cast<long>(Part::InnerWireTaper::SameAsOuter));
|
||||
}
|
||||
}
|
||||
|
||||
void Part::Extrusion::onChanged(const App::Property* prop)
|
||||
{
|
||||
if (prop == &FaceMakerMode) {
|
||||
|
||||
@@ -58,6 +58,7 @@ public:
|
||||
App::PropertyAngle TaperAngleRev;
|
||||
App::PropertyString FaceMakerClass;
|
||||
App::PropertyEnumeration FaceMakerMode;
|
||||
App::PropertyEnumeration InnerWireTaper;
|
||||
|
||||
/** @name methods override feature */
|
||||
//@{
|
||||
@@ -108,6 +109,7 @@ public:
|
||||
|
||||
static Base::Vector3d calculateShapeNormal(const App::PropertyLink& shapeLink);
|
||||
void onDocumentRestored() override;
|
||||
void Restore(Base::XMLReader& reader) override;
|
||||
|
||||
public: // mode enumerations
|
||||
enum eDirMode
|
||||
@@ -117,6 +119,7 @@ public: // mode enumerations
|
||||
dmNormal
|
||||
};
|
||||
static const char* eDirModeStrings[];
|
||||
static const char* eInnerWireTaperStrings[];
|
||||
|
||||
protected:
|
||||
void setupObject() override;
|
||||
|
||||
@@ -912,6 +912,7 @@ TopoShape FeatureExtrude::generateSingleExtrusionSide(
|
||||
|
||||
Part::ExtrusionParameters params;
|
||||
params.taperAngleFwd = Base::toRadians(taperAngleDeg);
|
||||
params.innerWireTaper = Part::InnerWireTaper::SameAsOuter;
|
||||
|
||||
if (std::fabs(params.taperAngleFwd) >= Precision::Angular()
|
||||
|| std::fabs(params.taperAngleRev) >= Precision::Angular()) {
|
||||
|
||||
Reference in New Issue
Block a user