mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-27 02:31:09 +00:00
More robust processing of IfcPolyline and IfcPolyLoop
This commit is contained in:
@@ -36,6 +36,7 @@
|
|||||||
#include <TopoDS_Face.hxx>
|
#include <TopoDS_Face.hxx>
|
||||||
#include <Geom_Curve.hxx>
|
#include <Geom_Curve.hxx>
|
||||||
#include <gp_Pln.hxx>
|
#include <gp_Pln.hxx>
|
||||||
|
#include <TColgp_SequenceOfPnt.hxx>
|
||||||
|
|
||||||
#include "../ifcparse/IfcParse.h"
|
#include "../ifcparse/IfcParse.h"
|
||||||
#include "../ifcparse/IfcUtil.h"
|
#include "../ifcparse/IfcUtil.h"
|
||||||
@@ -103,7 +104,7 @@ namespace IfcGeom {
|
|||||||
void SetValue(GeomValue var, double value);
|
void SetValue(GeomValue var, double value);
|
||||||
double GetValue(GeomValue var);
|
double GetValue(GeomValue var);
|
||||||
Ifc2x3::IfcProductDefinitionShape* tesselate(TopoDS_Shape& shape, double deflection, IfcEntities es);
|
Ifc2x3::IfcProductDefinitionShape* tesselate(TopoDS_Shape& shape, double deflection, IfcEntities es);
|
||||||
|
void remove_redundant_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol=-1.);
|
||||||
|
|
||||||
|
|
||||||
namespace Cache {
|
namespace Cache {
|
||||||
|
|||||||
@@ -574,4 +574,28 @@ Ifc2x3::IfcProductDefinitionShape* IfcGeom::tesselate(TopoDS_Shape& shape, doubl
|
|||||||
es->push(shapedef);
|
es->push(shapedef);
|
||||||
|
|
||||||
return shapedef;
|
return shapedef;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IfcGeom::remove_redundant_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol) {
|
||||||
|
if (tol <= 0.) tol = GetValue(GV_POINT_EQUALITY_TOLERANCE);
|
||||||
|
tol *= tol;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
bool removed = false;
|
||||||
|
int n = polygon.Length() - (closed ? 0 : 1);
|
||||||
|
for (int i = 1; i <= n; ++i) {
|
||||||
|
// wrap around to the first point in case of a closed loop
|
||||||
|
int j = (i % polygon.Length()) + 1;
|
||||||
|
double dist = polygon.Value(i).SquareDistance(polygon.Value(j));
|
||||||
|
if (dist < tol) {
|
||||||
|
// do not remove the first or last point to
|
||||||
|
// maintain connectivity with other wires
|
||||||
|
if ((closed && j == 1) || (!closed && j == n)) polygon.Remove(i);
|
||||||
|
else polygon.Remove(j);
|
||||||
|
removed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!removed) break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -221,7 +221,11 @@ bool IfcGeom::convert(const Ifc2x3::IfcConnectedFaceSet::ptr l, TopoDS_Shape& sh
|
|||||||
builder.SetMinTolerance(GetValue(GV_POINT_EQUALITY_TOLERANCE));
|
builder.SetMinTolerance(GetValue(GV_POINT_EQUALITY_TOLERANCE));
|
||||||
for( Ifc2x3::IfcFace::it it = faces->begin(); it != faces->end(); ++ it ) {
|
for( Ifc2x3::IfcFace::it it = faces->begin(); it != faces->end(); ++ it ) {
|
||||||
TopoDS_Face face;
|
TopoDS_Face face;
|
||||||
if ( IfcGeom::convert_face(*it,face) && face_area(face) > GetValue(GV_MINIMAL_FACE_AREA) ) {
|
bool converted_face = false;
|
||||||
|
try {
|
||||||
|
converted_face = IfcGeom::convert_face(*it,face);
|
||||||
|
} catch (...) {}
|
||||||
|
if ( converted_face && face_area(face) > GetValue(GV_MINIMAL_FACE_AREA) ) {
|
||||||
builder.Add(face);
|
builder.Add(face);
|
||||||
facesAdded = true;
|
facesAdded = true;
|
||||||
} else {
|
} else {
|
||||||
@@ -229,9 +233,11 @@ bool IfcGeom::convert(const Ifc2x3::IfcConnectedFaceSet::ptr l, TopoDS_Shape& sh
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( ! facesAdded ) return false;
|
if ( ! facesAdded ) return false;
|
||||||
builder.Perform();
|
try {
|
||||||
shape = builder.SewedShape();
|
builder.Perform();
|
||||||
valid_shell = BRepCheck_Analyzer(shape).IsValid();
|
shape = builder.SewedShape();
|
||||||
|
valid_shell = BRepCheck_Analyzer(shape).IsValid();
|
||||||
|
} catch(...) {}
|
||||||
if (valid_shell) {
|
if (valid_shell) {
|
||||||
try {
|
try {
|
||||||
ShapeFix_Solid solid;
|
ShapeFix_Solid solid;
|
||||||
@@ -244,6 +250,8 @@ bool IfcGeom::convert(const Ifc2x3::IfcConnectedFaceSet::ptr l, TopoDS_Shape& sh
|
|||||||
} catch (...) {}
|
} catch (...) {}
|
||||||
}
|
}
|
||||||
} catch(...) {}
|
} catch(...) {}
|
||||||
|
} else {
|
||||||
|
Logger::Message(Logger::LOG_WARNING,"Failed to sew faceset:",l->entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!valid_shell) {
|
if (!valid_shell) {
|
||||||
@@ -252,7 +260,11 @@ bool IfcGeom::convert(const Ifc2x3::IfcConnectedFaceSet::ptr l, TopoDS_Shape& sh
|
|||||||
builder.MakeCompound(compound);
|
builder.MakeCompound(compound);
|
||||||
for( Ifc2x3::IfcFace::it it = faces->begin(); it != faces->end(); ++ it ) {
|
for( Ifc2x3::IfcFace::it it = faces->begin(); it != faces->end(); ++ it ) {
|
||||||
TopoDS_Face face;
|
TopoDS_Face face;
|
||||||
if ( IfcGeom::convert_face(*it,face) && face_area(face) > GetValue(GV_MINIMAL_FACE_AREA) ) {
|
bool converted_face = false;
|
||||||
|
try {
|
||||||
|
converted_face = IfcGeom::convert_face(*it,face);
|
||||||
|
} catch (...) {}
|
||||||
|
if ( converted_face && face_area(face) > GetValue(GV_MINIMAL_FACE_AREA) ) {
|
||||||
builder.Add(compound,face);
|
builder.Add(compound,face);
|
||||||
facesAdded = true;
|
facesAdded = true;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -262,13 +262,20 @@ bool IfcGeom::convert(const Ifc2x3::IfcTrimmedCurve::ptr l, TopoDS_Wire& wire) {
|
|||||||
bool IfcGeom::convert(const Ifc2x3::IfcPolyline::ptr l, TopoDS_Wire& result) {
|
bool IfcGeom::convert(const Ifc2x3::IfcPolyline::ptr l, TopoDS_Wire& result) {
|
||||||
Ifc2x3::IfcCartesianPoint::list points = l->Points();
|
Ifc2x3::IfcCartesianPoint::list points = l->Points();
|
||||||
|
|
||||||
BRepBuilderAPI_MakeWire w;
|
// Parse and store the points in a sequence
|
||||||
gp_Pnt P1;gp_Pnt P2;
|
TColgp_SequenceOfPnt polygon;
|
||||||
for( Ifc2x3::IfcCartesianPoint::it it = points->begin(); it != points->end(); ++ it ) {
|
for(Ifc2x3::IfcCartesianPoint::it it = points->begin(); it != points->end(); ++ it) {
|
||||||
IfcGeom::convert(*it,P2);
|
gp_Pnt pnt;
|
||||||
if ( it != points->begin() && ( !P1.IsEqual(P2,GetValue(GV_POINT_EQUALITY_TOLERANCE)) ) )
|
IfcGeom::convert(*it, pnt);
|
||||||
w.Add(BRepBuilderAPI_MakeEdge(P1,P2));
|
polygon.Append(pnt);
|
||||||
P1 = P2;
|
}
|
||||||
|
|
||||||
|
// Remove points that are too close to one another
|
||||||
|
remove_redundant_points_from_loop(polygon, false);
|
||||||
|
|
||||||
|
BRepBuilderAPI_MakePolygon w;
|
||||||
|
for (int i = 1; i <= polygon.Length(); ++i) {
|
||||||
|
w.Add(polygon.Value(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
result = w.Wire();
|
result = w.Wire();
|
||||||
@@ -277,23 +284,41 @@ bool IfcGeom::convert(const Ifc2x3::IfcPolyline::ptr l, TopoDS_Wire& result) {
|
|||||||
bool IfcGeom::convert(const Ifc2x3::IfcPolyLoop::ptr l, TopoDS_Wire& result) {
|
bool IfcGeom::convert(const Ifc2x3::IfcPolyLoop::ptr l, TopoDS_Wire& result) {
|
||||||
Ifc2x3::IfcCartesianPoint::list points = l->Polygon();
|
Ifc2x3::IfcCartesianPoint::list points = l->Polygon();
|
||||||
|
|
||||||
BRepBuilderAPI_MakeWire w;
|
// Parse and store the points in a sequence
|
||||||
gp_Pnt P1;gp_Pnt P2;gp_Pnt F;
|
TColgp_SequenceOfPnt polygon;
|
||||||
int count = 0;
|
for(Ifc2x3::IfcCartesianPoint::it it = points->begin(); it != points->end(); ++ it) {
|
||||||
for( Ifc2x3::IfcCartesianPoint::it it = points->begin(); it != points->end(); ++ it ) {
|
gp_Pnt pnt;
|
||||||
IfcGeom::convert(*it,P2);
|
IfcGeom::convert(*it, pnt);
|
||||||
if ( it != points->begin() && ( !P1.IsEqual(P2,GetValue(GV_POINT_EQUALITY_TOLERANCE)) ) ) {
|
polygon.Append(pnt);
|
||||||
w.Add(BRepBuilderAPI_MakeEdge(P1,P2));
|
|
||||||
count ++;
|
|
||||||
} else if ( ! count ) F = P2;
|
|
||||||
P1 = P2;
|
|
||||||
}
|
}
|
||||||
if ( !P1.IsEqual(F,GetValue(GV_POINT_EQUALITY_TOLERANCE)) ) {
|
|
||||||
w.Add(BRepBuilderAPI_MakeEdge(P1,F));
|
|
||||||
count ++;
|
|
||||||
}
|
|
||||||
if ( count < 3 ) return false;
|
|
||||||
|
|
||||||
result = w.Wire();
|
// A loop should consist of at least three vertices
|
||||||
|
int original_count = polygon.Length();
|
||||||
|
if (original_count < 3) {
|
||||||
|
Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove points that are too close to one another
|
||||||
|
remove_redundant_points_from_loop(polygon, true);
|
||||||
|
|
||||||
|
int count = polygon.Length();
|
||||||
|
if (original_count - count != 0) {
|
||||||
|
std::stringstream ss; ss << (original_count - count) << " edges removed for:";
|
||||||
|
Logger::Message(Logger::LOG_WARNING, ss.str(), l->entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count < 3) {
|
||||||
|
Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BRepBuilderAPI_MakePolygon w;
|
||||||
|
for (int i = 1; i <= polygon.Length(); ++i) {
|
||||||
|
w.Add(polygon.Value(i));
|
||||||
|
}
|
||||||
|
w.Close();
|
||||||
|
|
||||||
|
result = w.Wire();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user