From e5247001cbc682e1b7746ab0fbf856b3fe3245ed Mon Sep 17 00:00:00 2001 From: "Zheng, Lei" Date: Thu, 22 Feb 2024 08:40:06 -0500 Subject: [PATCH] Toposhape/Part: Transfer in makESlice and makEMirror --- src/Mod/Part/App/CrossSection.cpp | 92 +++++++++++++++++++++++++ src/Mod/Part/App/CrossSection.h | 18 +++++ src/Mod/Part/App/TopoShape.h | 83 ++++++++++++++++++++++ src/Mod/Part/App/TopoShapeExpansion.cpp | 24 +++++++ 4 files changed, 217 insertions(+) diff --git a/src/Mod/Part/App/CrossSection.cpp b/src/Mod/Part/App/CrossSection.cpp index e118dba32e..c49aca4208 100644 --- a/src/Mod/Part/App/CrossSection.cpp +++ b/src/Mod/Part/App/CrossSection.cpp @@ -218,3 +218,95 @@ TopoDS_Wire CrossSection::fixWire(const TopoDS_Wire& wire) const aFix.FixClosed(); return aFix.Wire(); } + +TopoCrossSection::TopoCrossSection(double a, double b, double c, const TopoShape& s, const char *op) + : a(a), b(b), c(c), shape(s), op(op?op:Part::OpCodes::Slice) +{ +} + +void TopoCrossSection::slice(int idx, double d, std::vector &wires) const { + // Fixes: 0001228: Cross section of Torus in Part Workbench fails or give wrong results + // Fixes: 0001137: Incomplete slices when using Part.slice on a torus + bool found = false; + for(auto &s : shape.getSubTopoShapes(TopAbs_SOLID)) { + sliceSolid(idx, d, s, wires); + found = true; + } + if(!found) { + for(auto &s : shape.getSubTopoShapes(TopAbs_SHELL)) { + sliceNonSolid(idx, d, s, wires); + found = true; + } + if(!found) { + for(auto &s : shape.getSubTopoShapes(TopAbs_FACE)) + sliceNonSolid(idx, d, s, wires); + } + } +} + +TopoShape TopoCrossSection::slice(int idx, double d) const { + std::vector wires; + slice(idx,d,wires); + return TopoShape().makECompound(wires,0,false); +} + +void TopoCrossSection::sliceNonSolid(int idx, double d, + const TopoShape& shape, std::vector& wires) const +{ + BRepAlgoAPI_Section cs(shape.getShape(), gp_Pln(a,b,c,-d)); + if (cs.IsDone()) { + std::string prefix(op); + if(idx>1) { + prefix += '_'; + prefix += std::to_string(idx); + } + auto res = TopoShape().makEShape(cs,shape,prefix.c_str()).makEWires().getSubTopoShapes(TopAbs_WIRE); + wires.insert(wires.end(),res.begin(),res.end()); + } +} + +void TopoCrossSection::sliceSolid(int idx, double d, + const TopoShape& shape, std::vector& wires) const +{ + gp_Pln slicePlane(a,b,c,-d); + BRepBuilderAPI_MakeFace mkFace(slicePlane); + TopoShape face(idx); + face.setShape(mkFace.Face()); + + // Make sure to choose a point that does not lie on the plane (fixes #0001228) + gp_Vec tempVector(a,b,c); + tempVector.Normalize();//just in case. + tempVector *= (d+1.0); + gp_Pnt refPoint(0.0, 0.0, 0.0); + refPoint.Translate(tempVector); + + BRepPrimAPI_MakeHalfSpace mkSolid(TopoDS::Face(face.getShape()), refPoint); + TopoShape solid(idx); + std::string prefix(op); + if(idx>1) { + prefix += '_'; + prefix += std::to_string(idx); + } + solid.makEShape(mkSolid,face,prefix.c_str()); + BRepAlgoAPI_Cut mkCut(shape.getShape(), solid.getShape()); + + if (mkCut.IsDone()) { + TopoShape res(shape.Tag,shape.Hasher); + std::vector shapes; + shapes.push_back(shape); + shapes.push_back(solid); + res.makEShape(mkCut,shapes,prefix.c_str()); + for(auto &face : res.getSubTopoShapes(TopAbs_FACE)) { + BRepAdaptor_Surface adapt(TopoDS::Face(face.getShape())); + if (adapt.GetType() == GeomAbs_Plane) { + gp_Pln plane = adapt.Plane(); + if (plane.Axis().IsParallel(slicePlane.Axis(), Precision::Confusion()) && + plane.Distance(slicePlane.Location()) < Precision::Confusion()) { + auto repaired_wires = TopoShape(face.Tag).makEWires( + face.getSubTopoShapes(TopAbs_EDGE),prefix.c_str(),true).getSubTopoShapes(TopAbs_WIRE); + wires.insert(wires.end(),repaired_wires.begin(),repaired_wires.end()); + } + } + } + } +} diff --git a/src/Mod/Part/App/CrossSection.h b/src/Mod/Part/App/CrossSection.h index 8dfa95cdb9..b34829cb16 100644 --- a/src/Mod/Part/App/CrossSection.h +++ b/src/Mod/Part/App/CrossSection.h @@ -26,6 +26,7 @@ #include #include #include +#include "TopoShape.h" class TopoDS_Shape; @@ -52,6 +53,23 @@ private: const TopoDS_Shape& s; }; +class PartExport TopoCrossSection +{ +public: + TopoCrossSection(double a, double b, double c, const TopoShape& s, const char *op=0); + void slice(int idx, double d, std::vector &wires) const; + TopoShape slice(int idx, double d) const; + +private: + void sliceNonSolid(int idx, double d, const TopoShape&, std::vector& wires) const; + void sliceSolid(int idx, double d, const TopoShape&, std::vector& wires) const; + +private: + double a,b,c; + const TopoShape& shape; + const char *op; +}; + } #endif // PART_CROSSSECTION_H diff --git a/src/Mod/Part/App/TopoShape.h b/src/Mod/Part/App/TopoShape.h index 9b1e1a73bd..aec30fd84c 100644 --- a/src/Mod/Part/App/TopoShape.h +++ b/src/Mod/Part/App/TopoShape.h @@ -1330,6 +1330,89 @@ public: return TopoShape(0, Hasher).makeElementBoolean(maker, *this, op, tol); } + /** Make a mirrored shape + * + * @param source: the source shape + * @param axis: the axis for mirroring + * @param op: optional string to be encoded into topo naming for indicating + * the operation + * + * @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 &makEMirror(const TopoShape &source, const gp_Ax2& axis, const char *op=nullptr); + /** Make a mirrored shape + * + * @param source: the source shape + * @param axis: the axis for mirroring + * @param op: optional string to be encoded into topo naming for indicating + * the operation + * + * @return Return the new shape. The TopoShape itself is not modified. + */ + TopoShape makEMirror(const gp_Ax2& ax, const char *op=nullptr) const { + return TopoShape(0,Hasher).makEMirror(*this,ax,op); + } + + /** Make a cross section slice + * + * @param source: the source shape + * @param dir: direction of the normal of the section plane + * @param d: distance to move the section plane + * @param op: optional string to be encoded into topo naming for indicating + * the operation + * + * @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 &makESlice(const TopoShape &source, const Base::Vector3d& dir, double d, const char *op=nullptr); + /** Make a cross section slice + * + * @param source: the source shape + * @param dir: direction of the normal of the section plane + * @param d: distance to move the section plane + * @param op: optional string to be encoded into topo naming for indicating + * the operation + * + * @return Return the new shape. The TopoShape itself is not modified. + */ + TopoShape makESlice(const Base::Vector3d& dir, double d, const char *op=nullptr) const { + return TopoShape(0,Hasher).makESlice(*this,dir,d,op); + } + + /** Make multiple cross section slices + * + * @param source: the source shape + * @param dir: direction of the normal of the section plane + * @param distances: distances to move the section plane for making slices + * @param op: optional string to be encoded into topo naming for indicating + * the operation + * + * @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 &makESlices(const TopoShape &source, const Base::Vector3d& dir, + const std::vector &distances, const char *op=nullptr); + /** Make multiple cross section slices + * + * @param source: the source shape + * @param dir: direction of the normal of the section plane + * @param distances: distances to move the section plane for making slices + * @param op: optional string to be encoded into topo naming for indicating + * the operation + * + * @return Return the new shape. The TopoShape itself is not modified. + */ + TopoShape makESlices(const Base::Vector3d &dir, const std::vector &distances, const char *op=nullptr) const { + return TopoShape(0,Hasher).makESlices(*this,dir,distances,op); + } + /* Make fillet shape * * @param source: the source shape diff --git a/src/Mod/Part/App/TopoShapeExpansion.cpp b/src/Mod/Part/App/TopoShapeExpansion.cpp index 1fc8a6639c..efb1716c6a 100644 --- a/src/Mod/Part/App/TopoShapeExpansion.cpp +++ b/src/Mod/Part/App/TopoShapeExpansion.cpp @@ -2596,6 +2596,30 @@ struct MapperThruSections: MapperMaker } }; +TopoShape &TopoShape::makESlice(const TopoShape &shape, + const Base::Vector3d& dir, double d, const char *op) +{ + if(shape.isNull()) + HANDLE_NULL_SHAPE; + TopoCrossSection cs(dir.x, dir.y, dir.z,shape,op); + TopoShape res = cs.slice(1,d); + setShape(res._Shape); + Hasher = res.Hasher; + resetElementMap(res.elementMap()); + return *this; +} + +TopoShape &TopoShape::makESlices(const TopoShape &shape, + const Base::Vector3d& dir, const std::vector &d, const char *op) +{ + std::vector wires; + TopoCrossSection cs(dir.x, dir.y, dir.z, shape,op); + int i=0; + for(auto &dd : d) + cs.slice(++i,dd,wires); + return makECompound(wires,op,false); +} + TopoShape& TopoShape::makeElementFillet(const TopoShape& shape, const std::vector& edges, double radius1,