From c4b36466e81dcd65ac898f3a073e8e7ffd44440d Mon Sep 17 00:00:00 2001 From: "Zheng, Lei" Date: Thu, 1 Feb 2024 13:07:15 -0500 Subject: [PATCH] Transfer in makeElementRefine --- src/Mod/Part/App/TopoShape.h | 31 ++++++++ src/Mod/Part/App/TopoShapeExpansion.cpp | 96 +++++++++++++++++++++++++ src/Mod/Part/App/TopoShapeMapper.cpp | 62 ++++++++++++++++ src/Mod/Part/App/TopoShapeMapper.h | 7 ++ src/Mod/Part/App/modelRefine.h | 2 +- 5 files changed, 197 insertions(+), 1 deletion(-) diff --git a/src/Mod/Part/App/TopoShape.h b/src/Mod/Part/App/TopoShape.h index c5fa8e6e35..2ed5c3c38b 100644 --- a/src/Mod/Part/App/TopoShape.h +++ b/src/Mod/Part/App/TopoShape.h @@ -387,6 +387,7 @@ public: TopoDS_Shape removeShape(const std::vector& s) const; void sewShape(double tolerance = 1.0e-06); bool fix(double, double, double); + bool fixSolidOrientation(); bool removeInternalWires(double); TopoDS_Shape removeSplitter() const; TopoDS_Shape defeaturing(const std::vector& s) const; @@ -582,6 +583,36 @@ public: { return TopoShape().makeGTransform(*this, mat, op, copy); } + + /** Refine the input shape by merging faces/edges that share the same geometry + * + * @param source: input shape + * @param op: optional string to be encoded into topo naming for indicating + * the operation + * @param no_fail: if true, throw exception if failed to refine. Or else, + * the shape remains untouched if failed. + * + * @return The original content of this TopoShape is discarded and replaced + * with the refined 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 &makeElementRefine(const TopoShape &source, const char *op=nullptr, bool no_fail=true); + + /** Refine the input shape by merging faces/edges that share the same geometry + * + * @param source: input shape + * @param op: optional string to be encoded into topo naming for indicating + * the operation + * @param no_fail: if true, throw exception if failed to refine. Or else, + * the shape remains untouched if failed. + * + * @return Return a refined shape. The shape itself is not modified + */ + TopoShape makeElementRefine(const char *op=nullptr, bool no_fail=true) const { + return TopoShape(Tag,Hasher).makeElementRefine(*this,op,no_fail); + } + TopoShape& makeRefine(const TopoShape& shape, const char* op = nullptr, bool no_fail = true); TopoShape makeRefine(const char* op = nullptr, bool no_fail = true) const diff --git a/src/Mod/Part/App/TopoShapeExpansion.cpp b/src/Mod/Part/App/TopoShapeExpansion.cpp index b861b58eb4..29d74e4003 100644 --- a/src/Mod/Part/App/TopoShapeExpansion.cpp +++ b/src/Mod/Part/App/TopoShapeExpansion.cpp @@ -27,6 +27,7 @@ #ifndef _PreComp_ #include +#include #include #include #include @@ -42,10 +43,12 @@ #include "TopoShape.h" #include "TopoShapeCache.h" +#include "TopoShapeMapper.h" #include "FaceMaker.h" #include "TopoShapeOpCode.h" #include +#include FC_LOG_LEVEL_INIT("TopoShape", true, true) // NOLINT @@ -1511,6 +1514,49 @@ TopoShape& TopoShape::makeElementFace(const std::vector& shapes, return *this; } +class MyRefineMaker : public BRepBuilderAPI_RefineModel +{ +public: + MyRefineMaker(const TopoDS_Shape &s) + :BRepBuilderAPI_RefineModel(s) + {} + + void populate(ShapeMapper &mapper) + { + for (TopTools_DataMapIteratorOfDataMapOfShapeListOfShape it(this->myModified); it.More(); it.Next()) + { + if (it.Key().IsNull()) continue; + mapper.populate(MappingStatus::Generated, it.Key(), it.Value()); + } + } +}; + +TopoShape &TopoShape::makeElementRefine(const TopoShape &shape, const char *op, bool no_fail) { + if(shape.isNull()) { + if(!no_fail) + FC_THROWM(NullShapeException, "Null shape"); + _Shape.Nullify(); + return *this; + } + if(!op) op = Part::OpCodes::Refine; + bool closed = shape.isClosed(); + try { + MyRefineMaker mkRefine(shape.getShape()); + GenericShapeMapper mapper; + mkRefine.populate(mapper); + mapper.init(shape, mkRefine.Shape()); + makeShapeWithElementMap(mkRefine.Shape(), mapper, {shape}, op); + // For some reason, refine operation may reverse the solid + fixSolidOrientation(); + if (isClosed() == closed) + return *this; + }catch (Standard_Failure &) { + if(!no_fail) throw; + } + *this = shape; + return *this; +} + /** * Encode and set an element name in the elementMap. If a hasher is defined, apply it to the name. * @@ -1851,4 +1897,54 @@ TopoShape& TopoShape::makeElementShellFromWires(const std::vector& wi return *this; } +bool TopoShape::fixSolidOrientation() +{ + if (isNull()) + return false; + + if (shapeType() == TopAbs_SOLID) { + TopoDS_Solid solid = TopoDS::Solid(_Shape); + BRepLib::OrientClosedSolid(solid); + if (solid.IsEqual(_Shape)) + return false; + setShape(solid, false); + return true; + } + + if (shapeType() == TopAbs_COMPOUND + || shapeType() == TopAbs_COMPSOLID) + { + auto shapes = getSubTopoShapes(); + bool touched = false; + for (auto &s : shapes) { + if (s.fixSolidOrientation()) + touched = true; + } + if (!touched) + return false; + + BRep_Builder builder; + if (shapeType() == TopAbs_COMPOUND) { + TopoDS_Compound comp; + builder.MakeCompound(comp); + for(auto &s : shapes) { + if (!s.isNull()) + builder.Add(comp, s.getShape()); + } + setShape(comp, false); + } else { + TopoDS_CompSolid comp; + builder.MakeCompSolid(comp); + for(auto &s : shapes) { + if (!s.isNull()) + builder.Add(comp, s.getShape()); + } + setShape(comp, false); + } + return true; + } + + return false; +} + } // namespace Part diff --git a/src/Mod/Part/App/TopoShapeMapper.cpp b/src/Mod/Part/App/TopoShapeMapper.cpp index 4268a433d2..97f571d59d 100644 --- a/src/Mod/Part/App/TopoShapeMapper.cpp +++ b/src/Mod/Part/App/TopoShapeMapper.cpp @@ -1,6 +1,10 @@ +#include +#include +#include #include "PreCompiled.h" #include "TopoShapeMapper.h" +#include "Geometry.h" namespace Part { @@ -96,4 +100,62 @@ void ShapeMapper::insert(MappingStatus status, } }; +void GenericShapeMapper::init(const TopoShape &src, const TopoDS_Shape &dst) +{ + for (TopExp_Explorer exp(dst, TopAbs_FACE); exp.More(); exp.Next()) { + const TopoDS_Shape &dstFace = exp.Current(); + if (src.findShape(dstFace)) + continue; + + std::unordered_map map; + bool found = false; + + // Try to find a face in the src that shares at least two edges (or one + // closed edge) with dstFace. + // TODO: consider degenerative cases of two or more edges on the same line. + for (TopExp_Explorer it(dstFace, TopAbs_EDGE); it.More(); it.Next()) { + int idx = src.findShape(it.Current()); + if (!idx) + continue; + TopoDS_Edge e = TopoDS::Edge(it.Current()); + if(BRep_Tool::IsClosed(e)) + { + // closed edge, one face is enough + TopoDS_Shape face = src.findAncestorShape( + src.getSubShape(TopAbs_EDGE,idx), TopAbs_FACE); + if (!face.IsNull()) { + this->insert(MappingStatus::Generated, face, dstFace); + found = true; + break; + } + continue; + } + for (auto &face : src.findAncestorsShapes(src.getSubShape(TopAbs_EDGE,idx), TopAbs_FACE)) { + int &cnt = map[face]; + if (++cnt == 2) { + this->insert(MappingStatus::Generated, face, dstFace); + found = true; + break; + } + if (found) + break; + } + } + + if (found) continue; + + // if no face matches, try search by geometry surface + std::unique_ptr g(Geometry::fromShape(dstFace)); + if (!g) continue; + + for (auto &v : map) { + std::unique_ptr g2(Geometry::fromShape(v.first)); + if (g2 && g2->isSame(*g,1e-7,1e-12)) { + this->insert(MappingStatus::Generated, v.first, dstFace); + break; + } + } + } +} + } // namespace Part diff --git a/src/Mod/Part/App/TopoShapeMapper.h b/src/Mod/Part/App/TopoShapeMapper.h index 5b67c4deb2..69cbcc0791 100644 --- a/src/Mod/Part/App/TopoShapeMapper.h +++ b/src/Mod/Part/App/TopoShapeMapper.h @@ -212,6 +212,13 @@ struct PartExport ShapeMapper: TopoShape::Mapper std::unordered_set _modifiedShapes; }; +/** Generic shape mapper from a given source to an output shape + */ +struct PartExport GenericShapeMapper: ShapeMapper { + /// Populate the map with a given source shape to an output shape + void init(const TopoShape &src, const TopoDS_Shape &dst); +}; + /// Parameters for TopoShape::makeElementFilledFace() struct PartExport TopoShape::BRepFillingParams { diff --git a/src/Mod/Part/App/modelRefine.h b/src/Mod/Part/App/modelRefine.h index 46a0482dd8..ca14afb094 100644 --- a/src/Mod/Part/App/modelRefine.h +++ b/src/Mod/Part/App/modelRefine.h @@ -210,7 +210,7 @@ public: private: void LogModifications(const ModelRefine::FaceUniter& uniter); -private: +protected: TopTools_DataMapOfShapeListOfShape myModified; TopTools_ListOfShape myEmptyList; TopTools_ListOfShape myDeleted;