Toponaming: Cleanup verified face calls

This commit is contained in:
bgbsww
2024-05-20 16:17:38 -04:00
committed by Chris Hennes
parent d0036fa384
commit 9e2a8343a0
6 changed files with 158 additions and 136 deletions

View File

@@ -260,7 +260,7 @@ App::DocumentObjectExecReturn *Groove::execute()
TopoShape sketchshape;
try {
sketchshape = getVerifiedFace();
sketchshape = getTopoShapeVerifiedFace();
} catch (const Base::Exception& e) {
return new App::DocumentObjectExecReturn(e.what());
}

View File

@@ -170,7 +170,7 @@ App::DocumentObjectExecReturn* Helix::execute()
return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Error: unsupported mode"));
}
TopoDS_Shape sketchshape;
TopoDS_Shape sketchshape; // Fixme: Should this be TopoShape here and below?
try {
sketchshape = getVerifiedFace();
}

View File

@@ -1654,7 +1654,7 @@ App::DocumentObjectExecReturn* Hole::execute()
{
TopoShape profileshape;
try {
profileshape = getVerifiedFace();
profileshape = getTopoShapeVerifiedFace();
}
catch (const Base::Exception& e) {
return new App::DocumentObjectExecReturn(e.what());

View File

@@ -99,7 +99,7 @@ App::DocumentObjectExecReturn* Revolution::execute()
TopoShape sketchshape;
try {
sketchshape = getVerifiedFace();
sketchshape = getTopoShapeVerifiedFace();
}
catch (const Base::Exception& e) {
return new App::DocumentObjectExecReturn(e.what());

View File

@@ -169,121 +169,6 @@ Part::Feature* ProfileBased::getVerifiedObject(bool silent) const {
return static_cast<Part::Feature*>(result);
}
#ifdef FC_USE_TNP_FIX
TopoShape ProfileBased::getProfileShape() const
{
TopoShape shape;
const auto& subs = Profile.getSubValues();
auto profile = Profile.getValue();
if (subs.empty()) {
shape = Part::Feature::getTopoShape(profile);
}
else {
std::vector<TopoShape> shapes;
for (auto& sub : subs) {
shapes.push_back(
Part::Feature::getTopoShape(profile, sub.c_str(), /* needSubElement */ true));
}
shape = TopoShape(shape.Tag).makeElementCompound(shapes);
}
if (shape.isNull()) {
throw Part::NullShapeException("Linked shape object is empty");
}
return shape;
}
#else
Part::TopoShape ProfileBased::getProfileShape() const
{
auto shape = getTopoShape(Profile.getValue());
if (!shape.isNull() && !Profile.getSubValues().empty()) {
std::vector<Part::TopoShape> shapes;
for (auto& sub : Profile.getSubValues(true))
shapes.emplace_back(shape.getSubShape(sub.c_str()));
shape = Part::TopoShape().makeCompound(shapes);
}
return shape;
}
#endif
// TODO: Toponaming April 2024 Deprecated in favor of TopoShape method. Remove when possible.
TopoDS_Shape ProfileBased::getVerifiedFace(bool silent) const {
App::DocumentObject* result = Profile.getValue();
const char* err = nullptr;
std::string _err;
if (!result) {
err = "No profile linked";
}
else if (AllowMultiFace.getValue()) {
try {
auto shape = getProfileShape();
if (shape.isNull())
err = "Linked shape object is empty";
else {
auto faces = shape.getSubTopoShapes(TopAbs_FACE);
if (faces.empty()) {
if (!shape.hasSubShape(TopAbs_WIRE))
shape = shape.makeWires();
if (shape.hasSubShape(TopAbs_WIRE))
shape = shape.makeFace(nullptr, "Part::FaceMakerBullseye");
else
err = "Cannot make face from profile";
}
else if (faces.size() == 1)
shape = faces.front();
else
shape = TopoShape().makeCompound(faces);
}
if (!err)
return shape.getShape();
}
catch (Standard_Failure& e) {
_err = e.GetMessageString();
err = _err.c_str();
}
}
else {
if (result->isDerivedFrom<Part::Part2DObject>()) {
auto wires = getProfileWires();
return Part::FaceMakerCheese::makeFace(wires);
}
else if (result->isDerivedFrom<Part::Feature>()) {
if (Profile.getSubValues().empty())
err = "Linked object has no subshape specified";
else {
const Part::TopoShape& shape = Profile.getValue<Part::Feature*>()->Shape.getShape();
TopoDS_Shape sub = shape.getSubShape(Profile.getSubValues()[0].c_str());
if (sub.ShapeType() == TopAbs_FACE)
return TopoDS::Face(sub);
else if (sub.ShapeType() == TopAbs_WIRE) {
auto wire = TopoDS::Wire(sub);
if (!wire.Closed())
err = "Linked wire is not closed";
else {
BRepBuilderAPI_MakeFace mk(wire);
mk.Build();
return TopoDS::Face(mk.Shape());
}
}
else
err = "Linked Subshape cannot be used";
}
}
else
err = "Linked object is neither Sketch, Part2DObject or Part::Feature";
}
if (!silent && err) {
throw Base::RuntimeError(err);
}
return TopoDS_Face();
}
TopoShape ProfileBased::getTopoShapeVerifiedFace(bool silent,
[[maybe_unused]]bool doFit, // TODO: Remove parameter
bool allowOpen,
@@ -400,17 +285,17 @@ TopoShape ProfileBased::getTopoShapeVerifiedFace(bool silent,
}
// Toponaming April 2024: This appears to be new feature, not TNP:
// if (doFit && (std::abs(Fit.getValue()) > Precision::Confusion()
// || std::abs(InnerFit.getValue()) > Precision::Confusion())) {
//
// if (!shape.isNull())
// shape = shape.makEOffsetFace(Fit.getValue(),
// InnerFit.getValue(),
// static_cast<Part::TopoShape::JoinType>(FitJoin.getValue()),
// static_cast<Part::TopoShape::JoinType>(InnerFitJoin.getValue()));
// if (!openshape.isNull())
// openshape.makEOffset2D(Fit.getValue());
// }
// if (doFit && (std::abs(Fit.getValue()) > Precision::Confusion()
// || std::abs(InnerFit.getValue()) > Precision::Confusion())) {
//
// if (!shape.isNull())
// shape = shape.makeElementOffsetFace(Fit.getValue(),
// InnerFit.getValue(),
// static_cast<Part::TopoShape::JoinType>(FitJoin.getValue()),
// static_cast<Part::TopoShape::JoinType>(InnerFitJoin.getValue()));
// if (!openshape.isNull())
// openshape.makeElementOffset2D(Fit.getValue());
// }
if (!openshape.isNull()) {
if (shape.isNull()) {
@@ -443,6 +328,121 @@ TopoShape ProfileBased::getTopoShapeVerifiedFace(bool silent,
}
}
// TODO: Toponaming April 2024 Deprecated in favor of TopoShape method. Remove when possible.
TopoDS_Shape ProfileBased::getVerifiedFace(bool silent) const {
App::DocumentObject* result = Profile.getValue();
const char* err = nullptr;
std::string _err;
if (!result) {
err = "No profile linked";
}
else if (AllowMultiFace.getValue()) {
try {
auto shape = getProfileShape();
if (shape.isNull())
err = "Linked shape object is empty";
else {
auto faces = shape.getSubTopoShapes(TopAbs_FACE);
if (faces.empty()) {
if (!shape.hasSubShape(TopAbs_WIRE))
shape = shape.makeWires();
if (shape.hasSubShape(TopAbs_WIRE))
shape = shape.makeFace(nullptr, "Part::FaceMakerBullseye");
else
err = "Cannot make face from profile";
}
else if (faces.size() == 1)
shape = faces.front();
else
shape = TopoShape().makeCompound(faces);
}
if (!err)
return shape.getShape();
}
catch (Standard_Failure& e) {
_err = e.GetMessageString();
err = _err.c_str();
}
}
else {
if (result->isDerivedFrom<Part::Part2DObject>()) {
auto wires = getProfileWires();
return Part::FaceMakerCheese::makeFace(wires);
}
else if (result->isDerivedFrom<Part::Feature>()) {
if (Profile.getSubValues().empty())
err = "Linked object has no subshape specified";
else {
const Part::TopoShape& shape = Profile.getValue<Part::Feature*>()->Shape.getShape();
TopoDS_Shape sub = shape.getSubShape(Profile.getSubValues()[0].c_str());
if (sub.ShapeType() == TopAbs_FACE)
return TopoDS::Face(sub);
else if (sub.ShapeType() == TopAbs_WIRE) {
auto wire = TopoDS::Wire(sub);
if (!wire.Closed())
err = "Linked wire is not closed";
else {
BRepBuilderAPI_MakeFace mk(wire);
mk.Build();
return TopoDS::Face(mk.Shape());
}
}
else
err = "Linked Subshape cannot be used";
}
}
else
err = "Linked object is neither Sketch, Part2DObject or Part::Feature";
}
if (!silent && err) {
throw Base::RuntimeError(err);
}
return TopoDS_Face();
}
#ifdef FC_USE_TNP_FIX
TopoShape ProfileBased::getProfileShape() const
{
TopoShape shape;
const auto& subs = Profile.getSubValues();
auto profile = Profile.getValue();
if (subs.empty()) {
shape = Part::Feature::getTopoShape(profile);
}
else {
std::vector<TopoShape> shapes;
for (auto& sub : subs) {
shapes.push_back(
Part::Feature::getTopoShape(profile, sub.c_str(), /* needSubElement */ true));
}
shape = TopoShape(shape.Tag).makeElementCompound(shapes);
}
if (shape.isNull()) {
throw Part::NullShapeException("Linked shape object is empty");
}
return shape;
}
#else
Part::TopoShape ProfileBased::getProfileShape() const
{
auto shape = getTopoShape(Profile.getValue());
if (!shape.isNull() && !Profile.getSubValues().empty()) {
std::vector<Part::TopoShape> shapes;
for (auto& sub : Profile.getSubValues(true))
shapes.emplace_back(shape.getSubShape(sub.c_str()));
shape = Part::TopoShape().makeCompound(shapes);
}
return shape;
}
#endif
// TODO: Toponaming April 2024 Deprecated in favor of TopoShape method. Remove when possible.
std::vector<TopoDS_Wire> ProfileBased::getProfileWires() const {
@@ -920,13 +920,13 @@ void ProfileBased::addOffsetToFace(TopoShape& upToFace, const gp_Dir& dir, doubl
double ProfileBased::getThroughAllLength() const
{
TopoDS_Shape profileshape;
TopoShape profileshape;
TopoShape base;
profileshape = getVerifiedFace();
profileshape = getTopoShapeVerifiedFace();
base = getBaseTopoShape();
Bnd_Box box;
BRepBndLib::Add(base.getShape(), box);
BRepBndLib::Add(profileshape, box);
BRepBndLib::Add(profileshape.getShape(), box);
box.SetGap(0.0);
// The diagonal of the bounding box, plus 1% extra to eliminate risk of
// co-planar issues, gives a length that is guaranteed to go through all.
@@ -1297,11 +1297,11 @@ double ProfileBased::getReversedAngle(const Base::Vector3d & b, const Base::Vect
{
try {
Part::Feature* obj = getVerifiedObject();
TopoDS_Shape sketchshape = getVerifiedFace();
TopoShape sketchshape = getTopoShapeVerifiedFace();
// get centre of gravity of the sketch face
GProp_GProps props;
BRepGProp::SurfaceProperties(sketchshape, props);
BRepGProp::SurfaceProperties(sketchshape.getShape(), props);
gp_Pnt cog = props.CentreOfMass();
Base::Vector3d p_cog(cog.X(), cog.Y(), cog.Z());
// get direction to cog from its projection on the revolve axis
@@ -1479,7 +1479,7 @@ Base::Vector3d ProfileBased::getProfileNormal() const {
// For newer version, do not do fitting, as it may flip the face normal for
// some reason.
TopoShape shape = getVerifiedFace(true); //, _ProfileBasedVersion.getValue() <= 0);
TopoShape shape = getTopoShapeVerifiedFace(true); //, _ProfileBasedVersion.getValue() <= 0);
gp_Pln pln;
if (shape.findPlane(pln)) {

View File

@@ -108,6 +108,28 @@ class TestTopologicalNamingProblem(unittest.TestCase):
else:
self.assertTrue(self.Pad2.isValid()) # TNP problem is not present with ElementMaps
def testPartDesignElementMapSketch(self):
""" Test that creating a sketch results in a correct element map. """
# Arrange
body = self.Doc.addObject('PartDesign::Body', 'Body')
sketch = self.Doc.addObject('Sketcher::SketchObject', 'SketchPad')
body.addObject(sketch)
TestSketcherApp.CreateRectangleSketch(sketch, (0, 0), (1, 1))
# Act
self.Doc.recompute()
if body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023.
return
reverseMap = sketch.Shape.ElementReverseMap
faces = [name for name in reverseMap.keys() if name.startswith("Face")]
edges = [name for name in reverseMap.keys() if name.startswith("Edge")]
vertexes = [name for name in reverseMap.keys() if name.startswith("Vertex")]
# Assert
self.assertEqual(sketch.Shape.ElementMapSize,9)
self.assertEqual(len(reverseMap),9)
self.assertEqual(len(faces),1)
self.assertEqual(len(edges),4)
self.assertEqual(len(vertexes),4)
def testPartDesignElementMapPad(self):
""" Test that padding a sketch results in a correct element map. Note that comprehensive testing
of the geometric functionality of the Pad is in TestPad.py """