diff --git a/src/Mod/PartDesign/App/FeatureMultiTransform.cpp b/src/Mod/PartDesign/App/FeatureMultiTransform.cpp index b4ac76d554..9163668f32 100644 --- a/src/Mod/PartDesign/App/FeatureMultiTransform.cpp +++ b/src/Mod/PartDesign/App/FeatureMultiTransform.cpp @@ -75,23 +75,20 @@ const std::list MultiTransform::getTransformations(const std::vector transFeatures = Transformations.getValues(); - // Find centre of gravity of first original - // FIXME: This method will NOT give the expected result for more than one original! - Part::Feature* originalFeature = static_cast(originals.front()); - TopoDS_Shape original; + gp_Pnt cog; + if (!originals.empty()) { + // Find centre of gravity of first original + // FIXME: This method will NOT give the expected result for more than one original! + if (auto addFeature = + Base::freecad_dynamic_cast(originals.front())) { + TopoDS_Shape original = addFeature->AddSubShape.getShape().getShape(); - if (originalFeature->isDerivedFrom()) { - PartDesign::FeatureAddSub* addFeature = static_cast(originalFeature); - //if (addFeature->getAddSubType() == FeatureAddSub::Additive) - // original = addFeature->AddSubShape.getShape().getShape(); - //else - original = addFeature->AddSubShape.getShape().getShape(); + GProp_GProps props; + BRepGProp::VolumeProperties(original, props); + cog = props.CentreOfMass(); + } } - GProp_GProps props; - BRepGProp::VolumeProperties(original,props); - gp_Pnt cog = props.CentreOfMass(); - std::list result; std::list cogs; std::vector::const_iterator f; diff --git a/src/Mod/PartDesign/App/FeatureScaled.cpp b/src/Mod/PartDesign/App/FeatureScaled.cpp index 7cc1717e89..b66f15d980 100644 --- a/src/Mod/PartDesign/App/FeatureScaled.cpp +++ b/src/Mod/PartDesign/App/FeatureScaled.cpp @@ -64,23 +64,19 @@ const std::list Scaled::getTransformations(const std::vector(originals.front()); - TopoDS_Shape original; + gp_Pnt cog; + if (!originals.empty()) { + // Find centre of gravity of first original + // FIXME: This method will NOT give the expected result for more than one original! + if (auto feature = Base::freecad_dynamic_cast(originals.front())) { + TopoDS_Shape original = feature->AddSubShape.getShape().getShape(); - if (originalFeature->isDerivedFrom()) { - PartDesign::FeatureAddSub* Feature = static_cast(originalFeature); - //if(Feature->getAddSubType() == FeatureAddSub::Additive) - // original = Feature->AddSubShape.getShape().getShape(); - //else - original = Feature->AddSubShape.getShape().getShape(); + GProp_GProps props; + BRepGProp::VolumeProperties(original, props); + cog = props.CentreOfMass(); + } } - GProp_GProps props; - BRepGProp::VolumeProperties(original,props); - gp_Pnt cog = props.CentreOfMass(); - // Note: The original feature is NOT included in the list of transformations! Therefore // we start with occurrence number 1, not number 0 std::list transformations; diff --git a/src/Mod/PartDesign/App/FeatureTransformed.cpp b/src/Mod/PartDesign/App/FeatureTransformed.cpp index c52de2c4b5..dfdf030407 100644 --- a/src/Mod/PartDesign/App/FeatureTransformed.cpp +++ b/src/Mod/PartDesign/App/FeatureTransformed.cpp @@ -33,6 +33,8 @@ # include #endif +#include + #include #include #include @@ -56,12 +58,19 @@ namespace PartDesign { PROPERTY_SOURCE(PartDesign::Transformed, PartDesign::Feature) +std::array transformModeEnums = {"Transform tool shapes", + "Transform body", + nullptr}; + Transformed::Transformed() { ADD_PROPERTY(Originals,(nullptr)); Originals.setSize(0); Placement.setStatus(App::Property::ReadOnly, true); + ADD_PROPERTY(TransformMode, (static_cast(Mode::TransformToolShapes))); + TransformMode.setEnums(transformModeEnums.data()); + ADD_PROPERTY_TYPE(Refine,(0),"Part Design",(App::PropertyType)(App::Prop_None),"Refine shape (clean up redundant edges) after adding/subtracting"); //init Refine property @@ -175,8 +184,9 @@ void Transformed::handleChangedPropertyType(Base::XMLReader &reader, const char short Transformed::mustExecute() const { - if (Originals.isTouched()) + if (Originals.isTouched() || TransformMode.isTouched()) { return 1; + } return PartDesign::Feature::mustExecute(); } @@ -186,6 +196,11 @@ App::DocumentObjectExecReturn *Transformed::execute() return App::DocumentObject::StdReturn; } + auto const mode = static_cast(TransformMode.getValue()); + if (mode == Mode::TransformBody) { + Originals.setValues({}); + } + if(!this->BaseFeature.getValue()) { auto body = getFeatureBody(); if(body) { @@ -205,6 +220,10 @@ App::DocumentObjectExecReturn *Transformed::execute() originals.erase(eraseIter, originals.end()); } + if (mode == Mode::TransformToolShapes && originals.empty()) { + return App::DocumentObject::StdReturn; + } + // get transformations from subclass by calling virtual method std::vector transformations; try { @@ -274,45 +293,82 @@ App::DocumentObjectExecReturn *Transformed::execute() return shapeTools; }; - // NOTE: It would be possible to build a compound from all original addShapes/subShapes and then - // transform the compounds as a whole. But we choose to apply the transformations to each - // Original separately. This way it is easier to discover what feature causes a fuse/cut - // to fail. The downside is that performance suffers when there are many originals. But it seems - // safe to assume that in most cases there are few originals and many transformations - for (auto original : originals) - { - // Extract the original shape and determine whether to cut or to fuse - Part::TopoShape fuseShape; - Part::TopoShape cutShape; + switch (mode) { + case Mode::TransformToolShapes : + // NOTE: It would be possible to build a compound from all original addShapes/subShapes and then + // transform the compounds as a whole. But we choose to apply the transformations to each + // Original separately. This way it is easier to discover what feature causes a fuse/cut + // to fail. The downside is that performance suffers when there are many originals. But it seems + // safe to assume that in most cases there are few originals and many transformations + for (auto original : originals) + { + // Extract the original shape and determine whether to cut or to fuse + Part::TopoShape fuseShape; + Part::TopoShape cutShape; - if (original->isDerivedFrom()) { - PartDesign::FeatureAddSub* feature = static_cast(original); - feature->getAddSubShape(fuseShape, cutShape); - if (fuseShape.isNull() && cutShape.isNull()) - return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Shape of additive/subtractive feature is empty")); - gp_Trsf trsf = feature->getLocation().Transformation().Multiplied(trsfInv); + if (original->isDerivedFrom()) { + PartDesign::FeatureAddSub* feature = static_cast(original); + feature->getAddSubShape(fuseShape, cutShape); + if (fuseShape.isNull() && cutShape.isNull()) + return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Shape of additive/subtractive feature is empty")); + gp_Trsf trsf = feature->getLocation().Transformation().Multiplied(trsfInv); #ifdef FC_USE_TNP_FIX - if (!fuseShape.isNull()) - fuseShape = fuseShape.makeElementTransform(trsf); - if (!cutShape.isNull()) - cutShape = cutShape.makeElementTransform(trsf); + if (!fuseShape.isNull()) + fuseShape = fuseShape.makeElementTransform(trsf); + if (!cutShape.isNull()) + cutShape = cutShape.makeElementTransform(trsf); #else - if (!fuseShape.isNull()) - fuseShape = fuseShape.makeTransform(trsf); - if (!cutShape.isNull()) - cutShape = cutShape.makeTransform(trsf); + if (!fuseShape.isNull()) + fuseShape = fuseShape.makeTransform(trsf); + if (!cutShape.isNull()) + cutShape = cutShape.makeTransform(trsf); #endif - } - else { - return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Only additive and subtractive features can be transformed")); - } + } + else { + return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Only additive and subtractive features can be transformed")); + } - TopoDS_Shape current = support; - if (!fuseShape.isNull()) { + TopoDS_Shape current = support; + if (!fuseShape.isNull()) { + TopTools_ListOfShape shapeArguments; + shapeArguments.Append(current); + TopTools_ListOfShape shapeTools = getTransformedCompShape(fuseShape.getShape()); + if (!shapeTools.IsEmpty()) { + std::unique_ptr mkBool(new BRepAlgoAPI_Fuse()); + mkBool->SetArguments(shapeArguments); + mkBool->SetTools(shapeTools); + mkBool->Build(); + if (!mkBool->IsDone()) { + return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Boolean operation failed")); + } + current = mkBool->Shape(); + } + } + if (!cutShape.isNull()) { + TopTools_ListOfShape shapeArguments; + shapeArguments.Append(current); + TopTools_ListOfShape shapeTools = getTransformedCompShape(cutShape.getShape()); + if (!shapeTools.IsEmpty()) { + std::unique_ptr mkBool(new BRepAlgoAPI_Cut()); + mkBool->SetArguments(shapeArguments); + mkBool->SetTools(shapeTools); + mkBool->Build(); + if (!mkBool->IsDone()) { + return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Boolean operation failed")); + } + current = mkBool->Shape(); + } + } + + support = current; // Use result of this operation for fuse/cut of next original + } + break; + case Mode::TransformBody : + { TopTools_ListOfShape shapeArguments; - shapeArguments.Append(current); - TopTools_ListOfShape shapeTools = getTransformedCompShape(fuseShape.getShape()); + shapeArguments.Append(support); + TopTools_ListOfShape shapeTools = getTransformedCompShape(support); if (!shapeTools.IsEmpty()) { std::unique_ptr mkBool(new BRepAlgoAPI_Fuse()); mkBool->SetArguments(shapeArguments); @@ -321,26 +377,10 @@ App::DocumentObjectExecReturn *Transformed::execute() if (!mkBool->IsDone()) { return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Boolean operation failed")); } - current = mkBool->Shape(); + support = mkBool->Shape(); } + break; } - if (!cutShape.isNull()) { - TopTools_ListOfShape shapeArguments; - shapeArguments.Append(current); - TopTools_ListOfShape shapeTools = getTransformedCompShape(cutShape.getShape()); - if (!shapeTools.IsEmpty()) { - std::unique_ptr mkBool(new BRepAlgoAPI_Cut()); - mkBool->SetArguments(shapeArguments); - mkBool->SetTools(shapeTools); - mkBool->Build(); - if (!mkBool->IsDone()) { - return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Boolean operation failed")); - } - current = mkBool->Shape(); - } - } - - support = current; // Use result of this operation for fuse/cut of next original } support = refineShapeIfActive(support); diff --git a/src/Mod/PartDesign/App/FeatureTransformed.h b/src/Mod/PartDesign/App/FeatureTransformed.h index d9279de598..b68d2be759 100644 --- a/src/Mod/PartDesign/App/FeatureTransformed.h +++ b/src/Mod/PartDesign/App/FeatureTransformed.h @@ -42,12 +42,19 @@ class PartDesignExport Transformed : public PartDesign::Feature PROPERTY_HEADER_WITH_OVERRIDE(PartDesign::Transformed); public: + enum class Mode { + TransformToolShapes, + TransformBody + }; + Transformed(); - /** The shapes to be transformed + /** The features to be transformed */ App::PropertyLinkList Originals; + App::PropertyEnumeration TransformMode; + App::PropertyBool Refine; /**