From 8811a590b055c64da63098e2dac088c04dd424ff Mon Sep 17 00:00:00 2001 From: "Zheng, Lei" Date: Mon, 15 Jan 2024 22:41:24 -0500 Subject: [PATCH 1/5] ShapeMapper code from RT branch to new TopoShapeMapper files --- src/Mod/Part/App/CMakeLists.txt | 2 + src/Mod/Part/App/TopoShape.h | 56 ++++++ src/Mod/Part/App/TopoShapeMapper.cpp | 75 ++++++++ src/Mod/Part/App/TopoShapeMapper.h | 255 +++++++++++++++++++++++++++ 4 files changed, 388 insertions(+) create mode 100644 src/Mod/Part/App/TopoShapeMapper.cpp create mode 100644 src/Mod/Part/App/TopoShapeMapper.h diff --git a/src/Mod/Part/App/CMakeLists.txt b/src/Mod/Part/App/CMakeLists.txt index bf0ce716eb..1a85f3b620 100644 --- a/src/Mod/Part/App/CMakeLists.txt +++ b/src/Mod/Part/App/CMakeLists.txt @@ -533,6 +533,8 @@ SET(Part_SRCS TopoShapeCache.cpp TopoShapeCache.h TopoShapeExpansion.cpp + TopoShapeMapper.h + TopoShapeMapper.cpp TopoShapeOpCode.h edgecluster.cpp edgecluster.h diff --git a/src/Mod/Part/App/TopoShape.h b/src/Mod/Part/App/TopoShape.h index ad4ef2a780..a80ce07946 100644 --- a/src/Mod/Part/App/TopoShape.h +++ b/src/Mod/Part/App/TopoShape.h @@ -613,6 +613,27 @@ public: bool hasPendingElementMap() const; + /** Helper class to return the generated and modified shape given an input shape + * + * Shape history information is extracted using OCCT APIs + * BRepBuilderAPI_MakeShape::Generated/Modified(). However, there is often + * some glitches in various derived class. So we use this class as an + * abstraction, and create various derived classes to deal with the glitches. + */ + struct PartExport Mapper { + /// Helper vector for temporary storage of both generated and modified shapes + mutable std::vector _res; + virtual ~Mapper() {} + /// Return a list of shape generated from the given input shape + virtual const std::vector &generated(const TopoDS_Shape &) const { + return _res; + } + /// Return a list of shape modified from the given input shape + virtual const std::vector &modified(const TopoDS_Shape &) const { + return _res; + } + }; + /** Make a compound shape * * @param shapes: input shapes @@ -629,6 +650,41 @@ public: */ TopoShape &makeElementCompound(const std::vector &shapes, const char *op=nullptr, bool force=true); + struct BRepFillingParams; + + /** Provides information about the continuity of a curve. + * Corresponds to OCCT type GeomAbs_Shape + */ + enum class Continuity { + /// Only geometric continuity + C0, + /** for each point on the curve, the tangent vectors 'on the right' and 'on + * the left' are collinear with the same orientation. + */ + G1, + /** Continuity of the first derivative. The 'C1' curve is also 'G1' but, in + * addition, the tangent vectors 'on the right' and 'on the left' are equal. + */ + C1, + + /** For each point on the curve, the normalized normal vectors 'on the + * right' and 'on the left' are equal. + */ + G2, + + /// Continuity of the second derivative. + C2, + + /// Continuity of the third derivative. + C3, + + /** Continuity of the N-th derivative, whatever is the value given for N + * (infinite order of continuity). Also provides information about the + * continuity of a surface. + */ + CN, + }; + friend class TopoShapeCache; private: diff --git a/src/Mod/Part/App/TopoShapeMapper.cpp b/src/Mod/Part/App/TopoShapeMapper.cpp new file mode 100644 index 0000000000..89ea456a40 --- /dev/null +++ b/src/Mod/Part/App/TopoShapeMapper.cpp @@ -0,0 +1,75 @@ +#include "TopoShapeMapper.h" + +namespace Part +{ + +void ShapeMapper::expand(const TopoDS_Shape &d, std::vector &shapes) +{ + if (d.IsNull()) return; + for(TopExp_Explorer xp(d, TopAbs_FACE);xp.More();xp.Next()) + shapes.push_back(xp.Current()); + for(TopExp_Explorer xp(d, TopAbs_EDGE, TopAbs_FACE);xp.More();xp.Next()) + shapes.push_back(xp.Current()); + for(TopExp_Explorer xp(d, TopAbs_VERTEX, TopAbs_EDGE);xp.More();xp.Next()) + shapes.push_back(xp.Current()); +} + +void ShapeMapper::populate(bool generated, + const TopTools_ListOfShape &src, + const TopTools_ListOfShape &dst) +{ + for(TopTools_ListIteratorOfListOfShape it(src);it.More();it.Next()) + populate(generated, it.Value(), dst); +} + +void ShapeMapper::populate(bool generated, + const TopoShape &src, + const TopTools_ListOfShape &dst) +{ + if(src.isNull()) + return; + std::vector dstShapes; + for(TopTools_ListIteratorOfListOfShape it(dst);it.More();it.Next()) + expand(it.Value(), dstShapes); + insert(generated, src.getShape(), dstShapes); +} + +void ShapeMapper::insert(bool generated, const TopoDS_Shape &s, const TopoDS_Shape &d) +{ + if (s.IsNull() || d.IsNull()) return; + // Prevent an element shape from being both generated and modified + if (generated) { + if (_modifiedShapes.count(d)) + return; + _generatedShapes.insert(d); + } else { + if( _generatedShapes.count(d)) + return; + _modifiedShapes.insert(d); + } + auto &entry = generated?_generated[s]:_modified[s]; + if(entry.shapeSet.insert(d).second) + entry.shapes.push_back(d); +}; + +void ShapeMapper::insert(bool generated, const TopoDS_Shape &s, const std::vector &d) +{ + if (s.IsNull() || d.empty()) return; + auto &entry = generated?_generated[s]:_modified[s]; + for(auto &shape : d) { + // Prevent an element shape from being both generated and modified + if (generated) { + if (_modifiedShapes.count(shape)) + continue; + _generatedShapes.insert(shape); + } else { + if( _generatedShapes.count(shape)) + continue; + _modifiedShapes.insert(shape); + } + if(entry.shapeSet.insert(shape).second) + entry.shapes.push_back(shape); + } +}; + +} diff --git a/src/Mod/Part/App/TopoShapeMapper.h b/src/Mod/Part/App/TopoShapeMapper.h new file mode 100644 index 0000000000..736aebc21c --- /dev/null +++ b/src/Mod/Part/App/TopoShapeMapper.h @@ -0,0 +1,255 @@ +#include +#include +#include + +#include +#include +#include "TopoShape.h" + +class BRepBuilderAPI_MakeShape; +class BRepTools_History; +class BRepTools_ReShape; +class ShapeFix_Root; + +namespace Part +{ + +/// Shape hasher that ignore orientation +struct ShapeHasher { + inline size_t operator()(const TopoShape &s) const { + return std::hash {}(s.getShape()); + // return TopTools_ShapeMapHasher{}(s.getShape()); + } + inline size_t operator()(const TopoDS_Shape &s) const { + return std::hash {}(s); + } + inline bool operator()(const TopoShape &a, const TopoShape &b) const { + return a.getShape().IsSame(b.getShape()); + } + inline bool operator()(const TopoDS_Shape &a, const TopoDS_Shape &b) const { + return a.IsSame(b); + } + template + static inline void hash_combine(std::size_t& seed, const T& v) + { + // copied from boost::hash_combine + std::hash hasher; + seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2); + } + inline size_t operator()(const std::pair &s) const { + size_t res = std::hash {}(s.first.getShape()); + hash_combine(res, std::hash {}(s.second.getShape())); + return res; + } + inline size_t operator()(const std::pair &s) const { + size_t res = std::hash {}(s.first); + hash_combine(res, std::hash {}(s.second)); + return res; + } + inline bool operator()(const std::pair &a, + const std::pair &b) const { + return a.first.getShape().IsSame(b.first.getShape()) + && a.second.getShape().IsSame(b.second.getShape()); + } + inline bool operator()(const std::pair &a, + const std::pair &b) const { + return a.first.IsSame(b.first) + && a.second.IsSame(b.second); + } +}; + +/** Shape mapper for generic BRepBuilderAPI_MakeShape derived class + * + * Uses BRepBuilderAPI_MakeShape::Modified/Generated() function to extract + * shape history for generating mapped element names + */ +struct PartExport MapperMaker: TopoShape::Mapper { + BRepBuilderAPI_MakeShape &maker; + MapperMaker(BRepBuilderAPI_MakeShape &maker) + :maker(maker) + {} + virtual const std::vector &modified(const TopoDS_Shape &s) const override; + virtual const std::vector &generated(const TopoDS_Shape &s) const override; +}; + +/** Shape mapper for BRepTools_History + * + * Uses BRepTools_History::Modified/Generated() function to extract + * shape history for generating mapped element names + */ +struct PartExport MapperHistory: TopoShape::Mapper { + Handle(BRepTools_History) history; + MapperHistory(const Handle(BRepTools_History) &history); + MapperHistory(const Handle(BRepTools_ReShape) &reshape); + MapperHistory(ShapeFix_Root &fix); + virtual const std::vector &modified(const TopoDS_Shape &s) const override; + virtual const std::vector &generated(const TopoDS_Shape &s) const override; +}; + +/** Shape mapper for user defined shape mapping + */ +struct PartExport ShapeMapper: TopoShape::Mapper { + virtual ~ShapeMapper() noexcept = default; + + /** Populate mapping from a source shape to a list of shape + * + * @param generated: whether the shape is generated + * @param src: source shape + * @param dst: a list of sub shapes in the new shape + * + * The source will be expanded into sub shapes of faces, edges and vertices + * before being inserted into the map. + */ + void populate(bool generated, const TopoShape &src, const TopTools_ListOfShape &dst); + /** Populate mapping from a source sub shape to a list of shape + * + * @param generated: whether the shape is generated + * @param src: a list of sub shapes in the source shape + * @param dst: a list of sub shapes in the new shape + * + * The source will be expanded into sub shapes of faces, edges and vertices + * before being inserted into the map. + */ + void populate(bool generated, const TopTools_ListOfShape &src, const TopTools_ListOfShape &dst); + + /** Populate mapping from a source sub shape to a list of shape + * + * @param generated: whether the shape is generated + * @param src: a list of sub shapes in the source shape + * @param dst: a list of sub shapes in the new shape + * + * The source will be expanded into sub shapes of faces, edges and vertices + * before being inserted into the map. + */ + void populate(bool generated, const std::vector &src, const std::vector &dst) + { + for(auto &s : src) + populate(generated,s,dst); + } + + /** Populate mapping from a source sub shape to a list of shape + * + * @param generated: whether the shape is generated + * @param src: a sub shape of the source shape + * @param dst: a list of sub shapes in the new shape + * + * The source will be expanded into sub shapes of faces, edges and vertices + * before being inserted into the map. + */ + void populate(bool generated, const TopoShape &src, const std::vector &dst) + { + if(src.isNull()) + return; + std::vector dstShapes; + for(auto &d : dst) + expand(d.getShape(), dstShapes); + insert(generated, src.getShape(), dstShapes); + } + + /** Expand a shape into faces, edges and vertices + * @params d: shape to expand + * @param shapes: output sub shapes of faces, edges and vertices + */ + void expand(const TopoDS_Shape &d, std::vector &shapes); + + /** Insert a map entry from a sub shape in the source to a list of sub shapes in the new shape + * + * @params generated: whether the sub shapes are generated or modified + * @param s: a sub shape in the source + * @param d: a list of sub shapes in the new shape + */ + void insert(bool generated, const TopoDS_Shape &s, const std::vector &d); + + /** Insert a map entry from a sub shape in the source to a sub shape in the new shape + * + * @params generated: whether the sub shapes are generated or modified + * @param s: a sub shape in the source + * @param d: a list of sub shapes in the new shape + */ + void insert(bool generated, const TopoDS_Shape &s, const TopoDS_Shape &d); + + virtual const std::vector &generated(const TopoDS_Shape &s) const override { + auto iter = _generated.find(s); + if(iter != _generated.end()) + return iter->second.shapes; + return _res; + } + + virtual const std::vector &modified(const TopoDS_Shape &s) const override { + auto iter = _modified.find(s); + if(iter != _modified.end()) + return iter->second.shapes; + return _res; + } + + std::vector shapes; + std::unordered_set shapeSet; + + struct ShapeValue { + std::vector shapes; + std::unordered_set shapeSet; + }; + typedef std::unordered_map ShapeMap; + ShapeMap _generated; + std::unordered_set _generatedShapes; + ShapeMap _modified; + std::unordered_set _modifiedShapes; +}; + +/// Parameters for TopoShape::makEFilledFace() +struct PartExport TopoShape::BRepFillingParams { + /** Optional initial surface to begin the construction of the surface for the filled face. + * + * It is useful if the surface resulting from construction for the + * algorithm is likely to be complex. The support surface of the face + * under construction is computed by a deformation of Surf which satisfies + * the given constraints. The set of bounding edges defines the wire of + * the face. If no initial surface is given, the algorithm computes it + * automatically. If the set of edges is not connected (Free constraint), + * missing edges are automatically computed. Important: the initial + * surface must have orthogonal local coordinates, i.e. partial + * derivatives dS/du and dS/dv must be orthogonal at each point of + * surface. If this condition breaks, distortions of resulting surface are + * possible + */ + TopoShape surface; + /** Optional map from input edge to continutity order. The default + * continuity order is TopoShape::Continuity::C0. + */ + std::unordered_map orders; + /// Optional map from input shape to face used as support + std::unordered_map supports; + /// Optional begin index to the input shapes to be used as the boundary of the filled face. + int boundary_begin = -1; + /// Optional end index (last index + 1) to the input shapes to be used as the boundary of the filled face. + int boundary_end = -1; + /// The energe minimizing criterion degree; + unsigned int degree = 3; + /// The number of points on the curve NbPntsOnCur + unsigned int ptsoncurve = 15; + /// The number of iterations NbIter + unsigned int numiter = 2; + /// The Boolean Anisotropie + bool anisotropy = false; + /// The 2D tolerance Tol2d + double tol2d = 1e-5; + /// The 3D tolerance Tol3d + double tol3d = 1e-4; + /// The angular tolerance TolAng + double tolG1 = 0.01; + /// The tolerance for curvature TolCur + double tolG2 = 0.1; + /// The highest polynomial degree MaxDeg + unsigned int maxdeg = 8; + /** The greatest number of segments MaxSeg. + * + * If the Boolean Anistropie is true, the algorithm's performance is better + * in cases where the ratio of the length U and the length V indicate a + * great difference between the two. In other words, when the surface is, + * for example, extremely long. + */ + unsigned int maxseg = 9; +}; + + +} From 51ee04ca34047f37fcda30f9936dd461ee42ca30 Mon Sep 17 00:00:00 2001 From: bgbsww Date: Tue, 16 Jan 2024 19:13:29 -0500 Subject: [PATCH 2/5] Tests for transferred TopoShapeMapper objects --- tests/src/Mod/Part/App/CMakeLists.txt | 1 + tests/src/Mod/Part/App/TopoShapeMapper.cpp | 121 +++++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 tests/src/Mod/Part/App/TopoShapeMapper.cpp diff --git a/tests/src/Mod/Part/App/CMakeLists.txt b/tests/src/Mod/Part/App/CMakeLists.txt index f2467f3b12..9c642e65e2 100644 --- a/tests/src/Mod/Part/App/CMakeLists.txt +++ b/tests/src/Mod/Part/App/CMakeLists.txt @@ -15,4 +15,5 @@ target_sources( ${CMAKE_CURRENT_SOURCE_DIR}/TopoShape.cpp ${CMAKE_CURRENT_SOURCE_DIR}/TopoShapeCache.cpp ${CMAKE_CURRENT_SOURCE_DIR}/TopoShapeExpansion.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/TopoShapeMapper.cpp ) diff --git a/tests/src/Mod/Part/App/TopoShapeMapper.cpp b/tests/src/Mod/Part/App/TopoShapeMapper.cpp new file mode 100644 index 0000000000..047dd1c3a9 --- /dev/null +++ b/tests/src/Mod/Part/App/TopoShapeMapper.cpp @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later + +#include "gtest/gtest.h" +#include "src/App/InitApplication.h" +#include +#include "Mod/Part/App/TopoShapeMapper.h" + +#include +#include +#include +#include +#include +#include +#include + +// NOLINTBEGIN(readability-magic-numbers,cppcoreguidelines-avoid-magic-numbers) + +class TopoShapeMapperTest: public ::testing::Test +{ +protected: + static void SetUpTestSuite() + { + tests::initApplication(); + } + + void SetUp() override + { + _docName = App::GetApplication().getUniqueDocumentName("test"); + App::GetApplication().newDocument(_docName.c_str(), "testUser"); + } + + void TearDown() override + { + App::GetApplication().closeDocument(_docName.c_str()); + } + +private: + std::string _docName; +}; + +TEST_F(TopoShapeMapperTest, shapeHasherTests) +{ + // Arrange + auto edge = BRepBuilderAPI_MakeEdge(gp_Pnt(0.0, 0.0, 0.0), gp_Pnt(1.0, 0.0, 0.0)).Edge(); + Part::TopoShape topoShape {edge}; + auto edge2 = BRepBuilderAPI_MakeEdge(gp_Pnt(1.0, 0.0, 0.0), gp_Pnt(1.0, 1.0, 0.0)).Edge(); + Part::TopoShape topoShape2 {edge2}; + std::pair pair1(topoShape, topoShape2); + std::pair pair2(topoShape, topoShape); + std::pair pair3(edge, edge2); + std::pair pair4(edge, edge); + struct Part::ShapeHasher hasher; + + // Act + size_t hash1 = hasher(topoShape); + size_t hash2 = hasher(topoShape2); + size_t hash3 = hasher(edge); + size_t hash4 = hasher(edge2); + size_t hash5 = hasher(topoShape, topoShape); + size_t hash6 = hasher(topoShape, topoShape2); + size_t hash7 = hasher(edge, edge); + size_t hash8 = hasher(edge, edge2); + size_t hash9 = hasher(pair1); + size_t hash10 = hasher(pair2); + size_t hash11 = hasher(pair3); + size_t hash12 = hasher(pair4); + size_t hash13 = hasher(pair1, pair1); + size_t hash14 = hasher(pair1, pair2); + size_t hash15 = hasher(pair3, pair3); + size_t hash16 = hasher(pair3, pair4); + + // Assert + EXPECT_EQ(hash1, hash3); + EXPECT_EQ(hash2, hash4); + EXPECT_NE(hash1, hash2); + EXPECT_TRUE(hash5); + EXPECT_FALSE(hash6); + EXPECT_TRUE(hash7); + EXPECT_FALSE(hash8); + EXPECT_EQ(hash9, hash11); + EXPECT_EQ(hash10, hash12); + EXPECT_NE(hash9, hash10); + EXPECT_TRUE(hash13); + EXPECT_FALSE(hash14); + EXPECT_TRUE(hash15); + EXPECT_FALSE(hash16); +} + +TEST_F(TopoShapeMapperTest, mapperMakerTests) +{ + // How can this be tested? +} + +TEST_F(TopoShapeMapperTest, mapperHistoryTests) +{ + // How can this be tested? +} + +TEST_F(TopoShapeMapperTest, shapeMapperTests) +{ + // Arrange + auto mapper = Part::ShapeMapper(); + auto boxMaker1 = BRepPrimAPI_MakeBox(1.0, 1.0, 1.0); + boxMaker1.Build(); + auto box1 = boxMaker1.Shape(); + Part::TopoShape topoShape1 {box1}; + + // Act + auto e = topoShape1.getSubTopoShapes(TopAbs_EDGE); + mapper.populate(false, box1, {e[0], e[1], e[2], e[3]}); + mapper.populate(true, box1, {e[4], e[5], e[6]}); + std::vector vec1 = mapper.modified(box1); + std::vector vec2 = mapper.generated(box1); + + // Assert + EXPECT_EQ(vec1.size(), 4); + EXPECT_EQ(vec2.size(), 3); +} + + +// // NOLINTEND(readability-magic-numbers,cppcoreguidelines-avoid-magic-numbers) From 160ad0dc8186b50a3e059fb87a8e8ade0526a6d7 Mon Sep 17 00:00:00 2001 From: "Zheng, Lei" Date: Tue, 16 Jan 2024 22:43:39 -0500 Subject: [PATCH 3/5] Restore RT hash code for OCC < 7.8.0 --- src/Mod/Part/App/TopoShapeMapper.h | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/Mod/Part/App/TopoShapeMapper.h b/src/Mod/Part/App/TopoShapeMapper.h index 736aebc21c..f7f4a8e92a 100644 --- a/src/Mod/Part/App/TopoShapeMapper.h +++ b/src/Mod/Part/App/TopoShapeMapper.h @@ -2,6 +2,7 @@ #include #include +#include #include #include #include "TopoShape.h" @@ -17,11 +18,18 @@ namespace Part /// Shape hasher that ignore orientation struct ShapeHasher { inline size_t operator()(const TopoShape &s) const { +#if OCC_VERSION_HEX >= 0x070800 return std::hash {}(s.getShape()); - // return TopTools_ShapeMapHasher{}(s.getShape()); +#else + return s.getShape().HashCode(INT_MAX); +#endif } inline size_t operator()(const TopoDS_Shape &s) const { +#if OCC_VERSION_HEX >= 0x070800 return std::hash {}(s); +#else + return s.HashCode(INT_MAX); +#endif } inline bool operator()(const TopoShape &a, const TopoShape &b) const { return a.getShape().IsSame(b.getShape()); @@ -37,13 +45,23 @@ struct ShapeHasher { seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2); } inline size_t operator()(const std::pair &s) const { +#if OCC_VERSION_HEX >= 0x070800 size_t res = std::hash {}(s.first.getShape()); hash_combine(res, std::hash {}(s.second.getShape())); +#else + size_t res = s.first.getShape().HashCode(INT_MAX); + hash_combine(res, s.second.getShape().HashCode(INT_MAX)); +#endif return res; } inline size_t operator()(const std::pair &s) const { +#if OCC_VERSION_HEX >= 0x070800 size_t res = std::hash {}(s.first); hash_combine(res, std::hash {}(s.second)); +#else + size_t res = s.first.HashCode(INT_MAX); + hash_combine(res, s.second.HashCode(INT_MAX)); +#endif return res; } inline bool operator()(const std::pair &a, From 0cb513f0840f013ce4f0faf87ffcc687beb6f261 Mon Sep 17 00:00:00 2001 From: bgbsww Date: Wed, 17 Jan 2024 08:55:16 -0500 Subject: [PATCH 4/5] Move MapperMaker and MapperHistory out to future PR --- src/Mod/Part/App/TopoShapeMapper.h | 28 ---------------------- tests/src/Mod/Part/App/TopoShapeMapper.cpp | 12 +--------- 2 files changed, 1 insertion(+), 39 deletions(-) diff --git a/src/Mod/Part/App/TopoShapeMapper.h b/src/Mod/Part/App/TopoShapeMapper.h index f7f4a8e92a..89080ae46e 100644 --- a/src/Mod/Part/App/TopoShapeMapper.h +++ b/src/Mod/Part/App/TopoShapeMapper.h @@ -76,34 +76,6 @@ struct ShapeHasher { } }; -/** Shape mapper for generic BRepBuilderAPI_MakeShape derived class - * - * Uses BRepBuilderAPI_MakeShape::Modified/Generated() function to extract - * shape history for generating mapped element names - */ -struct PartExport MapperMaker: TopoShape::Mapper { - BRepBuilderAPI_MakeShape &maker; - MapperMaker(BRepBuilderAPI_MakeShape &maker) - :maker(maker) - {} - virtual const std::vector &modified(const TopoDS_Shape &s) const override; - virtual const std::vector &generated(const TopoDS_Shape &s) const override; -}; - -/** Shape mapper for BRepTools_History - * - * Uses BRepTools_History::Modified/Generated() function to extract - * shape history for generating mapped element names - */ -struct PartExport MapperHistory: TopoShape::Mapper { - Handle(BRepTools_History) history; - MapperHistory(const Handle(BRepTools_History) &history); - MapperHistory(const Handle(BRepTools_ReShape) &reshape); - MapperHistory(ShapeFix_Root &fix); - virtual const std::vector &modified(const TopoDS_Shape &s) const override; - virtual const std::vector &generated(const TopoDS_Shape &s) const override; -}; - /** Shape mapper for user defined shape mapping */ struct PartExport ShapeMapper: TopoShape::Mapper { diff --git a/tests/src/Mod/Part/App/TopoShapeMapper.cpp b/tests/src/Mod/Part/App/TopoShapeMapper.cpp index 047dd1c3a9..6f23f19b8d 100644 --- a/tests/src/Mod/Part/App/TopoShapeMapper.cpp +++ b/tests/src/Mod/Part/App/TopoShapeMapper.cpp @@ -86,16 +86,6 @@ TEST_F(TopoShapeMapperTest, shapeHasherTests) EXPECT_FALSE(hash16); } -TEST_F(TopoShapeMapperTest, mapperMakerTests) -{ - // How can this be tested? -} - -TEST_F(TopoShapeMapperTest, mapperHistoryTests) -{ - // How can this be tested? -} - TEST_F(TopoShapeMapperTest, shapeMapperTests) { // Arrange @@ -118,4 +108,4 @@ TEST_F(TopoShapeMapperTest, shapeMapperTests) } -// // NOLINTEND(readability-magic-numbers,cppcoreguidelines-avoid-magic-numbers) +// NOLINTEND(readability-magic-numbers,cppcoreguidelines-avoid-magic-numbers) From fae1cd569fb92d690937464b3d7f74cebcf1c784 Mon Sep 17 00:00:00 2001 From: bgbsww Date: Thu, 18 Jan 2024 11:46:15 -0500 Subject: [PATCH 5/5] Lint and other cleanups --- src/Mod/Part/App/TopoShapeMapper.cpp | 132 ++++++++++++--------- src/Mod/Part/App/TopoShapeMapper.h | 126 ++++++++++++-------- tests/src/Mod/Part/App/TopoShapeMapper.cpp | 89 ++++++++++---- 3 files changed, 222 insertions(+), 125 deletions(-) diff --git a/src/Mod/Part/App/TopoShapeMapper.cpp b/src/Mod/Part/App/TopoShapeMapper.cpp index 89ea456a40..69f9653d18 100644 --- a/src/Mod/Part/App/TopoShapeMapper.cpp +++ b/src/Mod/Part/App/TopoShapeMapper.cpp @@ -3,73 +3,95 @@ namespace Part { -void ShapeMapper::expand(const TopoDS_Shape &d, std::vector &shapes) +void ShapeMapper::expand(const TopoDS_Shape& d, std::vector& shapes) { - if (d.IsNull()) return; - for(TopExp_Explorer xp(d, TopAbs_FACE);xp.More();xp.Next()) - shapes.push_back(xp.Current()); - for(TopExp_Explorer xp(d, TopAbs_EDGE, TopAbs_FACE);xp.More();xp.Next()) - shapes.push_back(xp.Current()); - for(TopExp_Explorer xp(d, TopAbs_VERTEX, TopAbs_EDGE);xp.More();xp.Next()) - shapes.push_back(xp.Current()); -} - -void ShapeMapper::populate(bool generated, - const TopTools_ListOfShape &src, - const TopTools_ListOfShape &dst) -{ - for(TopTools_ListIteratorOfListOfShape it(src);it.More();it.Next()) - populate(generated, it.Value(), dst); -} - -void ShapeMapper::populate(bool generated, - const TopoShape &src, - const TopTools_ListOfShape &dst) -{ - if(src.isNull()) + if (d.IsNull()) { return; - std::vector dstShapes; - for(TopTools_ListIteratorOfListOfShape it(dst);it.More();it.Next()) - expand(it.Value(), dstShapes); - insert(generated, src.getShape(), dstShapes); + } + for (TopExp_Explorer xp(d, TopAbs_FACE); xp.More(); xp.Next()) { + shapes.push_back(xp.Current()); + } + for (TopExp_Explorer xp(d, TopAbs_EDGE, TopAbs_FACE); xp.More(); xp.Next()) { + shapes.push_back(xp.Current()); + } + for (TopExp_Explorer xp(d, TopAbs_VERTEX, TopAbs_EDGE); xp.More(); xp.Next()) { + shapes.push_back(xp.Current()); + } } -void ShapeMapper::insert(bool generated, const TopoDS_Shape &s, const TopoDS_Shape &d) +void ShapeMapper::populate(MappingStatus status, + const TopTools_ListOfShape& src, + const TopTools_ListOfShape& dst) { - if (s.IsNull() || d.IsNull()) return; + for (TopTools_ListIteratorOfListOfShape it(src); it.More(); it.Next()) { + populate(status, it.Value(), dst); + } +} + +void ShapeMapper::populate(MappingStatus status, + const TopoShape& src, + const TopTools_ListOfShape& dst) +{ + if (src.isNull()) { + return; + } + std::vector dstShapes; + for (TopTools_ListIteratorOfListOfShape it(dst); it.More(); it.Next()) { + expand(it.Value(), dstShapes); + } + insert(status, src.getShape(), dstShapes); +} + +void ShapeMapper::insert(MappingStatus status, const TopoDS_Shape& s, const TopoDS_Shape& d) +{ + if (s.IsNull() || d.IsNull()) { + return; + } // Prevent an element shape from being both generated and modified - if (generated) { - if (_modifiedShapes.count(d)) + if (status == MappingStatus::Generated) { + if (_modifiedShapes.count(d)) { return; + } _generatedShapes.insert(d); - } else { - if( _generatedShapes.count(d)) + } + else { + if (_generatedShapes.count(d)) { return; + } _modifiedShapes.insert(d); } - auto &entry = generated?_generated[s]:_modified[s]; - if(entry.shapeSet.insert(d).second) + auto& entry = (status == MappingStatus::Generated) ? _generated[s] : _modified[s]; + if (entry.shapeSet.insert(d).second) { entry.shapes.push_back(d); -}; - -void ShapeMapper::insert(bool generated, const TopoDS_Shape &s, const std::vector &d) -{ - if (s.IsNull() || d.empty()) return; - auto &entry = generated?_generated[s]:_modified[s]; - for(auto &shape : d) { - // Prevent an element shape from being both generated and modified - if (generated) { - if (_modifiedShapes.count(shape)) - continue; - _generatedShapes.insert(shape); - } else { - if( _generatedShapes.count(shape)) - continue; - _modifiedShapes.insert(shape); - } - if(entry.shapeSet.insert(shape).second) - entry.shapes.push_back(shape); } }; -} +void ShapeMapper::insert(MappingStatus status, + const TopoDS_Shape& s, + const std::vector& d) +{ + if (s.IsNull() || d.empty()) { + return; + } + auto& entry = (status == MappingStatus::Generated) ? _generated[s] : _modified[s]; + for (auto& shape : d) { + // Prevent an element shape from being both generated and modified + if (status == MappingStatus::Generated) { + if (_modifiedShapes.count(shape)) { + continue; + } + _generatedShapes.insert(shape); + } + else { + if (_generatedShapes.count(shape)) { + continue; + } + _modifiedShapes.insert(shape); + } + if (entry.shapeSet.insert(shape).second) { + entry.shapes.push_back(shape); + } + } +}; + +} // namespace Part diff --git a/src/Mod/Part/App/TopoShapeMapper.h b/src/Mod/Part/App/TopoShapeMapper.h index 89080ae46e..5b67c4deb2 100644 --- a/src/Mod/Part/App/TopoShapeMapper.h +++ b/src/Mod/Part/App/TopoShapeMapper.h @@ -12,39 +12,45 @@ class BRepTools_History; class BRepTools_ReShape; class ShapeFix_Root; -namespace Part +namespace Part { /// Shape hasher that ignore orientation -struct ShapeHasher { - inline size_t operator()(const TopoShape &s) const { +struct ShapeHasher +{ + inline size_t operator()(const TopoShape& s) const + { #if OCC_VERSION_HEX >= 0x070800 return std::hash {}(s.getShape()); #else return s.getShape().HashCode(INT_MAX); #endif } - inline size_t operator()(const TopoDS_Shape &s) const { + inline size_t operator()(const TopoDS_Shape& s) const + { #if OCC_VERSION_HEX >= 0x070800 return std::hash {}(s); #else return s.HashCode(INT_MAX); #endif } - inline bool operator()(const TopoShape &a, const TopoShape &b) const { + inline bool operator()(const TopoShape& a, const TopoShape& b) const + { return a.getShape().IsSame(b.getShape()); } - inline bool operator()(const TopoDS_Shape &a, const TopoDS_Shape &b) const { + inline bool operator()(const TopoDS_Shape& a, const TopoDS_Shape& b) const + { return a.IsSame(b); } - template + template static inline void hash_combine(std::size_t& seed, const T& v) { // copied from boost::hash_combine std::hash hasher; - seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2); + seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2); } - inline size_t operator()(const std::pair &s) const { + inline size_t operator()(const std::pair& s) const + { #if OCC_VERSION_HEX >= 0x070800 size_t res = std::hash {}(s.first.getShape()); hash_combine(res, std::hash {}(s.second.getShape())); @@ -54,7 +60,8 @@ struct ShapeHasher { #endif return res; } - inline size_t operator()(const std::pair &s) const { + inline size_t operator()(const std::pair& s) const + { #if OCC_VERSION_HEX >= 0x070800 size_t res = std::hash {}(s.first); hash_combine(res, std::hash {}(s.second)); @@ -64,130 +71,150 @@ struct ShapeHasher { #endif return res; } - inline bool operator()(const std::pair &a, - const std::pair &b) const { + inline bool operator()(const std::pair& a, + const std::pair& b) const + { return a.first.getShape().IsSame(b.first.getShape()) && a.second.getShape().IsSame(b.second.getShape()); } - inline bool operator()(const std::pair &a, - const std::pair &b) const { - return a.first.IsSame(b.first) - && a.second.IsSame(b.second); + inline bool operator()(const std::pair& a, + const std::pair& b) const + { + return a.first.IsSame(b.first) && a.second.IsSame(b.second); } }; +enum class MappingStatus +{ + Generated, + Modified +}; /** Shape mapper for user defined shape mapping */ -struct PartExport ShapeMapper: TopoShape::Mapper { +struct PartExport ShapeMapper: TopoShape::Mapper +{ virtual ~ShapeMapper() noexcept = default; /** Populate mapping from a source shape to a list of shape * - * @param generated: whether the shape is generated + * @param status: whether the shape is generated * @param src: source shape * @param dst: a list of sub shapes in the new shape * * The source will be expanded into sub shapes of faces, edges and vertices * before being inserted into the map. */ - void populate(bool generated, const TopoShape &src, const TopTools_ListOfShape &dst); + void populate(MappingStatus status, const TopoShape& src, const TopTools_ListOfShape& dst); /** Populate mapping from a source sub shape to a list of shape * - * @param generated: whether the shape is generated + * @param status: whether the shape is generated * @param src: a list of sub shapes in the source shape * @param dst: a list of sub shapes in the new shape * * The source will be expanded into sub shapes of faces, edges and vertices * before being inserted into the map. */ - void populate(bool generated, const TopTools_ListOfShape &src, const TopTools_ListOfShape &dst); + void populate(MappingStatus status, + const TopTools_ListOfShape& src, + const TopTools_ListOfShape& dst); /** Populate mapping from a source sub shape to a list of shape * - * @param generated: whether the shape is generated + * @param status: whether the shape is generated * @param src: a list of sub shapes in the source shape * @param dst: a list of sub shapes in the new shape * * The source will be expanded into sub shapes of faces, edges and vertices * before being inserted into the map. */ - void populate(bool generated, const std::vector &src, const std::vector &dst) + void populate(MappingStatus status, + const std::vector& src, + const std::vector& dst) { - for(auto &s : src) - populate(generated,s,dst); + for (auto& s : src) { + populate(status, s, dst); + } } /** Populate mapping from a source sub shape to a list of shape * - * @param generated: whether the shape is generated + * @param status: whether the shape is generated * @param src: a sub shape of the source shape * @param dst: a list of sub shapes in the new shape * * The source will be expanded into sub shapes of faces, edges and vertices * before being inserted into the map. */ - void populate(bool generated, const TopoShape &src, const std::vector &dst) + void populate(MappingStatus status, const TopoShape& src, const std::vector& dst) { - if(src.isNull()) + if (src.isNull()) { return; + } std::vector dstShapes; - for(auto &d : dst) + for (auto& d : dst) { expand(d.getShape(), dstShapes); - insert(generated, src.getShape(), dstShapes); + } + insert(status, src.getShape(), dstShapes); } /** Expand a shape into faces, edges and vertices * @params d: shape to expand * @param shapes: output sub shapes of faces, edges and vertices */ - void expand(const TopoDS_Shape &d, std::vector &shapes); + void expand(const TopoDS_Shape& d, std::vector& shapes); /** Insert a map entry from a sub shape in the source to a list of sub shapes in the new shape * - * @params generated: whether the sub shapes are generated or modified + * @params status: whether the sub shapes are generated or modified * @param s: a sub shape in the source * @param d: a list of sub shapes in the new shape */ - void insert(bool generated, const TopoDS_Shape &s, const std::vector &d); + void insert(MappingStatus status, const TopoDS_Shape& s, const std::vector& d); /** Insert a map entry from a sub shape in the source to a sub shape in the new shape * - * @params generated: whether the sub shapes are generated or modified + * @params status: whether the sub shapes are generated or modified * @param s: a sub shape in the source * @param d: a list of sub shapes in the new shape */ - void insert(bool generated, const TopoDS_Shape &s, const TopoDS_Shape &d); + void insert(MappingStatus status, const TopoDS_Shape& s, const TopoDS_Shape& d); - virtual const std::vector &generated(const TopoDS_Shape &s) const override { + const std::vector& generated(const TopoDS_Shape& s) const override + { auto iter = _generated.find(s); - if(iter != _generated.end()) + if (iter != _generated.end()) { return iter->second.shapes; + } return _res; } - virtual const std::vector &modified(const TopoDS_Shape &s) const override { + const std::vector& modified(const TopoDS_Shape& s) const override + { auto iter = _modified.find(s); - if(iter != _modified.end()) + if (iter != _modified.end()) { return iter->second.shapes; + } return _res; } std::vector shapes; - std::unordered_set shapeSet; + std::unordered_set shapeSet; - struct ShapeValue { + struct ShapeValue + { std::vector shapes; - std::unordered_set shapeSet; + std::unordered_set shapeSet; }; - typedef std::unordered_map ShapeMap; + typedef std::unordered_map ShapeMap; ShapeMap _generated; - std::unordered_set _generatedShapes; + std::unordered_set _generatedShapes; ShapeMap _modified; - std::unordered_set _modifiedShapes; + std::unordered_set _modifiedShapes; }; -/// Parameters for TopoShape::makEFilledFace() -struct PartExport TopoShape::BRepFillingParams { +/// Parameters for TopoShape::makeElementFilledFace() +struct PartExport TopoShape::BRepFillingParams +{ /** Optional initial surface to begin the construction of the surface for the filled face. * * It is useful if the surface resulting from construction for the @@ -211,7 +238,8 @@ struct PartExport TopoShape::BRepFillingParams { std::unordered_map supports; /// Optional begin index to the input shapes to be used as the boundary of the filled face. int boundary_begin = -1; - /// Optional end index (last index + 1) to the input shapes to be used as the boundary of the filled face. + /// Optional end index (last index + 1) to the input shapes to be used as the boundary of the + /// filled face. int boundary_end = -1; /// The energe minimizing criterion degree; unsigned int degree = 3; @@ -242,4 +270,4 @@ struct PartExport TopoShape::BRepFillingParams { }; -} +} // namespace Part diff --git a/tests/src/Mod/Part/App/TopoShapeMapper.cpp b/tests/src/Mod/Part/App/TopoShapeMapper.cpp index 6f23f19b8d..88c8fa18f6 100644 --- a/tests/src/Mod/Part/App/TopoShapeMapper.cpp +++ b/tests/src/Mod/Part/App/TopoShapeMapper.cpp @@ -38,7 +38,50 @@ private: std::string _docName; }; -TEST_F(TopoShapeMapperTest, shapeHasherTests) +TEST_F(TopoShapeMapperTest, shapeHasherSingle) +{ + // Arrange + auto edge = BRepBuilderAPI_MakeEdge(gp_Pnt(0.0, 0.0, 0.0), gp_Pnt(1.0, 0.0, 0.0)).Edge(); + Part::TopoShape topoShape {edge}; + auto edge2 = BRepBuilderAPI_MakeEdge(gp_Pnt(1.0, 0.0, 0.0), gp_Pnt(1.0, 1.0, 0.0)).Edge(); + Part::TopoShape topoShape2 {edge2}; + struct Part::ShapeHasher hasher; + + // Act + size_t hash1 = hasher(topoShape); + size_t hash2 = hasher(topoShape2); + size_t hash3 = hasher(edge); + size_t hash4 = hasher(edge2); + + // Assert + EXPECT_EQ(hash1, hash3); + EXPECT_EQ(hash2, hash4); + EXPECT_NE(hash1, hash2); +} + +TEST_F(TopoShapeMapperTest, shapeHasherDual) +{ + // Arrange + auto edge = BRepBuilderAPI_MakeEdge(gp_Pnt(0.0, 0.0, 0.0), gp_Pnt(1.0, 0.0, 0.0)).Edge(); + Part::TopoShape topoShape {edge}; + auto edge2 = BRepBuilderAPI_MakeEdge(gp_Pnt(1.0, 0.0, 0.0), gp_Pnt(1.0, 1.0, 0.0)).Edge(); + Part::TopoShape topoShape2 {edge2}; + struct Part::ShapeHasher hasher; + + // Act + size_t hash5 = hasher(topoShape, topoShape); + size_t hash6 = hasher(topoShape, topoShape2); + size_t hash7 = hasher(edge, edge); + size_t hash8 = hasher(edge, edge2); + + // Assert + EXPECT_TRUE(hash5); + EXPECT_FALSE(hash6); + EXPECT_TRUE(hash7); + EXPECT_FALSE(hash8); +} + +TEST_F(TopoShapeMapperTest, shapeHasherPair) { // Arrange auto edge = BRepBuilderAPI_MakeEdge(gp_Pnt(0.0, 0.0, 0.0), gp_Pnt(1.0, 0.0, 0.0)).Edge(); @@ -52,40 +95,44 @@ TEST_F(TopoShapeMapperTest, shapeHasherTests) struct Part::ShapeHasher hasher; // Act - size_t hash1 = hasher(topoShape); - size_t hash2 = hasher(topoShape2); - size_t hash3 = hasher(edge); - size_t hash4 = hasher(edge2); - size_t hash5 = hasher(topoShape, topoShape); - size_t hash6 = hasher(topoShape, topoShape2); - size_t hash7 = hasher(edge, edge); - size_t hash8 = hasher(edge, edge2); size_t hash9 = hasher(pair1); size_t hash10 = hasher(pair2); size_t hash11 = hasher(pair3); size_t hash12 = hasher(pair4); + + // Assert + EXPECT_EQ(hash9, hash11); + EXPECT_EQ(hash10, hash12); + EXPECT_NE(hash9, hash10); +} + +TEST_F(TopoShapeMapperTest, shapeHasherPairs) +{ + // Arrange + auto edge = BRepBuilderAPI_MakeEdge(gp_Pnt(0.0, 0.0, 0.0), gp_Pnt(1.0, 0.0, 0.0)).Edge(); + Part::TopoShape topoShape {edge}; + auto edge2 = BRepBuilderAPI_MakeEdge(gp_Pnt(1.0, 0.0, 0.0), gp_Pnt(1.0, 1.0, 0.0)).Edge(); + Part::TopoShape topoShape2 {edge2}; + std::pair pair1(topoShape, topoShape2); + std::pair pair2(topoShape, topoShape); + std::pair pair3(edge, edge2); + std::pair pair4(edge, edge); + struct Part::ShapeHasher hasher; + + // Act size_t hash13 = hasher(pair1, pair1); size_t hash14 = hasher(pair1, pair2); size_t hash15 = hasher(pair3, pair3); size_t hash16 = hasher(pair3, pair4); // Assert - EXPECT_EQ(hash1, hash3); - EXPECT_EQ(hash2, hash4); - EXPECT_NE(hash1, hash2); - EXPECT_TRUE(hash5); - EXPECT_FALSE(hash6); - EXPECT_TRUE(hash7); - EXPECT_FALSE(hash8); - EXPECT_EQ(hash9, hash11); - EXPECT_EQ(hash10, hash12); - EXPECT_NE(hash9, hash10); EXPECT_TRUE(hash13); EXPECT_FALSE(hash14); EXPECT_TRUE(hash15); EXPECT_FALSE(hash16); } + TEST_F(TopoShapeMapperTest, shapeMapperTests) { // Arrange @@ -97,8 +144,8 @@ TEST_F(TopoShapeMapperTest, shapeMapperTests) // Act auto e = topoShape1.getSubTopoShapes(TopAbs_EDGE); - mapper.populate(false, box1, {e[0], e[1], e[2], e[3]}); - mapper.populate(true, box1, {e[4], e[5], e[6]}); + mapper.populate(Part::MappingStatus::Modified, box1, {e[0], e[1], e[2], e[3]}); + mapper.populate(Part::MappingStatus::Generated, box1, {e[4], e[5], e[6]}); std::vector vec1 = mapper.modified(box1); std::vector vec2 = mapper.generated(box1);