diff --git a/src/ifcgeom/IfcGeomFunctions.cpp b/src/ifcgeom/IfcGeomFunctions.cpp index c4f233789d..fb24160a97 100644 --- a/src/ifcgeom/IfcGeomFunctions.cpp +++ b/src/ifcgeom/IfcGeomFunctions.cpp @@ -589,6 +589,7 @@ TopoDS_Vertex find_other(const TopoDS_Edge& edge, const TopoDS_Vertex& vertex) { } exp.Next(); } + return TopoDS_Vertex(); } TopoDS_Edge find_next(const TopTools_IndexedMapOfShape& edge_set, const TopTools_IndexedDataMapOfShapeListOfShape& vertex_to_edges, const TopoDS_Vertex& current, const TopoDS_Edge& previous_edge) { @@ -601,6 +602,7 @@ TopoDS_Edge find_next(const TopTools_IndexedMapOfShape& edge_set, const TopTools return edge; } } + return TopoDS_Edge(); } bool IfcGeom::fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& shape) { @@ -651,7 +653,16 @@ bool IfcGeom::fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& shape) { return false; } TopoDS_Vertex other = find_other(edge, current); - w.Add(edge); + if (other.IsNull()) { + // Dealing with a conical edge probably, for some reason + // this works better than adding the edge directly. + double u1, u2; + Handle(Geom_Curve) crv = BRep_Tool::Curve(edge, u1, u2); + w.Add(BRepBuilderAPI_MakeEdge(crv, u1, u2)); + break; + } else { + w.Add(edge); + } // See if the starting point of this loop has been reached. Note that // additional wires after this one potentially will be created. if (other.IsSame(first)) { diff --git a/src/ifcgeom/IfcGeomShapes.cpp b/src/ifcgeom/IfcGeomShapes.cpp index cf512b5b97..5552dbd412 100644 --- a/src/ifcgeom/IfcGeomShapes.cpp +++ b/src/ifcgeom/IfcGeomShapes.cpp @@ -562,57 +562,73 @@ bool IfcGeom::convert(const IfcSchema::IfcRectangularTrimmedSurface::ptr l, Topo } bool IfcGeom::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid::ptr l, TopoDS_Shape& shape) { - gp_Trsf trsf, axis, position; + gp_Trsf directrix, position; TopoDS_Shape face; TopoDS_Wire wire, section; - - if (!IfcGeom::convert_face(l->SweptArea(), face)) { - return false; - } - - if (!IfcGeom::convert_wire(l->Directrix(), wire)) { - return false; - } - - axis.SetTransformation(gp_Ax3(gp::Origin(), gp::DX(), -gp::DZ())); - IfcGeom::convert(l->Position(), position); if (!l->ReferenceSurface()->is(IfcSchema::Type::IfcPlane)) { - // Not implemented + Logger::Message(Logger::LOG_WARNING, "Reference surface not supported", l->ReferenceSurface()->entity); + return false; + } + + if (!IfcGeom::convert(l->Position(), position) || + !IfcGeom::convert_face(l->SweptArea(), face) || + !IfcGeom::convert_wire(l->Directrix(), wire) ) { return false; } gp_Pln pln; + gp_Pnt directrix_origin; + gp_Vec directrix_tangent; + bool directrix_on_plane = true; IfcGeom::convert((IfcSchema::IfcPlane*) l->ReferenceSurface(), pln); - trsf.SetTransformation(pln.Position()); - trsf.Invert(); - trsf.Multiply(axis); - + // As per Informal propositions 2: The Directrix shall lie on the ReferenceSurface. + // This is not always the case with the test files in the repository. I am not sure + // how to deal with this and whether my interpretation of the propositions is + // correct. However, if it has been asserted that the vertices of the directrix do + // not conform to the ReferenceSurface, the ReferenceSurface is ignored. + { + for (TopExp_Explorer exp(wire, TopAbs_VERTEX); exp.More(); exp.Next()) { + if (pln.Distance(BRep_Tool::Pnt(TopoDS::Vertex(exp.Current()))) > ALMOST_ZERO) { + directrix_on_plane = false; + Logger::Message(Logger::LOG_WARNING, "The Directrix does not lie on the ReferenceSurface", l->entity); + break; + } + } + } + + { + TopExp_Explorer exp(wire, TopAbs_EDGE); + TopoDS_Edge edge = TopoDS::Edge(exp.Current()); + double u0, u1; + Handle(Geom_Curve) crv = BRep_Tool::Curve(edge, u0, u1); + crv->D1(u0, directrix_origin, directrix_tangent); + } + + if (pln.Axis().Direction().IsNormal(directrix_tangent, Precision::Approximation()) && directrix_on_plane) { + directrix.SetTransformation(gp_Ax3(directrix_origin, directrix_tangent, pln.Axis().Direction()), gp::XOY()); + } else { + directrix.SetTransformation(gp_Ax3(directrix_origin, directrix_tangent), gp::XOY()); + } + face = BRepBuilderAPI_Transform(face, directrix); + // NB: Note that StartParam and EndParam param are ignored and the assumption is // made that the parametric range over which to be swept matches the IfcCurve in // its entirety. BRepOffsetAPI_MakePipeShell builder(wire); - face = BRepBuilderAPI_Transform(face, trsf); - - TopExp_Explorer exp(face, TopAbs_WIRE); - section = TopoDS::Wire(exp.Current()); + { TopExp_Explorer exp(face, TopAbs_WIRE); + section = TopoDS::Wire(exp.Current()); } builder.Add(section); builder.SetTransitionMode(BRepBuilderAPI_RightCorner); - builder.Build(); - - shape = builder.Shape(); - - bool succeeded = false; - try { - succeeded = IfcGeom::fill_nonmanifold_wires_with_planar_faces(shape); - } catch(...) {} - if (!succeeded) { - Logger::Message(Logger::LOG_WARNING, "Failed to cap solid for:", l->entity); + if (directrix_on_plane) { + builder.SetMode(pln.Axis().Direction()); } - + builder.Build(); + builder.MakeSolid(); + shape = builder.Shape(); shape.Move(position); return true;