Part: Fix regressions in MultiCommon boolean operation
This commit addresses two regressions in the MultiCommon feature: 1. Computation Logic: Fixed an issue where the common operation was calculated as the intersection of the first shape with the union of the rest (the default behavior of makeElementBoolean). It now correctly computes the intersection of all shapes sequentially. 2. Compound Handling: Added logic to expand a single compound input into its constituent shapes. Previously, a compound was treated as a single entity, leading to incorrect intersection results. To maintain backward compatibility, a hidden 'Behavior' property is introduced. This ensures that documents created in FreeCAD 1.0, which rely on the previous behavior, continue to render as originally intended while new objects use the corrected logic.
This commit is contained in:
committed by
Chris Hennes
parent
d3d6459484
commit
4dda92e599
@@ -34,6 +34,8 @@
|
||||
#include "TopoShapeOpCode.h"
|
||||
#include "modelRefine.h"
|
||||
|
||||
#include <Base/ProgramVersion.h>
|
||||
|
||||
|
||||
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<TopoShape> 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");
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user