PartDesign: Introduce ability to disable single-solid rule

This adds "SingleSolidRuleMode" enum that controls if PartDesign will
enforce singular solid. By default the single-solid is enforced so
nothing changes for the user, it must be explicitly disabled by setting
new Allow Compound boolean property on a given body.

Default for this value is controled using user parameter under
Mod/PartDesign/AllowCompoundDefault
This commit is contained in:
Kacper Donat
2024-05-11 14:17:02 +02:00
committed by Adrián Insaurralde Avalos
parent d0a35c8c03
commit e4ed0d883f
5 changed files with 61 additions and 14 deletions

View File

@@ -47,9 +47,8 @@ public:
/**
* The final feature of the body it is associated with.
* Note: tip may either point to the BaseFeature or to some feature inside the Group list.
* in case it points to the model the PartDesign::Body guaranties that it is a solid.
*/
App::PropertyLink Tip;
App::PropertyLink Tip;
/**
* A base object of the body, serves as a base object for the first feature of the body.

View File

@@ -40,7 +40,17 @@ using namespace PartDesign;
PROPERTY_SOURCE(PartDesign::Body, Part::BodyBase)
Body::Body() {
_GroupTouched.setStatus(App::Property::Output,true);
ADD_PROPERTY_TYPE(AllowCompound, (false), "Experimental", App::Prop_None, "Allow multiple solids in Body (experimental)");
_GroupTouched.setStatus(App::Property::Output, true);
static Base::Reference<ParameterGrp> hGrp = App::GetApplication()
.GetUserParameter()
.GetGroup("BaseApp/Preferences/Mod/PartDesign");
auto allowCompoundDefaultValue = hGrp->GetBool("AllowCompoundDefault", false);
ADD_PROPERTY(AllowCompound, (allowCompoundDefaultValue));
}
/*
@@ -428,7 +438,7 @@ void Body::onSettingDocument() {
Part::BodyBase::onSettingDocument();
}
void Body::onChanged (const App::Property* prop) {
void Body::onChanged(const App::Property* prop) {
// we neither load a project nor perform undo/redo
if (!this->isRestoring()
&& this->getDocument()
@@ -438,7 +448,6 @@ void Body::onChanged (const App::Property* prop) {
auto first = Group.getValues().empty() ? nullptr : Group.getValues().front();
if (BaseFeature.getValue()) {
//setup the FeatureBase if needed
if (!first || !first->isDerivedFrom(FeatureBase::getClassTypeId())) {
bf = static_cast<FeatureBase*>(getDocument()->addObject("PartDesign::FeatureBase", "BaseFeature"));
@@ -452,17 +461,26 @@ void Body::onChanged (const App::Property* prop) {
}
}
if (bf && (bf->BaseFeature.getValue() != BaseFeature.getValue()))
if (bf && (bf->BaseFeature.getValue() != BaseFeature.getValue())) {
bf->BaseFeature.setValue(BaseFeature.getValue());
}
}
else if( prop == &Group ) {
else if (prop == &Group) {
//if the FeatureBase was deleted we set the BaseFeature link to nullptr
if (BaseFeature.getValue() &&
(Group.getValues().empty() || !Group.getValues().front()->isDerivedFrom(FeatureBase::getClassTypeId()))) {
BaseFeature.setValue(nullptr);
}
}
else if (prop == &AllowCompound) {
// As disallowing compounds can break the model we need to recompute the whole tree.
// This will inform user about first place where there is more than one solid.
if (!AllowCompound.getValue()) {
for (auto feature : getFullModel()) {
feature->enforceRecompute();
}
}
}
}
Part::BodyBase::onChanged(prop);

View File

@@ -41,6 +41,7 @@ class PartDesignExport Body : public Part::BodyBase
PROPERTY_HEADER_WITH_OVERRIDE(PartDesign::Body);
public:
App::PropertyBool AllowCompound;
/// True if this body feature is active or was active when the document was last closed
//App::PropertyBool IsActive;

View File

@@ -91,10 +91,17 @@ short Feature::mustExecute() const
// TODO: Toponaming April 2024 Deprecated in favor of TopoShape method. Remove when possible.
TopoDS_Shape Feature::getSolid(const TopoDS_Shape& shape)
{
if (shape.IsNull())
if (shape.IsNull()) {
Standard_Failure::Raise("Shape is null");
}
// If single solid rule is not enforced we simply return the shape as is
if (singleSolidRuleMode() != Feature::SingleSolidRuleMode::Enforced) {
return shape;
}
TopExp_Explorer xp;
xp.Init(shape,TopAbs_SOLID);
xp.Init(shape, TopAbs_SOLID);
if (xp.More()) {
return xp.Current();
}
@@ -107,12 +114,19 @@ TopoShape Feature::getSolid(const TopoShape& shape)
if (shape.isNull()) {
throw Part::NullShapeException("Null shape");
}
// If single solid rule is not enforced we simply return the shape as is
if (singleSolidRuleMode() != Feature::SingleSolidRuleMode::Enforced) {
return shape;
}
int count = shape.countSubShapes(TopAbs_SOLID);
if(count) {
auto res = shape.getSubTopoShape(TopAbs_SOLID,1);
if (count) {
auto res = shape.getSubTopoShape(TopAbs_SOLID, 1);
res.fixSolidOrientation();
return res;
}
return shape;
}
@@ -153,12 +167,24 @@ int Feature::countSolids(const TopoDS_Shape& shape, TopAbs_ShapeEnum type)
bool Feature::isSingleSolidRuleSatisfied(const TopoDS_Shape& shape, TopAbs_ShapeEnum type)
{
if (singleSolidRuleMode() == Feature::SingleSolidRuleMode::Disabled) {
return true;
}
int solidCount = countSolids(shape, type);
return solidCount <= 1;
}
Feature::SingleSolidRuleMode Feature::singleSolidRuleMode()
{
auto body = getFeatureBody();
auto areCompoundSolidsAllowed = body->AllowCompound.getValue();
return areCompoundSolidsAllowed ? SingleSolidRuleMode::Disabled : SingleSolidRuleMode::Enforced;
}
const gp_Pnt Feature::getPointFromFace(const TopoDS_Face& f)
{
if (!f.Infinite()) {

View File

@@ -52,6 +52,8 @@ class PartDesignExport Feature : public Part::Feature, public App::SuppressibleE
public:
Feature();
enum SingleSolidRuleMode { Disabled = 0, Enforced = 1 };
/// Base feature which this feature will be fused into or cut out of
App::PropertyLink BaseFeature;
App::PropertyLinkHidden _Body;
@@ -96,14 +98,15 @@ protected:
* Get a solid of the given shape. If no solid is found an exception is raised.
*/
// TODO: Toponaming April 2024 Deprecated in favor of TopoShape method. Remove when possible.
static TopoDS_Shape getSolid(const TopoDS_Shape&);
TopoDS_Shape getSolid(const TopoDS_Shape&);
TopoShape getSolid(const TopoShape&);
static int countSolids(const TopoDS_Shape&, TopAbs_ShapeEnum type = TopAbs_SOLID);
/**
* Checks if the single-solid body rule is fulfilled.
*/
static bool isSingleSolidRuleSatisfied(const TopoDS_Shape&, TopAbs_ShapeEnum type = TopAbs_SOLID);
bool isSingleSolidRuleSatisfied(const TopoDS_Shape&, TopAbs_ShapeEnum type = TopAbs_SOLID);
SingleSolidRuleMode singleSolidRuleMode();
/// Grab any point from the given face
static const gp_Pnt getPointFromFace(const TopoDS_Face& f);