diff --git a/src/Mod/Part/App/FeaturePartCommon.cpp b/src/Mod/Part/App/FeaturePartCommon.cpp
index fd05813763..672b4cbd3e 100644
--- a/src/Mod/Part/App/FeaturePartCommon.cpp
+++ b/src/Mod/Part/App/FeaturePartCommon.cpp
@@ -34,6 +34,8 @@
#include "TopoShapeOpCode.h"
#include "modelRefine.h"
+#include
+
using namespace Part;
@@ -45,7 +47,6 @@ extern bool getRefineModelParameter();
PROPERTY_SOURCE(Part::Common, Part::Boolean)
-
Common::Common() = default;
const char* Common::opCode() const
@@ -63,6 +64,7 @@ BRepAlgoAPI_BooleanOperation* Common::makeOperation(const TopoDS_Shape& base, co
PROPERTY_SOURCE(Part::MultiCommon, Part::Feature)
+const char* MultiCommon::BehaviorEnums[] = {"CommonOfAllShapes", "CommonOfFirstAndRest", nullptr};
MultiCommon::MultiCommon()
{
@@ -85,17 +87,38 @@ MultiCommon::MultiCommon()
"Refine shape (clean up redundant edges) after this boolean operation"
);
+ ADD_PROPERTY_TYPE(
+ Behavior,
+ (CommonOfAllShapes),
+ "Compatibility",
+ App::Prop_Hidden,
+ "Determines how the common operation is computed: either as the intersection of all "
+ "shapes, or the intersection of the first shape with all remaining shapes (for "
+ "compatibility with FreeCAD 1.0)."
+ );
+ Behavior.setEnums(BehaviorEnums);
+
this->Refine.setValue(getRefineModelParameter());
}
short MultiCommon::mustExecute() const
{
- if (Shapes.isTouched()) {
+ if (Shapes.isTouched() || Behavior.isTouched()) {
return 1;
}
return 0;
}
+void MultiCommon::Restore(Base::XMLReader& reader)
+{
+ Feature::Restore(reader);
+
+ // For 1.0 and 1.0 only the order was common of first and the rest due to a bug
+ if (Base::getVersion(reader.ProgramVersion) == Base::Version::v1_0) {
+ Behavior.setValue(CommonOfFirstAndRest);
+ }
+}
+
App::DocumentObjectExecReturn* MultiCommon::execute()
{
std::vector shapes;
@@ -107,8 +130,31 @@ App::DocumentObjectExecReturn* MultiCommon::execute()
shapes.push_back(sh);
}
- TopoShape res {0};
- res.makeElementBoolean(Part::OpCodes::Common, shapes);
+ TopoShape res;
+
+ if (Behavior.getValue() == CommonOfAllShapes) {
+ // special case - if there is only one argument, and it is compound - expand it
+ if (shapes.size() == 1) {
+ TopoShape shape = shapes.front();
+
+ if (shape.shapeType() == TopAbs_COMPOUND) {
+ shapes.clear();
+ std::ranges::copy(shape.getSubTopoShapes(), std::back_inserter(shapes));
+ }
+ }
+
+ res = shapes.front();
+
+ // to achieve common of all shapes, we need to do it one shape at a time
+ for (const auto& tool : shapes) {
+ res = res.makeElementBoolean(OpCodes::Common, {res, tool});
+ }
+ }
+ else {
+ res = TopoShape(0);
+ res.makeElementBoolean(OpCodes::Common, shapes);
+ }
+
if (res.isNull()) {
throw Base::RuntimeError("Resulting shape is null");
}
diff --git a/src/Mod/Part/App/FeaturePartCommon.h b/src/Mod/Part/App/FeaturePartCommon.h
index 2f4fd501da..a92342cad0 100644
--- a/src/Mod/Part/App/FeaturePartCommon.h
+++ b/src/Mod/Part/App/FeaturePartCommon.h
@@ -49,6 +49,12 @@ protected:
//@}
};
+enum CommonBehavior
+{
+ CommonOfAllShapes,
+ CommonOfFirstAndRest,
+};
+
class PartExport MultiCommon: public Part::Feature
{
PROPERTY_HEADER_WITH_OVERRIDE(Part::MultiCommon);
@@ -59,6 +65,7 @@ public:
App::PropertyLinkList Shapes;
PropertyShapeHistory History;
App::PropertyBool Refine;
+ App::PropertyEnumeration Behavior;
/** @name methods override feature */
//@{
@@ -66,11 +73,17 @@ public:
App::DocumentObjectExecReturn* execute() override;
short mustExecute() const override;
//@}
+
+ void Restore(Base::XMLReader& reader) override;
+
/// returns the type name of the ViewProvider
const char* getViewProviderName() const override
{
return "PartGui::ViewProviderMultiCommon";
}
+
+private:
+ static const char* BehaviorEnums[];
};
} // namespace Part