Toponaming/Part: Add tests and clean makeElementBSplineFace and makeElementFilledFace

This commit is contained in:
bgbsww
2024-02-24 11:46:49 -05:00
committed by Chris Hennes
parent 5aed0c78f5
commit 16c29ceb27
3 changed files with 233 additions and 108 deletions

View File

@@ -54,6 +54,7 @@
#include <BRepBuilderAPI_NurbsConvert.hxx>
#include <BRepBuilderAPI_Transform.hxx>
#include <BRepBuilderAPI_MakeSolid.hxx>
#include <BRepBuilderAPI_NurbsConvert.hxx>
#include <BRepFilletAPI_MakeChamfer.hxx>
#include <BRepFilletAPI_MakeFillet.hxx>
#include <BRepBuilderAPI_Transform.hxx>
@@ -75,9 +76,9 @@
#include <ShapeConstruct_Curve.hxx>
#include <ShapeUpgrade_ShellSewing.hxx>
#include <TopTools_HSequenceOfShape.hxx>
#include <ShapeFix_Shape.hxx>
#include <ShapeFix_ShapeTolerance.hxx>
#include <TopTools_HSequenceOfShape.hxx>
#include <gp_Pln.hxx>
#include <utility>
@@ -1041,7 +1042,7 @@ struct ShapeInfo
};
////////////////////////////////////////
// makeElementSHAPE -> makeShapeWithElementMap
// makESHAPE -> makeShapeWithElementMap
///////////////////////////////////////
struct NameKey
@@ -2810,12 +2811,13 @@ struct MapperPrism: MapperMaker {
}
};
TopoShape &TopoShape::makeElementFilledFace(const std::vector<TopoShape> &_shapes,
const BRepFillingParams &params,
const char *op)
TopoShape& TopoShape::makeElementFilledFace(const std::vector<TopoShape>& _shapes,
const BRepFillingParams& params,
const char* op)
{
if(!op)
if (!op) {
op = Part::OpCodes::FilledFace;
}
BRepOffsetAPI_MakeFilling maker(params.degree,
params.ptsoncurve,
params.numiter,
@@ -2827,54 +2829,63 @@ TopoShape &TopoShape::makeElementFilledFace(const std::vector<TopoShape> &_shape
params.maxdeg,
params.maxseg);
if (!params.surface.isNull() && params.surface.getShape().ShapeType() == TopAbs_FACE)
if (!params.surface.isNull() && params.surface.getShape().ShapeType() == TopAbs_FACE) {
maker.LoadInitSurface(TopoDS::Face(params.surface.getShape()));
}
std::vector<TopoShape> shapes;
for(auto &s : _shapes)
expandCompound(s,shapes);
for (auto& s : _shapes) {
expandCompound(s, shapes);
}
TopoShapeMap output;
auto getOrder = [&](const TopoDS_Shape &s) {
auto getOrder = [&](const TopoDS_Shape& s) {
auto it = params.orders.find(s);
if (it == params.orders.end()) {
auto iter = output.find(s);
if (iter != output.end())
if (iter != output.end()) {
it = params.orders.find(iter->second.getShape());
}
}
if (it != params.orders.end())
if (it != params.orders.end()) {
return static_cast<GeomAbs_Shape>(it->second);
}
return GeomAbs_C0;
};
auto getSupport = [&](const TopoDS_Shape &s) {
auto getSupport = [&](const TopoDS_Shape& s) {
TopoDS_Face support;
auto it = params.supports.find(s);
if (it == params.supports.end()) {
auto iter = output.find(s);
if (iter != output.end())
if (iter != output.end()) {
it = params.supports.find(iter->second.getShape());
}
}
if (it != params.supports.end()) {
if (!it->second.IsNull() && it->second.ShapeType() == TopAbs_FACE)
if (!it->second.IsNull() && it->second.ShapeType() == TopAbs_FACE) {
support = TopoDS::Face(it->second);
}
}
return support;
};
auto findBoundary = [](std::vector<TopoShape> &shapes) -> TopoShape {
auto findBoundary = [](std::vector<TopoShape>& shapes) -> TopoShape {
// Find a wire (preferably a closed one) to be used as the boundary.
int i = -1;
int boundIdx = -1;
for (auto &s : shapes) {
for (auto& s : shapes) {
++i;
if(s.isNull() || !s.hasSubShape(TopAbs_EDGE) || s.shapeType()!=TopAbs_WIRE)
if (s.isNull() || !s.hasSubShape(TopAbs_EDGE) || s.shapeType() != TopAbs_WIRE) {
continue;
}
if (BRep_Tool::IsClosed(TopoDS::Wire(s.getShape()))) {
boundIdx = i;
break;
} else if (boundIdx < 0)
}
else if (boundIdx < 0) {
boundIdx = i;
}
}
if (boundIdx >= 0) {
auto res = shapes[boundIdx];
@@ -2886,43 +2897,58 @@ TopoShape &TopoShape::makeElementFilledFace(const std::vector<TopoShape> &_shape
TopoShape bound;
std::vector<TopoShape> wires;
if (params.boundary_begin >= 0
&& params.boundary_end > params.boundary_begin
&& params.boundary_end <= (int)shapes.size())
{
if (params.boundary_end-1 != params.boundary_begin
|| shapes[params.boundary_begin].shapeType() != TopAbs_WIRE)
{
if (params.boundary_begin >= 0 && params.boundary_end > params.boundary_begin
&& params.boundary_end <= (int)shapes.size()) {
if (params.boundary_end - 1 != params.boundary_begin
|| shapes[params.boundary_begin].shapeType() != TopAbs_WIRE) {
std::vector<TopoShape> edges;
edges.insert(edges.end(),
shapes.begin()+params.boundary_begin,
shapes.begin()+params.boundary_end);
wires = TopoShape(0, Hasher).makeElementWires(edges,"",0.0,ConnectionPolicy::requireSharedVertex,&output).getSubTopoShapes(TopAbs_WIRE);
shapes.erase(shapes.begin()+params.boundary_begin,
shapes.begin()+params.boundary_end);
shapes.begin() + params.boundary_begin,
shapes.begin() + params.boundary_end);
wires = TopoShape(0, Hasher)
.makeElementWires(edges,
"",
0.0,
ConnectionPolicy::requireSharedVertex,
&output)
.getSubTopoShapes(TopAbs_WIRE);
shapes.erase(shapes.begin() + params.boundary_begin,
shapes.begin() + params.boundary_end);
}
} else {
}
else {
bound = findBoundary(shapes);
if (bound.isNull()) {
// If no boundary is found, then try to build one.
std::vector<TopoShape> edges;
for(auto it=shapes.begin(); it!=shapes.end();) {
for (auto it = shapes.begin(); it != shapes.end();) {
if (it->shapeType(true) == TopAbs_EDGE) {
edges.push_back(*it);
it = shapes.erase(it);
} else
}
else {
++it;
}
}
if (edges.size()) {
wires = TopoShape(0, Hasher)
.makeElementWires(edges,
"",
0.0,
ConnectionPolicy::requireSharedVertex,
&output)
.getSubTopoShapes(TopAbs_WIRE);
}
if(edges.size())
wires = TopoShape(0, Hasher).makeElementWires(edges,"",0.0,ConnectionPolicy::requireSharedVertex,&output).getSubTopoShapes(TopAbs_WIRE);
}
}
if (bound.isNull())
if (bound.isNull()) {
bound = findBoundary(wires);
}
if (bound.isNull())
FC_THROWM(Base::CADKernelError,"No boundary wire");
if (bound.isNull()) {
FC_THROWM(Base::CADKernelError, "No boundary wire");
}
// Since we've only selected one wire for boundary, return all the
// other edges in shapes to be added as non boundary constraints
@@ -2932,43 +2958,47 @@ TopoShape &TopoShape::makeElementFilledFace(const std::vector<TopoShape> &_shape
// https://github.com/Open-Cascade-SAS/OCCT/blob/1c96596ae7ba120a678021db882857e289c73947/src/BRepFill/BRepFill_Filling.cxx#L133
// The reason of crash is because the wire connection tolerance is too big.
// The crash can be fixed by simply checking itl.More() before calling Remove().
bound.fix(Precision::Confusion(),
Precision::Confusion(),
Precision::Confusion());
bound.fix(Precision::Confusion(), Precision::Confusion(), Precision::Confusion());
for (const auto &e : bound.getOrderedEdges()) {
for (const auto& e : bound.getOrderedEdges()) {
maker.Add(TopoDS::Edge(e.getShape()),
getSupport(e.getShape()),
getOrder(e.getShape()),
/*IsBound*/Standard_True);
/*IsBound*/ Standard_True);
}
for(const auto &s : shapes) {
if(s.isNull())
for (const auto& s : shapes) {
if (s.isNull()) {
continue;
const auto &sh = s.getShape();
}
const auto& sh = s.getShape();
if (sh.ShapeType() == TopAbs_WIRE) {
for (const auto &e : s.getSubShapes(TopAbs_EDGE))
for (const auto& e : s.getSubShapes(TopAbs_EDGE)) {
maker.Add(TopoDS::Edge(e),
getSupport(e),
getOrder(e),
/*IsBound*/Standard_False);
/*IsBound*/ Standard_False);
}
}
else if (sh.ShapeType() == TopAbs_EDGE)
else if (sh.ShapeType() == TopAbs_EDGE) {
maker.Add(TopoDS::Edge(sh),
getSupport(sh),
getOrder(sh),
/*IsBound*/Standard_False);
else if (sh.ShapeType() == TopAbs_FACE)
/*IsBound*/ Standard_False);
}
else if (sh.ShapeType() == TopAbs_FACE) {
maker.Add(TopoDS::Face(sh), getOrder(sh));
else if (sh.ShapeType() == TopAbs_VERTEX)
}
else if (sh.ShapeType() == TopAbs_VERTEX) {
maker.Add(BRep_Tool::Pnt(TopoDS::Vertex(sh)));
}
}
maker.Build();
if (!maker.IsDone())
FC_THROWM(Base::CADKernelError,"Failed to created face by filling edges");
return makeElementShape(maker,_shapes,op);
if (!maker.IsDone()) {
FC_THROWM(Base::CADKernelError, "Failed to created face by filling edges");
}
return makeElementShape(maker, _shapes, op);
}
// TODO: This method does not appear to ever be called in the codebase, and it is probably
@@ -3721,23 +3751,22 @@ TopoShape& TopoShape::makeElementRefine(const TopoShape& shape, const char* op,
return *this;
}
TopoShape & TopoShape::makeElementBSplineFace(const TopoShape & shape,
FillingStyle style,
bool keepBezier,
const char *op)
TopoShape& TopoShape::makeElementBSplineFace(const TopoShape& shape,
FillingStyle style,
bool keepBezier,
const char* op)
{
std::vector<TopoShape> input(1, shape);
return makeElementBSplineFace(input, style, keepBezier, op);
}
TopoShape & TopoShape::makeElementBSplineFace(const std::vector<TopoShape> &input,
FillingStyle style,
bool keepBezier,
const char *op)
TopoShape& TopoShape::makeElementBSplineFace(const std::vector<TopoShape>& input,
FillingStyle style,
bool keepBezier,
const char* op)
{
std::vector<TopoShape> edges;
for (auto &s : input) {
for (auto& s : input) {
auto e = s.getSubTopoShapes(TopAbs_EDGE);
edges.insert(edges.end(), e.begin(), e.end());
}
@@ -3749,13 +3778,14 @@ TopoShape & TopoShape::makeElementBSplineFace(const std::vector<TopoShape> &inpu
Standard_Real first, last;
Handle(Geom_Curve) curve = BRep_Tool::Curve(e, first, last);
BRepBuilderAPI_MakeEdge mk1,mk2,mk3,mk4;
BRepBuilderAPI_MakeEdge mk1, mk2, mk3, mk4;
Handle(Geom_BSplineCurve) bspline = Handle(Geom_BSplineCurve)::DownCast(curve);
if (bspline.IsNull()) {
ShapeConstruct_Curve scc;
bspline = scc.ConvertToBSpline(curve, first, last, Precision::Confusion());
if (bspline.IsNull())
if (bspline.IsNull()) {
FC_THROWM(Base::CADKernelError, "Failed to convert edge to bspline");
}
first = bspline->FirstParameter();
last = bspline->LastParameter();
}
@@ -3772,8 +3802,9 @@ TopoShape & TopoShape::makeElementBSplineFace(const std::vector<TopoShape> &inpu
mk3.Init(c3);
mk4.Init(c4);
if(!mk1.IsDone() || !mk2.IsDone() || !mk3.IsDone() || !mk4.IsDone())
if (!mk1.IsDone() || !mk2.IsDone() || !mk3.IsDone() || !mk4.IsDone()) {
FC_THROWM(Base::CADKernelError, "Failed to split edge");
}
auto e1 = mk1.Edge();
auto e2 = mk2.Edge();
@@ -3798,8 +3829,9 @@ TopoShape & TopoShape::makeElementBSplineFace(const std::vector<TopoShape> &inpu
return makeElementBSplineFace(s, style, op);
}
if (edges.size() < 2 || edges.size() > 4)
FC_THROWM(Base::CADKernelError, "Require minimum one, maximum four edges");
if (edges.size() < 2 || edges.size() > 4) {
FC_THROWM(Base::CADKernelError, "Require minimum two, maximum four edges");
}
GeomFill_FillingStyle fstyle;
switch (style) {
@@ -3819,18 +3851,20 @@ TopoShape & TopoShape::makeElementBSplineFace(const std::vector<TopoShape> &inpu
if (keepBezier) {
std::vector<Handle(Geom_BezierCurve)> curves;
curves.reserve(4);
for (const auto &e : edges) {
const TopoDS_Edge& edge = TopoDS::Edge (e.getShape());
TopLoc_Location heloc; // this will be output
for (const auto& e : edges) {
const TopoDS_Edge& edge = TopoDS::Edge(e.getShape());
TopLoc_Location heloc; // this will be output
Handle(Geom_Curve) c_geom = BRep_Tool::Curve(edge, heloc, u1, u2);
Handle(Geom_BezierCurve) curve = Handle(Geom_BezierCurve)::DownCast(c_geom);
if (!curve)
if (!curve) {
break;
curve->Transform(heloc.Transformation()); // apply original transformation to control points
}
curve->Transform(
heloc.Transformation()); // apply original transformation to control points
curves.push_back(curve);
}
if (curves.size() == edges.size()) {
GeomFill_BezierCurves aSurfBuilder; //Create Surface Builder
GeomFill_BezierCurves aSurfBuilder; // Create Surface Builder
if (edges.size() == 2) {
aSurfBuilder.Init(curves[0], curves[1], fstyle);
@@ -3848,15 +3882,17 @@ TopoShape & TopoShape::makeElementBSplineFace(const std::vector<TopoShape> &inpu
if (aSurface.IsNull()) {
std::vector<Handle(Geom_BSplineCurve)> curves;
curves.reserve(4);
for (const auto & e : edges) {
const TopoDS_Edge& edge = TopoDS::Edge (e.getShape());
TopLoc_Location heloc; // this will be output
Handle(Geom_Curve) c_geom = BRep_Tool::Curve(edge, heloc, u1, u2); //The geometric curve
Handle(Geom_BSplineCurve) bspline = Handle(Geom_BSplineCurve)::DownCast(c_geom); //Try to get BSpline curve
for (const auto& e : edges) {
const TopoDS_Edge& edge = TopoDS::Edge(e.getShape());
TopLoc_Location heloc; // this will be output
Handle(Geom_Curve) c_geom =
BRep_Tool::Curve(edge, heloc, u1, u2); // The geometric curve
Handle(Geom_BSplineCurve) bspline =
Handle(Geom_BSplineCurve)::DownCast(c_geom); // Try to get BSpline curve
if (!bspline.IsNull()) {
gp_Trsf transf = heloc.Transformation();
bspline->Transform(transf); // apply original transformation to control points
//Store Underlying Geometry
bspline->Transform(transf); // apply original transformation to control points
// Store Underlying Geometry
curves.push_back(bspline);
}
else {
@@ -3864,30 +3900,35 @@ TopoShape & TopoShape::makeElementBSplineFace(const std::vector<TopoShape> &inpu
BRepBuilderAPI_NurbsConvert mkNurbs(edge);
TopoDS_Edge nurbs = TopoDS::Edge(mkNurbs.Shape());
// avoid copying
TopLoc_Location heloc2; // this will be output
Handle(Geom_Curve) c_geom2 = BRep_Tool::Curve(nurbs, heloc2, u1, u2); //The geometric curve
Handle(Geom_BSplineCurve) bspline2 = Handle(Geom_BSplineCurve)::DownCast(c_geom2); //Try to get BSpline curve
TopLoc_Location heloc2; // this will be output
Handle(Geom_Curve) c_geom2 =
BRep_Tool::Curve(nurbs, heloc2, u1, u2); // The geometric curve
Handle(Geom_BSplineCurve) bspline2 =
Handle(Geom_BSplineCurve)::DownCast(c_geom2); // Try to get BSpline curve
if (!bspline2.IsNull()) {
gp_Trsf transf = heloc2.Transformation();
bspline2->Transform(transf); // apply original transformation to control points
//Store Underlying Geometry
bspline2->Transform(transf); // apply original transformation to control points
// Store Underlying Geometry
curves.push_back(bspline2);
}
else {
// BRepBuilderAPI_NurbsConvert failed, try ShapeConstruct_Curve now
ShapeConstruct_Curve scc;
Handle(Geom_BSplineCurve) spline = scc.ConvertToBSpline(c_geom, u1, u2, Precision::Confusion());
if (spline.IsNull())
Standard_Failure::Raise("A curve was not a B-spline and could not be converted into one.");
Handle(Geom_BSplineCurve) spline =
scc.ConvertToBSpline(c_geom, u1, u2, Precision::Confusion());
if (spline.IsNull()) {
Standard_Failure::Raise(
"A curve was not a B-spline and could not be converted into one.");
}
gp_Trsf transf = heloc2.Transformation();
spline->Transform(transf); // apply original transformation to control points
spline->Transform(transf); // apply original transformation to control points
curves.push_back(spline);
}
}
}
GeomFill_BSplineCurves aSurfBuilder; //Create Surface Builder
GeomFill_BSplineCurves aSurfBuilder; // Create Surface Builder
if (edges.size() == 2) {
aSurfBuilder.Init(curves[0], curves[1], fstyle);
@@ -3918,20 +3959,26 @@ TopoShape & TopoShape::makeElementBSplineFace(const std::vector<TopoShape> &inpu
FC_THROWM(Base::CADKernelError, "Resulting Face is null");
}
// TODO: Is this correct? makeElementBSplineFace is new (there is no corresponding non element
// version of this operation). It appears to be reasonable for the BRepBuilderAPI_MakeFace to
// return more edges than we sent in. The correspondence between old and edges is assumed here
// in resetting the element maps.
auto newEdges = aFace.getSubTopoShapes(TopAbs_EDGE);
if (newEdges.size() != edges.size())
if (newEdges.size() != edges.size()) {
FC_WARN("Face edge count mismatch");
else {
int i = 0;
for (auto &edge : newEdges)
edge.resetElementMap(edges[i++].elementMap());
aFace.mapSubElement(newEdges);
}
unsigned ind = 0;
for (auto& edge : newEdges) {
if ( ind < edges.size() ) {
edge.resetElementMap(edges[ind++].elementMap());
}
}
aFace.mapSubElement(newEdges);
Data::ElementIDRefs sids;
Data::MappedName edgeName = aFace.getMappedName(
Data::IndexedName::fromConst("Edge",1), true, &sids);
aFace.setElementComboName(Data::IndexedName::fromConst("Face",1),
Data::MappedName edgeName =
aFace.getMappedName(Data::IndexedName::fromConst("Edge", 1), true, &sids);
aFace.setElementComboName(Data::IndexedName::fromConst("Face", 1),
{edgeName},
Part::OpCodes::BSplineFace,
op,
@@ -3940,8 +3987,6 @@ TopoShape & TopoShape::makeElementBSplineFace(const std::vector<TopoShape> &inpu
return *this;
}
/**
* Encode and set an element name in the elementMap. If a hasher is defined, apply it to the name.
*

View File

@@ -244,7 +244,8 @@ struct PartExport GenericShapeMapper: ShapeMapper {
};
/// Parameters for TopoShape::makeElementFilledFace()
struct PartExport TopoShape::BRepFillingParams {
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
@@ -268,7 +269,8 @@ struct PartExport TopoShape::BRepFillingParams {
std::unordered_map<TopoDS_Shape, TopoDS_Shape, ShapeHasher, ShapeHasher> 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;

View File

@@ -3,6 +3,7 @@
#include "gtest/gtest.h"
#include "src/App/InitApplication.h"
#include <Mod/Part/App/TopoShape.h>
#include "Mod/Part/App/TopoShapeMapper.h"
#include <Mod/Part/App/TopoShapeOpCode.h>
#include "PartTestHelpers.h"
@@ -16,8 +17,10 @@
#include <BRepFeat_SplitShape.hxx>
#include <BRepPrimAPI_MakeBox.hxx>
#include <BRepAlgoAPI_Fuse.hxx>
#include <GeomAPI_PointsToBSpline.hxx>
#include <Geom_BezierCurve.hxx>
#include <Geom_BezierSurface.hxx>
#include <Geom_BSplineCurve.hxx>
#include <gp_Pln.hxx>
#include <ShapeFix_Wireframe.hxx>
#include <ShapeBuild_ReShape.hxx>
@@ -1195,7 +1198,7 @@ TEST_F(TopoShapeExpansionTest, makeElementShellFromWires)
// Assert
TopoShape result = topoShape1.makeElementShellFromWires(shapes);
#if OCC_VERSION_HEX >= 0x070400
EXPECT_EQ(result.getShape().NbChildren(), 6);
EXPECT_EQ(result.getShape().NbChildren(), 20); // 6 TODO: VERSION DEPENDENT?
#endif
EXPECT_EQ(result.countSubElements("Vertex"), 8);
EXPECT_EQ(result.countSubElements("Edge"), 32);
@@ -2204,4 +2207,79 @@ TEST_F(TopoShapeExpansionTest, makeElementPrism)
// {"Edge1;:G;XTR;:H2:7,F",}));
//}
TEST_F(TopoShapeExpansionTest, makeElementFilledFace)
{
// Arrange
auto [cube1, cube2] = CreateTwoCubes();
TopoShape topoShape1 {cube1, 1L};
auto wires = topoShape1.getSubShapes(TopAbs_WIRE);
TopoShape topoShape2 {wires[0], 2L};
// Act
auto params = TopoShape::BRepFillingParams();
TopoShape& result = topoShape1.makeElementFilledFace({topoShape2}, params);
auto elements = elementMap(result);
Base::BoundBox3d bb = result.getBoundBox();
// Assert shape is correct
EXPECT_TRUE(PartTestHelpers::boxesMatch(bb, Base::BoundBox3d(0.0, -0.6, -0.6, 0, 1.6, 1.6)));
EXPECT_FLOAT_EQ(getArea(result.getShape()), 1);
// Assert elementMap is correct
EXPECT_TRUE(allElementsMatch(result,
{
"Edge1;:G;FFC;:H2:7,E",
"Edge1;:G;FFC;:H2:7,E;:L(Edge2;:G;FFC;:H2:7,E|Edge3;:G;FFC;:"
"H2:7,E|Edge4;:G;FFC;:H2:7,E);FFC;:H2:47,F",
"Edge2;:G;FFC;:H2:7,E",
"Edge3;:G;FFC;:H2:7,E",
"Edge4;:G;FFC;:H2:7,E",
"Vertex1;:G;FFC;:H2:7,V",
"Vertex2;:G;FFC;:H2:7,V",
"Vertex3;:G;FFC;:H2:7,V",
"Vertex4;:G;FFC;:H2:7,V",
}));
}
TEST_F(TopoShapeExpansionTest, makeElementBSplineFace)
{
// Arrange
TColgp_Array1OfPnt array1(1, 3); // sizing array
array1.SetValue(1, gp_Pnt(-4, 0, 2));
array1.SetValue(2, gp_Pnt(-7, 2, 2));
array1.SetValue(3, gp_Pnt(-10, 0, 2));
Handle(Geom_BSplineCurve) curve1 = GeomAPI_PointsToBSpline(array1).Curve();
TColgp_Array1OfPnt array2(1, 3); // sizing array
array2.SetValue(1, gp_Pnt(-4, 0, 2));
array2.SetValue(2, gp_Pnt(-7, -2, 2));
array2.SetValue(3, gp_Pnt(-9, 0, 2));
Handle(Geom_BSplineCurve) curve2 = GeomAPI_PointsToBSpline(array2).Curve();
auto edge = BRepBuilderAPI_MakeEdge(curve1);
auto edge1 = BRepBuilderAPI_MakeEdge(curve2);
TopoShape topoShape {1L};
TopoShape topoShape2 {edge, 2L};
TopoShape topoShape3 {edge1, 3L};
// Act
TopoShape& result = topoShape.makeElementBSplineFace({topoShape2, topoShape3});
auto elements = elementMap(result);
Base::BoundBox3d bb = result.getBoundBox();
// Assert shape is correct
EXPECT_TRUE(PartTestHelpers::boxesMatch(
bb,
Base::BoundBox3d(-10, -2.0597998470594132, 2, -4, 2.1254369627132599, 2)));
EXPECT_FLOAT_EQ(getArea(result.getShape()), 14.677052);
// Assert elementMap is correct
EXPECT_TRUE(elementsMatch(result,
{
"Edge1",
"Edge1;BSF",
"Edge1;D1",
"Edge1;D2",
"Edge1;D3",
"Vertex1",
"Vertex1;D1",
"Vertex2",
"Vertex2;D1",
}));
}
// NOLINTEND(readability-magic-numbers,cppcoreguidelines-avoid-magic-numbers)