diff --git a/src/ifcparse/IfcGeom.cpp b/src/ifcparse/IfcGeom.cpp index 3825beb698..fec6e8f053 100644 --- a/src/ifcparse/IfcGeom.cpp +++ b/src/ifcparse/IfcGeom.cpp @@ -39,23 +39,27 @@ #include #include #include +#include #include #include #include #include -#include -#include +#include +#include +#include #include #include #include #include #include +#include #include #include #include +#include #include #include @@ -72,7 +76,7 @@ bool IfcGeom::convert(IfcSchema::ExtrudedAreaSolid* IfcExtrudedAreaSolid, TopoDS_Shape& shape) { TopoDS_Face face; if ( ! IfcGeom::convert_face(IfcExtrudedAreaSolid->Profile(),face) ) return false; - const float height = IfcExtrudedAreaSolid->Height() * Ifc::Scale; + const float height = IfcExtrudedAreaSolid->Height() * Ifc::LengthUnit; gp_Trsf trsf; convert((IfcSchema::Axis2Placement3D*) IfcExtrudedAreaSolid->Placement().get(),trsf); @@ -98,7 +102,7 @@ bool IfcGeom::convert(IfcSchema::HalfSpaceSolid* IfcHalfSpaceSolid, TopoDS_Shape gp_Pln pln; IfcGeom::convert(IfcPlane,pln); gp_Pnt pnt = pln.Location(); - if ( !IfcHalfSpaceSolid->Flag() ^ (IfcHalfSpaceSolid->dt == IfcSchema::Enum::IfcPolygonalBoundedHalfSpace) ) pnt.Translate(pln.Axis().Direction()); + if ( !IfcHalfSpaceSolid->Flag() != (IfcHalfSpaceSolid->dt == IfcSchema::Enum::IfcPolygonalBoundedHalfSpace) ) pnt.Translate(pln.Axis().Direction()); else pnt.Translate(-pln.Axis().Direction()); shape = BRepPrimAPI_MakeHalfSpace(BRepBuilderAPI_MakeFace(pln),pnt).Solid(); return true; @@ -142,17 +146,19 @@ bool IfcGeom::convert(IfcSchema::BooleanClippingResult* IfcBooleanClippingResult } bool IfcGeom::convert(IfcSchema::ClosedShell* IfcClosedShell, TopoDS_Shape& shape) { if ( ! IfcGeom::convert((IfcSchema::OpenShell*) IfcClosedShell,shape) ) return false; - ShapeFix_Solid solid; - solid.LimitTolerance(0.001); - shape = solid.SolidFromShell(TopoDS::Shell(shape)); + try { + ShapeFix_Solid solid; + solid.LimitTolerance(0.01); + shape = solid.SolidFromShell(TopoDS::Shell(shape)); + } catch(...) {} return true; } bool IfcGeom::convert(IfcSchema::ConnectedFaceSet* IfcConnectedFaceSet, TopoDS_Shape& shape) { - return IfcGeom::convert((IfcSchema::OpenShell*) IfcConnectedFaceSet,shape); + return IfcGeom::convert((IfcSchema::ClosedShell*) IfcConnectedFaceSet,shape); } bool IfcGeom::convert(IfcSchema::OpenShell* IfcOpenShell, TopoDS_Shape& shape) { BRepOffsetAPI_Sewing builder; - builder.SetTolerance(0.001); + builder.SetTolerance(0.01); IfcEntities faces = IfcOpenShell->Faces(); bool facesAdded = false; for( IfcParse::Entities::it it = faces->begin(); it != faces->end(); ++ it ) { @@ -180,7 +186,7 @@ bool IfcGeom::convert(IfcSchema::Face* IfcFace, TopoDS_Face& face) { BRepBuilderAPI_MakeFace mf(wire, false); BRepBuilderAPI_FaceError er = mf.Error(); if ( er == BRepBuilderAPI_NotPlanar ) { - std::cout << "[Notice] Trying to fix non-planar face" << std::endl; + std::cout << "[Notice] Trying to fix non-planar face:" << std::endl << IfcFace->toString() << std::endl; ShapeFix_ShapeTolerance FTol; FTol.SetTolerance(wire, 0.01, TopAbs_WIRE); mf = BRepBuilderAPI_MakeFace(wire, false); @@ -206,11 +212,39 @@ bool IfcGeom::convert(IfcSchema::Face* IfcFace, TopoDS_Face& face) { face = TopoDS::Face(sfs.Shape()); return true; } +bool IfcGeom::convert(IfcSchema::CircleHollowProfileDef* IfcCircleHollowProfileDef, TopoDS_Face& face) { + const float r = IfcCircleHollowProfileDef->Radius() * Ifc::LengthUnit; + const float t = IfcCircleHollowProfileDef->WallThickness() * Ifc::LengthUnit; + + if ( r == 0.0f || t == 0.0f ) { + std::cout << "[Notice] Skipping zero sized profile:" << std::endl << IfcCircleHollowProfileDef->toString() << std::endl; + return false; + } + + gp_Trsf2d trsf; + IfcGeom::convert((IfcSchema::Axis2Placement2D*)IfcCircleHollowProfileDef->Placement().get(),trsf); + gp_Ax2 ax = gp_Ax2().Transformed(trsf); + + BRepBuilderAPI_MakeWire outer; + Handle(Geom_Circle) outerCircle = new Geom_Circle(ax, r); + outer.Add(BRepBuilderAPI_MakeEdge(outerCircle)); + BRepBuilderAPI_MakeFace mf(outer.Wire(), false); + + BRepBuilderAPI_MakeWire inner; + Handle(Geom_Circle) innerCirlce = new Geom_Circle(ax, r-t); + inner.Add(BRepBuilderAPI_MakeEdge(innerCirlce)); + mf.Add(inner); + + ShapeFix_Shape sfs(mf.Face()); + sfs.Perform(); + face = TopoDS::Face(sfs.Shape()); + return true; +} bool IfcGeom::convert(IfcSchema::CartesianPoint* IfcCartesianPoint, gp_Pnt& p) { if ( IfcCartesianPoint->arg(0)->count() == 3 ) - p = gp_Pnt(IfcCartesianPoint->X() * Ifc::Scale,IfcCartesianPoint->Y() * Ifc::Scale,IfcCartesianPoint->Z() * Ifc::Scale); + p = gp_Pnt(IfcCartesianPoint->X() * Ifc::LengthUnit,IfcCartesianPoint->Y() * Ifc::LengthUnit,IfcCartesianPoint->Z() * Ifc::LengthUnit); else - p = gp_Pnt(IfcCartesianPoint->X() * Ifc::Scale,IfcCartesianPoint->Y() * Ifc::Scale,0.0f); + p = gp_Pnt(IfcCartesianPoint->X() * Ifc::LengthUnit,IfcCartesianPoint->Y() * Ifc::LengthUnit,0.0f); return true; } bool IfcGeom::convert(IfcSchema::Direction* IfcDirection, gp_Vec& v) { @@ -226,7 +260,7 @@ bool IfcGeom::convert(IfcSchema::ArbitraryClosedProfileDef* IfcArbitraryClosedPr bool IfcGeom::convert(IfcSchema::ArbitraryProfileDefWithVoids* IfcArbitraryProfileDefWithVoids, TopoDS_Face& face) { TopoDS_Wire profile; if ( ! IfcGeom::convert_wire(IfcArbitraryProfileDefWithVoids->Polyline(),profile) ) return false; - BRepBuilderAPI_MakeFace mf(profile, false); + BRepBuilderAPI_MakeFace mf(profile, false); IfcEntities voids = IfcArbitraryProfileDefWithVoids->Voids(); for( IfcParse::Entities::it it = voids->begin(); it != voids->end(); ++ it ) { TopoDS_Wire hole; @@ -240,14 +274,14 @@ bool IfcGeom::convert(IfcSchema::ArbitraryProfileDefWithVoids* IfcArbitraryProfi return true; } bool IfcGeom::convert(IfcSchema::RectangleProfileDef* IfcRectangleProfileDef,class TopoDS_Wire& wire) { - const float x = IfcRectangleProfileDef->Width() / 2.0f * Ifc::Scale; - const float y = IfcRectangleProfileDef->Height() / 2.0f * Ifc::Scale; + const float x = IfcRectangleProfileDef->Width() / 2.0f * Ifc::LengthUnit; + const float y = IfcRectangleProfileDef->Height() / 2.0f * Ifc::LengthUnit; if ( x == 0.0f || y == 0.0f ) { - std::cout << "[Notice] Skipping zero sized profile" << std::endl; + std::cout << "[Notice] Skipping zero sized profile:" << std::endl << IfcRectangleProfileDef->toString() << std::endl; return false; } - + gp_Trsf2d trsf; IfcGeom::convert((IfcSchema::Axis2Placement2D*)IfcRectangleProfileDef->Placement().get(),trsf); @@ -264,6 +298,105 @@ bool IfcGeom::convert(IfcSchema::RectangleProfileDef* IfcRectangleProfileDef,cla wire = w.Wire(); return true; } +bool IfcGeom::convert(IfcSchema::CircleProfileDef* IfcCircleProfileDef,class TopoDS_Wire& wire) { + const float r = IfcCircleProfileDef->Radius() * Ifc::LengthUnit; + + if ( r == 0.0f ) { + std::cout << "[Notice] Skipping zero sized profile:" << std::endl << IfcCircleProfileDef->toString() << std::endl; + return false; + } + + gp_Trsf2d trsf; + IfcGeom::convert((IfcSchema::Axis2Placement2D*)IfcCircleProfileDef->Placement().get(),trsf); + + BRepBuilderAPI_MakeWire w; + +#ifdef SEGMENTED_CIRCLE + TopoDS_Vertex previous,current,first; + for ( int i = 0; i <= Ifc::CircleSegments; i ++ ) { + const float theta = (float) PI * i / Ifc::CircleSegments * 2; + current = i == Ifc::CircleSegments ? first : + BRepBuilderAPI_MakeVertex ( gp_Pnt(r * sin(theta), r * cos(theta), 0.0f) ).Vertex(); + if ( i ) { + w.Add(BRepBuilderAPI_MakeEdge(previous,current)); + } else { + first = current; + } + previous = current; + } +#else + gp_Ax2 ax = gp_Ax2().Transformed(trsf); + Handle(Geom_Circle) circle = new Geom_Circle(ax, r); + TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(circle); + w.Add(edge); +#endif + + wire = w.Wire(); + return true; +} +bool IfcGeom::convert(IfcSchema::CompositeCurve* IfcCompositeCurve, class TopoDS_Wire& wire) { + IfcEntities segments = IfcCompositeCurve->Segments(); + BRepBuilderAPI_MakeWire w; + for( IfcParse::Entities::it it = segments->begin(); it != segments->end(); ++ it ) { + IfcSchema::CompositeCurveSegment* segment = (IfcSchema::CompositeCurveSegment*)(*it).get(); + TopoDS_Wire wire2; + if ( ! IfcGeom::convert_wire(segment->ParentCurve(),wire2) ) continue; + ShapeFix_ShapeTolerance FTol; + FTol.SetTolerance(wire2, 0.01, TopAbs_WIRE); + w.Add(wire2); + if ( w.Error() != BRepBuilderAPI_WireDone ) { + std::cout << "[Error] Failed to join curve segments:" << std::endl << IfcCompositeCurve->toString() << std::endl; + return false; + } + } + wire = w.Wire(); + return true; +} +bool IfcGeom::convert(IfcSchema::TrimmedCurve* IfcTrimmedCurve, class TopoDS_Wire& wire) { + IfcEntity basis = IfcTrimmedCurve->BasisCurve(); + IfcEntity trim1 = *IfcTrimmedCurve->Trim1()->begin(); + IfcEntity trim2 = *IfcTrimmedCurve->Trim2()->begin(); + Handle(Geom_Curve) curve; + if ( ! IfcGeom::convert_curve(basis,curve) ) return false; + if ( trim1->dt != trim2->dt ) return false; + BRepBuilderAPI_MakeWire w; + if ( trim1->dt == IfcSchema::Enum::IfcParameterValue ) { + const float p1 = ((IfcSchema::ParameterValue*)trim1.get())->Value() * Ifc::PlaneAngleUnit; + const float p2 = ((IfcSchema::ParameterValue*)trim2.get())->Value() * Ifc::PlaneAngleUnit; + BRepBuilderAPI_MakeEdge e (curve,p1,p2); + w.Add(e.Edge()); + } else if ( trim1->dt == IfcSchema::Enum::IfcCartesianPoint ) { + gp_Pnt v1,v2; + IfcGeom::convert((IfcSchema::CartesianPoint*)trim1.get(),v1); + IfcGeom::convert((IfcSchema::CartesianPoint*)trim2.get(),v2); + BRepBuilderAPI_MakeEdge e (curve,v1,v2); + w.Add(e.Edge()); + } + wire = w.Wire(); + return true; +} +bool IfcGeom::convert(IfcSchema::Circle* IfcCircle, Handle(Geom_Curve)& curve) { + const float r = IfcCircle->Radius() * Ifc::LengthUnit; + if ( r == 0.0f ) { return false; } + IfcSchema::Axis2Placement2D* placement = (IfcSchema::Axis2Placement2D*) IfcCircle->Placement().get(); + gp_Trsf2d trsf; + IfcGeom::convert(placement, trsf); + gp_Ax2 ax = gp_Ax2().Transformed(trsf); + curve = new Geom_Circle(ax, r); + return true; +} +bool IfcGeom::convert(IfcSchema::Ellipse* IfcEllipse, Handle(Geom_Curve)& curve) { + float x = IfcEllipse->Axis1() * Ifc::LengthUnit; + float y = IfcEllipse->Axis2() * Ifc::LengthUnit; + if ( x == 0.0f || y == 0.0f || y > x ) { return false; } + IfcSchema::Axis2Placement2D* placement = (IfcSchema::Axis2Placement2D*) IfcEllipse->Placement().get(); + gp_Trsf2d trsf; + IfcGeom::convert(placement, trsf); + gp_Ax2 ax; + ax = gp_Ax2().Transformed(trsf); + curve = new Geom_Ellipse(ax, x, y); + return true; +} bool IfcGeom::convert(IfcSchema::Polyline* IfcPolyline, TopoDS_Wire& result) { IfcEntities points = IfcPolyline->Points(); @@ -272,7 +405,10 @@ bool IfcGeom::convert(IfcSchema::Polyline* IfcPolyline, TopoDS_Wire& result) { gp_Pnt P1;gp_Pnt P2; IfcGeom::convert((IfcSchema::CartesianPoint*)(*it).get(),P1); IfcParse::Entities::it next = it + 1; - if ( next == points->end() ) next = points->begin(); + if ( next == points->end() ) { + if ( IfcPolyline->dt == IfcSchema::Enum::IfcPolyloop ) next = points->begin(); + else break; + } IfcGeom::convert((IfcSchema::CartesianPoint*)(*next).get(),P2); if ( P1.X() == P2.X() && P1.Y() == P2.Y() && P1.Z() == P2.Z() ) continue; TopoDS_Edge e = BRepBuilderAPI_MakeEdge(P1,P2); @@ -290,8 +426,8 @@ bool IfcGeom::convert(IfcSchema::Axis2Placement3D* IfcAxis2Placement3D, gp_Trsf& IfcGeom::convert((IfcSchema::CartesianPoint*) IfcAxis2Placement3D->Origin().get(),o); try { - IfcGeom::convert((IfcSchema::Direction*) IfcAxis2Placement3D->Dir1().get(),z); - IfcGeom::convert((IfcSchema::Direction*) IfcAxis2Placement3D->Dir2().get(),x); + IfcGeom::convert((IfcSchema::Direction*) IfcAxis2Placement3D->Dir1().get(),z); + IfcGeom::convert((IfcSchema::Direction*) IfcAxis2Placement3D->Dir2().get(),x); } catch( IfcParse::IfcException& ) {} gp_Ax3 axis(o,z,x); @@ -311,13 +447,13 @@ bool IfcGeom::convert(IfcSchema::Plane* IfcPlane, gp_Pln& plane) { plane = gp_Pln(axis); return true; } -bool IfcGeom::convert(IfcSchema::Axis2Placement2D* IfcAxis2Placement2D, gp_Trsf2d& trsf) { +bool IfcGeom::convert(IfcSchema::Axis2Placement2D* IfcAxis2Placement2D, gp_Trsf2d& trsf) { gp_Pnt P; gp_Vec V; IfcGeom::convert((IfcSchema::CartesianPoint*) IfcAxis2Placement2D->Origin().get(),P); IfcGeom::convert((IfcSchema::Direction*) IfcAxis2Placement2D->Dir1().get(),V); - gp_Ax2d axis (gp_Pnt2d(P.X(),P.Y()),gp_Vec2d(V.X(),V.Y())); + gp_Ax2d axis(gp_Pnt2d(P.X(),P.Y()),gp_Vec2d(V.X(),V.Y())); trsf.SetTransformation(axis,gp_Ax2d()); return true; } @@ -347,7 +483,7 @@ bool IfcGeom::convert_openings(const IfcSchema::BuildingElement* IfcBuildingElem IfcEntities IfcShapes = IfcShapeRepresentation->Shapes(); for ( IfcParse::Entities::it shape = IfcShapes->begin(); shape != IfcShapes->end(); ++shape ) { TopoDS_Shape s; - if ( ! IfcGeom::convert_shape(*shape,s) ) continue; + if ( ! IfcGeom::convert_shape(*shape,s)) continue; s.Move(trsf); s.Move(trsf3); result = BRepAlgoAPI_Cut(result,s); @@ -369,4 +505,4 @@ bool IfcGeom::convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face) { if ( er != BRepBuilderAPI_FaceDone ) return false; face = mf.Face(); return true; -} +} \ No newline at end of file diff --git a/src/ifcparse/IfcGeomObjects.cpp b/src/ifcparse/IfcGeomObjects.cpp index 8e9324aabf..be6544761b 100644 --- a/src/ifcparse/IfcGeomObjects.cpp +++ b/src/ifcparse/IfcGeomObjects.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include "../ifcparse/IfcGeomObjects.h" #include "../ifcparse/IfcGeom.h" @@ -58,8 +59,8 @@ IfcGeomObjects::IfcMesh::IfcMesh(int i, TopoDS_Shape s) { // Triangulate the shape try { - BRepTools::Clean(s); - BRepMesh::Mesh(s,0.001f); + BRepTools::Clean(s); + BRepMesh::Mesh(s,0.001f); } catch(...) { std::cout << "[Error] Failed to triangulate IFC Entity #" << i << std::endl; return; @@ -167,8 +168,11 @@ IfcGeomObjects::IfcGeomObject* _get() { #endif // Find the IfcBuildingElements that refer to the current IfcShapeRepresentation entities = shaperep->parents(IfcSchema::Enum::IfcProductDefinitionShape)->parents(); + entities->pushs(shaperep->parents(IfcSchema::Enum::IfcProductRepresentation)->parents()); // 2x2 compatibility entities->pushs(shaperep->parents(IfcSchema::Enum::IfcRepresentationMap)->parents(IfcSchema::Enum::IfcMappedItem) ->parents(IfcSchema::Enum::IfcShapeRepresentation,1,"Body")->parents(IfcSchema::Enum::IfcProductDefinitionShape)->parents()); + entities->pushs(shaperep->parents(IfcSchema::Enum::IfcRepresentationMap)->parents(IfcSchema::Enum::IfcMappedItem) + ->parents(IfcSchema::Enum::IfcShapeRepresentation,1,"Body")->parents(IfcSchema::Enum::IfcProductRepresentation)->parents()); if ( ! entities->size ) { _nextShape(); continue; @@ -223,6 +227,7 @@ IfcGeomObjects::IfcGeomObject* _get() { try { if (openings && openings->size) IfcGeom::convert_openings(entity,openings,temp_shape,trsf); } catch( IfcParse::IfcException& e ) {std::cout << "[Warning] " << e.what() << std::endl; } + catch(StdFail_NotDone&) { std::cout << "[Error] Unknown modelling processing openings for:" << std::endl << entity->toString() << std::endl; } if ( use_world_coords ) { shape = new IfcGeomObjects::IfcMesh(shaperep->id,temp_shape.Moved(trsf)); trsf = gp_Trsf(); diff --git a/src/ifcparse/IfcMacro.h b/src/ifcparse/IfcMacro.h index e8996d92a7..caf8a0f2b4 100644 --- a/src/ifcparse/IfcMacro.h +++ b/src/ifcparse/IfcMacro.h @@ -29,6 +29,7 @@ #undef IFC_FACE_CLASS #undef IFC_SKIP_CLASS #undef IFC_WIRE_CLASS +#undef IFC_CURVE_CLASS #undef IFC_HELPER_CLASS #undef IFC_END_CLASS #undef IFC_REF @@ -44,6 +45,7 @@ #define IFC_SHAPE_CLASS(N) IFC_CLASS(N,"") #define IFC_FACE_CLASS(N) IFC_CLASS(N,"") #define IFC_WIRE_CLASS(N) IFC_CLASS(N,"") +#define IFC_CURVE_CLASS(N) IFC_CLASS(N,"") #define IFC_HELPER_CLASS(N) IFC_CLASS(N,"") #define IFC_SKIP_CLASS(N) #define IFC_END_CLASS }; @@ -61,6 +63,7 @@ #define IFC_SHAPE_CLASS(N) #define IFC_FACE_CLASS(N) #define IFC_WIRE_CLASS(N) +#define IFC_CURVE_CLASS(N) #define IFC_HELPER_CLASS(N) #define IFC_SKIP_CLASS(N) #define IFC_END_CLASS @@ -76,6 +79,7 @@ #ifdef IFC_PARSE_ENUM #define IFC_SHAPE_CLASS(N) Ifc##N, #define IFC_WIRE_CLASS(N) Ifc##N, +#define IFC_CURVE_CLASS(N) Ifc##N, #define IFC_FACE_CLASS(N) Ifc##N, #define IFC_CLASS(N,T) Ifc##N, #define IFC_HELPER_CLASS(N) Ifc##N, @@ -94,6 +98,7 @@ #define IFC_SHAPE_CLASS(N) if ( strcasecmp(a.c_str()+3,#N) == 0 ) { return IfcSchema::Enum::Ifc##N; } #define IFC_FACE_CLASS(N) IFC_SHAPE_CLASS(N) #define IFC_WIRE_CLASS(N) IFC_SHAPE_CLASS(N) +#define IFC_CURVE_CLASS(N) IFC_SHAPE_CLASS(N) #define IFC_HELPER_CLASS(N) IFC_SHAPE_CLASS(N) #define IFC_CLASS(N,T) IFC_SHAPE_CLASS(N) #define IFC_SKIP_CLASS(N) if ( strcasecmp(a.c_str()+3,#N) == 0 ) { return IfcSchema::Enum::IfcDontCare; } @@ -111,6 +116,7 @@ #define IFC_SHAPE_CLASS(N) if ( t == IfcSchema::Enum::Ifc##N ) return "Ifc" #N; #define IFC_FACE_CLASS(N) IFC_SHAPE_CLASS(N) #define IFC_WIRE_CLASS(N) IFC_SHAPE_CLASS(N) +#define IFC_CURVE_CLASS(N) IFC_SHAPE_CLASS(N) #define IFC_HELPER_CLASS(N) IFC_SHAPE_CLASS(N) #define IFC_CLASS(N,T) IFC_SHAPE_CLASS(N) #define IFC_SKIP_CLASS(N) @@ -128,6 +134,7 @@ #define IFC_SHAPE_CLASS(N) bool convert(IfcSchema::N* Ifc##N,TopoDS_Shape& result); #define IFC_FACE_CLASS(N) bool convert(IfcSchema::N* Ifc##N,TopoDS_Face& result); #define IFC_WIRE_CLASS(N) bool convert(IfcSchema::N* Ifc##N,TopoDS_Wire& result); +#define IFC_CURVE_CLASS(N) bool convert(IfcSchema::N* Ifc##N,Handle(Geom_Curve)& result); #define IFC_HELPER_CLASS(N) #define IFC_CLASS(N,T) bool convert(IfcSchema::N* Ifc##N,T& result); #define IFC_SKIP_CLASS(N) @@ -145,6 +152,7 @@ #define IFC_SHAPE_CLASS(N) if ( L->dt == IfcSchema::Enum::Ifc##N ) { IfcSchema::N* x = (IfcSchema::N*) L.get(); bool b = false; try { b = IfcGeom::convert(x,result); } catch(IfcParse::IfcException& e) { std::cout << "[Error] " << e.what() << std::endl;} catch(StdFail_NotDone&) { std::cout << "[Error] Unknown modelling error" << std::endl; } if (!b) std::cout << "[Error] Failed to convert:" << std::endl << x->toString() << std::endl; return b; } #define IFC_FACE_CLASS(N) #define IFC_WIRE_CLASS(N) +#define IFC_CURVE_CLASS(N) #define IFC_HELPER_CLASS(N) #define IFC_CLASS(N,T) #define IFC_SKIP_CLASS(N) @@ -162,6 +170,7 @@ #define IFC_SHAPE_CLASS(N) #define IFC_FACE_CLASS(N) #define IFC_WIRE_CLASS(N) if ( L->dt == IfcSchema::Enum::Ifc##N ) { IfcSchema::N* x = (IfcSchema::N*) L.get(); return IfcGeom::convert(x,result); } +#define IFC_CURVE_CLASS(N) #define IFC_HELPER_CLASS(N) #define IFC_CLASS(N,T) #define IFC_SKIP_CLASS(N) @@ -179,6 +188,25 @@ #define IFC_SHAPE_CLASS(N) #define IFC_FACE_CLASS(N) if ( L->dt == IfcSchema::Enum::Ifc##N ) { IfcSchema::N* x = (IfcSchema::N*) L.get(); return IfcGeom::convert(x,result); } #define IFC_WIRE_CLASS(N) if ( L->dt == IfcSchema::Enum::Ifc##N ) { IfcSchema::N* x = (IfcSchema::N*) L.get(); if ( ! IfcGeom::convert(x,wire) ) return false; return IfcGeom::convert_wire_to_face(wire,result); } +#define IFC_CURVE_CLASS(N) +#define IFC_HELPER_CLASS(N) +#define IFC_CLASS(N,T) +#define IFC_SKIP_CLASS(N) +#define IFC_END_CLASS +#define IFC_REF(C,N,I) +#define IFC_REFS(C,N,I) +#define IFC_FLT(C,N,I) +#define IFC_FLT_SUB(C,N,I,J) +#define IFC_INT(C,N,I) +#define IFC_STR(C,N,I) +#define IFC_BOOL(C,N,I) +#endif + +#ifdef IFC_CURVE_SRC +#define IFC_SHAPE_CLASS(N) +#define IFC_FACE_CLASS(N) +#define IFC_WIRE_CLASS(N) +#define IFC_CURVE_CLASS(N) if ( L->dt == IfcSchema::Enum::Ifc##N ) { IfcSchema::N* x = (IfcSchema::N*) L.get(); return IfcGeom::convert(x,result); } #define IFC_HELPER_CLASS(N) #define IFC_CLASS(N,T) #define IFC_SKIP_CLASS(N) diff --git a/src/ifcparse/IfcParse.cpp b/src/ifcparse/IfcParse.cpp index 0146ed2a9a..bbebc6b7eb 100644 --- a/src/ifcparse/IfcParse.cpp +++ b/src/ifcparse/IfcParse.cpp @@ -57,6 +57,10 @@ Argument::Argument(const std::string& s) { if ( _data == -1 ) { _data = datatypes.size(); datatypes.push_back(s); } } } +Argument::Argument(const EntityPtr e) { + type = SUB_ENTITY; + _entity = e; +} std::string Argument::s() const { if ( type == OPERATOR ) { std::string r; r.push_back((char)_data); return r; } if ( type == DATATYPE ) return datatypes[_data]; @@ -76,6 +80,10 @@ bool Argument::b() const { if ( type != ENUMERATION ) throw IfcException(); return s() == "T"; } +EntityPtr Argument::r() const { + if ( type != SUB_ENTITY ) throw IfcException(); + return _entity; +} bool Argument::isOp(char op) const { return type == OPERATOR && ( op == 0 || op == ((char)_data) ); } @@ -87,6 +95,7 @@ std::string Argument::toString() const { else if ( type == STRING ) ss << "'" << s() << "'"; else if ( type == ENUMERATION ) ss << "." << s() << "."; else if ( type == IDENTIFIER ) ss << "#" << i(); + else if ( type == SUB_ENTITY ) ss << _entity->toString(); return ss.str(); } std::vector Argument::datatypes; @@ -104,10 +113,11 @@ void ArgumentList::_push() { _args.push_back(a); _current = a; } -void ArgumentList::_pop() { - if ( _levels.empty() ) return; - _current = _levels.back(); +bool ArgumentList::_pop() { _levels.pop_back(); + if ( _levels.empty() ) return true; + _current = _levels.back(); + return _levels.empty(); } void ArgumentList::_append(const Argument* v) { ArgumentList* a = new ArgumentList(); @@ -120,7 +130,7 @@ std::string ArgumentList::toString() const { std::stringstream ss; ss << "("; std::vector::const_iterator it; for ( it = _args.begin() ; it != _args.end(); ++ it ) { - if ( it != _args.begin() ) ss << ","; + if ( it != _args.begin() ) ss << ","; ss << (*it)->toString(); } ss << ")"; @@ -135,8 +145,11 @@ int ArgumentList::count() const { return _arg ? 1 : _args.size(); } ArgumentList* ArgumentList::arg(int i) const { return _args[i]; } EntityPtr ArgumentList::ref() const { - if ( _arg->isOp('$') ) throw IfcException(); - return Ifc::EntityById(_arg->i()); + if ( _arg->type == Argument::IDENTIFIER ) { + return Ifc::EntityById(_arg->i()); + } else { + return _arg->r(); + } } EntitiesPtr ArgumentList::refs() const { EntitiesPtr l (new Entities()); @@ -145,6 +158,8 @@ EntitiesPtr ArgumentList::refs() const { ArgumentList* a = *it; if ( a->_arg && a->_arg->type == Argument::IDENTIFIER ) { l->push(Ifc::EntityById(a->_arg->i())); + } else if ( a->_arg && a->_arg->type == Argument::SUB_ENTITY ) { + l->push(a->_arg->r()); } } return l; @@ -160,12 +175,13 @@ ArgumentList::~ArgumentList() { inline bool Entity::term(char last) { return last == '(' || last == ')' || last == '=' || last == ',' || last == ';'; } -Entity::Entity(std::istream* ss, std::vector& refs) { +Entity::Entity(std::istream* ss, std::vector& refs, bool sub) { std::string curvar; curvar.reserve(64); bool inStr = false; char c[1] = ""; int state = -1; + int previousPos = -1; args = 0; _dt = 0; id = -1; @@ -177,31 +193,46 @@ Entity::Entity(std::istream* ss, std::vector& refs) { curvar.clear(); curvar.push_back(*c); if ( state < 10 ) state ++; - if ( state == 0 ) { + if ( !sub && !state ) { if ( v->type == Argument::IDENTIFIER ) { id = v->i(); } else { state = -1; } - } else if ( state == 1 ) { + } else if ( ! sub && (state == 1) ) { if ( ! v->isOp('=') ) state = -1; - } else if ( state == 2 ) { + } else if ( (sub && !state) || (!sub && state == 2) ) { if ( v->type == Argument::DATATYPE ) { dt = IfcSchema::Enum::FromString(v->s()); _dt = v; continue; } } else if ( args ) { - if ( v->isOp('(') ) args->_push(); - else if ( v->isOp(')') ) args->_pop(); - else if ( ! v->isOp(',') && !v->isOp(';') ) { - args->_append(v); - if ( v->type == Argument::IDENTIFIER ) refs.push_back(v->i()); - continue; + if ( v->isOp('(') ) + args->_push(); + else if ( v->isOp(')') ) { + bool closed = args->_pop(); + if ( closed && sub ) { + delete v; + return; + } + } else if ( ! v->isOp(',') && !v->isOp(';') ) { + if ( v->type == Argument::DATATYPE ) { + ss->seekg(previousPos-1,std::ios_base::beg); + Argument* a = new Argument(EntityPtr(new Entity(ss,refs,true))); + ss->seekg(-1,std::ios_base::cur); + curvar.clear(); + args->_append(a); + } else { + args->_append(v); + if ( v->type == Argument::IDENTIFIER ) refs.push_back(v->i()); + continue; + } } } else if ( v->isOp('(') ) { args = new ArgumentList(); } + previousPos = ss->tellg(); delete v; } else curvar.push_back(*c); if ( *c == '\'' ) inStr = !inStr; @@ -224,7 +255,8 @@ ArgumentList* Entity::arg(int i) const { std::string Entity::toString() const { std::stringstream ss; if ( isAssignment() ) { - ss << "#" << id << "=" << datatype() << args->toString(); + if ( id > 0 ) ss << "#" << id << "="; + ss << datatype() << args->toString(); } return ss.str(); } @@ -296,7 +328,7 @@ File::File(std::string fn, bool debug) { EntityPtr il (new Entity(pf,refs)); if ( il->isAssignment() ) { if ( debug ) - std::cout << il->toString(); + std::cout << il->toString() << std::endl; if ( il->dt == IfcSchema::Enum::IfcDontCare ) { continue; } @@ -362,28 +394,29 @@ EntityPtr Ifc::EntityById(int id) { } bool Ifc::Init(std::string fn) { f = new File(fn, false); - IfcEntities units = EntitiesByType(IfcSchema::Enum::IfcSIUnit); - Ifc::Scale = 1.0f; + IfcEntity IfcUnitAssigment = *EntitiesByType(IfcSchema::Enum::IfcUnitAssignment)->begin(); + IfcEntities units = ((IfcSchema::UnitAssignment*)IfcUnitAssigment.get())->Units(); + Ifc::LengthUnit = 1.0f; if ( units ) for ( IfcParse::Entities::it it = units->begin(); it != units->end(); it ++ ) { - IfcSchema::SIUnit* unit = (IfcSchema::SIUnit*)(*it).get(); - if ( unit->Type() == "LENGTHUNIT" ) { - if ( unit->Prefix() == "EXA" ) Ifc::Scale = (float) 1e18; - else if ( unit->Prefix() == "PETA" ) Ifc::Scale = (float) 1e15; - else if ( unit->Prefix() == "TERA" ) Ifc::Scale = (float) 1e12; - else if ( unit->Prefix() == "GIGA" ) Ifc::Scale = (float) 1e9; - else if ( unit->Prefix() == "MEGA" ) Ifc::Scale = (float) 1e6; - else if ( unit->Prefix() == "KILO" ) Ifc::Scale = (float) 1e3; - else if ( unit->Prefix() == "HECTO" ) Ifc::Scale = (float) 1e2; - else if ( unit->Prefix() == "DECA" ) Ifc::Scale = (float) 1; - else if ( unit->Prefix() == "DECI" ) Ifc::Scale = (float) 1e-1; - else if ( unit->Prefix() == "CENTI" ) Ifc::Scale = (float) 1e-2; - else if ( unit->Prefix() == "MILLI" ) Ifc::Scale = (float) 1e-3; - else if ( unit->Prefix() == "MICRO" ) Ifc::Scale = (float) 1e-6; - else if ( unit->Prefix() == "NANO" ) Ifc::Scale = (float) 1e-9; - else if ( unit->Prefix() == "PICO" ) Ifc::Scale = (float) 1e-12; - else if ( unit->Prefix() == "FEMTO" ) Ifc::Scale = (float) 1e-15; - else if ( unit->Prefix() == "ATTO" ) Ifc::Scale = (float) 1e-18; + IfcEntity unit = *it; + float value = 1.0f; + std::string UnitType = ""; + if ( unit->dt == IfcSchema::Enum::IfcConversionBasedUnit ) { + IfcSchema::ConversionBasedUnit* IfcConversionBasedUnit = (IfcSchema::ConversionBasedUnit*)(*it).get(); + IfcSchema::MeasureWithUnit* IfcMeasureWithUnit = (IfcSchema::MeasureWithUnit*)IfcConversionBasedUnit->ConversionFactor().get(); + unit = IfcMeasureWithUnit->Unit(); + value = IfcMeasureWithUnit->Value()->arg(0)->f(); + } + if ( unit->dt == IfcSchema::Enum::IfcSIUnit ) { + IfcSchema::SIUnit* IfcSIUnit = (IfcSchema::SIUnit*)(*it).get(); + value *= UnitPrefixToValue(IfcSIUnit->UnitPrefix()); + UnitType = IfcSIUnit->UnitType(); + } + if ( UnitType == "LENGTHUNIT" ) { + Ifc::LengthUnit = value; + } else if ( UnitType == "PLANEANGLEUNIT" ) { + Ifc::PlaneAngleUnit = value; } } return f->valid; @@ -395,4 +428,26 @@ void Ifc::Dispose() { Argument::enumstrings.clear(); } File* Ifc::f = 0; -float Ifc::Scale = 1.0f; +float Ifc::LengthUnit = 1.0f; +float Ifc::PlaneAngleUnit = 1.0f; +int Ifc::CircleSegments = 32; + +float UnitPrefixToValue( const std::string& s ) { + if ( s == "EXA" ) return (float) 1e18; + else if ( s == "PETA" ) return (float) 1e15; + else if ( s == "TERA" ) return (float) 1e12; + else if ( s == "GIGA" ) return (float) 1e9; + else if ( s == "MEGA" ) return (float) 1e6; + else if ( s == "KILO" ) return (float) 1e3; + else if ( s == "HECTO" ) return (float) 1e2; + else if ( s == "DECA" ) return (float) 1; + else if ( s == "DECI" ) return (float) 1e-1; + else if ( s == "CENTI" ) return (float) 1e-2; + else if ( s == "MILLI" ) return (float) 1e-3; + else if ( s == "MICRO" ) return (float) 1e-6; + else if ( s == "NANO" ) return (float) 1e-9; + else if ( s == "PICO" ) return (float) 1e-12; + else if ( s == "FEMTO" ) return (float) 1e-15; + else if ( s == "ATTO" ) return (float) 1e-18; + else return 1.0f; +} diff --git a/src/ifcparse/IfcParse.h b/src/ifcparse/IfcParse.h index 1e8735d8ca..372aede8fa 100644 --- a/src/ifcparse/IfcParse.h +++ b/src/ifcparse/IfcParse.h @@ -49,6 +49,11 @@ class Ifc; namespace IfcParse { + class Entity; + class Entities; + typedef SHARED_PTR EntityPtr; + typedef SHARED_PTR EntitiesPtr; + class Argument { private: static std::vector datatypes; @@ -56,12 +61,14 @@ namespace IfcParse { static std::vector argstrings; int _data; - float _number; + float _number; + EntityPtr _entity; public: - enum vartype { IDENTIFIER, STRING, NUMBER, OPERATOR, ENUMERATION, DATATYPE }; + enum vartype { IDENTIFIER, STRING, NUMBER, OPERATOR, ENUMERATION, DATATYPE, SUB_ENTITY }; vartype type; Argument(const std::string& s); + Argument(const EntityPtr e); bool isOp(char op = 0) const; @@ -69,6 +76,7 @@ namespace IfcParse { int i() const; std::string s() const; bool b() const; + EntityPtr r() const; std::string toString() const; @@ -77,11 +85,6 @@ namespace IfcParse { friend class ::Ifc; }; - class Entity; - class Entities; - typedef SHARED_PTR EntityPtr; - typedef SHARED_PTR EntitiesPtr; - class ArgumentList { private: std::vector _levels; @@ -89,7 +92,7 @@ namespace IfcParse { ArgumentList* _current; const Argument* _arg; void _push(); - void _pop(); + bool _pop(); void _append(const Argument* v); public: ArgumentList(); @@ -118,7 +121,7 @@ namespace IfcParse { ArgumentList* args; Argument* _dt; - Entity(std::istream* ss, std::vector& refs); + Entity(std::istream* ss, std::vector& refs, bool sub = false); ~Entity(); ArgumentList* arg(int i) const; @@ -174,6 +177,8 @@ namespace IfcParse { typedef IfcParse::EntityPtr IfcEntity; typedef IfcParse::EntitiesPtr IfcEntities; +float UnitPrefixToValue(const std::string& s); + class Ifc { private: static IfcParse::File* f; @@ -183,7 +188,9 @@ public: static IfcEntity EntityById(int id); static bool Init(std::string fn); static void Dispose(); - static float Scale; + static float LengthUnit; + static float PlaneAngleUnit; + static int CircleSegments; }; #endif diff --git a/src/ifcparse/IfcSchema.h b/src/ifcparse/IfcSchema.h index 56a6eb7aea..c627ee619e 100644 --- a/src/ifcparse/IfcSchema.h +++ b/src/ifcparse/IfcSchema.h @@ -120,6 +120,28 @@ IFC_FLT(RectangleProfileDef,Width,3) IFC_FLT(RectangleProfileDef,Height,4) IFC_END_CLASS +IFC_WIRE_CLASS(CircleProfileDef) +IFC_REF(CircleProfileDef,Placement,2) +IFC_FLT(CircleProfileDef,Radius,3) +IFC_END_CLASS + +IFC_FACE_CLASS(CircleHollowProfileDef) +IFC_REF(CircleHollowProfileDef,Placement,2) +IFC_FLT(CircleHollowProfileDef,Radius,3) +IFC_FLT(CircleHollowProfileDef,WallThickness,4) +IFC_END_CLASS + +IFC_CURVE_CLASS(Circle) +IFC_REF(Circle,Placement,0) +IFC_FLT(Circle,Radius,1) +IFC_END_CLASS + +IFC_CURVE_CLASS(Ellipse) +IFC_REF(Ellipse,Placement,0) +IFC_FLT(Ellipse,Axis1,1) +IFC_FLT(Ellipse,Axis2,2) +IFC_END_CLASS + IFC_CLASS(CartesianPoint,gp_Pnt) IFC_FLT_SUB(CartesianPoint,X,0,0) IFC_FLT_SUB(CartesianPoint,Y,0,1) @@ -152,10 +174,23 @@ IFC_WIRE_CLASS(Polyline) IFC_REFS(Polyline,Points,0) IFC_END_CLASS +IFC_WIRE_CLASS(CompositeCurve) +IFC_REFS(CompositeCurve,Segments,0) +IFC_BOOL(CompositeCurve,SelfIntersects,1) +IFC_END_CLASS + IFC_WIRE_CLASS(Polyloop) IFC_REFS(Polyloop,Points,0) IFC_END_CLASS +IFC_WIRE_CLASS(TrimmedCurve) +IFC_REF(TrimmedCurve,BasisCurve,0) +IFC_REFS(TrimmedCurve,Trim1,1) +IFC_REFS(TrimmedCurve,Trim2,2) +IFC_BOOL(TrimmedCurve,SenseAgreement,3) +IFC_STR(TrimmedCurve,MasterRepresentation,4) +IFC_END_CLASS + IFC_HELPER_CLASS(BuildingElement) IFC_STR(BuildingElement,Guid,0) IFC_REF(BuildingElement,Owner,1) @@ -168,15 +203,43 @@ IFC_HELPER_CLASS(ShapeRepresentation) IFC_REFS(ShapeRepresentation,Shapes,3) IFC_END_CLASS +IFC_HELPER_CLASS(CompositeCurveSegment) +IFC_STR(CompositeCurveSegment,Transition,0) +IFC_BOOL(CompositeCurveSegment,SameSense,1) +IFC_REF(CompositeCurveSegment,ParentCurve,2) +IFC_END_CLASS + IFC_HELPER_CLASS(SIUnit) -IFC_STR(SIUnit,Type,1) -IFC_STR(SIUnit,Prefix,2) +IFC_STR(SIUnit,UnitType,1) +IFC_STR(SIUnit,UnitPrefix,2) IFC_STR(SIUnit,Name,3) IFC_END_CLASS +IFC_HELPER_CLASS(ConversionBasedUnit) +IFC_REF(ConversionBasedUnit,Dimensions,0) +IFC_STR(ConversionBasedUnit,UnitType,1) +IFC_STR(ConversionBasedUnit,Name,2) +IFC_REF(ConversionBasedUnit,ConversionFactor,3) +IFC_END_CLASS +IFC_HELPER_CLASS(MeasureWithUnit) +IFC_REF(MeasureWithUnit,Value,0) +IFC_REF(MeasureWithUnit,Unit,1) +IFC_END_CLASS +IFC_HELPER_CLASS(UnitAssignment) +IFC_REFS(UnitAssignment,Units,0) +IFC_END_CLASS + +IFC_HELPER_CLASS(ParameterValue) +IFC_FLT(ParameterValue,Value,0) +IFC_END_CLASS +IFC_HELPER_CLASS(RatioMeasure) +IFC_FLT(RatioMeasure,Value,0) +IFC_END_CLASS IFC_HELPER_CLASS(ProductDefinitionShape) IFC_REFS(ProductDefinitionShape,ShapeReps,2) IFC_END_CLASS +IFC_HELPER_CLASS(ProductRepresentation) // 2x2 compatibility +IFC_END_CLASS IFC_HELPER_CLASS(RepresentationMap) IFC_END_CLASS IFC_HELPER_CLASS(MappedItem) @@ -193,4 +256,5 @@ IFC_SKIP_CLASS(ComplexProperty) IFC_SKIP_CLASS(RelDefinesByProperty) IFC_SKIP_CLASS(MaterialLayer) IFC_SKIP_CLASS(MaterialLayerSet) -IFC_SKIP_CLASS(MaterialLayerSetUsage) \ No newline at end of file +IFC_SKIP_CLASS(MaterialLayerSetUsage) +IFC_SKIP_CLASS(PresentationLayerAssignment) \ No newline at end of file diff --git a/src/ifcparse/IfcTypes.cpp b/src/ifcparse/IfcTypes.cpp index 7986b1d90f..cc866077b1 100644 --- a/src/ifcparse/IfcTypes.cpp +++ b/src/ifcparse/IfcTypes.cpp @@ -17,7 +17,7 @@ * * ********************************************************************************/ -#include "StdFail_NotDone.hxx" +#include #include "../ifcparse/IfcTypes.h" #include "../ifcparse/IfcEnum.h" @@ -46,6 +46,15 @@ bool IfcGeom::convert_wire(const IfcEntity L, TopoDS_Wire &result) { return false; } +bool IfcGeom::convert_curve(const IfcEntity L, Handle(Geom_Curve) &result) { + if ( ! L ) return false; +#define IFC_CURVE_SRC +#include "../ifcparse/IfcSchema.h" +#undef IFC_CURVE_SRC + std::cout << "[Error] Failed to interpret:" << std::endl << L->toString() << std::endl; + return false; +} + bool IfcGeom::convert_face(const IfcEntity L, TopoDS_Face &result) { if ( ! L ) return false; TopoDS_Wire wire; diff --git a/src/ifcparse/IfcTypes.h b/src/ifcparse/IfcTypes.h index da82c6d993..2d6da0ab69 100644 --- a/src/ifcparse/IfcTypes.h +++ b/src/ifcparse/IfcTypes.h @@ -26,6 +26,7 @@ #include #include #include +#include #include "../ifcparse/IfcParse.h" @@ -42,6 +43,7 @@ namespace IfcGeom { bool convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face); bool convert_shape(const IfcEntity L, TopoDS_Shape& result); bool convert_wire(const IfcEntity L, TopoDS_Wire& result); + bool convert_curve(const IfcEntity L, Handle(Geom_Curve)& result); bool convert_face(const IfcEntity L, TopoDS_Face& result); bool convert_openings(const IfcSchema::BuildingElement* IfcBuildingElement, const IfcEntities openings, TopoDS_Shape& result, const gp_Trsf& trsf); }