Skip to content

Commit 297812d

Browse files
committed
Better handling of consecutive circular arc segments
1 parent 7205f01 commit 297812d

File tree

1 file changed

+58
-12
lines changed

1 file changed

+58
-12
lines changed

src/ifcgeom/IfcGeomWires.cpp

Lines changed: 58 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@
4343
#include <gp_Pln.hxx>
4444
#include <gp_Circ.hxx>
4545

46+
#include <GC_MakeCircle.hxx>
47+
4648
#include <TColgp_Array1OfPnt.hxx>
4749
#include <TColgp_Array1OfPnt2d.hxx>
4850
#include <TColStd_Array1OfReal.hxx>
@@ -109,14 +111,57 @@ namespace {
109111

110112
// Returns new wire with the edge replaced by a linear edge with the vertex v moved to p
111113
TopoDS_Wire adjust(const TopoDS_Wire& w, const TopoDS_Vertex& v, const gp_Pnt& p) {
112-
BRep_Builder b;
113-
TopoDS_Vertex v2;
114-
b.MakeVertex(v2, p, BRep_Tool::Tolerance(v));
114+
TopTools_IndexedDataMapOfShapeListOfShape map;
115+
TopExp::MapShapesAndAncestors(w, TopAbs_VERTEX, TopAbs_EDGE, map);
116+
117+
bool all_linear = true, single_circle = false, first = true;
118+
TopTools_ListOfShape edges;
119+
if (map.FindFromKey(v, edges)) {
120+
TopTools_ListIteratorOfListOfShape it(edges);
121+
for (; it.More(); it.Next()) {
122+
const TopoDS_Edge& e = TopoDS::Edge(it.Value());
123+
double _, __;
124+
Handle(Geom_Curve) crv = BRep_Tool::Curve(e, _, __);
125+
const bool is_line = crv->DynamicType() == STANDARD_TYPE(Geom_Line);
126+
const bool is_circle = crv->DynamicType() == STANDARD_TYPE(Geom_Circle);
127+
all_linear = all_linear && all_linear;
128+
single_circle = first && is_circle;
129+
}
130+
}
131+
132+
if (all_linear) {
133+
BRep_Builder b;
134+
TopoDS_Vertex v2;
135+
b.MakeVertex(v2, p, BRep_Tool::Tolerance(v));
136+
137+
ShapeBuild_ReShape reshape;
138+
reshape.Replace(v.Oriented(TopAbs_FORWARD), v2);
115139

116-
ShapeBuild_ReShape reshape;
117-
reshape.Replace(v.Oriented(TopAbs_FORWARD), v2);
140+
return TopoDS::Wire(reshape.Apply(w));
141+
} else if (single_circle) {
142+
TopoDS_Vertex v1, v2;
143+
TopExp::Vertices(w, v1, v2);
144+
145+
gp_Pnt p1, p2, p3;
146+
p1 = v.IsEqual(v1) ? p : BRep_Tool::Pnt(v1);
147+
p3 = v.IsEqual(v2) ? p : BRep_Tool::Pnt(v2);
148+
149+
double a, b;
150+
Handle(Geom_Curve) crv = BRep_Tool::Curve(TopoDS::Edge(edges.First()), a, b);
151+
crv->D0((a + b) / 2., p2);
152+
153+
GC_MakeCircle mc(p1, p2, p3);
154+
if (!mc.IsDone()) {
155+
throw IfcGeom::geometry_exception("Failed to adjust circle");
156+
}
118157

119-
return TopoDS::Wire(reshape.Apply(w));
158+
TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(mc.Value(), p1, p3).Edge();
159+
BRepBuilderAPI_MakeWire builder;
160+
builder.Add(edge);
161+
return builder.Wire();
162+
} else {
163+
throw IfcGeom::geometry_exception("Unexpected wire to adjust");
164+
}
120165
}
121166

122167
// A wrapper around BRepBuilderAPI_MakeWire that makes sure segments are connected either by moving end points or by adding intermediate segments
@@ -193,17 +238,20 @@ namespace {
193238
const bool is_line1 = c1->DynamicType() == STANDARD_TYPE(Geom_Line);
194239
const bool is_line2 = c2->DynamicType() == STANDARD_TYPE(Geom_Line);
195240

196-
// Adjust the segment that is linear
197-
if (is_line1) {
241+
const bool is_circle1 = c1->DynamicType() == STANDARD_TYPE(Geom_Circle);
242+
const bool is_circle2 = c2->DynamicType() == STANDARD_TYPE(Geom_Circle);
243+
244+
// Preferably adjust the segment that is linear
245+
if (is_line1 || (is_circle1 && !is_line2)) {
198246
mw_.Add(adjust(w1, w12, p2));
199247
Logger::Message(Logger::LOG_ERROR, "Adjusted edge end-point with distance " + boost::lexical_cast<std::string>(dist) + " on:", inst_->entity);
200-
} else if (is_line2 && !last) {
248+
} else if ((is_line2 || is_circle2) && !last) {
201249
mw_.Add(w1);
202250
override_next_ = true;
203251
next_override_ = p1;
204252
Logger::Message(Logger::LOG_ERROR, "Adjusted edge end-point with distance " + boost::lexical_cast<std::string>(dist) + " on:", inst_->entity);
205253
} else {
206-
// If both aren't linear an edge is added
254+
// In all other cases an edge is added
207255
mw_.Add(w1);
208256
mw_.Add(BRepBuilderAPI_MakeEdge(p1, p2));
209257
Logger::Message(Logger::LOG_ERROR, "Added additional segment to close gap with length " + boost::lexical_cast<std::string>(dist) + " to:", inst_->entity);
@@ -721,8 +769,6 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSubedge* l, TopoDS_Wire& resul
721769

722770
#ifdef USE_IFC4
723771

724-
#include <GC_MakeCircle.hxx>
725-
726772
bool IfcGeom::Kernel::convert(const IfcSchema::IfcIndexedPolyCurve* l, TopoDS_Wire& result) {
727773

728774
IfcSchema::IfcCartesianPointList* point_list = l->Points();

0 commit comments

Comments
 (0)