mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-19 14:41:25 +00:00
Fill holes in composite curves, fixes #282
This commit is contained in:
@@ -616,17 +616,18 @@ bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool IfcGeom::Kernel::convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face) {
|
bool IfcGeom::Kernel::convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face) {
|
||||||
|
ShapeFix_ShapeTolerance FTol;
|
||||||
|
FTol.SetTolerance(wire, getValue(GV_PRECISION), TopAbs_WIRE);
|
||||||
|
|
||||||
BRepBuilderAPI_MakeFace mf(wire, false);
|
BRepBuilderAPI_MakeFace mf(wire, false);
|
||||||
BRepBuilderAPI_FaceError er = mf.Error();
|
BRepBuilderAPI_FaceError er = mf.Error();
|
||||||
if ( er == BRepBuilderAPI_NotPlanar ) {
|
|
||||||
ShapeFix_ShapeTolerance FTol;
|
if (er != BRepBuilderAPI_FaceDone) {
|
||||||
FTol.SetTolerance(wire, 0.01, TopAbs_WIRE);
|
Logger::Error("Failed to create face.");
|
||||||
mf.~BRepBuilderAPI_MakeFace();
|
return false;
|
||||||
new (&mf) BRepBuilderAPI_MakeFace(wire);
|
|
||||||
er = mf.Error();
|
|
||||||
}
|
}
|
||||||
if ( er != BRepBuilderAPI_FaceDone ) return false;
|
|
||||||
face = mf.Face();
|
face = mf.Face();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -166,41 +166,45 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire
|
|||||||
}
|
}
|
||||||
|
|
||||||
BRepBuilderAPI_MakeWire w;
|
BRepBuilderAPI_MakeWire w;
|
||||||
TopoDS_Vertex v1, v2, last;
|
TopoDS_Vertex wire_first_vertex, wire_last_vertex, edge_first_vertex, edge_last_vertex;
|
||||||
IfcSchema::IfcCompositeCurveSegment::list::ptr segments = l->Segments();
|
IfcSchema::IfcCompositeCurveSegment::list::ptr segments = l->Segments();
|
||||||
|
|
||||||
|
const double precision_sq_2 = 2 * getValue(GV_PRECISION) * getValue(GV_PRECISION);
|
||||||
|
|
||||||
for( IfcSchema::IfcCompositeCurveSegment::list::it it = segments->begin(); it != segments->end(); ++ it ) {
|
for(IfcSchema::IfcCompositeCurveSegment::list::it it = segments->begin(); it != segments->end(); ++it) {
|
||||||
|
|
||||||
IfcSchema::IfcCurve* curve = (*it)->ParentCurve();
|
IfcSchema::IfcCurve* curve = (*it)->ParentCurve();
|
||||||
TopoDS_Wire wire2;
|
TopoDS_Wire segment;
|
||||||
|
|
||||||
if ( !convert_wire(curve, wire2) ) {
|
if (!convert_wire(curve, segment)) {
|
||||||
Logger::Message(Logger::LOG_ERROR, "Failed to convert curve:", curve->entity);
|
Logger::Message(Logger::LOG_ERROR, "Failed to convert curve:", curve->entity);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ! (*it)->SameSense() ) wire2.Reverse();
|
if (!(*it)->SameSense()) {
|
||||||
|
segment.Reverse();
|
||||||
|
}
|
||||||
|
|
||||||
ShapeFix_ShapeTolerance FTol;
|
ShapeFix_ShapeTolerance FTol;
|
||||||
FTol.SetTolerance(wire2, getValue(GV_PRECISION), TopAbs_WIRE);
|
FTol.SetTolerance(segment, getValue(GV_PRECISION), TopAbs_WIRE);
|
||||||
|
|
||||||
/*
|
TopExp::Vertices(segment, edge_first_vertex, edge_last_vertex);
|
||||||
// Create a line segment between distant vertices?
|
|
||||||
if ( it != segments->begin() ) {
|
if (it == segments->begin()) {
|
||||||
TopExp_Explorer exp (wire2,TopAbs_VERTEX);
|
wire_first_vertex = edge_first_vertex;
|
||||||
const TopoDS_Vertex& first_vertex = TopoDS::Vertex(exp.Current());
|
} else {
|
||||||
gp_Pnt first = BRep_Tool::Pnt(first_vertex);
|
gp_Pnt first = BRep_Tool::Pnt(edge_first_vertex);
|
||||||
gp_Pnt last = BRep_Tool::Pnt(last_vertex);
|
gp_Pnt last = BRep_Tool::Pnt(wire_last_vertex);
|
||||||
Standard_Real distance = first.Distance(last);
|
|
||||||
if ( distance > ALMOST_ZERO ) {
|
Standard_Real distance = first.SquareDistance(last);
|
||||||
w.Add( BRepBuilderAPI_MakeEdge( last_vertex, first_vertex ) );
|
if (distance > precision_sq_2) {
|
||||||
|
w.Add(BRepBuilderAPI_MakeEdge(wire_last_vertex, edge_first_vertex));
|
||||||
|
|
||||||
|
Logger::Message(Logger::LOG_ERROR, "Closed gap on:", l->entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
TopExp::Vertices(wire2, v1, v2);
|
w.Add(segment);
|
||||||
|
|
||||||
w.Add(wire2);
|
|
||||||
|
|
||||||
if ( w.Error() != BRepBuilderAPI_WireDone ) {
|
if ( w.Error() != BRepBuilderAPI_WireDone ) {
|
||||||
if (w.Error() == BRepBuilderAPI_NonManifoldWire) {
|
if (w.Error() == BRepBuilderAPI_NonManifoldWire) {
|
||||||
@@ -215,24 +219,24 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire
|
|||||||
int precision = 4;
|
int precision = 4;
|
||||||
double d = 0.;
|
double d = 0.;
|
||||||
|
|
||||||
if (!last.IsNull()) {
|
if (!wire_last_vertex.IsNull()) {
|
||||||
p1 = BRep_Tool::Pnt(last);
|
p1 = BRep_Tool::Pnt(wire_last_vertex);
|
||||||
}
|
}
|
||||||
if (!v1.IsNull()) {
|
if (!edge_first_vertex.IsNull()) {
|
||||||
p2 = BRep_Tool::Pnt(v1);
|
p2 = BRep_Tool::Pnt(edge_first_vertex);
|
||||||
}
|
}
|
||||||
if (!last.IsNull() && !v1.IsNull()) {
|
if (!wire_last_vertex.IsNull() && !edge_first_vertex.IsNull()) {
|
||||||
d = p1.Distance(p2);
|
d = p1.Distance(p2);
|
||||||
precision = ceil(-log10(d)) + 3;
|
precision = ceil(-log10(d)) + 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!last.IsNull()) {
|
if (!wire_last_vertex.IsNull()) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << std::setprecision(precision) << "Last vertex at (" << p1.X() << " " << p1.Y() << " " << p1.Z() << ")";
|
ss << std::setprecision(precision) << "Last vertex at (" << p1.X() << " " << p1.Y() << " " << p1.Z() << ")";
|
||||||
Logger::Message(Logger::LOG_NOTICE, ss.str());
|
Logger::Message(Logger::LOG_NOTICE, ss.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!v1.IsNull()) {
|
if (!edge_first_vertex.IsNull()) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << std::setprecision(precision) << "Segment starts at (" << p2.X() << " " << p2.Y() << " " << p2.Z() << ")";
|
ss << std::setprecision(precision) << "Segment starts at (" << p2.X() << " " << p2.Y() << " " << p2.Z() << ")";
|
||||||
if (d > 0.) {
|
if (d > 0.) {
|
||||||
@@ -246,9 +250,21 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
last = v2;
|
wire_last_vertex = edge_last_vertex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gp_Pnt first = BRep_Tool::Pnt(edge_last_vertex);
|
||||||
|
gp_Pnt last = BRep_Tool::Pnt(wire_first_vertex);
|
||||||
|
|
||||||
|
Standard_Real distance = first.SquareDistance(last);
|
||||||
|
if (distance > precision_sq_2) {
|
||||||
|
w.Add(BRepBuilderAPI_MakeEdge(edge_last_vertex, wire_first_vertex));
|
||||||
|
|
||||||
|
Logger::Message(Logger::LOG_ERROR, "Closed gap on:", l->entity);
|
||||||
|
}
|
||||||
|
|
||||||
wire = w.Wire();
|
wire = w.Wire();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,16 +272,20 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire&
|
|||||||
IfcSchema::IfcCurve* basis_curve = l->BasisCurve();
|
IfcSchema::IfcCurve* basis_curve = l->BasisCurve();
|
||||||
bool isConic = basis_curve->is(IfcSchema::Type::IfcConic);
|
bool isConic = basis_curve->is(IfcSchema::Type::IfcConic);
|
||||||
double parameterFactor = isConic ? getValue(GV_PLANEANGLE_UNIT) : getValue(GV_LENGTH_UNIT);
|
double parameterFactor = isConic ? getValue(GV_PLANEANGLE_UNIT) : getValue(GV_LENGTH_UNIT);
|
||||||
|
|
||||||
Handle(Geom_Curve) curve;
|
Handle(Geom_Curve) curve;
|
||||||
if ( !convert_curve(basis_curve,curve) ) return false;
|
if ( !convert_curve(basis_curve,curve) ) return false;
|
||||||
|
|
||||||
bool trim_cartesian = l->MasterRepresentation() != IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER;
|
bool trim_cartesian = l->MasterRepresentation() != IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER;
|
||||||
IfcEntityList::ptr trims1 = l->Trim1();
|
IfcEntityList::ptr trims1 = l->Trim1();
|
||||||
IfcEntityList::ptr trims2 = l->Trim2();
|
IfcEntityList::ptr trims2 = l->Trim2();
|
||||||
|
|
||||||
unsigned sense_agreement = l->SenseAgreement() ? 0 : 1;
|
unsigned sense_agreement = l->SenseAgreement() ? 0 : 1;
|
||||||
double flts[2];
|
double flts[2];
|
||||||
gp_Pnt pnts[2];
|
gp_Pnt pnts[2];
|
||||||
bool has_flts[2] = {false,false};
|
bool has_flts[2] = {false,false};
|
||||||
bool has_pnts[2] = {false,false};
|
bool has_pnts[2] = {false,false};
|
||||||
|
|
||||||
BRepBuilderAPI_MakeWire w;
|
BRepBuilderAPI_MakeWire w;
|
||||||
for ( IfcEntityList::it it = trims1->begin(); it != trims1->end(); it ++ ) {
|
for ( IfcEntityList::it it = trims1->begin(); it != trims1->end(); it ++ ) {
|
||||||
IfcUtil::IfcBaseClass* i = *it;
|
IfcUtil::IfcBaseClass* i = *it;
|
||||||
@@ -278,6 +298,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire&
|
|||||||
has_flts[sense_agreement] = true;
|
has_flts[sense_agreement] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( IfcEntityList::it it = trims2->begin(); it != trims2->end(); it ++ ) {
|
for ( IfcEntityList::it it = trims2->begin(); it != trims2->end(); it ++ ) {
|
||||||
IfcUtil::IfcBaseClass* i = *it;
|
IfcUtil::IfcBaseClass* i = *it;
|
||||||
if ( i->is(IfcSchema::Type::IfcCartesianPoint) ) {
|
if ( i->is(IfcSchema::Type::IfcCartesianPoint) ) {
|
||||||
@@ -289,18 +310,19 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire&
|
|||||||
has_flts[1-sense_agreement] = true;
|
has_flts[1-sense_agreement] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trim_cartesian &= has_pnts[0] && has_pnts[1];
|
trim_cartesian &= has_pnts[0] && has_pnts[1];
|
||||||
bool trim_cartesian_failed = !trim_cartesian;
|
bool trim_cartesian_failed = !trim_cartesian;
|
||||||
if ( trim_cartesian ) {
|
if ( trim_cartesian ) {
|
||||||
if ( pnts[0].Distance(pnts[1]) < getValue(GV_WIRE_CREATION_TOLERANCE) ) {
|
if ( pnts[0].Distance(pnts[1]) < 2 * getValue(GV_PRECISION) ) {
|
||||||
Logger::Message(Logger::LOG_WARNING,"Skipping segment with length below tolerance level:",l->entity);
|
Logger::Message(Logger::LOG_WARNING,"Skipping segment with length below tolerance level:",l->entity);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ShapeFix_ShapeTolerance FTol;
|
ShapeFix_ShapeTolerance FTol;
|
||||||
TopoDS_Vertex v1 = BRepBuilderAPI_MakeVertex(pnts[0]);
|
TopoDS_Vertex v1 = BRepBuilderAPI_MakeVertex(pnts[0]);
|
||||||
TopoDS_Vertex v2 = BRepBuilderAPI_MakeVertex(pnts[1]);
|
TopoDS_Vertex v2 = BRepBuilderAPI_MakeVertex(pnts[1]);
|
||||||
FTol.SetTolerance(v1, getValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_VERTEX);
|
FTol.SetTolerance(v1, getValue(GV_PRECISION), TopAbs_VERTEX);
|
||||||
FTol.SetTolerance(v2, getValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_VERTEX);
|
FTol.SetTolerance(v2, getValue(GV_PRECISION), TopAbs_VERTEX);
|
||||||
BRepBuilderAPI_MakeEdge e (curve,v1,v2);
|
BRepBuilderAPI_MakeEdge e (curve,v1,v2);
|
||||||
if ( ! e.IsDone() ) {
|
if ( ! e.IsDone() ) {
|
||||||
BRepBuilderAPI_EdgeError err = e.Error();
|
BRepBuilderAPI_EdgeError err = e.Error();
|
||||||
@@ -312,6 +334,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire&
|
|||||||
w.Add(e.Edge());
|
w.Add(e.Edge());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( (!trim_cartesian || trim_cartesian_failed) && (has_flts[0] && has_flts[1]) ) {
|
if ( (!trim_cartesian || trim_cartesian_failed) && (has_flts[0] && has_flts[1]) ) {
|
||||||
// The Geom_Line is constructed from a gp_Pnt and gp_Dir, whereas the IfcLine
|
// The Geom_Line is constructed from a gp_Pnt and gp_Dir, whereas the IfcLine
|
||||||
// is defined by an IfcCartesianPoint and an IfcVector with Magnitude. Because
|
// is defined by an IfcCartesianPoint and an IfcVector with Magnitude. Because
|
||||||
@@ -341,8 +364,18 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire&
|
|||||||
} else if ( trim_cartesian_failed && (has_pnts[0] && has_pnts[1]) ) {
|
} else if ( trim_cartesian_failed && (has_pnts[0] && has_pnts[1]) ) {
|
||||||
w.Add(BRepBuilderAPI_MakeEdge(pnts[0],pnts[1]));
|
w.Add(BRepBuilderAPI_MakeEdge(pnts[0],pnts[1]));
|
||||||
}
|
}
|
||||||
if ( w.IsDone() ) {
|
|
||||||
|
if (w.IsDone()) {
|
||||||
wire = w.Wire();
|
wire = w.Wire();
|
||||||
|
|
||||||
|
// When SenseAgreement == .F. the vertices above have been reversed to
|
||||||
|
// comply with the direction of conical curves. The ordering of the
|
||||||
|
// vertices then still needs to be reversed in order to have begin and
|
||||||
|
// end vertex consistent with IFC.
|
||||||
|
if (sense_agreement != 0) { // .F.
|
||||||
|
wire.Reverse();
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
Reference in New Issue
Block a user