Merge pull request #12417 from bgbsww/bgbsww-toponamingLinearize

Toponaming/Part: transfer in linearize
This commit is contained in:
Chris Hennes
2024-02-15 18:02:08 -06:00
committed by GitHub
3 changed files with 162 additions and 8 deletions

View File

@@ -59,10 +59,11 @@ namespace Part
struct ShapeHasher;
class TopoShape;
class TopoShapeCache;
typedef std::unordered_map<TopoShape, TopoShape, ShapeHasher, ShapeHasher> TopoShapeMap;
using TopoShapeMap = std::unordered_map<TopoShape, TopoShape, ShapeHasher, ShapeHasher>;
/* A special sub-class to indicate null shapes
*/
// NOLINTNEXTLINE cppcoreguidelines-special-member-functions
class PartExport NullShapeException: public Base::ValueError
{
public:
@@ -76,6 +77,7 @@ public:
/* A special sub-class to indicate boolean failures
*/
// NOLINTNEXTLINE cppcoreguidelines-special-member-functions
class PartExport BooleanException: public Base::CADKernelError
{
public:
@@ -89,6 +91,7 @@ public:
class PartExport ShapeSegment: public Data::Segment
{
// NOLINTNEXTLINE cppcoreguidelines-avoid-non-const-global-variables
TYPESYSTEM_HEADER_WITH_OVERRIDE();
public:
@@ -124,17 +127,32 @@ enum class CheckGeometry
ignoreGeometry,
checkGeometry
};
enum class LinearizeFace
{
noFaces,
linearizeFaces
};
enum class LinearizeEdge
{
noEdges,
linearizeEdges
};
/** The representation for a CAD Shape
*/
// NOLINTNEXTLINE cppcoreguidelines-special-member-functions
class PartExport TopoShape: public Data::ComplexGeoData
{
// NOLINTNEXTLINE cppcoreguidelines-avoid-non-const-global-variables
TYPESYSTEM_HEADER_WITH_OVERRIDE();
public:
TopoShape(long Tag=0,
TopoShape(long Tag=0, // NOLINT google-explicit-constructor
App::StringHasherRef hasher=App::StringHasherRef(),
const TopoDS_Shape &shape=TopoDS_Shape()); // Cannot be made explicit
TopoShape(const TopoDS_Shape&,
TopoShape(const TopoDS_Shape&, // NOLINT google-explicit-constructor
long Tag=0,
App::StringHasherRef hasher=App::StringHasherRef()); // Cannot be made explicit
TopoShape(const TopoShape&);
@@ -203,7 +221,7 @@ public:
uint16_t flags = 0) const override;
void setFaces(const std::vector<Base::Vector3d>& Points,
const std::vector<Facet>& faces,
double tolerance = 1.0e-06);
double tolerance = 1.0e-06); // NOLINT
void getDomains(std::vector<Domain>&) const;
//@}
@@ -219,13 +237,13 @@ public:
std::vector<const char*> getElementTypes() const override;
unsigned long countSubElements(const char* Type) const override;
/// get the subelement by type and number
Data::Segment* getSubElement(const char* Type, unsigned long) const override;
Data::Segment* getSubElement(const char* Type, unsigned long index) const override;
/** Get lines from segment */
void getLinesFromSubElement(const Data::Segment*,
void getLinesFromSubElement(const Data::Segment* segment,
std::vector<Base::Vector3d>& Points,
std::vector<Line>& lines) const override;
/** Get faces from segment */
void getFacesFromSubElement(const Data::Segment*,
void getFacesFromSubElement(const Data::Segment* segment,
std::vector<Base::Vector3d>& Points,
std::vector<Base::Vector3d>& PointNormals,
std::vector<Facet>& faces) const override;
@@ -273,7 +291,7 @@ public:
/// get the Topo"sub"Shape with the given name
PyObject* getPySubShape(const char* Type, bool silent = false) const;
PyObject* getPyObject() override;
void setPyObject(PyObject*) override;
void setPyObject(PyObject* obj) override;
/** @name Save/restore */
//@{
@@ -317,6 +335,10 @@ public:
bool isInfinite() const;
/// Checks whether the shape is a planar face
bool isPlanar(double tol = 1.0e-7) const;
/// Check if this shape is a single linear edge, works on BSplineCurve and BezierCurve
bool isLinearEdge(Base::Vector3d *dir = nullptr, Base::Vector3d *base = nullptr) const;
/// Check if this shape is a single planar face, works on BSplineSurface and BezierSurface
bool isPlanarFace(double tol=1e-7) const;
//@}
/** @name Boolean operation*/
@@ -680,6 +702,12 @@ public:
}
//@}
/** Try to simplify geometry of any linear/planar subshape to line/plane
*
* @return Return true if the shape is modified
*/
bool linearize(LinearizeFace face, LinearizeEdge edge);
static TopAbs_ShapeEnum shapeType(const char* type, bool silent = false);
static TopAbs_ShapeEnum shapeType(char type, bool silent = false);
TopAbs_ShapeEnum shapeType(bool silent = false) const;

View File

@@ -34,6 +34,7 @@
#include <BRepTools.hxx>
#include <BRep_Builder.hxx>
#include <BRep_Tool.hxx>
#include <BRepAdaptor_CompCurve.hxx>
#include <BRepAlgoAPI_BooleanOperation.hxx>
#include <BRepAlgoAPI_Common.hxx>
#include <BRepAlgoAPI_Cut.hxx>
@@ -71,6 +72,8 @@
#include "Geometry.h"
#include <App/ElementNamingUtils.h>
#include <BRepLib.hxx>
#include "Geometry.h"
FC_LOG_LEVEL_INIT("TopoShape", true, true) // NOLINT
@@ -2490,6 +2493,82 @@ TopoShape TopoShape::splitWires(std::vector<TopoShape>* inner, SplitWireReorient
return TopoShape {};
}
bool TopoShape::isLinearEdge(Base::Vector3d* dir, Base::Vector3d* base) const
{
if (isNull() || getShape().ShapeType() != TopAbs_EDGE) {
return false;
}
if (!GeomCurve::isLinear(BRepAdaptor_Curve(TopoDS::Edge(getShape())).Curve().Curve(),
dir,
base)) {
return false;
}
// BRep_Tool::Curve() will transform the returned geometry, so no need to
// check the shape's placement.
return true;
}
bool TopoShape::isPlanarFace(double tol) const
{
if (isNull() || getShape().ShapeType() != TopAbs_FACE) {
return false;
}
return GeomSurface::isPlanar(BRepAdaptor_Surface(TopoDS::Face(getShape())).Surface().Surface(),
nullptr,
tol);
}
// TODO: Refactor this into two methods. Totally separate concerns here.
bool TopoShape::linearize(LinearizeFace do_face, LinearizeEdge do_edge)
{
bool touched = false;
BRep_Builder builder;
// Note: changing edge geometry seems to mess up with face (or shell, or solid)
// Probably need to do some fix afterwards.
if (do_edge == LinearizeEdge::linearizeEdges) {
for (auto& edge : getSubTopoShapes(TopAbs_EDGE)) {
TopoDS_Edge e = TopoDS::Edge(edge.getShape());
BRepAdaptor_Curve curve(e);
if (curve.GetType() == GeomAbs_Line || !edge.isLinearEdge()) {
continue;
}
std::unique_ptr<Geometry> geo(
Geometry::fromShape(e.Located(TopLoc_Location()).Oriented(TopAbs_FORWARD)));
std::unique_ptr<Geometry> gline(static_cast<GeomCurve*>(geo.get())->toLine());
if (gline) {
touched = true;
builder.UpdateEdge(e,
Handle(Geom_Curve)::DownCast(gline->handle()),
e.Location(),
BRep_Tool::Tolerance(e));
}
}
}
if (do_face == LinearizeFace::linearizeFaces) {
for (auto& face : getSubTopoShapes(TopAbs_FACE)) {
TopoDS_Face f = TopoDS::Face(face.getShape());
BRepAdaptor_Surface surf(f);
if (surf.GetType() == GeomAbs_Plane || !face.isPlanarFace()) {
continue;
}
std::unique_ptr<Geometry> geo(
Geometry::fromShape(f.Located(TopLoc_Location()).Oriented(TopAbs_FORWARD)));
std::unique_ptr<Geometry> gplane(static_cast<GeomSurface*>(geo.get())->toPlane());
if (gplane) {
touched = true;
builder.UpdateFace(f,
Handle(Geom_Surface)::DownCast(gplane->handle()),
f.Location(),
BRep_Tool::Tolerance(f));
}
}
}
return touched;
}
struct MapperFill: Part::TopoShape::Mapper
{
BRepFill_Generator& maker;

View File

@@ -7,12 +7,17 @@
#include "PartTestHelpers.h"
#include <BRepAdaptor_CompCurve.hxx>
#include <BRepAdaptor_Surface.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <BRepBuilderAPI_MakeWire.hxx>
#include <BRepBuilderAPI_Transform.hxx>
#include <BRepFeat_SplitShape.hxx>
#include <BRepPrimAPI_MakeBox.hxx>
#include <BRepAlgoAPI_Fuse.hxx>
#include <GC_MakeCircle.hxx>
#include <Geom_BezierCurve.hxx>
#include <Geom_BezierSurface.hxx>
#include <gp_Pln.hxx>
#include <TopExp_Explorer.hxx>
#include <TopoDS_Edge.hxx>
@@ -1111,4 +1116,46 @@ TEST_F(TopoShapeExpansionTest, makeElementDraftTopoShapes)
EXPECT_EQ(result3.getElementMap().size(), 0); // No element map in non reference call.
}
TEST_F(TopoShapeExpansionTest, makeElementLinearizeEdge)
{
// Arrange
TColgp_Array1OfPnt points {1, 2};
points.SetValue(1, gp_Pnt(0.0, 0.0, 0.0));
points.SetValue(2, gp_Pnt(1.0, 0.0, 0.0));
auto line1 = new Geom_BezierCurve(points);
auto edge1 = BRepBuilderAPI_MakeEdge(line1).Edge();
TopoShape topoShape1 {edge1, 1L};
// Act
auto edges = topoShape1.getSubTopoShapes(TopAbs_EDGE);
BRepAdaptor_Curve curve(TopoDS::Edge(edges.front().getShape()));
topoShape1.linearize(LinearizeFace::noFaces, LinearizeEdge::linearizeEdges);
auto edges2 = topoShape1.getSubTopoShapes(TopAbs_EDGE);
BRepAdaptor_Curve curve2(TopoDS::Edge(edges2.front().getShape()));
// Assert
EXPECT_EQ(curve.GetType(), GeomAbs_BezierCurve);
EXPECT_EQ(curve2.GetType(), GeomAbs_Line);
}
TEST_F(TopoShapeExpansionTest, makeElementLinearizeFace)
{
TColgp_Array2OfPnt points2 {1, 2, 1, 2};
points2.SetValue(1, 1, gp_Pnt(0.0, 0.0, 0.0));
points2.SetValue(2, 1, gp_Pnt(1.0, 0.0, 0.0));
points2.SetValue(1, 2, gp_Pnt(0.0, 1.0, 0.0));
points2.SetValue(2, 2, gp_Pnt(1.0, 1.0, 0.0));
auto face1 = new Geom_BezierSurface(points2);
auto surf1 = BRepBuilderAPI_MakeFace(face1, 0.1).Face();
TopoShape topoShape2 {surf1, 2L};
// Act
auto faces = topoShape2.getSubTopoShapes(TopAbs_FACE);
BRepAdaptor_Surface surface(TopoDS::Face(faces.front().getShape()));
topoShape2.linearize(LinearizeFace::linearizeFaces, LinearizeEdge::noEdges);
auto faces2 = topoShape2.getSubTopoShapes(TopAbs_FACE);
BRepAdaptor_Surface surface2(TopoDS::Face(faces.front().getShape()));
// Assert
EXPECT_EQ(surface.GetType(), GeomAbs_BezierSurface);
EXPECT_EQ(surface2.GetType(), GeomAbs_Plane);
}
// NOLINTEND(readability-magic-numbers,cppcoreguidelines-avoid-magic-numbers)