Fill holes in composite curves, fixes #282

This commit is contained in:
Thomas Krijnen
2017-11-08 13:27:45 +01:00
parent 6cd59aa121
commit b7ce547a0c
2 changed files with 73 additions and 39 deletions
+8 -7
View File
@@ -616,17 +616,18 @@ bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity,
#endif
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_FaceError er = mf.Error();
if ( er == BRepBuilderAPI_NotPlanar ) {
ShapeFix_ShapeTolerance FTol;
FTol.SetTolerance(wire, 0.01, TopAbs_WIRE);
mf.~BRepBuilderAPI_MakeFace();
new (&mf) BRepBuilderAPI_MakeFace(wire);
er = mf.Error();
if (er != BRepBuilderAPI_FaceDone) {
Logger::Error("Failed to create face.");
return false;
}
if ( er != BRepBuilderAPI_FaceDone ) return false;
face = mf.Face();
return true;
}
+65 -32
View File
@@ -166,41 +166,45 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire
}
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();
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();
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);
continue;
}
if ( ! (*it)->SameSense() ) wire2.Reverse();
if (!(*it)->SameSense()) {
segment.Reverse();
}
ShapeFix_ShapeTolerance FTol;
FTol.SetTolerance(wire2, getValue(GV_PRECISION), TopAbs_WIRE);
FTol.SetTolerance(segment, getValue(GV_PRECISION), TopAbs_WIRE);
/*
// Create a line segment between distant vertices?
if ( it != segments->begin() ) {
TopExp_Explorer exp (wire2,TopAbs_VERTEX);
const TopoDS_Vertex& first_vertex = TopoDS::Vertex(exp.Current());
gp_Pnt first = BRep_Tool::Pnt(first_vertex);
gp_Pnt last = BRep_Tool::Pnt(last_vertex);
Standard_Real distance = first.Distance(last);
if ( distance > ALMOST_ZERO ) {
w.Add( BRepBuilderAPI_MakeEdge( last_vertex, first_vertex ) );
TopExp::Vertices(segment, edge_first_vertex, edge_last_vertex);
if (it == segments->begin()) {
wire_first_vertex = edge_first_vertex;
} else {
gp_Pnt first = BRep_Tool::Pnt(edge_first_vertex);
gp_Pnt last = BRep_Tool::Pnt(wire_last_vertex);
Standard_Real distance = first.SquareDistance(last);
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(wire2);
w.Add(segment);
if ( w.Error() != BRepBuilderAPI_WireDone ) {
if (w.Error() == BRepBuilderAPI_NonManifoldWire) {
@@ -215,24 +219,24 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire
int precision = 4;
double d = 0.;
if (!last.IsNull()) {
p1 = BRep_Tool::Pnt(last);
if (!wire_last_vertex.IsNull()) {
p1 = BRep_Tool::Pnt(wire_last_vertex);
}
if (!v1.IsNull()) {
p2 = BRep_Tool::Pnt(v1);
if (!edge_first_vertex.IsNull()) {
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);
precision = ceil(-log10(d)) + 3;
}
if (!last.IsNull()) {
if (!wire_last_vertex.IsNull()) {
std::stringstream ss;
ss << std::setprecision(precision) << "Last vertex at (" << p1.X() << " " << p1.Y() << " " << p1.Z() << ")";
Logger::Message(Logger::LOG_NOTICE, ss.str());
}
if (!v1.IsNull()) {
if (!edge_first_vertex.IsNull()) {
std::stringstream ss;
ss << std::setprecision(precision) << "Segment starts at (" << p2.X() << " " << p2.Y() << " " << p2.Z() << ")";
if (d > 0.) {
@@ -246,9 +250,21 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire
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();
return true;
}
@@ -256,16 +272,20 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire&
IfcSchema::IfcCurve* basis_curve = l->BasisCurve();
bool isConic = basis_curve->is(IfcSchema::Type::IfcConic);
double parameterFactor = isConic ? getValue(GV_PLANEANGLE_UNIT) : getValue(GV_LENGTH_UNIT);
Handle(Geom_Curve) curve;
if ( !convert_curve(basis_curve,curve) ) return false;
bool trim_cartesian = l->MasterRepresentation() != IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER;
IfcEntityList::ptr trims1 = l->Trim1();
IfcEntityList::ptr trims2 = l->Trim2();
unsigned sense_agreement = l->SenseAgreement() ? 0 : 1;
double flts[2];
gp_Pnt pnts[2];
bool has_flts[2] = {false,false};
bool has_pnts[2] = {false,false};
BRepBuilderAPI_MakeWire w;
for ( IfcEntityList::it it = trims1->begin(); it != trims1->end(); it ++ ) {
IfcUtil::IfcBaseClass* i = *it;
@@ -278,6 +298,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire&
has_flts[sense_agreement] = true;
}
}
for ( IfcEntityList::it it = trims2->begin(); it != trims2->end(); it ++ ) {
IfcUtil::IfcBaseClass* i = *it;
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;
}
}
trim_cartesian &= has_pnts[0] && has_pnts[1];
bool trim_cartesian_failed = !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);
return false;
}
ShapeFix_ShapeTolerance FTol;
TopoDS_Vertex v1 = BRepBuilderAPI_MakeVertex(pnts[0]);
TopoDS_Vertex v2 = BRepBuilderAPI_MakeVertex(pnts[1]);
FTol.SetTolerance(v1, getValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_VERTEX);
FTol.SetTolerance(v2, getValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_VERTEX);
FTol.SetTolerance(v1, getValue(GV_PRECISION), TopAbs_VERTEX);
FTol.SetTolerance(v2, getValue(GV_PRECISION), TopAbs_VERTEX);
BRepBuilderAPI_MakeEdge e (curve,v1,v2);
if ( ! e.IsDone() ) {
BRepBuilderAPI_EdgeError err = e.Error();
@@ -312,6 +334,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire&
w.Add(e.Edge());
}
}
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
// 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]) ) {
w.Add(BRepBuilderAPI_MakeEdge(pnts[0],pnts[1]));
}
if ( w.IsDone() ) {
if (w.IsDone()) {
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;
} else {
return false;