PartDesign: change feature DressUp behavior when used for pattern

Repurpose DressUp.SupportTransform property to define the following
behavior,

* When disabled (default), only the dressing will be used for patterning.

* When enabled, the additive/subtractive shape of the dressed base
  feature will be used for patterning. Any dressing that is not applied
  to the based feature will be ignored.

* If the dressing is applied to non-additive/subtractive feature, then
  only the dressing will be used for patterning.

New API FreatureAddSub::getAddSubShape() is added to account for the
fact that a dressing (e.g. a fillet) can be either additive or
subtractive, which means that a DressUP feature may contain both
additive and subtractive shapes.

FeatureTransformed is modified to perform both fusion and cut if
required.
This commit is contained in:
Zheng, Lei
2020-03-21 15:22:48 +08:00
committed by wmayer
parent 8b23d814f8
commit a045f58a85
6 changed files with 162 additions and 99 deletions

View File

@@ -51,9 +51,10 @@ DressUp::DressUp()
Placement.setStatus(App::Property::ReadOnly, true);
ADD_PROPERTY_TYPE(SupportTransform,(false),"Base", App::Prop_None,
"Enable support for transformed patterns");
"Include the base additive/subtractive shape when used in pattern features.\n"
"If disabled, only the dressed part of the shape is used for patterning.");
addSubType = Additive;
AddSubShape.setStatus(App::Property::Output, true);
}
short DressUp::mustExecute() const
@@ -63,12 +64,6 @@ short DressUp::mustExecute() const
return PartDesign::Feature::mustExecute();
}
void DressUp::setupObject()
{
SupportTransform.setValue(true);
Feature::setupObject();
}
void DressUp::positionByBaseFeature(void)
{
Part::Feature *base = static_cast<Part::Feature*>(BaseFeature.getValue());
@@ -182,43 +177,94 @@ void DressUp::onChanged(const App::Property* prop)
BaseFeature.setValue (Base.getValue());
}
} else if (prop == &Shape || prop == &SupportTransform) {
// This is an expensive operation and to avoid to perform it unnecessarily it's not sufficient
// to check for the 'Restore' flag of the dress-up feature because at that time it's already reset.
// Instead the 'Restore' flag of the document must be checked.
// For more details see: https://forum.freecadweb.org/viewtopic.php?f=3&t=43799 (and issue 4276)
if (!getDocument()->testStatus(App::Document::Restoring) &&
!getDocument()->isPerformingTransaction()) {
Part::TopoShape s;
auto base = Base::freecad_dynamic_cast<FeatureAddSub>(getBaseObject(true));
if(!base) {
addSubType = Additive;
if(!SupportTransform.getValue())
s = getBaseShape();
else
s = Shape.getShape();
s.setPlacement(Base::Placement());
} else if (!SupportTransform.getValue()) {
addSubType = base->getAddSubType();
s = base->AddSubShape.getShape();
} else {
addSubType = base->getAddSubType();
Part::TopoShape baseShape = base->getBaseTopoShape(true);
baseShape.setPlacement(Base::Placement());
Part::TopoShape shape = Shape.getShape();
shape.setPlacement(Base::Placement());
if (baseShape.isNull() || !baseShape.hasSubShape(TopAbs_SOLID)) {
s = shape;
addSubType = Additive;
} else if (addSubType == Additive)
s = shape.cut(baseShape.getShape());
else
s = baseShape.cut(shape.getShape());
}
AddSubShape.setValue(s);
!getDocument()->isPerformingTransaction())
{
// AddSubShape in DressUp acts as a shape cache. And here we shall
// invalidate the cache upon changes in Shape. Other features
// (currently only feature Transformed) shall call getAddSubShape()
// to rebuild the cache. This allow us to perform expensive
// calculation of AddSubShape only when necessary.
AddSubShape.setValue(Part::TopoShape());
}
}
Feature::onChanged(prop);
}
void DressUp::getAddSubShape(Part::TopoShape &addShape, Part::TopoShape &subShape)
{
Part::TopoShape res = AddSubShape.getShape();
if(res.isNull()) {
try {
std::vector<Part::TopoShape> shapes;
Part::TopoShape shape = Shape.getShape();
shape.setPlacement(Base::Placement());
FeatureAddSub *base = nullptr;
if(SupportTransform.getValue())
base = Base::freecad_dynamic_cast<FeatureAddSub>(getBaseObject(true));
Part::TopoShape baseShape;
if(base) {
baseShape = base->getBaseTopoShape(true);
baseShape.setPlacement(Base::Placement());
if (base->getAddSubType() == Additive) {
if(!baseShape.isNull() && baseShape.hasSubShape(TopAbs_SOLID))
shapes.push_back(shape.cut(baseShape.getShape()));
else
shapes.push_back(shape);
} else {
BRep_Builder builder;
TopoDS_Compound comp;
builder.MakeCompound(comp);
// push an empty compound to indicate null additive shape
shapes.emplace_back(comp);
if(!baseShape.isNull() && baseShape.hasSubShape(TopAbs_SOLID))
shapes.push_back(baseShape.cut(shape.getShape()));
else
shapes.push_back(shape);
}
} else {
baseShape = getBaseTopoShape();
baseShape.setPlacement(Base::Placement());
shapes.push_back(shape.cut(baseShape.getShape()));
shapes.push_back(baseShape.cut(shape.getShape()));
}
// Make a compound to contain both additive and subtractive shape,
// bceause a dressing (e.g. a fillet) can either be additive or
// subtractive. And the dressup feature can contain mixture of both.
AddSubShape.setValue(Part::TopoShape().makECompound(shapes));
} catch (Standard_Failure &e) {
FC_THROWM(Base::CADKernelError, "Failed to calculate AddSub shape: "
<< e.GetMessageString());
}
res = AddSubShape.getShape();
}
if(res.isNull())
throw Part::NullShapeException("Null AddSub shape");
if(res.getShape().ShapeType() != TopAbs_COMPOUND) {
addShape = res;
} else {
int count = res.countSubShapes(TopAbs_SHAPE);
if(!count)
throw Part::NullShapeException("Null AddSub shape");
if(count) {
Part::TopoShape s = res.getSubShape(TopAbs_SHAPE, 1);
if(!s.isNull() && s.hasSubShape(TopAbs_SOLID))
addShape = s;
}
if(count > 1) {
Part::TopoShape s = res.getSubShape(TopAbs_SHAPE, 2);
if(!s.isNull() && s.hasSubShape(TopAbs_SOLID))
subShape = s;
}
}
}
}