PartDesign: decouple refine and other geometric computation (#17008)

This commit is contained in:
Florian Foinant-Willig
2024-12-02 17:57:30 +01:00
committed by GitHub
parent e5c2c81685
commit 70184ba59d
14 changed files with 141 additions and 5 deletions

View File

@@ -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();

View File

@@ -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();

View File

@@ -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<App::Property*> 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()) {

View File

@@ -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;
};

View File

@@ -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);
}

View File

@@ -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."));

View File

@@ -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);
}

View File

@@ -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())) {

View File

@@ -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<HelixMode>(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));
}

View File

@@ -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<TopoShape> 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())) {

View File

@@ -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<std::string>& 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));
}

View File

@@ -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);

View File

@@ -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));

View File

@@ -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;