From f8cca40b149400815956a83f6a81a60119758619 Mon Sep 17 00:00:00 2001 From: "Zheng, Lei" Date: Sat, 24 Feb 2024 16:19:25 -0500 Subject: [PATCH 1/5] Toposhape/Part: Transfer in replacEShape and removEShape --- src/Mod/Part/App/TopoShape.h | 42 +++++++++++++++++++++++++ src/Mod/Part/App/TopoShapeExpansion.cpp | 37 +++++++++++++++++++++- 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/src/Mod/Part/App/TopoShape.h b/src/Mod/Part/App/TopoShape.h index b5840144f3..b972b6a5d7 100644 --- a/src/Mod/Part/App/TopoShape.h +++ b/src/Mod/Part/App/TopoShape.h @@ -1041,6 +1041,48 @@ public: double tol3d = 0.0, double tolBound = 0.0, double tolAngluar = 0.0); + /* Make a shape with some subshapes replaced + * + * @param source: the source shape + * @param s: replacement mapping the existing sub shape of source to new shapes + * + * @return The original content of this TopoShape is discarded and replaced + * with the new shape. The function returns the TopoShape itself as + * a self reference so that multiple operations can be carried out + * for the same shape in the same line of code. + */ + TopoShape &replacEShape(const TopoShape &source, const std::vector > &s); + /* Make a new shape using this shape with some subshapes replaced by others + * + * @param s: replacement mapping the existing sub shape of source to new shapes + * + * @return Return the new shape. The TopoShape itself is not modified. + */ + TopoShape replacEShape(const std::vector > &s) const { + return TopoShape(0,Hasher).replacEShape(*this,s); + } + + /* Make a shape with some subshapes removed + * + * @param source: the source shape + * @param s: the subshapes to be removed + * + * @return The original content of this TopoShape is discarded and replaced + * with the new shape. The function returns the TopoShape itself as + * a self reference so that multiple operations can be carried out + * for the same shape in the same line of code. + */ + TopoShape &removEShape(const TopoShape &source, const std::vector& s); + /* Make a new shape using this shape with some subshapes removed + * + * @param s: the subshapes to be removed + * + * @return Return the new shape. The TopoShape itself is not modified. + */ + TopoShape removEShape(const std::vector& s) const { + return TopoShape(0,Hasher).removEShape(*this,s); + } + /** Make shape using generalized fusion and return the modified sub shapes * diff --git a/src/Mod/Part/App/TopoShapeExpansion.cpp b/src/Mod/Part/App/TopoShapeExpansion.cpp index b6829b3260..e60c7780b2 100644 --- a/src/Mod/Part/App/TopoShapeExpansion.cpp +++ b/src/Mod/Part/App/TopoShapeExpansion.cpp @@ -3059,7 +3059,7 @@ TopoShape& TopoShape::makeElementSolid(const TopoShape& shape, const char* op) } return *this; } - + TopoShape& TopoShape::makeElementMirror(const TopoShape& shape, const gp_Ax2& ax2, const char* op) { if (!op) { @@ -3108,6 +3108,41 @@ TopoShape& TopoShape::makeElementSlices(const TopoShape& shape, return makeElementCompound(wires, op, SingleShapeCompoundCreationPolicy::returnShape); } +TopoShape &TopoShape::replacEShape(const TopoShape &shape, + const std::vector > &s) +{ + if(shape.isNull()) + HANDLE_NULL_SHAPE; + BRepTools_ReShape reshape; + std::vector shapes; + shapes.reserve(s.size()+1); + for (auto &v : s) { + if(v.first.isNull() || v.second.isNull()) + HANDLE_NULL_INPUT; + reshape.Replace(v.first.getShape(), v.second.getShape()); + shapes.push_back(v.second); + } + shapes.push_back(shape); + setShape(reshape.Apply(shape.getShape(),TopAbs_SHAPE)); + mapSubElement(shapes); + return *this; +} + +TopoShape &TopoShape::removEShape(const TopoShape &shape, const std::vector& s) +{ + if(shape.isNull()) + HANDLE_NULL_SHAPE; + BRepTools_ReShape reshape; + for(auto &sh : s) { + if(sh.isNull()) + HANDLE_NULL_INPUT; + reshape.Remove(sh.getShape()); + } + setShape(reshape.Apply(shape.getShape(), TopAbs_SHAPE)); + mapSubElement(shape); + return *this; +} + TopoShape& TopoShape::makeElementFillet(const TopoShape& shape, const std::vector& edges, double radius1, From 698f306c185f8591eb5c24e57c6e5f68e4662535 Mon Sep 17 00:00:00 2001 From: bgbsww Date: Sat, 24 Feb 2024 16:59:45 -0500 Subject: [PATCH 2/5] Toposhape/Part: Clean and test replacEShape and removEShape --- src/Mod/Part/App/TopoShape.h | 21 ++-- src/Mod/Part/App/TopoShapeExpansion.cpp | 37 ++++--- tests/src/Mod/Part/App/TopoShapeExpansion.cpp | 98 +++++++++++++++---- 3 files changed, 115 insertions(+), 41 deletions(-) diff --git a/src/Mod/Part/App/TopoShape.h b/src/Mod/Part/App/TopoShape.h index b972b6a5d7..bc60bb4b57 100644 --- a/src/Mod/Part/App/TopoShape.h +++ b/src/Mod/Part/App/TopoShape.h @@ -1040,8 +1040,9 @@ public: const char* op = nullptr, double tol3d = 0.0, double tolBound = 0.0, - double tolAngluar = 0.0); - /* Make a shape with some subshapes replaced + double tolAngular = 0.0); + + /* Make a shape with some subshapes replaced. * * @param source: the source shape * @param s: replacement mapping the existing sub shape of source to new shapes @@ -1051,15 +1052,17 @@ public: * a self reference so that multiple operations can be carried out * for the same shape in the same line of code. */ - TopoShape &replacEShape(const TopoShape &source, const std::vector > &s); + TopoShape& replaceElementShape(const TopoShape& source, + const std::vector>& s); /* Make a new shape using this shape with some subshapes replaced by others * * @param s: replacement mapping the existing sub shape of source to new shapes * * @return Return the new shape. The TopoShape itself is not modified. */ - TopoShape replacEShape(const std::vector > &s) const { - return TopoShape(0,Hasher).replacEShape(*this,s); + TopoShape replaceElementShape(const std::vector>& s) const + { + return TopoShape(0, Hasher).replaceElementShape(*this, s); } /* Make a shape with some subshapes removed @@ -1072,18 +1075,18 @@ public: * a self reference so that multiple operations can be carried out * for the same shape in the same line of code. */ - TopoShape &removEShape(const TopoShape &source, const std::vector& s); + TopoShape& removeElementShape(const TopoShape& source, const std::vector& s); /* Make a new shape using this shape with some subshapes removed * * @param s: the subshapes to be removed * * @return Return the new shape. The TopoShape itself is not modified. */ - TopoShape removEShape(const std::vector& s) const { - return TopoShape(0,Hasher).removEShape(*this,s); + TopoShape removeElementShape(const std::vector& s) const + { + return TopoShape(0, Hasher).removeElementShape(*this, s); } - /** Make shape using generalized fusion and return the modified sub shapes * * @param sources: the source shapes diff --git a/src/Mod/Part/App/TopoShapeExpansion.cpp b/src/Mod/Part/App/TopoShapeExpansion.cpp index e60c7780b2..2495395751 100644 --- a/src/Mod/Part/App/TopoShapeExpansion.cpp +++ b/src/Mod/Part/App/TopoShapeExpansion.cpp @@ -3108,34 +3108,41 @@ TopoShape& TopoShape::makeElementSlices(const TopoShape& shape, return makeElementCompound(wires, op, SingleShapeCompoundCreationPolicy::returnShape); } -TopoShape &TopoShape::replacEShape(const TopoShape &shape, - const std::vector > &s) +TopoShape& TopoShape::replaceElementShape(const TopoShape& shape, + const std::vector>& s) { - if(shape.isNull()) - HANDLE_NULL_SHAPE; + if (shape.isNull()) { + FC_THROWM(NullShapeException, "Null shape"); + } BRepTools_ReShape reshape; std::vector shapes; - shapes.reserve(s.size()+1); - for (auto &v : s) { - if(v.first.isNull() || v.second.isNull()) - HANDLE_NULL_INPUT; + shapes.reserve(s.size() + 1); + for (auto& v : s) { + if (v.first.isNull() || v.second.isNull()) { + FC_THROWM(NullShapeException, "Null input shape"); + } reshape.Replace(v.first.getShape(), v.second.getShape()); shapes.push_back(v.second); } + // TODO: This does not work when replacing a shape in a compound. Should we replace with + // something else? + // Note that remove works with a compound. shapes.push_back(shape); - setShape(reshape.Apply(shape.getShape(),TopAbs_SHAPE)); + setShape(reshape.Apply(shape.getShape(), TopAbs_SHAPE)); mapSubElement(shapes); return *this; } -TopoShape &TopoShape::removEShape(const TopoShape &shape, const std::vector& s) +TopoShape& TopoShape::removeElementShape(const TopoShape& shape, const std::vector& s) { - if(shape.isNull()) - HANDLE_NULL_SHAPE; + if (shape.isNull()) { + FC_THROWM(NullShapeException, "Null shape"); + } BRepTools_ReShape reshape; - for(auto &sh : s) { - if(sh.isNull()) - HANDLE_NULL_INPUT; + for (auto& sh : s) { + if (sh.isNull()) { + FC_THROWM(NullShapeException, "Null input shape"); + } reshape.Remove(sh.getShape()); } setShape(reshape.Apply(shape.getShape(), TopAbs_SHAPE)); diff --git a/tests/src/Mod/Part/App/TopoShapeExpansion.cpp b/tests/src/Mod/Part/App/TopoShapeExpansion.cpp index e12642891a..6ffdd86d69 100644 --- a/tests/src/Mod/Part/App/TopoShapeExpansion.cpp +++ b/tests/src/Mod/Part/App/TopoShapeExpansion.cpp @@ -172,24 +172,24 @@ TEST_F(TopoShapeExpansionTest, makeElementCompoundTwoCubes) EXPECT_TRUE( allElementsMatch(topoShape, { - "Edge1;:H1,E;:H7,E", "Edge2;:H1,E;:H7,E", "Edge3;:H1,E;:H7,E", - "Edge4;:H1,E;:H7,E", "Edge1;:H2,E;:H7,E", "Edge2;:H2,E;:H7,E", - "Edge3;:H2,E;:H7,E", "Edge4;:H2,E;:H7,E", "Edge1;:H3,E;:H7,E", - "Edge2;:H3,E;:H7,E", "Edge3;:H3,E;:H7,E", "Edge4;:H3,E;:H7,E", - "Edge1;:H8,E;:He,E", "Edge2;:H8,E;:He,E", "Edge3;:H8,E;:He,E", - "Edge4;:H8,E;:He,E", "Edge1;:H9,E;:He,E", "Edge2;:H9,E;:He,E", - "Edge3;:H9,E;:He,E", "Edge4;:H9,E;:He,E", "Edge1;:Ha,E;:He,E", - "Edge2;:Ha,E;:He,E", "Edge3;:Ha,E;:He,E", "Edge4;:Ha,E;:He,E", - "Vertex1;:H8,V;:He,V", "Vertex2;:H8,V;:He,V", "Vertex3;:H8,V;:He,V", - "Vertex4;:H8,V;:He,V", "Vertex1;:H9,V;:He,V", "Vertex2;:H9,V;:He,V", - "Vertex3;:H9,V;:He,V", "Vertex4;:H9,V;:He,V", "Face1;:H1,F;:H7,F", - "Face1;:H2,F;:H7,F", "Face1;:H3,F;:H7,F", "Face1;:H4,F;:H7,F", - "Face1;:H5,F;:H7,F", "Face1;:H6,F;:H7,F", "Face1;:H8,F;:He,F", + "Vertex1;:H1,V;:H7,V", "Vertex2;:H1,V;:H7,V", "Vertex3;:H1,V;:H7,V", + "Vertex4;:H1,V;:H7,V", "Vertex1;:H2,V;:H7,V", "Vertex2;:H2,V;:H7,V", + "Vertex3;:H2,V;:H7,V", "Vertex4;:H2,V;:H7,V", "Face1;:H8,F;:He,F", "Face1;:H9,F;:He,F", "Face1;:Ha,F;:He,F", "Face1;:Hb,F;:He,F", - "Face1;:Hc,F;:He,F", "Face1;:Hd,F;:He,F", "Vertex1;:H1,V;:H7,V", - "Vertex2;:H1,V;:H7,V", "Vertex3;:H1,V;:H7,V", "Vertex4;:H1,V;:H7,V", - "Vertex1;:H2,V;:H7,V", "Vertex2;:H2,V;:H7,V", "Vertex3;:H2,V;:H7,V", - "Vertex4;:H2,V;:H7,V", + "Face1;:Hc,F;:He,F", "Face1;:Hd,F;:He,F", "Edge1;:H8,E;:He,E", + "Edge2;:H8,E;:He,E", "Edge3;:H8,E;:He,E", "Edge4;:H8,E;:He,E", + "Edge1;:H9,E;:He,E", "Edge2;:H9,E;:He,E", "Edge3;:H9,E;:He,E", + "Edge4;:H9,E;:He,E", "Edge1;:Ha,E;:He,E", "Edge2;:Ha,E;:He,E", + "Edge3;:Ha,E;:He,E", "Edge4;:Ha,E;:He,E", "Vertex1;:H8,V;:He,V", + "Vertex2;:H8,V;:He,V", "Vertex3;:H8,V;:He,V", "Vertex4;:H8,V;:He,V", + "Vertex1;:H9,V;:He,V", "Vertex2;:H9,V;:He,V", "Vertex3;:H9,V;:He,V", + "Vertex4;:H9,V;:He,V", "Edge1;:H1,E;:H7,E", "Edge2;:H1,E;:H7,E", + "Edge3;:H1,E;:H7,E", "Edge4;:H1,E;:H7,E", "Edge1;:H2,E;:H7,E", + "Edge2;:H2,E;:H7,E", "Edge3;:H2,E;:H7,E", "Edge4;:H2,E;:H7,E", + "Edge1;:H3,E;:H7,E", "Edge2;:H3,E;:H7,E", "Edge3;:H3,E;:H7,E", + "Edge4;:H3,E;:H7,E", "Face1;:H1,F;:H7,F", "Face1;:H2,F;:H7,F", + "Face1;:H3,F;:H7,F", "Face1;:H4,F;:H7,F", "Face1;:H5,F;:H7,F", + "Face1;:H6,F;:H7,F", })); } @@ -2282,4 +2282,68 @@ TEST_F(TopoShapeExpansionTest, makeElementBSplineFace) })); } +TEST_F(TopoShapeExpansionTest, replaceElementShape) +{ + // Arrange + auto [cube1, cube2] = CreateTwoTopoShapeCubes(); + // We can't use a compound in replaceElementShape, so we'll make a replacement wire and a shell + auto wire {BRepBuilderAPI_MakeWire( + BRepBuilderAPI_MakeEdge(gp_Pnt(0.0, 0.0, 0.0), gp_Pnt(1.0, 0.0, 0.0)), + BRepBuilderAPI_MakeEdge(gp_Pnt(1.0, 0.0, 0.0), gp_Pnt(1.0, 1.0, 0.0)), + BRepBuilderAPI_MakeEdge(gp_Pnt(1.0, 1.0, 0.0), gp_Pnt(0.0, 0.0, 0.0))) + .Wire()}; + auto shell = cube1.makeElementShell(); + auto wires = shell.getSubTopoShapes(TopAbs_WIRE); + // Act + TopoShape& result = shell.replaceElementShape(shell, {{wires[0], wire}}); + Base::BoundBox3d bb = result.getBoundBox(); + // Assert shape is correct + EXPECT_TRUE(PartTestHelpers::boxesMatch(bb, Base::BoundBox3d(0.0, 0.0, 0.0, 1.0, 1.0, 1.0))); + EXPECT_FLOAT_EQ(getArea(result.getShape()), 5); + EXPECT_EQ(result.countSubElements("Wire"), 6); + // Assert that we're creating a correct element map + EXPECT_TRUE(result.getMappedChildElements().empty()); + EXPECT_TRUE(elementsMatch( + result, + { + "Edge1", "Edge1;:H1,E", "Edge1;:H2,E", "Edge1;:H3,E", "Edge2", + "Edge2;:H1,E", "Edge2;:H2,E", "Edge2;:H3,E", "Edge3", "Edge3;:H1,E", + "Edge3;:H2,E", "Edge3;:H3,E", "Edge4;:H1,E", "Edge4;:H2,E", "Edge4;:H3,E", + "Face1;:H2,F", "Face1;:H3,F", "Face1;:H4,F", "Face1;:H5,F", "Face1;:H6,F", + "Vertex1", "Vertex1;:H1,V", "Vertex1;:H2,V", "Vertex2", "Vertex2;:H1,V", + "Vertex2;:H2,V", "Vertex3", "Vertex3;:H1,V", "Vertex3;:H2,V", "Vertex4;:H1,V", + "Vertex4;:H2,V", + })); +} + +TEST_F(TopoShapeExpansionTest, removeElementShape) +{ + // Arrange + auto [cube1, cube2] = CreateTwoTopoShapeCubes(); + auto faces = cube1.getSubTopoShapes(TopAbs_FACE); + // Act + TopoShape result = cube1.removeElementShape({faces[0]}); + Base::BoundBox3d bb = result.getBoundBox(); + // Assert shape is correct + EXPECT_TRUE(PartTestHelpers::boxesMatch(bb, Base::BoundBox3d(0.0, 0.0, 0.0, 1.0, 1.0, 1.0))); + EXPECT_FLOAT_EQ(getArea(result.getShape()), 5); + EXPECT_EQ(result.countSubShapes("Compound"), 1); + EXPECT_EQ(result.countSubShapes("Face"), 5); + // Assert that we're creating a correct element map + EXPECT_TRUE(result.getMappedChildElements().empty()); + EXPECT_TRUE( + elementsMatch(result, + { + "Edge1;:H1,E;:H7,E", "Edge1;:H2,E;:H7,E", "Edge1;:H3,E;:H7,E", + "Edge2;:H1,E;:H7,E", "Edge2;:H2,E;:H7,E", "Edge2;:H3,E;:H7,E", + "Edge3;:H1,E;:H7,E", "Edge3;:H2,E;:H7,E", "Edge3;:H3,E;:H7,E", + "Edge4;:H1,E;:H7,E", "Edge4;:H2,E;:H7,E", "Edge4;:H3,E;:H7,E", + "Face1;:H2,F;:H7,F", "Face1;:H3,F;:H7,F", "Face1;:H4,F;:H7,F", + "Face1;:H5,F;:H7,F", "Face1;:H6,F;:H7,F", "Vertex1;:H1,V;:H7,V", + "Vertex1;:H2,V;:H7,V", "Vertex2;:H1,V;:H7,V", "Vertex2;:H2,V;:H7,V", + "Vertex3;:H1,V;:H7,V", "Vertex3;:H2,V;:H7,V", "Vertex4;:H1,V;:H7,V", + "Vertex4;:H2,V;:H7,V", + })); +} + // NOLINTEND(readability-magic-numbers,cppcoreguidelines-avoid-magic-numbers) From 59b563ca69a54bb6c078fd5c16071af6671b1b6b Mon Sep 17 00:00:00 2001 From: "Zheng, Lei" Date: Tue, 27 Feb 2024 10:09:32 -0500 Subject: [PATCH 3/5] Toponaming/Part: trasnfer in getElementName --- src/App/GeoFeature.cpp | 38 +++- src/App/GeoFeature.h | 6 +- src/App/IndexedName.h | 12 ++ src/App/MappedName.h | 22 +++ src/Mod/Part/App/PartFeature.cpp | 232 ++++++++++++++++++++++++ src/Mod/Part/App/PartFeature.h | 33 ++++ src/Mod/Part/App/TopoShape.cpp | 14 ++ src/Mod/Part/App/TopoShape.h | 8 +- src/Mod/Part/App/TopoShapeExpansion.cpp | 81 +++++++++ 9 files changed, 440 insertions(+), 6 deletions(-) diff --git a/src/App/GeoFeature.cpp b/src/App/GeoFeature.cpp index aeb67d8c70..c6a5b8762c 100644 --- a/src/App/GeoFeature.cpp +++ b/src/App/GeoFeature.cpp @@ -25,6 +25,7 @@ #include +#include "ComplexGeoData.h" #include "GeoFeature.h" #include "GeoFeatureGroupExtension.h" #include "ElementNamingUtils.h" @@ -78,17 +79,46 @@ PyObject* GeoFeature::getPyObject() return Py::new_reference_to(PythonObject); } - -std::pair GeoFeature::getElementName( - const char *name, ElementNameType type) const +std::pair +GeoFeature::getElementName(const char *name, ElementNameType type) const { (void)type; std::pair ret; if(!name) return ret; + auto prop = getPropertyOfGeometry(); + if(!prop) return std::make_pair("", name); - ret.second = name; + auto geo = prop->getComplexData(); + if(!geo) return std::make_pair("", name); + + return _getElementName(name, geo->getElementName(name)); +} + +std::pair +GeoFeature::_getElementName(const char *name, const Data::MappedElement &mapped) const +{ + std::pair ret; + if (mapped.index && mapped.name) { + std::ostringstream ss; + ss << Data::ComplexGeoData::elementMapPrefix() + << mapped.name << '.' << mapped.index; + ret.first = ss.str(); + mapped.index.toString(ret.second); + } else if (mapped.name) { +// FC_TRACE("element mapped name " << name << " not found in " << getFullName()); + ret.first = name; + const char *dot = strrchr(name,'.'); + if(dot) { + // deliberately mangle the old style element name to signal a + // missing reference + ret.second = Data::MISSING_PREFIX; + ret.second += dot+1; + } + } else { + mapped.index.toString(ret.second); + } return ret; } diff --git a/src/App/GeoFeature.h b/src/App/GeoFeature.h index 9f71ee58c7..e43ba869e1 100644 --- a/src/App/GeoFeature.h +++ b/src/App/GeoFeature.h @@ -26,7 +26,7 @@ #include "DocumentObject.h" #include "PropertyGeo.h" - +#include "MappedElement.h" namespace App { @@ -120,6 +120,10 @@ public: * @return Base::Placement The transformation from the global reference coordinate system */ Base::Placement globalPlacement() const; + +protected: + std::pair _getElementName(const char* name, + const Data::MappedElement& mapped) const; }; } //namespace App diff --git a/src/App/IndexedName.h b/src/App/IndexedName.h index 85282b9545..4d5d470e9b 100644 --- a/src/App/IndexedName.h +++ b/src/App/IndexedName.h @@ -147,6 +147,18 @@ public: return result; } + const char * toString(std::string & s) const + { + // Note! s is not cleared on purpose. + std::size_t offset = s.size(); + s += this->type; + if (this->index > 0) + s += std::to_string(this->index); + return s.c_str() + offset; + } + + + /// An indexedName is represented as the simple concatenation of the name and its index, e.g. /// "EDGE1" or "FACE42". friend std::ostream & operator<<(std::ostream & stream, const IndexedName & indexedName) diff --git a/src/App/MappedName.h b/src/App/MappedName.h index 355533e1bd..0d8c30d6d6 100644 --- a/src/App/MappedName.h +++ b/src/App/MappedName.h @@ -474,6 +474,28 @@ public: return appendToBuffer(res, startPosition, len); } + const char * toString(std::string &s, int from=0, int len=-1) const + { + std::size_t offset = s.size(); + int count = this->size(); + if (from < 0) + from = 0; + else if (from >= count) + return s.c_str()+s.size(); + if (len < 0 || len > count - from) + len = count - from; + s.reserve(s.size() + len); + if (from < this->data.size()) { + count = this->data.size() - from; + if (len < count) + count = len; + s.append(this->data.constData()+from, count); + len -= count; + } + s.append(this->postfix.constData(), len); + return s.c_str() + offset; + } + /// Given a (possibly non-empty) std::string buffer, append this instance to it, starting at a /// specified position, and continuing for a specified number of bytes. /// diff --git a/src/Mod/Part/App/PartFeature.cpp b/src/Mod/Part/App/PartFeature.cpp index c830b31ac3..98893da657 100644 --- a/src/Mod/Part/App/PartFeature.cpp +++ b/src/Mod/Part/App/PartFeature.cpp @@ -757,3 +757,235 @@ bool Part::checkIntersection(const TopoDS_Shape& first, const TopoDS_Shape& seco } } + +/** + * Override getElementName to support the Export type. Other calls are passed to the original + * method + * @param name The name to search for, or if non existent, name of current Feature is returned + * @param type An element type name. + * @return The element name located, of + */ +std::pair Feature::getElementName(const char* name, + ElementNameType type) const +{ + if (type != ElementNameType::Export) { + return App::GeoFeature::getElementName(name, type); + } + + // This function is overridden to provide higher level shape topo names that + // are generated on demand, e.g. Wire, Shell, Solid, etc. + + auto prop = Base::freecad_dynamic_cast(getPropertyOfGeometry()); + if (!prop) { + return App::GeoFeature::getElementName(name, type); + } + + TopoShape shape = prop->getShape(); + Data::MappedElement mapped = shape.getElementName(name); + auto res = shape.shapeTypeAndIndex(mapped.index); + static const int MinLowerTopoNames = 3; + static const int MaxLowerTopoNames = 10; + if (res.second && !mapped.name) { + // Here means valid index name, but no mapped name, check to see if + // we shall generate the high level topo name. + // + // The general idea of the algorithm is to find the minimum number of + // lower elements that can identify the given higher element, and + // combine their names to generate the name for the higher element. + // + // In theory, all it takes to find one lower element that only appear + // in the given higher element. To make the algorithm more robust + // against model changes, we shall take minimum MinLowerTopoNames lower + // elements. + // + // On the other hand, it may be possible to take too many elements for + // disambiguation. We shall limit to maximum MaxLowerTopoNames. If the + // chosen elements are not enough to disambiguate the higher element, + // we'll include an index for disambiguation. + + auto subshape = shape.getSubTopoShape(res.first, res.second, true); + TopAbs_ShapeEnum lower; + Data::IndexedName idxName; + if (!subshape.isNull()) { + switch (res.first) { + case TopAbs_WIRE: + lower = TopAbs_EDGE; + idxName = Data::IndexedName::fromConst("Edge", 1); + break; + case TopAbs_SHELL: + case TopAbs_SOLID: + case TopAbs_COMPOUND: + case TopAbs_COMPSOLID: + lower = TopAbs_FACE; + idxName = Data::IndexedName::fromConst("Face", 1); + break; + default: + lower = TopAbs_SHAPE; + } + if (lower != TopAbs_SHAPE) { + typedef std::pair> NameEntry; + std::vector indices; + std::vector names; + std::vector ancestors; + int count = 0; + for (auto& ss : subshape.getSubTopoShapes(lower)) { + auto name = ss.getMappedName(idxName); + if (!name) { + continue; + } + indices.emplace_back(name.size(), + shape.findAncestors(ss.getShape(), res.first)); + names.push_back(name); + if (indices.back().second.size() == 1 && ++count >= MinLowerTopoNames) { + break; + } + } + + if (names.size() >= MaxLowerTopoNames) { + std::stable_sort(indices.begin(), + indices.end(), + [](const NameEntry& a, const NameEntry& b) { + return a.second.size() < b.second.size(); + }); + std::vector sorted; + auto pos = 0; + sorted.reserve(names.size()); + for (auto& v : indices) { + size_t size = ancestors.size(); + if (size == 0) { + ancestors = v.second; + } + else if (size > 1) { + for (auto it = ancestors.begin(); it != ancestors.end();) { + if (std::find(v.second.begin(), v.second.end(), *it) + == v.second.end()) { + it = ancestors.erase(it); + if (ancestors.size() == 1) { + break; + } + } + else { + ++it; + } + } + } + auto itPos = sorted.end(); + if (size == 1 || size != ancestors.size()) { + itPos = sorted.begin() + pos; + ++pos; + } + sorted.insert(itPos, names[v.first]); + if (size == 1 && sorted.size() >= MinLowerTopoNames) { + break; + } + } + } + + names.resize(std::min((int)names.size(), MaxLowerTopoNames)); + if (names.size()) { + std::string op; + if (ancestors.size() > 1) { + // The current chosen elements are not enough to + // identify the higher element, generate an index for + // disambiguation. + auto it = std::find(ancestors.begin(), ancestors.end(), res.second); + if (it == ancestors.end()) { + assert(0 && "ancestor not found"); // this shouldn't happened + } + else { + op = Data::POSTFIX_TAG + std::to_string(it - ancestors.begin()); + } + } + + // Note: setting names to shape will change its underlying + // shared element name table. This actually violates the + // const'ness of this function. + // + // To be const correct, we should have made the element + // name table to be implicit sharing (i.e. copy on change). + // + // Not sure if there is any side effect of indirectly + // change the element map inside the Shape property without + // recording the change in undo stack. + // + mapped.name = shape.setElementComboName(mapped.index, + names, + mapped.index.getType(), + op.c_str()); + } + } + } + return App::GeoFeature::_getElementName(name, mapped); + } + + if (!res.second && mapped.name) { + const char* dot = strchr(name, '.'); + if (dot) { + ++dot; + // Here means valid mapped name, but cannot find the corresponding + // indexed name. This usually means the model has been changed. The + // original indexed name is usually appended to the mapped name + // separated by a dot. We use it as a clue to decode the combo name + // set above, and try to single out one sub shape that has all the + // lower elements encoded in the combo name. But since we don't + // always use all the lower elements for encoding, this can only be + // consider a heuristics. + if (Data::hasMissingElement(dot)) { + dot += strlen(Data::MISSING_PREFIX); + } + std::pair occindex = shape.shapeTypeAndIndex(dot); + if (occindex.second > 0) { + auto idxName = Data::IndexedName::fromConst(shape.shapeName(occindex.first).c_str(), + occindex.second); + std::string postfix; + auto names = + shape.decodeElementComboName(idxName, mapped.name, idxName.getType(), &postfix); + std::vector ancestors; + for (auto& name : names) { + auto index = shape.getIndexedName(name); + if (!index) { + ancestors.clear(); + break; + } + auto oidx = shape.shapeTypeAndIndex(index); + auto subshape = shape.getSubShape(oidx.first, oidx.second); + if (subshape.IsNull()) { + ancestors.clear(); + break; + } + auto current = shape.findAncestors(subshape, occindex.first); + if (ancestors.empty()) { + ancestors = std::move(current); + } + else { + for (auto it = ancestors.begin(); it != ancestors.end();) { + if (std::find(current.begin(), current.end(), *it) == current.end()) { + it = ancestors.erase(it); + } + else { + ++it; + } + } + if (ancestors.empty()) { // model changed beyond recognition, bail! + break; + } + } + } + if (ancestors.size() > 1 && boost::starts_with(postfix, Data::POSTFIX_INDEX)) { + std::istringstream iss(postfix.c_str() + strlen(Data::POSTFIX_INDEX)); + int idx; + if (iss >> idx && idx >= 0 && idx < (int)ancestors.size()) { + ancestors.resize(1, ancestors[idx]); + } + } + if (ancestors.size() == 1) { + idxName.setIndex(ancestors.front()); + mapped.index = idxName; + return App::GeoFeature::_getElementName(name, mapped); + } + } + } + } + + return App::GeoFeature::getElementName(name, type); +} \ No newline at end of file diff --git a/src/Mod/Part/App/PartFeature.h b/src/Mod/Part/App/PartFeature.h index 543e03f96d..b93d80b6e0 100644 --- a/src/Mod/Part/App/PartFeature.h +++ b/src/Mod/Part/App/PartFeature.h @@ -64,6 +64,39 @@ public: PyObject* getPyObject() override; + std::pair getElementName( + const char *name, ElementNameType type=Normal) const override; + +// static std::list getElementHistory(App::DocumentObject *obj, +// const char *name, bool recursive=true, bool sameType=false); +// +// static QVector +// getRelatedElements(App::DocumentObject *obj, const char *name, bool sameType=true, bool withCache=true); +// +// /** Obtain the element name from a feature based of the element name of its source feature +// * +// * @param obj: current feature +// * @param subname: sub-object/element reference +// * @param src: source feature +// * @param srcSub: sub-object/element reference of the source +// * @param single: if true, then return upon first match is found, or else +// * return all matches. Multiple matches are possible for +// * compound of multiple instances of the same source shape. +// * +// * @return Return a vector of pair of new style and old style element names. +// */ +// static QVector +// getElementFromSource(App::DocumentObject *obj, +// const char *subname, +// App::DocumentObject *src, +// const char *srcSub, +// bool single = false); +// +// TopLoc_Location getLocation() const; +// +// virtual DocumentObject *getSubObject(const char *subname, PyObject **pyObj, +// Base::Matrix4D *mat, bool transform, int depth) const override; + TopLoc_Location getLocation() const; DocumentObject *getSubObject(const char *subname, PyObject **pyObj, diff --git a/src/Mod/Part/App/TopoShape.cpp b/src/Mod/Part/App/TopoShape.cpp index 4cbb2db9d6..e669441deb 100644 --- a/src/Mod/Part/App/TopoShape.cpp +++ b/src/Mod/Part/App/TopoShape.cpp @@ -477,6 +477,20 @@ std::pair TopoShape::shapeTypeAndIndex(const char *name) { return std::make_pair(type,idx); } +std::pair +TopoShape::shapeTypeAndIndex(const Data::IndexedName & element) +{ + if (!element) + return std::make_pair(TopAbs_SHAPE, 0); + static const std::string _subshape("SubShape"); + if (boost::equals(element.getType(), _subshape)) + return std::make_pair(TopAbs_SHAPE, element.getIndex()); + TopAbs_ShapeEnum shapetype = shapeType(element.getType(), true); + if (shapetype == TopAbs_SHAPE) + return std::make_pair(TopAbs_SHAPE, 0); + return std::make_pair(shapetype, element.getIndex()); +} + TopAbs_ShapeEnum TopoShape::shapeType(const char *type, bool silent) { if(type) { initShapeNameMap(); diff --git a/src/Mod/Part/App/TopoShape.h b/src/Mod/Part/App/TopoShape.h index b5840144f3..ca3445f354 100644 --- a/src/Mod/Part/App/TopoShape.h +++ b/src/Mod/Part/App/TopoShape.h @@ -1131,13 +1131,19 @@ public: static const std::string& shapeName(TopAbs_ShapeEnum type, bool silent = false); const std::string& shapeName(bool silent = false) const; static std::pair shapeTypeAndIndex(const char* name); + static std::pair shapeTypeAndIndex(const Data::IndexedName &name); - Data::MappedName setElementComboName(const Data::IndexedName & element, + Data::MappedName setElementComboName(const Data::IndexedName & element, const std::vector &names, const char *marker=nullptr, const char *op=nullptr, const Data::ElementIDRefs *sids=nullptr); + std::vector decodeElementComboName(const Data::IndexedName& element, + const Data::MappedName& name, + const char* marker = nullptr, + std::string* postfix = nullptr) const; + /** @name sub shape cached functions * * Mapped element names introduces some overhead when getting sub shapes diff --git a/src/Mod/Part/App/TopoShapeExpansion.cpp b/src/Mod/Part/App/TopoShapeExpansion.cpp index b6829b3260..44ad847205 100644 --- a/src/Mod/Part/App/TopoShapeExpansion.cpp +++ b/src/Mod/Part/App/TopoShapeExpansion.cpp @@ -4054,6 +4054,87 @@ Data::MappedName TopoShape::setElementComboName(const Data::IndexedName& element return elementMap()->setElementName(element, newName, Tag, &sids); } +std::vector +TopoShape::decodeElementComboName(const Data::IndexedName &element, + const Data::MappedName &name, + const char *marker, + std::string *postfix) const +{ + std::vector names; + if (!element) + return names; + if (!marker) + marker = ""; + int plen = (int)elementMapPrefix().size(); + int markerLen = strlen(marker); + int len; + int pos = name.findTagInElementName(nullptr, &len); + if (pos < 0) { + // It is possible to encode combo name without using a tag, e.g. + // Sketcher object creates wire using edges that are created by itself, + // so there will be no tag to encode. + // + // In this case, just search for the brackets + len = name.find("("); + if (len < 0) { + // No bracket is also possible, if there is only one name in the combo + pos = len = name.size(); + } else { + pos = name.find(")"); + if (pos < 0) { + // non closing bracket? + return {}; + } + ++pos; + } + if (len <= (int)markerLen) + return {}; + len -= markerLen+plen; + } + + if (name.find(elementMapPrefix(), len) != len + || name.find(marker, len+plen) != len+plen) + return {}; + + names.emplace_back(name, 0, len); + + std::string text; + len += plen + markerLen; + name.toString(text, len, pos-len); + + if (this->Hasher) { + if (auto id = App::StringID::fromString(names.back().toRawBytes())) { + if (App::StringIDRef sid = this->Hasher->getID(id)) { + names.pop_back(); + names.emplace_back(sid); + } + else + return names; + } + if (auto id = App::StringID::fromString(text.c_str())) { + if (App::StringIDRef sid = this->Hasher->getID(id)) + text = sid.dataToText(); + else + return names; + } + } + if (text.empty() || text[0] != '(') + return names; + auto endPos = text.rfind(')'); + if (endPos == std::string::npos) + return names; + + if (postfix) + *postfix = text.substr(endPos+1); + + text.resize(endPos); + std::istringstream iss(text.c_str()+1); + std::string token; + while(std::getline(iss, token, '|')) + names.emplace_back(token); + return names; +} + /** * Reorient the outer and inner wires of the TopoShape * From 7d0afaec5461e074d011ccde06bafe60e53a2f1b Mon Sep 17 00:00:00 2001 From: bgbsww Date: Tue, 27 Feb 2024 10:11:35 -0500 Subject: [PATCH 4/5] Toposhape/Part: cleanup and test getElementName --- src/App/GeoFeature.cpp | 4 +- src/App/IndexedName.h | 12 ----- src/App/MappedName.h | 22 --------- src/Mod/Part/App/PartFeature.cpp | 2 +- src/Mod/Part/App/PartFeature.h | 30 ------------ src/Mod/Part/App/TopoShapeExpansion.cpp | 54 ++++++++++++--------- tests/src/Mod/Part/App/CMakeLists.txt | 1 + tests/src/Mod/Part/App/PartFeature.cpp | 62 +++++++++++++++++++++++++ 8 files changed, 98 insertions(+), 89 deletions(-) create mode 100644 tests/src/Mod/Part/App/PartFeature.cpp diff --git a/src/App/GeoFeature.cpp b/src/App/GeoFeature.cpp index c6a5b8762c..92421cb912 100644 --- a/src/App/GeoFeature.cpp +++ b/src/App/GeoFeature.cpp @@ -105,7 +105,7 @@ GeoFeature::_getElementName(const char *name, const Data::MappedElement &mapped) ss << Data::ComplexGeoData::elementMapPrefix() << mapped.name << '.' << mapped.index; ret.first = ss.str(); - mapped.index.toString(ret.second); + mapped.index.appendToStringBuffer(ret.second); } else if (mapped.name) { // FC_TRACE("element mapped name " << name << " not found in " << getFullName()); ret.first = name; @@ -117,7 +117,7 @@ GeoFeature::_getElementName(const char *name, const Data::MappedElement &mapped) ret.second += dot+1; } } else { - mapped.index.toString(ret.second); + mapped.index.appendToStringBuffer(ret.second); } return ret; } diff --git a/src/App/IndexedName.h b/src/App/IndexedName.h index 4d5d470e9b..85282b9545 100644 --- a/src/App/IndexedName.h +++ b/src/App/IndexedName.h @@ -147,18 +147,6 @@ public: return result; } - const char * toString(std::string & s) const - { - // Note! s is not cleared on purpose. - std::size_t offset = s.size(); - s += this->type; - if (this->index > 0) - s += std::to_string(this->index); - return s.c_str() + offset; - } - - - /// An indexedName is represented as the simple concatenation of the name and its index, e.g. /// "EDGE1" or "FACE42". friend std::ostream & operator<<(std::ostream & stream, const IndexedName & indexedName) diff --git a/src/App/MappedName.h b/src/App/MappedName.h index 0d8c30d6d6..355533e1bd 100644 --- a/src/App/MappedName.h +++ b/src/App/MappedName.h @@ -474,28 +474,6 @@ public: return appendToBuffer(res, startPosition, len); } - const char * toString(std::string &s, int from=0, int len=-1) const - { - std::size_t offset = s.size(); - int count = this->size(); - if (from < 0) - from = 0; - else if (from >= count) - return s.c_str()+s.size(); - if (len < 0 || len > count - from) - len = count - from; - s.reserve(s.size() + len); - if (from < this->data.size()) { - count = this->data.size() - from; - if (len < count) - count = len; - s.append(this->data.constData()+from, count); - len -= count; - } - s.append(this->postfix.constData(), len); - return s.c_str() + offset; - } - /// Given a (possibly non-empty) std::string buffer, append this instance to it, starting at a /// specified position, and continuing for a specified number of bytes. /// diff --git a/src/Mod/Part/App/PartFeature.cpp b/src/Mod/Part/App/PartFeature.cpp index 98893da657..2212f4695a 100644 --- a/src/Mod/Part/App/PartFeature.cpp +++ b/src/Mod/Part/App/PartFeature.cpp @@ -988,4 +988,4 @@ std::pair Feature::getElementName(const char* name, } return App::GeoFeature::getElementName(name, type); -} \ No newline at end of file +} diff --git a/src/Mod/Part/App/PartFeature.h b/src/Mod/Part/App/PartFeature.h index b93d80b6e0..5e377e6e55 100644 --- a/src/Mod/Part/App/PartFeature.h +++ b/src/Mod/Part/App/PartFeature.h @@ -67,36 +67,6 @@ public: std::pair getElementName( const char *name, ElementNameType type=Normal) const override; -// static std::list getElementHistory(App::DocumentObject *obj, -// const char *name, bool recursive=true, bool sameType=false); -// -// static QVector -// getRelatedElements(App::DocumentObject *obj, const char *name, bool sameType=true, bool withCache=true); -// -// /** Obtain the element name from a feature based of the element name of its source feature -// * -// * @param obj: current feature -// * @param subname: sub-object/element reference -// * @param src: source feature -// * @param srcSub: sub-object/element reference of the source -// * @param single: if true, then return upon first match is found, or else -// * return all matches. Multiple matches are possible for -// * compound of multiple instances of the same source shape. -// * -// * @return Return a vector of pair of new style and old style element names. -// */ -// static QVector -// getElementFromSource(App::DocumentObject *obj, -// const char *subname, -// App::DocumentObject *src, -// const char *srcSub, -// bool single = false); -// -// TopLoc_Location getLocation() const; -// -// virtual DocumentObject *getSubObject(const char *subname, PyObject **pyObj, -// Base::Matrix4D *mat, bool transform, int depth) const override; - TopLoc_Location getLocation() const; DocumentObject *getSubObject(const char *subname, PyObject **pyObj, diff --git a/src/Mod/Part/App/TopoShapeExpansion.cpp b/src/Mod/Part/App/TopoShapeExpansion.cpp index 44ad847205..93ce4de8e6 100644 --- a/src/Mod/Part/App/TopoShapeExpansion.cpp +++ b/src/Mod/Part/App/TopoShapeExpansion.cpp @@ -4054,17 +4054,18 @@ Data::MappedName TopoShape::setElementComboName(const Data::IndexedName& element return elementMap()->setElementName(element, newName, Tag, &sids); } -std::vector -TopoShape::decodeElementComboName(const Data::IndexedName &element, - const Data::MappedName &name, - const char *marker, - std::string *postfix) const +std::vector TopoShape::decodeElementComboName(const Data::IndexedName& element, + const Data::MappedName& name, + const char* marker, + std::string* postfix) const { std::vector names; - if (!element) + if (!element) { return names; - if (!marker) + } + if (!marker) { marker = ""; + } int plen = (int)elementMapPrefix().size(); int markerLen = strlen(marker); int len; @@ -4079,7 +4080,8 @@ TopoShape::decodeElementComboName(const Data::IndexedName &element, if (len < 0) { // No bracket is also possible, if there is only one name in the combo pos = len = name.size(); - } else { + } + else { pos = name.find(")"); if (pos < 0) { // non closing bracket? @@ -4087,20 +4089,21 @@ TopoShape::decodeElementComboName(const Data::IndexedName &element, } ++pos; } - if (len <= (int)markerLen) + if (len <= (int)markerLen) { return {}; - len -= markerLen+plen; + } + len -= markerLen + plen; } - if (name.find(elementMapPrefix(), len) != len - || name.find(marker, len+plen) != len+plen) + if (name.find(elementMapPrefix(), len) != len || name.find(marker, len + plen) != len + plen) { return {}; + } names.emplace_back(name, 0, len); std::string text; len += plen + markerLen; - name.toString(text, len, pos-len); + name.appendToBuffer(text, len, pos - len); if (this->Hasher) { if (auto id = App::StringID::fromString(names.back().toRawBytes())) { @@ -4108,30 +4111,37 @@ TopoShape::decodeElementComboName(const Data::IndexedName &element, names.pop_back(); names.emplace_back(sid); } - else + else { return names; + } } if (auto id = App::StringID::fromString(text.c_str())) { - if (App::StringIDRef sid = this->Hasher->getID(id)) + if (App::StringIDRef sid = this->Hasher->getID(id)) { text = sid.dataToText(); - else + } + else { return names; + } } } - if (text.empty() || text[0] != '(') + if (text.empty() || text[0] != '(') { return names; + } auto endPos = text.rfind(')'); - if (endPos == std::string::npos) + if (endPos == std::string::npos) { return names; + } - if (postfix) - *postfix = text.substr(endPos+1); + if (postfix) { + *postfix = text.substr(endPos + 1); + } text.resize(endPos); - std::istringstream iss(text.c_str()+1); + std::istringstream iss(text.c_str() + 1); std::string token; - while(std::getline(iss, token, '|')) + while (std::getline(iss, token, '|')) { names.emplace_back(token); + } return names; } diff --git a/tests/src/Mod/Part/App/CMakeLists.txt b/tests/src/Mod/Part/App/CMakeLists.txt index ee397c0f81..ceea6c5787 100644 --- a/tests/src/Mod/Part/App/CMakeLists.txt +++ b/tests/src/Mod/Part/App/CMakeLists.txt @@ -11,6 +11,7 @@ target_sources( ${CMAKE_CURRENT_SOURCE_DIR}/FeaturePartCut.cpp ${CMAKE_CURRENT_SOURCE_DIR}/FeaturePartFuse.cpp ${CMAKE_CURRENT_SOURCE_DIR}/FeatureRevolution.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/PartFeature.cpp ${CMAKE_CURRENT_SOURCE_DIR}/PartFeatures.cpp ${CMAKE_CURRENT_SOURCE_DIR}/PartTestHelpers.cpp ${CMAKE_CURRENT_SOURCE_DIR}/TopoShape.cpp diff --git a/tests/src/Mod/Part/App/PartFeature.cpp b/tests/src/Mod/Part/App/PartFeature.cpp new file mode 100644 index 0000000000..f42d306245 --- /dev/null +++ b/tests/src/Mod/Part/App/PartFeature.cpp @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later + +#include "gtest/gtest.h" + +#include "Mod/Part/App/FeaturePartCommon.h" +#include +#include +#include "PartTestHelpers.h" + +using namespace Part; +using namespace PartTestHelpers; + +class FeaturePartTest: public ::testing::Test, public PartTestHelperClass +{ +protected: + static void SetUpTestSuite() + { + tests::initApplication(); + } + + + void SetUp() override + { + createTestDoc(); + _common = dynamic_cast(_doc->addObject("Part::Common")); + } + + void TearDown() override + {} + + Common* _common = nullptr; // NOLINT Can't be private in a test framework +}; + +TEST_F(FeaturePartTest, testGetElementName) +{ + // Arrange + _boxes[0]->Shape.getShape().Tag = 1L; + _boxes[1]->Shape.getShape().Tag = 2L; + _common->Base.setValue(_boxes[0]); + _common->Tool.setValue(_boxes[1]); + + // Act + _common->execute(); + const TopoShape& ts = _common->Shape.getShape(); + + auto namePair = _common->getElementName("test"); + auto namePairExport = _common->getElementName("test", App::GeoFeature::Export); + auto namePairSelf = _common->getElementName(nullptr); + // Assert + EXPECT_STREQ(namePair.first.c_str(), ""); + EXPECT_STREQ(namePair.second.c_str(), "test"); + EXPECT_STREQ(namePairExport.first.c_str(), ""); + EXPECT_STREQ(namePairExport.second.c_str(), "test"); + EXPECT_STREQ(namePairSelf.first.c_str(), ""); + EXPECT_STREQ(namePairSelf.second.c_str(), ""); +#ifndef FC_USE_TNP_FIX + EXPECT_EQ(ts.getElementMap().size(), 0); +#else + EXPECT_EQ(ts.getElementMap().size(), 26); // Value and code TBD +#endif + // TBD +} From a4efcf0533d69ee63c967bc9270ad06687ea8716 Mon Sep 17 00:00:00 2001 From: Chris Hennes Date: Wed, 28 Feb 2024 19:18:45 -0600 Subject: [PATCH 5/5] Toponaming/Part: Clang-format cleanup --- src/App/GeoFeature.cpp | 32 +++++++++++++++++++------------- src/Mod/Part/App/TopoShape.cpp | 12 +++++++----- src/Mod/Part/App/TopoShape.h | 2 +- 3 files changed, 27 insertions(+), 19 deletions(-) diff --git a/src/App/GeoFeature.cpp b/src/App/GeoFeature.cpp index 92421cb912..1c96e9e299 100644 --- a/src/App/GeoFeature.cpp +++ b/src/App/GeoFeature.cpp @@ -88,37 +88,43 @@ GeoFeature::getElementName(const char *name, ElementNameType type) const if(!name) return ret; auto prop = getPropertyOfGeometry(); - if(!prop) return std::make_pair("", name); + if (!prop) { + return std::make_pair("", name); + } auto geo = prop->getComplexData(); - if(!geo) return std::make_pair("", name); + if (!geo) { + return std::make_pair("", name); + } return _getElementName(name, geo->getElementName(name)); } -std::pair -GeoFeature::_getElementName(const char *name, const Data::MappedElement &mapped) const +std::pair +GeoFeature::_getElementName(const char* name, const Data::MappedElement& mapped) const { - std::pair ret; + std::pair ret; if (mapped.index && mapped.name) { std::ostringstream ss; - ss << Data::ComplexGeoData::elementMapPrefix() - << mapped.name << '.' << mapped.index; + ss << Data::ComplexGeoData::elementMapPrefix() << mapped.name << '.' << mapped.index; ret.first = ss.str(); mapped.index.appendToStringBuffer(ret.second); - } else if (mapped.name) { -// FC_TRACE("element mapped name " << name << " not found in " << getFullName()); + } + else if (mapped.name) { + // FC_TRACE("element mapped name " << name << " not found in " << getFullName()); ret.first = name; - const char *dot = strrchr(name,'.'); - if(dot) { + const char* dot = strrchr(name, '.'); + if (dot) { // deliberately mangle the old style element name to signal a // missing reference ret.second = Data::MISSING_PREFIX; - ret.second += dot+1; + ret.second += dot + 1; } - } else { + } + else { mapped.index.appendToStringBuffer(ret.second); } + return ret; } diff --git a/src/Mod/Part/App/TopoShape.cpp b/src/Mod/Part/App/TopoShape.cpp index e669441deb..b303f2ad50 100644 --- a/src/Mod/Part/App/TopoShape.cpp +++ b/src/Mod/Part/App/TopoShape.cpp @@ -477,17 +477,19 @@ std::pair TopoShape::shapeTypeAndIndex(const char *name) { return std::make_pair(type,idx); } -std::pair -TopoShape::shapeTypeAndIndex(const Data::IndexedName & element) +std::pair TopoShape::shapeTypeAndIndex(const Data::IndexedName& element) { - if (!element) + if (!element) { return std::make_pair(TopAbs_SHAPE, 0); + } static const std::string _subshape("SubShape"); - if (boost::equals(element.getType(), _subshape)) + if (boost::equals(element.getType(), _subshape)) { return std::make_pair(TopAbs_SHAPE, element.getIndex()); + } TopAbs_ShapeEnum shapetype = shapeType(element.getType(), true); - if (shapetype == TopAbs_SHAPE) + if (shapetype == TopAbs_SHAPE) { return std::make_pair(TopAbs_SHAPE, 0); + } return std::make_pair(shapetype, element.getIndex()); } diff --git a/src/Mod/Part/App/TopoShape.h b/src/Mod/Part/App/TopoShape.h index ca3445f354..788648522d 100644 --- a/src/Mod/Part/App/TopoShape.h +++ b/src/Mod/Part/App/TopoShape.h @@ -1131,7 +1131,7 @@ public: static const std::string& shapeName(TopAbs_ShapeEnum type, bool silent = false); const std::string& shapeName(bool silent = false) const; static std::pair shapeTypeAndIndex(const char* name); - static std::pair shapeTypeAndIndex(const Data::IndexedName &name); + static std::pair shapeTypeAndIndex(const Data::IndexedName &name); Data::MappedName setElementComboName(const Data::IndexedName & element, const std::vector &names,