From 923771f4481b30110ff5f5e4a9e3495aa6bfe8bc Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Fri, 22 Jan 2021 16:32:51 +0100 Subject: [PATCH] #1269 implement SurfaceCurveSweptAreaSolid with non-planar ref --- src/ifcgeom/IfcGeomShapes.cpp | 71 ++++++++++++++++++++++++++--------- 1 file changed, 53 insertions(+), 18 deletions(-) diff --git a/src/ifcgeom/IfcGeomShapes.cpp b/src/ifcgeom/IfcGeomShapes.cpp index 84fa4fea17..f0f4f945c1 100644 --- a/src/ifcgeom/IfcGeomShapes.cpp +++ b/src/ifcgeom/IfcGeomShapes.cpp @@ -91,6 +91,7 @@ #include #include +#include #include #include #include @@ -104,6 +105,8 @@ #include +#include + #include "../ifcgeom/IfcGeom.h" #include @@ -1024,11 +1027,22 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangularTrimmedSurface* l, bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid* l, TopoDS_Shape& shape) { gp_Trsf directrix; TopoDS_Shape face; + TopoDS_Face surface_face; TopoDS_Wire wire, section; - if (!l->ReferenceSurface()->declaration().is(IfcSchema::IfcPlane::Class())) { - Logger::Message(Logger::LOG_WARNING, "Reference surface not supported", l->ReferenceSurface()); - return false; + const bool is_plane = l->ReferenceSurface()->declaration().is(IfcSchema::IfcPlane::Class()); + + if (!is_plane) { + TopoDS_Shape surface_shell; + if (!convert_shape(l->ReferenceSurface(), surface_shell)) { + return false; + } + if (count(surface_shell, TopAbs_FACE) != 1) { + return false; + } + std::ofstream ofs("debug.txt"); + BRepTools::Dump(surface_shell, ofs); + surface_face = TopoDS::Face(TopExp_Explorer(surface_shell, TopAbs_FACE).Current()); } gp_Trsf trsf; @@ -1048,25 +1062,28 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid* l, gp_Pln pln; gp_Pnt directrix_origin; gp_Vec directrix_tangent; - bool directrix_on_plane = true; - IfcGeom::Kernel::convert((IfcSchema::IfcPlane*) l->ReferenceSurface(), pln); + bool directrix_on_plane = is_plane; - // 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); - break; + if (is_plane) { + IfcGeom::Kernel::convert((IfcSchema::IfcPlane*) l->ReferenceSurface(), pln); + + // 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); + break; + } } } } - { + { TopExp_Explorer exp(wire, TopAbs_EDGE); TopoDS_Edge edge = TopoDS::Edge(exp.Current()); double u0, u1; @@ -1074,13 +1091,29 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid* l, crv->D1(u0, directrix_origin, directrix_tangent); } - if (pln.Axis().Direction().IsNormal(directrix_tangent, Precision::Approximation()) && directrix_on_plane) { + if (is_plane && 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 if (!is_plane) { + ShapeAnalysis_Surface sas(BRep_Tool::Surface(surface_face)); + auto pnt2d = sas.ValueOfUV(directrix_origin, getValue(GV_PRECISION) * 10.); + BRepGProp_Face prop(surface_face); + gp_Pnt _; + gp_Vec surface_normal; + prop.Normal(pnt2d.X(), pnt2d.Y(), _, surface_normal); + directrix.SetTransformation(gp_Ax3(directrix_origin, directrix_tangent, surface_normal), gp::XOY()); } else { directrix.SetTransformation(gp_Ax3(directrix_origin, directrix_tangent), gp::XOY()); } face = BRepBuilderAPI_Transform(face, directrix); + if (!is_plane) { + TopExp_Explorer exp(wire, TopAbs_EDGE); + for (; exp.More(); exp.Next()) { + ShapeFix_Edge sfe; + sfe.FixAddPCurve(TopoDS::Edge(exp.Current()), surface_face, false, getValue(GV_PRECISION)); + } + } + // 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. @@ -1093,6 +1126,8 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid* l, builder.SetTransitionMode(BRepBuilderAPI_RightCorner); if (directrix_on_plane) { builder.SetMode(pln.Axis().Direction()); + } else if (!is_plane) { + builder.SetMode(surface_face); } builder.Build(); builder.MakeSolid();