bool IfcGeom::Kernel::convert(const IfcSchema::IfcCurveBoundedPlane* l, TopoDS_Shape& face) { gp_Pln pln; IfcGeom::Kernel::convert(l->BasisSurface(), pln); gp_Trsf trsf; trsf.SetTransformation(pln.Position(), gp::XOY()); TopoDS_Wire outer; convert_wire(l->OuterBoundary(), outer); BRepBuilderAPI_MakeFace mf (outer); mf.Add(outer); IfcSchema::IfcCurve::list::ptr inner = l->InnerBoundaries(); for (IfcSchema::IfcCurve::list::it it = inner->begin(); it != inner->end(); ++it) { TopoDS_Wire inner; convert_wire(*it, inner); mf.Add(inner); } ShapeFix_Shape sfs(mf.Face()); sfs.Perform(); face = TopoDS::Face(sfs.Shape()).Moved(trsf); return true; }
bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdgeLoop* l, TopoDS_Wire& result) { IfcSchema::IfcOrientedEdge::list::ptr li = l->EdgeList(); BRepBuilderAPI_MakeWire mw; for (IfcSchema::IfcOrientedEdge::list::it it = li->begin(); it != li->end(); ++it) { IfcSchema::IfcOrientedEdge* e = *it; IfcSchema::IfcPoint* pnt1 = ((IfcSchema::IfcVertexPoint*) e->EdgeStart())->VertexGeometry(); IfcSchema::IfcPoint* pnt2 = ((IfcSchema::IfcVertexPoint*) e->EdgeEnd())->VertexGeometry(); if (!pnt1->is(IfcSchema::Type::IfcCartesianPoint) || !pnt2->is(IfcSchema::Type::IfcCartesianPoint)) { Logger::Message(Logger::LOG_ERROR, "Only IfcCartesianPoints are supported for VertexGeometry", l->entity); return false; } gp_Pnt p1, p2; if (!IfcGeom::Kernel::convert(((IfcSchema::IfcCartesianPoint*)pnt1), p1) || !IfcGeom::Kernel::convert(((IfcSchema::IfcCartesianPoint*)pnt2), p2)) { return false; } mw.Add(BRepBuilderAPI_MakeEdge(p1, p2)); continue; IfcSchema::IfcEdge* base = e->EdgeElement(); TopoDS_Wire w; if (convert_wire(e->EdgeElement(), w)) { if (!e->Orientation()) w.Reverse(); mw.Add(w); } } result = mw; return true; }
bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryProfileDefWithVoids* l, TopoDS_Shape& face) { TopoDS_Wire profile; if ( ! convert_wire(l->OuterCurve(),profile) ) return false; BRepBuilderAPI_MakeFace mf(profile); IfcSchema::IfcCurve::list::ptr voids = l->InnerCurves(); for( IfcSchema::IfcCurve::list::it it = voids->begin(); it != voids->end(); ++ it ) { TopoDS_Wire hole; if ( convert_wire(*it,hole) ) { mf.Add(hole); } } ShapeFix_Shape sfs(mf.Face()); sfs.Perform(); face = TopoDS::Face(sfs.Shape()); return true; }
bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdgeCurve* l, TopoDS_Wire& result) { IfcSchema::IfcPoint* pnt1 = ((IfcSchema::IfcVertexPoint*) l->EdgeStart())->VertexGeometry(); IfcSchema::IfcPoint* pnt2 = ((IfcSchema::IfcVertexPoint*) l->EdgeEnd())->VertexGeometry(); if (!pnt1->is(IfcSchema::Type::IfcCartesianPoint) || !pnt2->is(IfcSchema::Type::IfcCartesianPoint)) { Logger::Message(Logger::LOG_ERROR, "Only IfcCartesianPoints are supported for VertexGeometry", l->entity); return false; } gp_Pnt p1, p2; if (!IfcGeom::Kernel::convert(((IfcSchema::IfcCartesianPoint*)pnt1), p1) || !IfcGeom::Kernel::convert(((IfcSchema::IfcCartesianPoint*)pnt2), p2)) { return false; } BRepBuilderAPI_MakeWire mw; Handle_Geom_Curve crv; // The lack of a clear separation between topological and geometrical entities // is starting to get problematic. If the underlying curve is bounded it is // assumed that a topological wire can be crafted from it. After which an // attempt is made to reconstruct it from the individual curves and the vertices // of the IfcEdgeCurve. const bool is_bounded = l->EdgeGeometry()->is(IfcSchema::Type::IfcBoundedCurve); if (!is_bounded && convert_curve(l->EdgeGeometry(), crv)) { mw.Add(BRepBuilderAPI_MakeEdge(crv, p1, p2)); result = mw; return true; } else if (is_bounded && convert_wire(l->EdgeGeometry(), result)) { if (!l->SameSense()) std::swap(pnt1, pnt2); TopExp_Explorer exp(result, TopAbs_EDGE); bool first = true; while (exp.More()) { const TopoDS_Edge& ed = TopoDS::Edge(exp.Current()); Standard_Real u1, u2; Handle(Geom_Curve) ecrv = BRep_Tool::Curve(ed, u1, u2); exp.Next(); const bool last = !exp.More(); first = false; if (first && last) { mw.Add(BRepBuilderAPI_MakeEdge(ecrv, p1, p2)); } else if (first) { gp_Pnt pu; ecrv->D0(u2, pu); mw.Add(BRepBuilderAPI_MakeEdge(ecrv, p1, pu)); } else if (last) { gp_Pnt pu; ecrv->D0(u1, pu); mw.Add(BRepBuilderAPI_MakeEdge(ecrv, pu, p2)); } else { mw.Add(BRepBuilderAPI_MakeEdge(ecrv, u1, u2)); } } result = mw; return true; } else { return false; } }
bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolygonalBoundedHalfSpace* l, TopoDS_Shape& shape) { TopoDS_Shape halfspace; if ( ! IfcGeom::Kernel::convert((IfcSchema::IfcHalfSpaceSolid*)l,halfspace) ) return false; TopoDS_Wire wire; if ( ! convert_wire(l->PolygonalBoundary(),wire) || ! wire.Closed() ) return false; gp_Trsf trsf; if ( ! convert(l->Position(),trsf) ) return false; TColgp_SequenceOfPnt points; if (wire_to_sequence_of_point(wire, points)) { remove_duplicate_points_from_loop(points, wire.Closed()); // Note: wire always closed, as per if statement above remove_collinear_points_from_loop(points, wire.Closed()); sequence_of_point_to_wire(points, wire, wire.Closed()); } TopoDS_Shape prism = BRepPrimAPI_MakePrism(BRepBuilderAPI_MakeFace(wire),gp_Vec(0,0,200)); gp_Trsf down; down.SetTranslation(gp_Vec(0,0,-100.0)); // `trsf` and `down` both have a unit scale factor prism.Move(trsf*down); shape = BRepAlgoAPI_Common(halfspace,prism); return true; }
bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryClosedProfileDef* l, TopoDS_Shape& face) { TopoDS_Wire wire; if ( ! convert_wire(l->OuterCurve(),wire) ) return false; TopoDS_Face f; bool success = convert_wire_to_face(wire, f); if (success) face = f; return success; }
bool IfcGeom::Kernel::convert(const IfcSchema::IfcOrientedEdge* l, TopoDS_Wire& result) { if (convert_wire(l->EdgeElement(), result)) { if (!l->Orientation()) { result.Reverse(); } return true; } else { return false; } }
bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolygonalBoundedHalfSpace* l, TopoDS_Shape& shape) { TopoDS_Shape halfspace; if ( ! IfcGeom::Kernel::convert((IfcSchema::IfcHalfSpaceSolid*)l,halfspace) ) return false; TopoDS_Wire wire; if ( ! convert_wire(l->PolygonalBoundary(),wire) || ! wire.Closed() ) return false; gp_Trsf trsf; convert(l->Position(),trsf); TopoDS_Shape prism = BRepPrimAPI_MakePrism(BRepBuilderAPI_MakeFace(wire),gp_Vec(0,0,200)); gp_Trsf down; down.SetTranslation(gp_Vec(0,0,-100.0)); prism.Move(trsf*down); shape = BRepAlgoAPI_Common(halfspace,prism); return true; }
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCenterLineProfileDef* l, TopoDS_Shape& face) { const double d = l->Thickness() * getValue(GV_LENGTH_UNIT) / 2.; TopoDS_Wire wire; if (!convert_wire(l->Curve(), wire)) return false; // BRepOffsetAPI_MakeOffset insists on creating circular arc // segments for joining the curves that constitute the center // line. This is probably not in accordance with the IFC spec. // Although it does not specify a method to join segments // explicitly, it does dictate 'a constant thickness along the // curve'. Therefore for simple singular wires a quick // alternative is provided that uses a straight join. TopExp_Explorer exp(wire, TopAbs_EDGE); TopoDS_Edge edge = TopoDS::Edge(exp.Current()); exp.Next(); if (!exp.More()) { double u1, u2; Handle(Geom_Curve) curve = BRep_Tool::Curve(edge, u1, u2); Handle(Geom_TrimmedCurve) trim = new Geom_TrimmedCurve(curve, u1, u2); Handle(Geom_OffsetCurve) c1 = new Geom_OffsetCurve(trim, d, gp::DZ()); Handle(Geom_OffsetCurve) c2 = new Geom_OffsetCurve(trim, -d, gp::DZ()); gp_Pnt c1a, c1b, c2a, c2b; c1->D0(c1->FirstParameter(), c1a); c1->D0(c1->LastParameter(), c1b); c2->D0(c2->FirstParameter(), c2a); c2->D0(c2->LastParameter(), c2b); BRepBuilderAPI_MakeWire mw; mw.Add(BRepBuilderAPI_MakeEdge(c1)); mw.Add(BRepBuilderAPI_MakeEdge(c1a, c2a)); mw.Add(BRepBuilderAPI_MakeEdge(c2)); mw.Add(BRepBuilderAPI_MakeEdge(c2b, c1b)); face = BRepBuilderAPI_MakeFace(mw.Wire()); } else { BRepOffsetAPI_MakeOffset offset(BRepBuilderAPI_MakeFace(gp_Pln(gp::Origin(), gp::DZ()))); offset.AddWire(wire); offset.Perform(d); face = BRepBuilderAPI_MakeFace(TopoDS::Wire(offset)); } return true; }
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSubedge* l, TopoDS_Wire& result) { TopoDS_Wire temp; if (convert_wire(l->ParentEdge(), result) && convert((IfcSchema::IfcEdge*) l, temp)) { TopExp_Explorer exp(result, TopAbs_EDGE); TopoDS_Edge edge = TopoDS::Edge(exp.Current()); Standard_Real u1, u2; Handle(Geom_Curve) crv = BRep_Tool::Curve(edge, u1, u2); TopoDS_Vertex v1, v2; TopExp::Vertices(temp, v1, v2); BRepBuilderAPI_MakeWire mw; mw.Add(BRepBuilderAPI_MakeEdge(crv, v1, v2)); result = mw.Wire(); return true; } else { return false; } }
bool IfcGeom::Kernel::convert(const IfcSchema::IfcEdgeLoop* l, TopoDS_Wire& result) { IfcSchema::IfcOrientedEdge::list::ptr li = l->EdgeList(); BRepBuilderAPI_MakeWire mw; for (IfcSchema::IfcOrientedEdge::list::it it = li->begin(); it != li->end(); ++it) { TopoDS_Wire w; if (convert_wire(*it, w)) { if (!(*it)->Orientation()) w.Reverse(); TopoDS_Iterator topoit(w, false); for (; topoit.More(); topoit.Next()) { const TopoDS_Edge& e = TopoDS::Edge(topoit.Value()); mw.Add(e); } // mw.Add(w); } } result = mw; return true; }
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceOfLinearExtrusion* l, TopoDS_Shape& shape) { TopoDS_Wire wire; if ( !convert_wire(l->SweptCurve(), wire) ) { TopoDS_Face face; if ( !convert_face(l->SweptCurve(),face) ) return false; TopExp_Explorer exp(face, TopAbs_WIRE); wire = TopoDS::Wire(exp.Current()); } const double height = l->Depth() * getValue(GV_LENGTH_UNIT); gp_Trsf trsf; IfcGeom::Kernel::convert(l->Position(),trsf); gp_Dir dir; convert(l->ExtrudedDirection(),dir); shape = BRepPrimAPI_MakePrism(wire, height*dir); shape.Move(trsf); return !shape.IsNull(); }
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceOfRevolution* l, TopoDS_Shape& shape) { TopoDS_Wire wire; if ( !convert_wire(l->SweptCurve(), wire) ) { TopoDS_Face face; if ( !convert_face(l->SweptCurve(),face) ) return false; TopExp_Explorer exp(face, TopAbs_WIRE); wire = TopoDS::Wire(exp.Current()); } gp_Ax1 ax1; IfcGeom::Kernel::convert(l->AxisPosition(), ax1); gp_Trsf trsf; IfcGeom::Kernel::convert(l->Position(),trsf); shape = BRepPrimAPI_MakeRevol(wire, ax1); shape.Move(trsf); return !shape.IsNull(); }
bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire& wire) { if ( getValue(GV_PLANEANGLE_UNIT)<0 ) { Logger::Message(Logger::LOG_WARNING,"Creating a composite curve without unit information:",l->entity); // Temporarily pretend we do have unit information setValue(GV_PLANEANGLE_UNIT,1.0); bool succes_radians = false; bool succes_degrees = false; bool use_radians = false; bool use_degrees = false; // First try radians TopoDS_Wire wire_radians, wire_degrees; try { succes_radians = IfcGeom::Kernel::convert(l,wire_radians); } catch (...) {} // Now try degrees setValue(GV_PLANEANGLE_UNIT,0.0174532925199433); try { succes_degrees = IfcGeom::Kernel::convert(l,wire_degrees); } catch (...) {} // Restore to unknown unit state setValue(GV_PLANEANGLE_UNIT,-1.0); if ( succes_degrees && ! succes_radians ) { use_degrees = true; } else if ( succes_radians && ! succes_degrees ) { use_radians = true; } else if ( succes_radians && succes_degrees ) { if ( wire_degrees.Closed() && ! wire_radians.Closed() ) { use_degrees = true; } else if ( wire_radians.Closed() && ! wire_degrees.Closed() ) { use_radians = true; } else { // No heuristic left to prefer the one over the other, // apparently both variants are equally succesful. // The curve might be composed of only straight segments. // Let's go with the wire created using radians as that // at least is a SI unit. use_radians = true; } } if ( use_radians ) { Logger::Message(Logger::LOG_NOTICE,"Used radians to create composite curve"); wire = wire_radians; } else if ( use_degrees ) { Logger::Message(Logger::LOG_NOTICE,"Used degrees to create composite curve"); wire = wire_degrees; } return use_radians || use_degrees; } IfcSchema::IfcCompositeCurveSegment::list::ptr segments = l->Segments(); BRepBuilderAPI_MakeWire w; //TopoDS_Vertex last_vertex; for( IfcSchema::IfcCompositeCurveSegment::list::it it = segments->begin(); it != segments->end(); ++ it ) { IfcSchema::IfcCurve* curve = (*it)->ParentCurve(); TopoDS_Wire wire2; if ( !convert_wire(curve,wire2) ) { Logger::Message(Logger::LOG_ERROR,"Failed to convert curve:",curve->entity); continue; } if ( ! (*it)->SameSense() ) wire2.Reverse(); ShapeFix_ShapeTolerance FTol; FTol.SetTolerance(wire2, getValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_WIRE); /*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 ) ); } }*/ w.Add(wire2); //last_vertex = w.Vertex(); if ( w.Error() != BRepBuilderAPI_WireDone ) { Logger::Message(Logger::LOG_ERROR,"Failed to join curve segments:",l->entity); return false; } } wire = w.Wire(); return true; }
bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) { IfcSchema::IfcFaceBound::list::ptr bounds = l->Bounds(); Handle(Geom_Surface) face_surface; const bool is_face_surface = l->is(IfcSchema::Type::IfcFaceSurface); if (is_face_surface) { IfcSchema::IfcFaceSurface* fs = (IfcSchema::IfcFaceSurface*) l; fs->FaceSurface(); // FIXME: Surfaces are interpreted as a TopoDS_Shape TopoDS_Shape surface_shape; if (!convert_shape(fs->FaceSurface(), surface_shape)) return false; // FIXME: Assert this obtaines the only face TopExp_Explorer exp(surface_shape, TopAbs_FACE); if (!exp.More()) return false; TopoDS_Face surface = TopoDS::Face(exp.Current()); face_surface = BRep_Tool::Surface(surface); } const int num_bounds = bounds->size(); int num_outer_bounds = 0; for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) { IfcSchema::IfcFaceBound* bound = *it; if (bound->is(IfcSchema::Type::IfcFaceOuterBound)) num_outer_bounds ++; } // The number of outer bounds should be one according to the schema. Also Open Cascade // expects this, but it is not strictly checked. Regardless, if the number is greater, // the face will still be processed as long as there are no holes. A compound of faces // is returned in that case. if (num_bounds > 1 && num_outer_bounds > 1 && num_bounds != num_outer_bounds) { Logger::Message(Logger::LOG_ERROR, "Invalid configuration of boundaries for:", l->entity); return false; } TopoDS_Compound compound; BRep_Builder builder; if (num_outer_bounds > 1) { builder.MakeCompound(compound); } // The builder is initialized on the heap because of the various different moments // of initialization depending on the configuration of surfaces and boundaries. BRepBuilderAPI_MakeFace* mf = 0; bool success = false; int processed = 0; for (int process_interior = 0; process_interior <= 1; ++process_interior) { for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) { IfcSchema::IfcFaceBound* bound = *it; IfcSchema::IfcLoop* loop = bound->Bound(); bool same_sense = bound->Orientation(); const bool is_interior = !bound->is(IfcSchema::Type::IfcFaceOuterBound) && (num_bounds > 1) && (num_outer_bounds < num_bounds); // The exterior face boundary is processed first if (is_interior == !process_interior) continue; TopoDS_Wire wire; if (!convert_wire(loop, wire)) { Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", loop->entity); delete mf; return false; } /* The approach below does not result in a significant speed-up if (loop->is(IfcSchema::Type::IfcPolyLoop) && processed == 0 && face_surface.IsNull()) { IfcSchema::IfcPolyLoop* polyloop = (IfcSchema::IfcPolyLoop*) loop; IfcSchema::IfcCartesianPoint::list::ptr points = polyloop->Polygon(); if (points->size() == 3) { // Help Open Cascade by finding the plane more efficiently IfcSchema::IfcCartesianPoint::list::it point_iterator = points->begin(); gp_Pnt a, b, c; convert(*point_iterator++, a); convert(*point_iterator++, b); convert(*point_iterator++, c); const gp_XYZ ab = (b.XYZ() - a.XYZ()); const gp_XYZ ac = (c.XYZ() - a.XYZ()); const gp_Vec cross = ab.Crossed(ac); if (cross.SquareMagnitude() > ALMOST_ZERO) { const gp_Dir n = cross; face_surface = new Geom_Plane(a, n); } } } */ if (!same_sense) { wire.Reverse(); } bool flattened_wire = false; if (!mf) { process_wire: if (face_surface.IsNull()) { mf = new BRepBuilderAPI_MakeFace(wire); } else { /// @todo check necessity of false here mf = new BRepBuilderAPI_MakeFace(face_surface, wire, false); } /* BRepBuilderAPI_FaceError er = mf->Error(); if (er == BRepBuilderAPI_NotPlanar) { ShapeFix_ShapeTolerance FTol; FTol.SetTolerance(wire, getValue(GV_PRECISION), TopAbs_WIRE); delete mf; mf = new BRepBuilderAPI_MakeFace(wire); } */ if (mf->IsDone()) { TopoDS_Face outer_face_bound = mf->Face(); // In case of (non-planar) face surface, p-curves need to be computed. // For planar faces, Open Cascade generates p-curves on the fly. if (!face_surface.IsNull()) { TopExp_Explorer exp(outer_face_bound, TopAbs_EDGE); for (; exp.More(); exp.Next()) { const TopoDS_Edge& edge = TopoDS::Edge(exp.Current()); ShapeFix_Edge fix_edge; fix_edge.FixAddPCurve(edge, outer_face_bound, false, getValue(GV_PRECISION)); } } if (BRepCheck_Face(outer_face_bound).OrientationOfWires() == BRepCheck_BadOrientationOfSubshape) { wire.Reverse(); same_sense = !same_sense; delete mf; if (face_surface.IsNull()) { mf = new BRepBuilderAPI_MakeFace(wire); } else { mf = new BRepBuilderAPI_MakeFace(face_surface, wire); } ShapeFix_Face fix(mf->Face()); fix.FixOrientation(); fix.Perform(); outer_face_bound = fix.Face(); } // If the wires are reversed the face needs to be reversed as well in order // to maintain the counter-clock-wise ordering of the bounding wire's vertices. bool all_reversed = true; TopoDS_Iterator jt(outer_face_bound, false); for (; jt.More(); jt.Next()) { const TopoDS_Wire& w = TopoDS::Wire(jt.Value()); if ((w.Orientation() != TopAbs_REVERSED) == same_sense) { all_reversed = false; } } if (all_reversed) { outer_face_bound.Reverse(); } if (num_outer_bounds > 1) { builder.Add(compound, outer_face_bound); delete mf; mf = 0; } else if (num_bounds > 1) { // Reinitialize the builder to the outer face // bound in order to add holes more robustly. delete mf; // TODO: What about the face_surface? mf = new BRepBuilderAPI_MakeFace(outer_face_bound); } else { face = outer_face_bound; success = true; } } else { const bool non_planar = mf->Error() == BRepBuilderAPI_NotPlanar; delete mf; if (!non_planar || flattened_wire || !flatten_wire(wire)) { Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary", bound->entity); return false; } else { Logger::Message(Logger::LOG_ERROR, "Flattening face boundary", bound->entity); flattened_wire = true; goto process_wire; } } } else { mf->Add(wire); } processed ++; } } if (!success) { success = processed == num_bounds; if (success) { if (num_outer_bounds > 1) { face = compound; } else { success = success && mf->IsDone(); if (success) { face = mf->Face(); } } } } if (success) { ShapeFix_ShapeTolerance FTol; FTol.SetTolerance(face, getValue(GV_PRECISION), TopAbs_FACE); } delete mf; return success; }
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid* l, TopoDS_Shape& shape) { gp_Trsf directrix, position; TopoDS_Shape face; TopoDS_Wire wire, section; if (!l->ReferenceSurface()->is(IfcSchema::Type::IfcPlane)) { Logger::Message(Logger::LOG_WARNING, "Reference surface not supported", l->ReferenceSurface()->entity); return false; } if (!IfcGeom::Kernel::convert(l->Position(), position) || !convert_face(l->SweptArea(), face) || !convert_wire(l->Directrix(), wire) ) { return false; } gp_Pln pln; gp_Pnt directrix_origin; gp_Vec directrix_tangent; bool directrix_on_plane = true; 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->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); { TopExp_Explorer exp(face, TopAbs_WIRE); section = TopoDS::Wire(exp.Current()); } builder.Add(section); builder.SetTransitionMode(BRepBuilderAPI_RightCorner); if (directrix_on_plane) { builder.SetMode(pln.Axis().Direction()); } builder.Build(); builder.MakeSolid(); shape = builder.Shape(); shape.Move(position); return true; }
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSweptDiskSolid* l, TopoDS_Shape& shape) { TopoDS_Wire wire, section1, section2; bool hasInnerRadius = l->hasInnerRadius(); if (!convert_wire(l->Directrix(), wire)) { return false; } gp_Ax2 directrix; { gp_Pnt directrix_origin; gp_Vec directrix_tangent; 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); directrix = gp_Ax2(directrix_origin, directrix_tangent); } const double r1 = l->Radius() * getValue(GV_LENGTH_UNIT); Handle(Geom_Circle) circle = new Geom_Circle(directrix, r1); section1 = BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(circle)); if (hasInnerRadius) { const double r2 = l->InnerRadius() * getValue(GV_LENGTH_UNIT); if (r2 < getValue(GV_PRECISION)) { // Subtraction of pipes with small radii is unstable. hasInnerRadius = false; } else { Handle(Geom_Circle) circle = new Geom_Circle(directrix, r2); section2 = BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(circle)); } } // 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. // NB2: Contrary to IfcSurfaceCurveSweptAreaSolid the transition mode has been // set to create round corners as this has proven to work better with the types // of directrices encountered, which do not necessarily conform to a surface. { BRepOffsetAPI_MakePipeShell builder(wire); builder.Add(section1); builder.SetTransitionMode(BRepBuilderAPI_RoundCorner); builder.Build(); builder.MakeSolid(); shape = builder.Shape(); } if (hasInnerRadius) { BRepOffsetAPI_MakePipeShell builder(wire); builder.Add(section2); builder.SetTransitionMode(BRepBuilderAPI_RoundCorner); builder.Build(); builder.MakeSolid(); TopoDS_Shape inner = builder.Shape(); BRepAlgoAPI_Cut brep_cut(shape, inner); bool is_valid = false; if (brep_cut.IsDone()) { TopoDS_Shape result = brep_cut; ShapeFix_Shape fix(result); fix.Perform(); result = fix.Shape(); is_valid = BRepCheck_Analyzer(result).IsValid() != 0; if (is_valid) { shape = result; } } if (!is_valid) { Logger::Message(Logger::LOG_WARNING, "Failed to subtract inner radius void for:", l->entity); } } return true; }
bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryOpenProfileDef* l, TopoDS_Wire& result) { return convert_wire(l->Curve(), result); }