From 8767f6e52aaa15d44bc43efd77c95982947db4c6 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Mon, 11 Jul 2011 09:33:18 +0000 Subject: [PATCH] IfcBlender: updated to Blender 2.58 (Patch by Yorik van Havre) IfcParse: lazy loading of entities IfcGeom: caching of binary entities --- src/ifcblender/IfcBlender.py | 12 +- src/ifcobj/IfcObj.cpp | 10 +- src/ifcobj/ObjMaterials.h | 19 +- src/ifcparse/IfcEnum.cpp | 10 +- src/ifcparse/IfcEnum.h | 1 + src/ifcparse/IfcGeom.cpp | 133 +++-- src/ifcparse/IfcGeomObjects.cpp | 37 +- src/ifcparse/IfcGeomObjects.h | 27 +- src/ifcparse/IfcMacro.h | 190 +++---- src/ifcparse/IfcParse.cpp | 877 +++++++++++++++++++------------- src/ifcparse/IfcParse.h | 301 +++++++---- src/ifcparse/IfcSchema.h | 90 +++- src/ifcparse/IfcTypes.cpp | 43 +- src/ifcparse/IfcTypes.h | 6 + 14 files changed, 1081 insertions(+), 675 deletions(-) diff --git a/src/ifcblender/IfcBlender.py b/src/ifcblender/IfcBlender.py index 6710484090..9239685c95 100644 --- a/src/ifcblender/IfcBlender.py +++ b/src/ifcblender/IfcBlender.py @@ -23,11 +23,10 @@ bl_info = { "description": "Import files in the "\ "Industry Foundation Classes (.ifc) file format", "author": "Thomas Krijnen, IfcOpenShell", - "blender": (2, 5, 6), - "api": 32738, + "blender": (2, 5, 8), + "api": 37702, "location": "File > Import", - "warning": "This addon requires several "\ - "Open CASCADE libraries to be installed", + "warning": "", "wiki_url": "http://sourceforge.net/apps/"\ "mediawiki/ifcopenshell/index.php", "tracker_url": "http://sourceforge.net/tracker/?group_id=543113", @@ -37,8 +36,7 @@ bl_info = { import bpy import mathutils from bpy.props import * -from io_utils import ImportHelper - +from bpy_extras.io_utils import ImportHelper class ImportIFC(bpy.types.Operator, ImportHelper): bl_idname = "import_scene.ifc" @@ -54,7 +52,7 @@ class ImportIFC(bpy.types.Operator, ImportHelper): ids = {} while True: ob = IfcImport.Get() - if not ob.type in ['IFCSPACE', 'IFCOPENINGELEMENT']: + if not ob.type in ['IfcSpace', 'IfcOpeningElement']: f = ob.mesh.faces v = ob.mesh.verts m = ob.matrix diff --git a/src/ifcobj/IfcObj.cpp b/src/ifcobj/IfcObj.cpp index fcb77f511f..5d2845c92c 100644 --- a/src/ifcobj/IfcObj.cpp +++ b/src/ifcobj/IfcObj.cpp @@ -27,6 +27,7 @@ #include #include +#include #include "../ifcparse/IfcGeomObjects.h" #include "../ifcobj/ObjMaterials.h" @@ -56,12 +57,15 @@ int main ( int argc, char** argv ) { fObj << "mtllib " << fnMtl << std::endl; std::set materials; + time_t start,end; + time(&start); + // The functions IfcGeomObjects::Get() and IfcGeomObjects::Next() wrap an iterator of all geometrical entities in the Ifc file. // IfcGeomObjects::Get() returns an IfcGeomObjects::IfcGeomObject (see IfcObjects.h for definition) // IfcGeomObjects::Next() is used to poll whether more geometrical entities are available do { const IfcGeomObjects::IfcGeomObject* o = IfcGeomObjects::Get(); - if ( o->type == "IFCSPACE" || o->type == "IFCOPENINGELEMENT" ) continue; + if ( o->type == "IfcSpace" || o->type == "IfcOpeningElement" ) continue; fObj << "o " << o->name << std::endl; fObj << "usemtl " << o->type << std::endl; materials.insert(o->type); @@ -85,4 +89,8 @@ int main ( int argc, char** argv ) { for( std::set::iterator it = materials.begin(); it != materials.end(); ++ it ) { fMtl << GetMaterial(*it); } + + time(&end); + int dif = (int) difftime (end,start); + printf ("Conversion took %d seconds\n", dif ); } diff --git a/src/ifcobj/ObjMaterials.h b/src/ifcobj/ObjMaterials.h index f2fcc05909..e9117e1cb7 100644 --- a/src/ifcobj/ObjMaterials.h +++ b/src/ifcobj/ObjMaterials.h @@ -50,14 +50,15 @@ public: }; ObjMaterial GetMaterial(const std::string& s) { - if ( s == "IFCSITE" ) { return ObjMaterial("IFCSITE",0.75f,0.8f,0.65f); } - if ( s == "IFCSLAB" ) { return ObjMaterial("IFCSLAB",0.4f,0.4f,0.4f); } - if ( s == "IFCWALLSTANDARDCASE" ) { return ObjMaterial("IFCWALLSTANDARDCASE",0.9f,0.9f,0.9f); } - if ( s == "IFCWALL" ) { return ObjMaterial("IFCWALL",0.9f,0.9f,0.9f); } - if ( s == "IFCWINDOW" ) { return ObjMaterial("IFCWINDOW",0.75f,0.8f,0.75f,1.0f,1.0f,1.0f,0.0f,0.0f,0.0f,500.0f,0.3f); } - if ( s == "IFCDOOR" ) { return ObjMaterial("IFCDOOR",0.55f,0.3f,0.15f); } - if ( s == "IFCBEAM" ) { return ObjMaterial("IFCBEAM",0.75f,0.7f,0.7f); } - if ( s == "IFCRAILING" ) { return ObjMaterial("IFCRAILING",0.75f,0.7f,0.7f); } - if ( s == "IFCMEMBER" ) { return ObjMaterial("IFCRAILING",0.75f,0.7f,0.7f); } + if ( s == "IfcSite" ) { return ObjMaterial("IfcSite",0.75f,0.8f,0.65f); } + if ( s == "IfcSlab" ) { return ObjMaterial("IfcSlab",0.4f,0.4f,0.4f); } + if ( s == "IfcWallStandardCase" ) { return ObjMaterial("IfcWallStandardCase",0.9f,0.9f,0.9f); } + if ( s == "IfcWall" ) { return ObjMaterial("IfcWall",0.9f,0.9f,0.9f); } + if ( s == "IfcWindow" ) { return ObjMaterial("IfcWindow",0.75f,0.8f,0.75f,1.0f,1.0f,1.0f,0.0f,0.0f,0.0f,500.0f,0.3f); } + if ( s == "IfcDoor" ) { return ObjMaterial("IfcDoor",0.55f,0.3f,0.15f); } + if ( s == "IfcBeam" ) { return ObjMaterial("IfcBeam",0.75f,0.7f,0.7f); } + if ( s == "IfcRailing" ) { return ObjMaterial("IfcRailing",0.65f,0.6f,0.6f); } + if ( s == "IfcMember" ) { return ObjMaterial("IfcMember",0.65f,0.6f,0.6f); } + if ( s == "IfcPlate" ) { return ObjMaterial("IfcPlate",0.8f,0.8f,0.8f); } return ObjMaterial(s); } \ No newline at end of file diff --git a/src/ifcparse/IfcEnum.cpp b/src/ifcparse/IfcEnum.cpp index 6df66132de..2619310946 100644 --- a/src/ifcparse/IfcEnum.cpp +++ b/src/ifcparse/IfcEnum.cpp @@ -38,5 +38,13 @@ std::string IfcSchema::Enum::ToString(IfcTypes t) { #include "../ifcparse/IfcSchema.h" #undef IFC_PARSE_ENUM_STR - return ""; + return "IfcUnknown"; +} + +bool IfcSchema::Enum::ShouldRender(IfcTypes t) { + if ( t == IfcUnknown ) return false; +#define IFC_PARSE_RENDER +#include "../ifcparse/IfcSchema.h" +#undef IFC_PARSE_RENDER + else return false; } \ No newline at end of file diff --git a/src/ifcparse/IfcEnum.h b/src/ifcparse/IfcEnum.h index 92421b1a56..c2a8d37fda 100644 --- a/src/ifcparse/IfcEnum.h +++ b/src/ifcparse/IfcEnum.h @@ -42,6 +42,7 @@ namespace IfcSchema { }; IfcTypes FromString(const std::string& a); std::string ToString(IfcTypes t); + bool ShouldRender(IfcTypes t); } } #endif diff --git a/src/ifcparse/IfcGeom.cpp b/src/ifcparse/IfcGeom.cpp index 19097df209..bcd3d1d8a1 100644 --- a/src/ifcparse/IfcGeom.cpp +++ b/src/ifcparse/IfcGeom.cpp @@ -31,8 +31,10 @@ #include #include +#include #include #include +#include #include #include #include @@ -76,6 +78,17 @@ #include +namespace IfcGeom { + namespace Cache { +#define IFC_GEOM_CACHE +#include "../ifcparse/IfcSchema.h" +#undef IFC_GEOM_CACHE + } +} +#define IN_CACHE(T,E,t,e) std::map::const_iterator it = Cache::T.find(E->id);\ + if ( it != Cache::T.end() ) { e = *(it->second); return true; } +#define CACHE(T,E,e) Cache::T[E->id] = e; + bool IfcGeom::convert(IfcSchema::ExtrudedAreaSolid* IfcExtrudedAreaSolid, TopoDS_Shape& shape) { TopoDS_Face face; if ( ! IfcGeom::convert_face(IfcExtrudedAreaSolid->Profile(),face) ) return false; @@ -83,12 +96,10 @@ bool IfcGeom::convert(IfcSchema::ExtrudedAreaSolid* IfcExtrudedAreaSolid, TopoDS gp_Trsf trsf; convert((IfcSchema::Axis2Placement3D*) IfcExtrudedAreaSolid->Placement().get(),trsf); - gp_Vec dir3; - convert((IfcSchema::Direction*) IfcExtrudedAreaSolid->Dir().get(),dir3); - - gp_Vec extrude = dir3.Scaled(height); + gp_Dir dir; + convert((IfcSchema::Direction*) IfcExtrudedAreaSolid->Dir().get(),dir); - shape = BRepPrimAPI_MakePrism(face,extrude); + shape = BRepPrimAPI_MakePrism(face,height*dir); shape.Move(trsf); return ! shape.IsNull(); } @@ -100,13 +111,15 @@ bool IfcGeom::convert(IfcSchema::FaceBasedSurfaceModel* IfcFaceBasedSurfaceModel } bool IfcGeom::convert(IfcSchema::HalfSpaceSolid* IfcHalfSpaceSolid, TopoDS_Shape& shape) { IfcEntity surf = IfcHalfSpaceSolid->Surface(); - if ( surf->dt != IfcSchema::Enum::IfcPlane ) return false; + if ( surf->type != IfcSchema::Enum::IfcPlane ) return false; IfcSchema::Plane* IfcPlane = (IfcSchema::Plane*)surf.get(); 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()); - else pnt.Translate(-pln.Axis().Direction()); + bool reverse = IfcHalfSpaceSolid->Flag(); + if ( IfcHalfSpaceSolid->type == IfcSchema::Enum::IfcPolygonalBoundedHalfSpace ) reverse = !reverse; + if ( reverse ) pnt.Translate(-pln.Axis().Direction()); + else pnt.Translate(pln.Axis().Direction()); shape = BRepPrimAPI_MakeHalfSpace(BRepBuilderAPI_MakeFace(pln),pnt).Solid(); return true; } @@ -119,8 +132,8 @@ bool IfcGeom::convert(IfcSchema::PolygonalBoundedHalfSpace* IfcPolygonalBoundedH convert((IfcSchema::Axis2Placement3D*) IfcPolygonalBoundedHalfSpace->Placement().get(),trsf); TopoDS_Shape extrusion = BRepPrimAPI_MakePrism(BRepBuilderAPI_MakeFace(wire),gp_Vec(0,0,20000.0)); gp_Trsf down; down.SetTranslation(gp_Vec(0,0,-10000.0)); - extrusion.Move(down); extrusion.Move(trsf); + extrusion.Move(down); shape = BRepAlgoAPI_Cut(extrusion,halfspace); return true; } @@ -189,7 +202,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 << IfcFace->toString() << 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); @@ -197,7 +210,7 @@ bool IfcGeom::convert(IfcSchema::Face* IfcFace, TopoDS_Face& face) { } if ( er != BRepBuilderAPI_FaceDone ) return false; - if ( bounds->size == 1 ) { + if ( bounds->Size() == 1 ) { face = mf.Face(); return true; } @@ -243,23 +256,32 @@ bool IfcGeom::convert(IfcSchema::CircleHollowProfileDef* IfcCircleHollowProfileD 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::LengthUnit,IfcCartesianPoint->Y() * Ifc::LengthUnit,IfcCartesianPoint->Z() * Ifc::LengthUnit); - else - p = gp_Pnt(IfcCartesianPoint->X() * Ifc::LengthUnit,IfcCartesianPoint->Y() * Ifc::LengthUnit,0.0f); +bool IfcGeom::convert(IfcSchema::CartesianPoint* IfcCartesianPoint, gp_Pnt& point) { + IN_CACHE(CartesianPoint,IfcCartesianPoint,gp_Pnt,point) + gp_Pnt* p = new gp_Pnt( + IfcCartesianPoint->X() * Ifc::LengthUnit, + IfcCartesianPoint->Y() * Ifc::LengthUnit, + ((*IfcCartesianPoint)[0]->Size() == 3) ? (IfcCartesianPoint->Z() * Ifc::LengthUnit) : 0.0f + ); + CACHE(CartesianPoint,IfcCartesianPoint,p) + point = *p; return true; } -bool IfcGeom::convert(IfcSchema::Direction* IfcDirection, gp_Vec& v) { - if ( IfcDirection->arg(0)->count() == 3 ) - v = gp_Vec(IfcDirection->X(),IfcDirection->Y(),IfcDirection->Z()); - else - v = gp_Vec(IfcDirection->X(),IfcDirection->Y(),0.0f); +bool IfcGeom::convert(IfcSchema::Direction* IfcDirection, gp_Dir& dir) { + IN_CACHE(Direction,IfcDirection,gp_Dir,dir); + gp_Dir* d = new gp_Dir( + IfcDirection->X(), + IfcDirection->Y(), + ((*IfcDirection)[0]->Size() == 3) ? IfcDirection->Z() : 0.0f + ); + CACHE(Direction,IfcDirection,d); + dir = *d; return true; } bool IfcGeom::convert(IfcSchema::Vector* IfcVector, gp_Vec& v) { - IfcGeom::convert((IfcSchema::Direction*)IfcVector->Orientation().get(),v); - v.Scale(IfcVector->Magnitude()); + gp_Dir d; + IfcGeom::convert((IfcSchema::Direction*)IfcVector->Orientation().get(),d); + v = IfcVector->Magnitude() * Ifc::LengthUnit * d; return true; } bool IfcGeom::convert(IfcSchema::ArbitraryClosedProfileDef* IfcArbitraryClosedProfileDef, TopoDS_Wire& wire) { @@ -434,7 +456,7 @@ bool IfcGeom::convert(IfcSchema::CompositeCurve* IfcCompositeCurve, class TopoDS } bool IfcGeom::convert(IfcSchema::TrimmedCurve* IfcTrimmedCurve, class TopoDS_Wire& wire) { IfcEntity basis = IfcTrimmedCurve->BasisCurve(); - bool isConic = basis->dt == IfcSchema::Enum::IfcCircle || basis->dt == IfcSchema::Enum::IfcEllipse; + bool isConic = basis->type == IfcSchema::Enum::IfcCircle || basis->type == IfcSchema::Enum::IfcEllipse; float parameterFactor = isConic ? Ifc::PlaneAngleUnit : Ifc::LengthUnit; Handle(Geom_Curve) curve; if ( ! IfcGeom::convert_curve(basis,curve) ) return false; @@ -448,23 +470,23 @@ bool IfcGeom::convert(IfcSchema::TrimmedCurve* IfcTrimmedCurve, class TopoDS_Wir BRepBuilderAPI_MakeWire w; for ( IfcParse::Entities::it it = trims1->begin(); it != trims1->end(); it ++ ) { const IfcEntity i = *it; - if ( i->dt == IfcSchema::Enum::IfcCartesianPoint && cartesian ) { + if ( i->type == IfcSchema::Enum::IfcCartesianPoint && cartesian ) { IfcGeom::convert( (IfcSchema::CartesianPoint*) i.get(), pnt1 ); trimmed1 = true; - } else if ( i->dt == IfcSchema::Enum::IfcParameterValue ) { + } else if ( i->type == IfcSchema::Enum::IfcParameterValue ) { flt1 = ((IfcSchema::ParameterValue*)i.get())->Value() * parameterFactor; trimmed1 = true; } } for ( IfcParse::Entities::it it = trims2->begin(); it != trims2->end(); it ++ ) { const IfcEntity i = *it; - if ( i->dt == IfcSchema::Enum::IfcCartesianPoint && cartesian && trimmed1 ) { + if ( i->type == IfcSchema::Enum::IfcCartesianPoint && cartesian && trimmed1 ) { gp_Pnt pnt2; IfcGeom::convert( (IfcSchema::CartesianPoint*) i.get(), pnt2 ); BRepBuilderAPI_MakeEdge e (curve,pnt1,pnt2); w.Add(e.Edge()); trimmed2 = true; - } else if ( i->dt == IfcSchema::Enum::IfcParameterValue && trimmed1 ) { + } else if ( i->type == IfcSchema::Enum::IfcParameterValue && trimmed1 ) { float flt2 = ((IfcSchema::ParameterValue*)i.get())->Value() * parameterFactor; BRepBuilderAPI_MakeEdge e (curve,flt1,flt2); w.Add(e.Edge()); @@ -507,18 +529,27 @@ bool IfcGeom::convert(IfcSchema::Polyline* IfcPolyline, TopoDS_Wire& result) { IfcEntities points = IfcPolyline->Points(); BRepBuilderAPI_MakeWire w; + int count = 0; for( IfcParse::Entities::it it = points->begin(); it != points->end(); ++ it ) { gp_Pnt P1;gp_Pnt P2; IfcGeom::convert((IfcSchema::CartesianPoint*)(*it).get(),P1); IfcParse::Entities::it next = it + 1; if ( next == points->end() ) { - if ( IfcPolyline->dt == IfcSchema::Enum::IfcPolyloop ) next = points->begin(); + if ( IfcPolyline->type == 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; + //std::cout << P1.X() << "," << P1.Y() << "," << P1.Z() << " -> " << P2.X() << "," <type == IfcSchema::Enum::IfcPolyloop ) { + std::cout << "[Notice] Skipping loop with " << count << " edges:" << std::endl << IfcPolyline->toString() << std::endl; + return false; } result = w.Wire(); @@ -528,25 +559,29 @@ bool IfcGeom::convert(IfcSchema::Polyloop* IfcPolyloop, TopoDS_Wire& result) { return IfcGeom::convert((IfcSchema::Polyline*)IfcPolyloop,result); } bool IfcGeom::convert(IfcSchema::Axis2Placement3D* IfcAxis2Placement3D, gp_Trsf& trsf) { - gp_Pnt o;gp_Vec axis = gp_Vec(0,0,1);gp_Vec refDirection; bool hasRef = false; + IN_CACHE(Axis2Placement3D,IfcAxis2Placement3D,gp_Trsf,trsf); + gp_Trsf* t = new gp_Trsf(); + gp_Pnt o;gp_Dir axis = gp_Dir(0,0,1);gp_Dir refDirection; bool hasRef = false; IfcGeom::convert((IfcSchema::CartesianPoint*) IfcAxis2Placement3D->Origin().get(),o); try { IfcGeom::convert((IfcSchema::Direction*) IfcAxis2Placement3D->Axis().get(),axis); IfcGeom::convert((IfcSchema::Direction*) IfcAxis2Placement3D->RefDirection().get(),refDirection); hasRef = true; } catch( IfcParse::IfcException& ) {} - gp_Ax3 ax3; if ( hasRef ) ax3 = gp_Ax3(o,axis,refDirection); else ax3 = gp_Ax3(o,axis); + t->SetTransformation(ax3, gp_Ax3(gp_Pnt(),gp_Dir(0,0,1),gp_Dir(1,0,0))); - trsf.SetTransformation(ax3, gp_Ax3(gp_Pnt(),gp_Dir(0,0,1),gp_Dir(1,0,0))); + CACHE(Axis2Placement3D,IfcAxis2Placement3D,t); + trsf = *t; return true; } bool IfcGeom::convert(IfcSchema::Plane* IfcPlane, gp_Pln& plane) { + IN_CACHE(Plane,IfcPlane,gp_Pln,plane) IfcSchema::Axis2Placement3D* IfcAxis2Placement3D = (IfcSchema::Axis2Placement3D*) IfcPlane->Placement().get(); - gp_Pnt o;gp_Vec axis = gp_Vec(0,0,1);gp_Vec refDirection; bool hasRef = false; + gp_Pnt o;gp_Dir axis = gp_Dir(0,0,1);gp_Dir refDirection; bool hasRef = false; IfcGeom::convert((IfcSchema::CartesianPoint*) IfcAxis2Placement3D->Origin().get(),o); try { @@ -559,30 +594,41 @@ bool IfcGeom::convert(IfcSchema::Plane* IfcPlane, gp_Pln& plane) { if ( hasRef ) ax3 = gp_Ax3(o,axis,refDirection); else ax3 = gp_Ax3(o,axis); - plane = gp_Pln(ax3); + gp_Pln* ppln = new gp_Pln(ax3); + CACHE(Plane,IfcPlane,ppln); + plane = *ppln; return true; } bool IfcGeom::convert(IfcSchema::Axis2Placement2D* IfcAxis2Placement2D, gp_Trsf2d& trsf) { - gp_Pnt P; gp_Vec V (1,0,0); + IN_CACHE(Axis2Placement2D,IfcAxis2Placement2D,gp_Trsf2d,trsf) + gp_Pnt P; gp_Dir V (1,0,0); + gp_Trsf2d* ptrsf = new gp_Trsf2d(); IfcGeom::convert((IfcSchema::CartesianPoint*) IfcAxis2Placement2D->Origin().get(),P); try { IfcGeom::convert((IfcSchema::Direction*) IfcAxis2Placement2D->Axis().get(),V); } catch( IfcParse::IfcException& ) {} - gp_Ax2d axis(gp_Pnt2d(P.X(),P.Y()),gp_Vec2d(V.X(),V.Y())); - trsf.SetTransformation(axis,gp_Ax2d()); + gp_Ax2d axis(gp_Pnt2d(P.X(),P.Y()),gp_Dir2d(V.X(),V.Y())); + ptrsf->SetTransformation(axis,gp_Ax2d()); + + CACHE(Axis2Placement2D,IfcAxis2Placement2D,ptrsf); + trsf = *ptrsf; return true; } bool IfcGeom::convert(IfcSchema::LocalPlacement* IfcLocalPlacement, gp_Trsf& trsf) { + IN_CACHE(LocalPlacement,IfcLocalPlacement,gp_Trsf,trsf) + gp_Trsf* ptrsf = new gp_Trsf(); while (1) { gp_Trsf trsf2; IfcGeom::convert((IfcSchema::Axis2Placement3D*) IfcLocalPlacement->Placement().get(),trsf2); - trsf.PreMultiply(trsf2); + ptrsf->PreMultiply(trsf2); try { IfcLocalPlacement = (IfcSchema::LocalPlacement*) IfcLocalPlacement->Parent().get(); } catch ( IfcParse::IfcException ) { break; } } + CACHE(LocalPlacement,IfcLocalPlacement,ptrsf); + trsf = *ptrsf; return true; } bool IfcGeom::convert_openings(const IfcSchema::BuildingElement* IfcBuildingElement, @@ -592,7 +638,7 @@ bool IfcGeom::convert_openings(const IfcSchema::BuildingElement* IfcBuildingElem IfcSchema::BuildingElement* IfcOpeningElement = (IfcSchema::BuildingElement*) IfcRelVoidsElement->Opening().get(); gp_Trsf trsf; IfcGeom::convert((IfcSchema::LocalPlacement*) IfcOpeningElement->Placement().get(),trsf); - gp_Trsf trsf3 = trsf2.Inverted(); + trsf.PreMultiply(trsf2.Inverted()); IfcSchema::ProductDefinitionShape* IfcProductDefinitionShape = (IfcSchema::ProductDefinitionShape*) IfcOpeningElement->Shape().get(); IfcEntities IfcShapeReps = IfcProductDefinitionShape->ShapeReps(); for ( IfcParse::Entities::it shaperep = IfcShapeReps->begin(); shaperep != IfcShapeReps->end(); ++shaperep ) { @@ -602,7 +648,6 @@ bool IfcGeom::convert_openings(const IfcSchema::BuildingElement* IfcBuildingElem TopoDS_Shape s; if ( ! IfcGeom::convert_shape(*shape,s)) continue; s.Move(trsf); - s.Move(trsf3); result = BRepAlgoAPI_Cut(result,s); } } @@ -613,7 +658,7 @@ bool IfcGeom::convert_wire_to_face(const TopoDS_Wire& wire, 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; ShapeFix_ShapeTolerance FTol; FTol.SetTolerance(wire, 0.01, TopAbs_WIRE); mf = BRepBuilderAPI_MakeFace(wire, false); @@ -651,4 +696,10 @@ bool IfcGeom::profile_helper(int numVerts, float* verts, int numFillets, int* fi delete[] vertices; return true; +} +void IfcGeom::Cache::Purge() { +#define IFC_GEOM_CACHE_PURGE +#include "../ifcparse/IfcSchema.h" +#undef IFC_GEOM_CACHE_PURGE + PurgeShapeCache(); } \ No newline at end of file diff --git a/src/ifcparse/IfcGeomObjects.cpp b/src/ifcparse/IfcGeomObjects.cpp index 5b1710b704..717f3b956f 100644 --- a/src/ifcparse/IfcGeomObjects.cpp +++ b/src/ifcparse/IfcGeomObjects.cpp @@ -40,17 +40,15 @@ // Welds vertices that belong to different faces int IfcGeomObjects::IfcMesh::addvert(gp_Pnt p) { - int i = 0; const float X = (float)p.X();const float Y = (float)p.Y();const float Z = (float)p.Z(); - for ( std::vector::const_iterator it = verts.begin(); it != verts.end(); ) { - const float x = *it; ++it; - const float y = *it; ++it; - const float z = *it; ++it; - if ( X == x && Y == y && Z == z ) return i; - ++i; - } + const float X = (float)p.X();const float Y = (float)p.Y();const float Z = (float)p.Z(); + const VertKey key = VertKey(X,std::pair(Y,Z)); + VertKeyMap::const_iterator it = welds.find(key); + if ( it != welds.end() ) return it->second; verts.push_back(X); verts.push_back(Y); verts.push_back(Z); + int i = welds.size(); + welds[key] = i; return i; } @@ -159,7 +157,8 @@ IfcGeomObjects::IfcGeomObject* _get() { } shaperep = *outer; if ( ! entities ) { - if ( shaperep->arg(1)->s() != "Body" ) { + const std::string arg1 = *(*shaperep)[1]; + if ( arg1 != "Body" ) { _nextShape(); continue; } @@ -168,12 +167,12 @@ 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) + entities->push(shaperep->parents(IfcSchema::Enum::IfcProductRepresentation)->parents()); // 2x2 compatibility + entities->push(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) + entities->push(shaperep->parents(IfcSchema::Enum::IfcRepresentationMap)->parents(IfcSchema::Enum::IfcMappedItem) ->parents(IfcSchema::Enum::IfcShapeRepresentation,1,"Body")->parents(IfcSchema::Enum::IfcProductRepresentation)->parents()); - if ( ! entities->size ) { + if ( ! entities->Size() ) { _nextShape(); continue; } @@ -191,7 +190,7 @@ IfcGeomObjects::IfcGeomObject* _get() { IfcEntities l = ((IfcSchema::ShapeRepresentation*)shaperep.get())->Shapes(); for( IfcParse::Entities::it it = l->begin(); it != l->end(); ++ it ) { const IfcEntity ifcshape = *it; - if ( ifcshape->dt == IfcSchema::Enum::IfcMappedItem ) continue; + if ( ifcshape->type == IfcSchema::Enum::IfcMappedItem ) continue; TopoDS_Shape ss; if ( IfcGeom::convert_shape(ifcshape,ss) && ! ss.IsNull() ) { builder.Add(shapes,ss); @@ -217,15 +216,15 @@ IfcGeomObjects::IfcGeomObject* _get() { IfcGeom::convert((IfcSchema::LocalPlacement*)(entity->Placement().get()),trsf); } catch( IfcParse::IfcException& e ) {std::cout << "[Error] " << e.what() << std::endl; _nextShape(); } IfcEntities openings = IfcEntities(); - if ( entity->dt != IfcSchema::Enum::IfcOpeningElement ) { + if ( entity->type != IfcSchema::Enum::IfcOpeningElement ) { openings = entity->parents(IfcSchema::Enum::IfcRelVoidsElement); } - if ( (openings && openings->size) || use_world_coords ) { + if ( (openings && openings->Size()) || use_world_coords ) { if ( shape ) delete shape; TopoDS_Shape temp_shape (shapes); try { - if (openings && openings->size) IfcGeom::convert_openings(entity,openings,temp_shape,trsf); + 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 ) { @@ -237,7 +236,7 @@ IfcGeomObjects::IfcGeomObject* _get() { } else if ( ! shape ) { shape = new IfcGeomObjects::IfcMesh(shaperep->id,shapes); } - return new IfcGeomObjects::IfcGeomObject(guid, entity->datatype(), trsf, shape); + return new IfcGeomObjects::IfcGeomObject(guid, entity->Datatype(), trsf, shape); } } @@ -272,7 +271,7 @@ extern bool IfcGeomObjects::Init(char* fn, bool world_coords) { if ( ! currentGeomObj ) return false; done = 0; - total = shapereps->size; + total = shapereps->Size(); return 1; } extern int IfcGeomObjects::Progress() { diff --git a/src/ifcparse/IfcGeomObjects.h b/src/ifcparse/IfcGeomObjects.h index 37ca93382d..00f84a6d41 100644 --- a/src/ifcparse/IfcGeomObjects.h +++ b/src/ifcparse/IfcGeomObjects.h @@ -33,20 +33,20 @@ * * * IfcGeomObject represents the actual IfcBuildingElements. * * IfcGeomObject.name is the GUID of the element * - * IfcGeomObject.type is the datatype of the element e.g. IFCWINDOW * + * IfcGeomObject.type is the datatype of the element e.g. IfcWindow * * IfcGeomObject.mesh is a pointer to an IfcMesh * * IfcGeomObject.matrix is a 4x3 matrix that defines the orientation and * * translation of the mesh in relation to the world origin * * * - * Init(char* fn, bool world_coords) parses the IFC file in fn, returns true - * on succes, world_coords = true will result in all IfcGeomObject.matrix - * being an identity matrix and IfcMesh.verts containing global positions + * Init(char* fn, bool world_coords) parses the IFC file in fn, returns true * + * on succes, world_coords = true will result in all IfcGeomObject.matrix * + * being an identity matrix and IfcMesh.verts containing global positions * * * - * Get() returns a pointer to the current IfcGeomObject + * Get() returns a pointer to the current IfcGeomObject * * * - * Next() returns true if there is an entity yet available + * Next() returns true if there is an entity yet available * * * - * Progress() returns an int in [0..100] that indicates the overall progress + * Progress() returns an int in [0..100] that indicates the overall progress * * * ********************************************************************************/ @@ -55,6 +55,7 @@ #include #include +#include #include #include @@ -64,6 +65,9 @@ namespace IfcGeomObjects { typedef std::vector::const_iterator IntIt; typedef std::vector::const_iterator FltIt; + typedef std::pair< float,std::pair > VertKey; + typedef std::map VertKeyMap; + typedef std::pair Edge; class IfcMesh { public: @@ -71,15 +75,16 @@ namespace IfcGeomObjects { std::vector verts; std::vector faces; std::vector edges; + VertKeyMap welds; IfcMesh(int i, TopoDS_Shape s); private: int addvert(gp_Pnt p); inline void addedge(int n1, int n2, std::map,int>& edgecount, std::vector >& edges_temp) { - if ( edgecount.find(std::pair((std::min)(n1,n2),(std::max)(n1,n2))) == edgecount.end() ) - edgecount[std::pair((std::min)(n1,n2),(std::max)(n1,n2))] = 0; - edgecount[std::pair((std::min)(n1,n2),(std::max)(n1,n2))] ++; - edges_temp.push_back(std::pair((std::min)(n1,n2),(std::max)(n1,n2))); + const Edge e = Edge( (std::min)(n1,n2),(std::max)(n1,n2) ); + if ( edgecount.find(e) == edgecount.end() ) edgecount[e] = 1; + else edgecount[e] ++; + edges_temp.push_back(e); } }; diff --git a/src/ifcparse/IfcMacro.h b/src/ifcparse/IfcMacro.h index caf8a0f2b4..8ee001f085 100644 --- a/src/ifcparse/IfcMacro.h +++ b/src/ifcparse/IfcMacro.h @@ -31,6 +31,7 @@ #undef IFC_WIRE_CLASS #undef IFC_CURVE_CLASS #undef IFC_HELPER_CLASS +#undef IFC_RENDER_CLASS #undef IFC_END_CLASS #undef IFC_REF #undef IFC_REFS @@ -47,7 +48,7 @@ #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_RENDER_CLASS(N) IFC_CLASS(N,"") #define IFC_END_CLASS }; #define IFC_REF(C,N,I) IfcEntity N(); #define IFC_REFS(C,N,I) IfcEntities N(); @@ -59,21 +60,13 @@ #endif #ifdef IFC_PARSE_SOURCE -#define IFC_CLASS(N,T) -#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 -#define IFC_REF(C,N,I) IfcEntity C::N() { return this->arg(I)->ref(); } -#define IFC_REFS(C,N,I) IfcEntities C::N() { return this->arg(I)->refs(); } -#define IFC_FLT(C,N,I) float C::N() { return this->arg(I)->f(); } -#define IFC_FLT_SUB(C,N,I,J) float C::N() { return this->arg(I)->arg(J)->f(); } -#define IFC_INT(C,N,I) int C::N() { return this->arg(I)->i(); } -#define IFC_STR(C,N,I) std::string C::N() { return this->arg(I)->s(); } -#define IFC_BOOL(C,N,I) bool C::N() { return this->arg(I)->b(); } +#define IFC_REF(C,N,I) IfcEntity C::N() { return *(*this)[I]; } +#define IFC_REFS(C,N,I) IfcEntities C::N() { return *(*this)[I]; } +#define IFC_FLT(C,N,I) float C::N() { return *(*this)[I]; } +#define IFC_FLT_SUB(C,N,I,J) float C::N() { return *(*(*this)[I])[J]; } +#define IFC_INT(C,N,I) int C::N() { return *(*this)[I]; } +#define IFC_STR(C,N,I) std::string C::N() { return *(*this)[I]; } +#define IFC_BOOL(C,N,I) bool C::N() { return *(*this)[I]; } #endif #ifdef IFC_PARSE_ENUM @@ -83,15 +76,7 @@ #define IFC_FACE_CLASS(N) Ifc##N, #define IFC_CLASS(N,T) Ifc##N, #define IFC_HELPER_CLASS(N) Ifc##N, -#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) +#define IFC_RENDER_CLASS(N) Ifc##N, #endif #ifdef IFC_PARSE_STR_ENUM @@ -101,15 +86,8 @@ #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_RENDER_CLASS(N) IFC_SHAPE_CLASS(N) #define IFC_SKIP_CLASS(N) if ( strcasecmp(a.c_str()+3,#N) == 0 ) { return IfcSchema::Enum::IfcDontCare; } -#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_PARSE_ENUM_STR @@ -118,16 +96,12 @@ #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_RENDER_CLASS(N) IFC_SHAPE_CLASS(N) #define IFC_CLASS(N,T) IFC_SHAPE_CLASS(N) -#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_PARSE_RENDER +#define IFC_RENDER_CLASS(N) if ( t == IfcSchema::Enum::Ifc##N ) return true; #endif #ifdef IFC_GEOM_HEADER @@ -135,87 +109,79 @@ #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) -#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_SHAPE_SRC -#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) -#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) +#define IFC_SHAPE_CLASS(N) else if ( L->type == IfcSchema::Enum::Ifc##N ) { IfcSchema::N* x = (IfcSchema::N*) L.get(); try { r = 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; } } #endif #ifdef IFC_WIRE_SRC -#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) -#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) +#define IFC_WIRE_CLASS(N) else if ( L->type == IfcSchema::Enum::Ifc##N ) { IfcSchema::N* x = (IfcSchema::N*) L.get(); r = IfcGeom::convert(x,result); } #endif #ifdef IFC_FACE_SRC -#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) +#define IFC_FACE_CLASS(N) else if ( L->type == IfcSchema::Enum::Ifc##N ) { IfcSchema::N* x = (IfcSchema::N*) L.get(); r = IfcGeom::convert(x,result); } +#define IFC_WIRE_CLASS(N) else if ( L->type == IfcSchema::Enum::Ifc##N ) { IfcSchema::N* x = (IfcSchema::N*) L.get(); TopoDS_Wire wire; if ( ! IfcGeom::convert(x,wire) ) r = false; r = IfcGeom::convert_wire_to_face(wire,result); } #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) -#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) +#define IFC_CURVE_CLASS(N) if ( L->type == IfcSchema::Enum::Ifc##N ) { IfcSchema::N* x = (IfcSchema::N*) L.get(); return IfcGeom::convert(x,result); } #endif + +#ifdef IFC_GEOM_CACHE +#define IFC_CLASS(N,T) std::map N; +#endif + +#ifdef IFC_GEOM_CACHE_PURGE +#define IFC_CLASS(N,T) for(std::map::const_iterator it = N.begin(); it != N.end(); it ++ ) delete it->second; N.clear(); +#endif + +#ifndef IFC_CLASS +#define IFC_CLASS(N,T) +#endif +#ifndef IFC_SHAPE_CLASS +#define IFC_SHAPE_CLASS(N) +#endif +#ifndef IFC_FACE_CLASS +#define IFC_FACE_CLASS(N) +#endif +#ifndef IFC_SKIP_CLASS +#define IFC_SKIP_CLASS(N) +#endif +#ifndef IFC_WIRE_CLASS +#define IFC_WIRE_CLASS(N) +#endif +#ifndef IFC_CURVE_CLASS +#define IFC_CURVE_CLASS(N) +#endif +#ifndef IFC_HELPER_CLASS +#define IFC_HELPER_CLASS(N) +#endif +#ifndef IFC_RENDER_CLASS +#define IFC_RENDER_CLASS(N) +#endif +#ifndef IFC_END_CLASS +#define IFC_END_CLASS +#endif +#ifndef IFC_REF +#define IFC_REF(C,N,I) +#endif +#ifndef IFC_REFS +#define IFC_REFS(C,N,I) +#endif +#ifndef IFC_FLT +#define IFC_FLT(C,N,I) +#endif +#ifndef IFC_FLT_SUB +#define IFC_FLT_SUB(C,N,I,J) +#endif +#ifndef IFC_INT +#define IFC_INT(C,N,I) +#endif +#ifndef IFC_STR +#define IFC_STR(C,N,I) +#endif +#ifndef IFC_BOOL +#define IFC_BOOL(C,N,I) +#endif \ No newline at end of file diff --git a/src/ifcparse/IfcParse.cpp b/src/ifcparse/IfcParse.cpp index 61a4177edc..4e263a1717 100644 --- a/src/ifcparse/IfcParse.cpp +++ b/src/ifcparse/IfcParse.cpp @@ -1,21 +1,21 @@ /******************************************************************************** - * * - * This file is part of IfcOpenShell. * - * * - * IfcOpenShell is free software: you can redistribute it and/or modify * - * it under the terms of the Lesser GNU General Public License as published by * - * the Free Software Foundation, either version 3.0 of the License, or * - * (at your option) any later version. * - * * - * IfcOpenShell is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * Lesser GNU General Public License for more details. * - * * - * You should have received a copy of the Lesser GNU General Public License * - * along with this program. If not, see . * - * * - ********************************************************************************/ +* * +* This file is part of IfcOpenShell. * +* * +* IfcOpenShell is free software: you can redistribute it and/or modify * +* it under the terms of the Lesser GNU General Public License as published by * +* the Free Software Foundation, either version 3.0 of the License, or * +* (at your option) any later version. * +* * +* IfcOpenShell is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* Lesser GNU General Public License for more details. * +* * +* You should have received a copy of the Lesser GNU General Public License * +* along with this program. If not, see . * +* * +********************************************************************************/ #include "../ifcparse/IfcParse.h" #include "../ifcparse/IfcEnum.h" @@ -23,261 +23,409 @@ using namespace IfcParse; -Argument::Argument(const std::string& s) { - const char first = s[0]; - const int strlen = s.size(); - const char last = s[strlen-1]; - if ( first == '#' ) { - type = IDENTIFIER; - std::istringstream iss(s.substr(1)); - iss >> _data; - } else if ( first == '(' || first == ')' || first == '=' || first == '$' || first == '*' || first == ';' || first == ',' ) { - type = OPERATOR; - _data = first; - } else if ( first == '\'' && last == '\'' ) { - type = STRING; - _data = -1; - std::string t = s.substr(1,s.size()-2); - for ( int i = 0; i < (int)argstrings.size(); ++ i ) if ( argstrings[i] == t ) { _data = i; break; } - if ( _data == -1 ) { _data = argstrings.size(); argstrings.push_back(t); } - } else if ( first == '.' && last == '.' ) { - type = ENUMERATION; - _data = -1; - std::string t = s.substr(1,s.size()-2); - for ( int i = 0; i < (int)enumstrings.size(); ++ i ) if ( enumstrings[i] == t ) { _data = i; break; } - if ( _data == -1 ) { _data = enumstrings.size(); enumstrings.push_back(t); } - } else if ( ( first >= 48 && first <= 57 ) || first == '-' || first == '.' ) { - type = NUMBER; - std::istringstream iss(s); - iss >> _number; +// +// Opens the file, gets the filesize and reads a chunk in memory +// +File::File(const std::string& fn) { + eof = false; + stream.open(fn.c_str(),std::ios_base::binary); + stream.seekg(0,std::ios_base::end); + size = stream.tellg(); + stream.seekg(0,std::ios_base::beg); + buffer = new char[size < BUF_SIZE ? size : BUF_SIZE]; + ptr = 0; + len = 0; + offset = 0; + ReadBuffer(false); +} + +void File::Close() { + stream.close(); + delete[] buffer; +} + +// +// Reads a chunk of BUF_SIZE in memory and increments cursor if requested +// +void File::ReadBuffer(bool inc) { + if ( inc ) { + offset += len; + stream.seekg(offset,std::ios_base::beg); + } + eof = stream.eof(); + if ( eof ) return; + stream.read(buffer,size < BUF_SIZE ? size : BUF_SIZE); + len = stream.gcount(); + eof = len == 0; + ptr = 0; +} + +// +// Seeks an arbitrary position in the file +// +void File::Seek(unsigned int o) { + if ( o >= offset && (o < (offset+len)) ) { + ptr = o - offset; } else { - type = DATATYPE; - _data = -1; - for ( int i = 0; i < (int)datatypes.size(); ++ i ) if ( datatypes[i] == s ) { _data = i; break; } - if ( _data == -1 ) { _data = datatypes.size(); datatypes.push_back(s); } + offset = o; + stream.clear(); + stream.seekg(o,std::ios_base::beg); + ReadBuffer(false); } } -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]; - if ( type == STRING ) return argstrings[_data]; - if ( type == ENUMERATION ) return enumstrings[_data]; - throw IfcException(); -} -float Argument::f() const { - if ( type != NUMBER ) throw IfcException(); - return _number; -} -int Argument::i() const { - if ( type != IDENTIFIER ) throw IfcException(); - return _data; -} -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) ); -} -std::string Argument::toString() const { - if ( type == DATATYPE ) return s(); - else if ( type == OPERATOR ) return s(); - std::stringstream ss; - if ( type == NUMBER ) ss << f(); - 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; -std::vector Argument::argstrings; -std::vector Argument::enumstrings; -ArgumentList::ArgumentList() { - _levels.push_back(this); - _current = this; - _arg = 0; -} -void ArgumentList::_push() { - ArgumentList* a = new ArgumentList(); - _levels.push_back(a); - _args.push_back(a); - _current = a; -} -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(); - a->_arg = v; - _current->_args.push_back(a); +// +// Returns the character at the cursor +// +char File::Peek() { + return buffer[ptr]; } +// +// Returns the character at specified offset +// +char File::Read(unsigned int o) { + if ( o >= offset && (o < (offset+len)) ) { + return buffer[o-offset]; + } else { + stream.clear(); + stream.seekg(o,std::ios_base::beg); + return stream.peek(); + } +} + +// +// Returns the cursor position +// +unsigned int File::Tell() { + return offset + ptr; +} + +// +// Increments cursor and reads new chunk if necessary +// +void File::Inc() { + if ( ++ptr == len ) { ReadBuffer(); } +} + +Tokens::Tokens(IfcParse::File *f) { + file = f; +} + +// +// Returns the offset of the current Token and moves cursor to next +// +Token Tokens::Next() { + + if ( file->eof ) return TokenPtr(); + + char c; + + // Trim whitespace + while ( !file->eof ) { + c = file->Peek(); + if ( (c == ' ' || c == '\r' || c == '\n' || c == '\t' ) ) file->Inc(); + else break; + } + + if ( file->eof ) return TokenPtr(); + unsigned int pos = file->Tell(); + + bool inString = false; + bool inComment = false; + + // If the cursor is at [()=,;$*] we know token consists of single char + if ( c == '(' || c == ')' || c == '=' || c == ',' || c == ';' || c == '$' || c == '*' ) { + file->Inc(); + return TokenPtr(c); + } + + int len = 0; + + char p = 0; + while ( ! file->eof ) { + + // Read character and increment pointer if not starting a new token + char c = file->Peek(); + if ( len && (!inString || inComment) && (c == '(' || c == ')' || c == '=' || c == ',' || c == ';' ) ) break; + file->Inc(); + + // Skip whitespace if not in comment or string + if ( !inComment && !inString && (c == ' ' || c == '\r' || c == '\n' || c == '\t' ) ) continue; + + len ++; + + // Keep track of whether cursor is inside a string or comment + if ( inComment && p == '*' && c == '/' ) inComment = false; + else if ( !inString && !inComment && p == '/' && c == '*' ) inComment = true; + else if ( !inComment && c == '\'' ) inString = ! inString; + + p = c; + } + if ( len ) return TokenPtr(pos); + else return TokenPtr(); +} + +// +// Reads a std::string from the file at specified offset +// Omits whitespace and comments +// +std::string Tokens::TokenString(unsigned int offset) { + unsigned int old_offset = file->Tell(); + file->Seek(offset); + bool inString = false; + bool inComment = false; + std::string buffer; + buffer.reserve(128); + char p = 0; + while ( ! file->eof ) { + char c = file->Peek(); + if ( buffer.size() && (!inString || inComment) && (c == '(' || c == ')' || c == '=' || c == ',' || c == ';' ) ) break; + file->Inc(); + if ( !inComment && !inString && (c == ' ' || c == '\r' || c == '\n' || c == '\t' ) ) continue; + if ( !inComment ) buffer.push_back(c); + if ( inComment && p == '*' && c == '/' ) inComment = false; + else if ( !inString && !inComment && p == '/' && c == '*' ) inComment = true; + else if ( !inComment && c == '\'' ) inString = ! inString; + p = c; + } + file->Seek(old_offset); + return buffer; +} + +// +// Functions for creating Tokens from an arbitary file offset. +// The first 4 bits are reserved for Tokens of type ()=,;$* +// +Token IfcParse::TokenPtr(unsigned int offset) { return offset + 128; } +Token IfcParse::TokenPtr(char c) { return c; } +Token IfcParse::TokenPtr() { return 0; } + +// +// Functions to convert Tokens to binary data +// +unsigned int TokenFunc::Offset(Token t) { return t - 128; } +bool TokenFunc::startsWith(Token t, char c) { + return Ifc::file->Read(Offset(t)) == c; +} +bool TokenFunc::isOperator(Token t, char op) { + return (t < 128) && (!op || op == t); +} +bool TokenFunc::isIdentifier(Token t) { + return ! isOperator(t) && startsWith(t, '#'); +} +bool TokenFunc::isString(Token t) { + return ! isOperator(t) && startsWith(t, '\''); +} +bool TokenFunc::isEnumeration(Token t) { + return ! isOperator(t) && startsWith(t, '.'); +} +bool TokenFunc::isDatatype(Token t) { + return ! isOperator(t) && startsWith(t, 'I'); +} +int TokenFunc::asInt(Token t) { + if ( ! isIdentifier(t) ) throw IfcException("Token is not an identifier"); + const std::string str = asString(t); + return atoi(str.c_str()+1); +} +bool TokenFunc::asBool(Token t) { + const std::string str = asString(t); + return str == "T"; +} +float TokenFunc::asFloat(Token t) { + const std::string str = asString(t); + return (float) atof(str.c_str()); +} +std::string TokenFunc::asString(Token t) { + if ( isOperator(t,'$') ) return ""; + else if ( isOperator(t) ) throw IfcException("Token is not a string"); + std::string str = Ifc::tokens->TokenString(t - 128); + return isString(t) || isEnumeration(t) ? str.substr(1,str.size()-2) : str; +} +std::string TokenFunc::toString(Token t) { + if ( isOperator(t) ) return std::string ( (char*) &t, 1 ); + else return asString(t); +} + + +TokenArgument::TokenArgument(Token t) { + token = t; +} + +EntityArgument::EntityArgument(EntityPtr e) { + entity = e; +} + +// +// Reads the arguments from a list of token +// Aditionally, stores the ids (i.e. #[\d]+) in a vector +// +ArgumentList::ArgumentList(Tokens* t, std::vector& ids) { + while( Token next = t->Next() ) { + if ( TokenFunc::isOperator(next,',') ) continue; + if ( TokenFunc::isOperator(next,')') ) break; + if ( TokenFunc::isOperator(next,'(') ) Push( ArgumentPtr(new ArgumentList(t,ids)) ); + else { + if ( TokenFunc::isIdentifier(next) ) ids.push_back(TokenFunc::asInt(next)); + if ( TokenFunc::isDatatype(next) ) { + Ifc::file->Seek(TokenFunc::Offset(next)); + EntityPtr entity = EntityPtr(new Entity(0,t,ids,true)); + Push ( ArgumentPtr(new EntityArgument(entity)) ); + } else { + Push ( ArgumentPtr(new TokenArgument(next)) ); + } + } + } +} + +void ArgumentList::Push(ArgumentPtr l) { + list.push_back(l); +} + +// +// Functions for casting the ArgumentList to other types +// +ArgumentList::operator int() const { throw IfcException("Argument is not an integer"); } +ArgumentList::operator bool() const { throw IfcException("Argument is not a boolean"); } +ArgumentList::operator float() const { throw IfcException("Argument is not a number"); } +ArgumentList::operator std::string() const { throw IfcException("Argument is not a string"); } +ArgumentList::operator EntityPtr() const { throw IfcException("Argument is not an IFC type"); } +ArgumentList::operator EntitiesPtr() const { + EntitiesPtr l (new Entities()); + std::vector::const_iterator it; + for ( it = list.begin(); it != list.end(); ++ it ) { + // FIXME: account for $ + const EntityPtr entity = **it; + l->push(entity); + } + return l; +} +unsigned int ArgumentList::Size() const { return list.size(); } +ArgumentPtr ArgumentList::operator [] (unsigned int i) const { + if ( i >= list.size() ) + throw IfcException("Argument index out of range"); + return list[i]; +} std::string ArgumentList::toString() const { - if ( _arg ) return _arg->toString(); - std::stringstream ss; ss << "("; - std::vector::const_iterator it; - for ( it = _args.begin() ; it != _args.end(); ++ it ) { - if ( it != _args.begin() ) ss << ","; + std::stringstream ss; + ss << "("; + for( std::vector::const_iterator it = list.begin(); it != list.end(); it ++ ) { + if ( it != list.begin() ) ss << ","; ss << (*it)->toString(); } ss << ")"; return ss.str(); } -float ArgumentList::f() const { return _arg->f(); } -bool ArgumentList::b() const { return _arg->b(); } -int ArgumentList::i() const { return _arg->i(); } -std::string ArgumentList::s() const { return _arg->s(); } -int ArgumentList::count() const { return _arg ? 1 : _args.size(); } -ArgumentList* ArgumentList::arg(int i) const { - if ( i >= count() ) { - throw IfcException(); - } else { - return _args[i]; - } +// +// Functions for casting the TokenArgument to other types +// +TokenArgument::operator int() const { return TokenFunc::asInt(token); } +TokenArgument::operator bool() const { return TokenFunc::asBool(token); } +TokenArgument::operator float() const { return TokenFunc::asFloat(token); } +TokenArgument::operator std::string() const { return TokenFunc::asString(token); } +TokenArgument::operator EntityPtr() const { return Ifc::EntityById(TokenFunc::asInt(token)); } +TokenArgument::operator EntitiesPtr() const { throw IfcException("Argument is not a list of entities"); } +unsigned int TokenArgument::Size() const { return 1; } +ArgumentPtr TokenArgument::operator [] (unsigned int i) const { throw IfcException("Argument is not a list of arguments"); } +std::string TokenArgument::toString() const { return TokenFunc::asString(token); } + +// +// Functions for casting the EntityArgument to other types +// +EntityArgument::operator int() const { throw IfcException("Argument is not an integer"); } +EntityArgument::operator bool() const { throw IfcException("Argument is not a boolean"); } +EntityArgument::operator float() const { throw IfcException("Argument is not a number"); } +EntityArgument::operator std::string() const { throw IfcException("Argument is not a string"); } +EntityArgument::operator EntityPtr() const { return entity; } +EntityArgument::operator EntitiesPtr() const { throw IfcException("Argument is not a list of entities"); } +unsigned int EntityArgument::Size() const { return 1; } +ArgumentPtr EntityArgument::operator [] (unsigned int i) const { throw IfcException("Argument is not a list of arguments"); } +std::string EntityArgument::toString() const { return entity->toString(); } + +// +// Reads an Entity from the list of Tokens +// If the type of the Entity is not known, the ArgumentList is not loaded +// +Entity::Entity(unsigned int i, Tokens* t, std::vector& ids, bool parse) { + Token datatype = t->Next(); + if ( ! TokenFunc::isDatatype(datatype)) throw IfcException("Unexpected token while parsing entity"); + type = IfcSchema::Enum::FromString(TokenFunc::asString(datatype)); + id = i; + args = ArgumentPtr(); + offset = TokenFunc::Offset(datatype); + if ( (type != IfcSchema::Enum::IfcDontCare && type != IfcSchema::Enum::IfcUnknown) || parse ) + Load(ids, false); } -EntityPtr ArgumentList::ref() const { - if ( _arg->type == Argument::IDENTIFIER ) { - return Ifc::EntityById(_arg->i()); - } else { - return _arg->r(); +// +// Reads an Entity from the list of Tokens at the specified offset in the file +// +Entity::Entity(unsigned int i, Tokens* t, unsigned int o) { + std::vector ids; + id = i; + offset = o; + Load(ids, true); +} + +// +// Access the Nth argument from the ArgumentList +// +ArgumentPtr Entity::operator [] (unsigned int i) { + if ( ! args ) { + std::vector ids; + Load(ids, true); } + return (*args)[i]; } -EntitiesPtr ArgumentList::refs() const { - EntitiesPtr l (new Entities()); - std::vector::const_iterator it; - for ( it = _args.begin(); it != _args.end(); ++ it ) { - 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()); - } + +// +// Load the ArgumentList +// +void Entity::Load(std::vector& ids, bool seek) { + if ( seek ) { + Ifc::file->Seek(offset); + Token datatype = Ifc::tokens->Next(); + if ( ! TokenFunc::isDatatype(datatype) ) throw IfcException("Unexpected token while parsing entity"); + type = IfcSchema::Enum::FromString(TokenFunc::asString(datatype)); } - return l; + Token open = Ifc::tokens->Next(); + args = ArgumentPtr(new ArgumentList(Ifc::tokens, ids)); + unsigned int old_offset = Ifc::file->Tell(); + Token semilocon = Ifc::tokens->Next(); + if ( ! TokenFunc::isOperator(semilocon,';') ) Ifc::file->Seek(old_offset); } -ArgumentList::~ArgumentList() { - if ( _arg ) delete _arg; - else { - while( ! _args.empty() ) { - delete _args.back(); _args.pop_back(); - } + +// +// Returns a CamelCase string representation of the datatype as it is defined in IfcSchema.h +// +std::string Entity::Datatype() const { + return IfcSchema::Enum::ToString(type); +} + +// +// Returns a string representation of the entity +// Note that this initializes the entity if it is not initialized +// +std::string Entity::toString() { + if ( ! args ) { + std::vector ids; + Load(ids, true); } -} -inline bool Entity::term(char last) { - return last == '(' || last == ')' || last == '=' || last == ',' || last == ';'; -} -Entity::Entity(std::istream* ss, std::vector& refs, bool sub) { - std::string curvar; - curvar.reserve(64); - bool inStr = false; - bool inComment = false; - char c[1] = ""; - char p[1] = ""; - int state = -1; - int previousPos = -1; - args = 0; - _dt = 0; - id = -1; - do { - ss->read(c,1); - if ( !inComment && !inStr && ((*c) == ' ' || (*c) == '\r' || (*c) == '\n' || (*c) == '\t') ) continue; - if ( curvar.size() && !inComment && !inStr && ( term(*c) || term(*curvar.rbegin())) ) { - Argument* v = new Argument(curvar); - curvar.clear(); - curvar.push_back(*c); - if ( state < 10 ) state ++; - if ( !sub && !state ) { - if ( v->type == Argument::IDENTIFIER ) { - id = v->i(); - } else { - state = -1; - } - } else if ( ! sub && (state == 1) ) { - if ( ! v->isOp('=') ) state = -1; - } 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(')') ) { - 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 if ( ! inComment ) curvar.push_back(*c); - if ( !inComment && *c == '\'' ) inStr = !inStr; - else if ( !inStr && *p == '/' && *c == '*' ) { inComment = true; curvar.clear(); } - else if ( !inStr && *p == '*' && *c == '/' ) inComment = false; - p[0] = c[0]; - } while ( !ss->eof() && (*c != ';' || inStr) ); -} -Entity::~Entity() { - delete args; - delete _dt; -} -bool Entity::isAssignment() const { - return args > 0; -} -std::string Entity::datatype() const { - if ( _dt ) return _dt->s(); - else return IfcSchema::Enum::ToString(dt); -} -ArgumentList* Entity::arg(int i) const { - return this->args->arg(i); -} -std::string Entity::toString() const { std::stringstream ss; - if ( isAssignment() ) { - if ( id > 0 ) ss << "#" << id << "="; - ss << datatype() << args->toString(); - } + ss << "#" << id << "=" << Datatype() << args->toString(); return ss.str(); } + +// +// Returns the entities of type c that have this entity in their ArgumentList +// EntitiesPtr Entity::parents(IfcSchema::Enum::IfcTypes c) { EntitiesPtr l = EntitiesPtr(new Entities()); EntitiesPtr all = Ifc::EntitiesByReference(id); if ( ! all ) return l; for( Entities::it it = all->begin(); it != all->end();++ it ) { - if ( c == IfcSchema::Enum::ALL || (*it)->dt == c ) { + if ( c == IfcSchema::Enum::ALL || (*it)->type == c ) { l->push(*it); } } @@ -287,163 +435,169 @@ EntitiesPtr Entity::parents(IfcSchema::Enum::IfcTypes c, int i, const std::strin EntitiesPtr l = EntitiesPtr(new Entities()); EntitiesPtr all = parents(c); for( Entities::it it = all->begin(); it != all->end();++ it ) { - if ( (*it)->arg(i)->s() == a ) { + const std::string s = *((**it)[i]); + if ( s == a ) { l->push(*it); } } return l; } - void Entities::push(EntityPtr l) { - if ( l ) { - ls.push_back(l); - size = ls.size(); - } + if ( l ) ls.push_back(l); } -void Entities::pushs(EntitiesPtr l) { +void Entities::push(EntitiesPtr l) { for( it i = l->begin(); i != l->end(); ++i ) { if ( *i ) ls.push_back(*i); } - size = ls.size(); } +int Entities::Size() const { return ls.size(); } Entities::it Entities::begin() { return ls.begin(); } Entities::it Entities::end() { return ls.end(); } + +// +// Returns the entities of type c that have one of these entities in their ArgumentList +// EntitiesPtr Entities::parents(IfcSchema::Enum::IfcTypes c) { EntitiesPtr l = EntitiesPtr(new Entities()); for( it i = begin(); i != end(); ++i ) { - l->pushs((*i)->parents(c)); + l->push((*i)->parents(c)); } return l; } EntitiesPtr Entities::parents(IfcSchema::Enum::IfcTypes c, int ar, const std::string& a) { EntitiesPtr l = EntitiesPtr(new Entities()); for( it i = begin(); i != end(); ++i ) { - l->pushs((*i)->parents(c,ar,a)); + l->push((*i)->parents(c,ar,a)); } return l; } EntityPtr Entities::operator[] (int i) { return ls[i]; } -Entities::Entities() { - size = 0; -} -File::File(const std::string& fn, bool debug) { - valid = false; - std::ifstream f(fn.c_str()); - if ( ! f.is_open() ) return; - valid = true; - std::istream *pf = (std::istream*) &f; - while( !pf->eof() ) { - std::vector refs; - EntityPtr il (new Entity(pf,refs)); - if ( il->isAssignment() ) { - if ( debug ) - std::cout << il->toString() << std::endl; - if ( il->dt == IfcSchema::Enum::IfcDontCare ) { - continue; - } - EntitiesPtr l = EntitiesByType(il->dt); - if ( l == 0 ) { - l = EntitiesPtr(new Entities()); - bytype[il->dt] = l; - } - l->push(il); - byid[il->id] = il; - - std::vector::const_iterator it; - for( it = refs.begin(); it != refs.end();++ it ) { - const int _id = *it; - EntitiesPtr L = EntitiesByReference(_id); + +// +// Parses the IFC file in fn +// Creates the maps +// Gets the unit definitins from the file +// +bool Ifc::Init(const std::string& fn) { + file = new File (fn); + tokens = new Tokens (file); + Token token = 0; + Token previous = 0; + unsigned int currentId = 0; + lastId = 0; + int x = 0; + EntityPtr entity; + std::cout << "Scanning file..." << std::endl; + while ( true ) { + if ( currentId ) { + std::vector ids; + entity = EntityPtr(new Entity(currentId,tokens,ids)); + if ( !((++x)%1000) ) std::cout << "\r#" << currentId << " "; + if ( entity->type != IfcSchema::Enum::IfcDontCare && entity->type != IfcSchema::Enum::IfcUnknown) { + byid[currentId] = entity; + EntitiesPtr L = EntitiesByType(entity->type); if ( L == 0 ) { L = EntitiesPtr(new Entities()); - byref[_id] = L; + bytype[entity->type] = L; } - L->push(il); + L->push(entity); + for( std::vector::const_iterator it = ids.begin(); it != ids.end(); ++it ) { + const int arg_id = *it; + EntitiesPtr L = EntitiesByReference(arg_id); + if ( L == 0 ) { + L = EntitiesPtr(new Entities()); + byref[arg_id] = L; + } + L->push(entity); + } + } else { + offsets[currentId] = entity->offset; + } + currentId = 0; + } else token = tokens->Next(); + if ( ! token ) break; + if ( previous && TokenFunc::isIdentifier(previous) ) { + int id = TokenFunc::asInt(previous); + if ( TokenFunc::isOperator(token,'=') ) { + currentId = id; + } else { + EntitiesPtr L = EntitiesByReference(id); + if ( L == 0 ) { + L = EntitiesPtr(new Entities()); + byref[id] = L; + } + L->push(entity); } } + previous = token; } - f.close(); -} -EntitiesPtr File::EntitiesByType(IfcSchema::Enum::IfcTypes t) { - std::map::const_iterator it; - it = bytype.find(t); - return (it == bytype.end()) ? EntitiesPtr() : (*it).second; -} -EntitiesPtr File::EntitiesByReference(int t) { - std::map::const_iterator it; - it = byref.find(t); - return (it == byref.end()) ? EntitiesPtr() : (*it).second; -} -EntityPtr File::EntityById(int id) { - std::map::const_iterator it; - it = byid.find(id); - if ( it == byid.end() ) throw IfcException(id); - return (*it).second; -} -IfcException::IfcException(int id) { - std::stringstream ss; - ss << "Unable to find IFC Entity #" << id; - w = ss.str(); -} -IfcException::IfcException() { - w = "Unexpected argument supplied"; -} + std::cout << "\rDone! " << std::endl; -const char* IfcException::what() const throw(){ return w.c_str(); } -IfcException::~IfcException() throw(){ } - -EntitiesPtr Ifc::EntitiesByType(IfcSchema::Enum::IfcTypes t) { - return f->EntitiesByType(t); -} -EntitiesPtr Ifc::EntitiesByReference(int t) { - return f->EntitiesByReference(t); -} -EntityPtr Ifc::EntityById(int id) { - return f->EntityById(id); -} -bool Ifc::Init(const std::string& fn) { - f = new File(fn, false); 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 ++ ) { - 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(); - try { - unit = IfcMeasureWithUnit->Unit(); - value = IfcMeasureWithUnit->Value()->arg(0)->f(); - } catch (... ) {} - } - 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; + for ( IfcParse::Entities::it it = units->begin(); it != units->end(); it ++ ) { + IfcEntity unit = *it; + float value = 1.0f; + std::string UnitType = ""; + if ( unit->type == IfcSchema::Enum::IfcConversionBasedUnit ) { + IfcSchema::ConversionBasedUnit* IfcConversionBasedUnit = (IfcSchema::ConversionBasedUnit*)(*it).get(); + IfcSchema::MeasureWithUnit* IfcMeasureWithUnit = (IfcSchema::MeasureWithUnit*)IfcConversionBasedUnit->ConversionFactor().get(); + try { + unit = IfcMeasureWithUnit->Unit(); + value = *((*IfcMeasureWithUnit->Value())[0]); + } catch (...) {} + } + if ( unit->type == 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 true; +} + +EntitiesPtr Ifc::EntitiesByType(IfcSchema::Enum::IfcTypes t) { + MapEntitiesByType::const_iterator it = bytype.find(t); + return (it == bytype.end()) ? EntitiesPtr() : it->second; +} +EntitiesPtr Ifc::EntitiesByReference(int t) { + MapEntitiesByRef::const_iterator it = byref.find(t); + return (it == byref.end()) ? EntitiesPtr() : it->second; +} +EntityPtr Ifc::EntityById(int id) { + MapEntityById::const_iterator it = byid.find(id); + if ( it == byid.end() ) { + MapOffsetById::const_iterator it2 = offsets.find(id); + if ( it2 == offsets.end() ) throw IfcException("Entity not found"); + const unsigned int offset = (*it2).second; + EntityPtr entity = EntityPtr(new Entity(id,Ifc::tokens,offset)); + byid[id] = entity; + return entity; } - return f->valid; + return it->second; } +IfcException::IfcException(std::string e) { error = e; } +const char* IfcException::what() const { return error.c_str(); } void Ifc::Dispose() { - delete f; - Argument::datatypes.clear(); - Argument::argstrings.clear(); - Argument::enumstrings.clear(); + file->Close(); + delete file; + delete tokens; + offsets.clear(); + bytype.clear(); + byid.clear(); + byref.clear(); + IfcGeom::Cache::Purge(); } -File* Ifc::f = 0; -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; @@ -464,3 +618,14 @@ float UnitPrefixToValue( const std::string& s ) { else if ( s == "ATTO" ) return (float) 1e-18; else return 1.0f; } + +File* Ifc::file = 0; +unsigned int Ifc::lastId = 0; +Tokens* Ifc::tokens = 0; +float Ifc::LengthUnit = 1.0f; +float Ifc::PlaneAngleUnit = 1.0f; +int Ifc::CircleSegments = 32; +MapEntitiesByType Ifc::bytype; +MapEntityById Ifc::byid; +MapEntitiesByRef Ifc::byref; +MapOffsetById Ifc::offsets; diff --git a/src/ifcparse/IfcParse.h b/src/ifcparse/IfcParse.h index d7b8b22276..8ba9842a63 100644 --- a/src/ifcparse/IfcParse.h +++ b/src/ifcparse/IfcParse.h @@ -17,6 +17,13 @@ * * ********************************************************************************/ +/******************************************************************************** + * * + * This file provides functions for loading an IFC file into memory and access * + * its entities either by ID, by an IfcSchema::Enum::IfcType or by reference * + * * + ********************************************************************************/ + #ifndef IFCPARSE_H #define IFCPARSE_H @@ -31,21 +38,21 @@ // Pick a shared pointer implementation #ifdef __GNUC__ - #include - #define SHARED_PTR std::tr1::shared_ptr +#include +#define SHARED_PTR std::tr1::shared_ptr #else - #ifdef _MSC_VER - #include - #define SHARED_PTR std::tr1::shared_ptr - #else - #include - #define SHARED_PTR boost::shared_ptr - #endif +#ifdef _MSC_VER +#include +#define SHARED_PTR std::tr1::shared_ptr +#else +#include +#define SHARED_PTR boost::shared_ptr +#endif #endif #include "../ifcparse/IfcEnum.h" -class Ifc; +const int BUF_SIZE = (32 * 1024 * 1024); namespace IfcParse { @@ -54,135 +61,225 @@ namespace IfcParse { typedef SHARED_PTR EntityPtr; typedef SHARED_PTR EntitiesPtr; - class Argument { + // + // Reads a file in chunks of BUF_SIZE and provides + // functions to randomly access its contents + // + class File { private: - static std::vector datatypes; - static std::vector enumstrings; - static std::vector argstrings; - - int _data; - float _number; - EntityPtr _entity; + std::ifstream stream; + char* buffer; + unsigned int ptr; + unsigned int len; + unsigned int offset; + void ReadBuffer(bool inc=true); public: - 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; - - float f() const; - int i() const; - std::string s() const; - bool b() const; - EntityPtr r() const; - - std::string toString() const; - - std::string typeString() const; - - friend class ::Ifc; + bool eof; + unsigned int size; + File(const std::string& fn); + char Peek(); + char Read(unsigned int offset); + void Inc(); + void Close(); + void Seek(unsigned int offset); + unsigned int Tell(); }; - class ArgumentList { + typedef unsigned int Token; + + // + // Provides functions to convert Tokens to binary data + // Tokens are merely offsets to where they can be read in the file + // + class TokenFunc { private: - std::vector _levels; - std::vector _args; - ArgumentList* _current; - const Argument* _arg; - void _push(); - bool _pop(); - void _append(const Argument* v); - public: - ArgumentList(); - ~ArgumentList(); - - float f() const; - int i() const; - std::string s() const; - bool b() const; - EntityPtr ref() const; - EntitiesPtr refs() const; - ArgumentList* arg(int i) const; - - int count() const; - std::string toString() const; - - friend class Entity; + static bool startsWith(Token t, char c); + public: + static unsigned int Offset(Token t); + static bool isString(Token t); + static bool isIdentifier(Token t); + static bool isOperator(Token t, char op = 0); + static bool isEnumeration(Token t); + static bool isDatatype(Token t); + static int asInt(Token t); + static bool asBool(Token t); + static float asFloat(Token t); + static std::string asString(Token t); + static std::string toString(Token t); }; + // + // Functions for creating Tokens from an arbitary file offset + // The first 4 bits are reserved for Tokens of type ()=,;$* + // + Token TokenPtr(unsigned int offset); + Token TokenPtr(char c); + Token TokenPtr(); + + // + // Interprets a file as a sequential stream of Tokens + // + class Tokens { + private: + File* file; + public: + Tokens(File* f); + Token Next(); + std::string TokenString(unsigned int offset); + }; + + class Argument; + typedef SHARED_PTR ArgumentPtr; + + // + // Base class of all kind of Arguments used in IFC entity defintions + // + class Argument { + protected: + public: + virtual operator int() const = 0; + virtual operator bool() const = 0; + virtual operator float() const = 0; + virtual operator std::string() const = 0; + virtual operator EntityPtr() const = 0; + virtual operator EntitiesPtr() const = 0; + virtual unsigned int Size() const = 0; + virtual ArgumentPtr operator [] (unsigned int i) const = 0; + virtual std::string toString() const = 0; + }; + + // + // Argument of type list, e.g. + // #1=IfcDirection((1.,0.,0.)); + // ========== + // + class ArgumentList: public Argument { + private: + std::vector list; + void Push(ArgumentPtr l); + public: + ArgumentList(Tokens* t, std::vector& ids); + operator int() const; + operator bool() const; + operator float() const; + operator std::string() const; + operator EntityPtr() const; + operator EntitiesPtr() const; + unsigned int Size() const; + ArgumentPtr operator [] (unsigned int i) const; + std::string toString() const; + }; + + // + // Argument of type scalar or string, e.g. + // #1=IfcVector(#2,1.0); + // == === + // + class TokenArgument : public Argument { + private: + Token token; + public: + TokenArgument(Token t); + operator int() const; + operator bool() const; + operator float() const; + operator std::string() const; + operator EntityPtr() const; + operator EntitiesPtr() const; + unsigned int Size() const; + ArgumentPtr operator [] (unsigned int i) const; + std::string toString() const; + }; + + // + // Argument of an IFC type + // #1=IfcTrimmedCurve(#2,(IFCPARAMETERVALUE(0.)),(IFCPARAMETERVALUE(1.)),.T.,.PARAMETER.); + // ===================== ===================== + // + class EntityArgument : public Argument { + private: + EntityPtr entity; + public: + EntityArgument(EntityPtr e); + operator int() const; + operator bool() const; + operator float() const; + operator std::string() const; + operator EntityPtr() const; + operator EntitiesPtr() const; + unsigned int Size() const; + ArgumentPtr operator [] (unsigned int i) const; + std::string toString() const; + }; + + // + // Entity defined in an IFC file, e.g. + // #1=IfcDirection((1.,0.,0.)); + // ============================ + // class Entity { private: - inline bool term(char last); + ArgumentPtr args; + void Load(std::vector& ids, bool seek); public: - int id; - IfcSchema::Enum::IfcTypes dt; - ArgumentList* args; - Argument* _dt; - - Entity(std::istream* ss, std::vector& refs, bool sub = false); - ~Entity(); - - ArgumentList* arg(int i) const; - std::string toString() const; - + unsigned int id; + unsigned int offset; + IfcSchema::Enum::IfcTypes type; + Entity(unsigned int i, Tokens* t, std::vector& ids, bool parse = false); + Entity(unsigned int i, Tokens* t, unsigned int o); EntitiesPtr parents(IfcSchema::Enum::IfcTypes c = IfcSchema::Enum::ALL); EntitiesPtr parents(IfcSchema::Enum::IfcTypes c, int i, const std::string& a); - bool isAssignment() const; - std::string datatype() const; + ArgumentPtr operator[] (unsigned int i); + std::string toString(); + std::string Datatype() const; }; + // + // A list of IFC entities + // class Entities { - private: std::vector ls; public: - int size; typedef std::vector::const_iterator it; void push(EntityPtr l); - void pushs(EntitiesPtr l); + void push(EntitiesPtr l); it begin(); it end(); EntitiesPtr parents(IfcSchema::Enum::IfcTypes c = IfcSchema::Enum::ALL); EntitiesPtr parents(IfcSchema::Enum::IfcTypes c, int i, const std::string& a); - Entities(); EntityPtr operator[] (int i); - }; - - class File { - public: - std::map bytype; - std::map byid; - std::map byref; - bool valid; - - File(const std::string& fn, bool debug = false); - EntitiesPtr EntitiesByType(IfcSchema::Enum::IfcTypes t); - EntitiesPtr EntitiesByReference(int id); - EntityPtr EntityById(int id); + int Size() const; }; class IfcException : public std::exception { private: - std::string w; + std::string error; public: - IfcException(int id); - IfcException(); - ~IfcException() throw(); - virtual const char* what() const throw(); + IfcException(std::string e); + const char* what() const throw(); }; - } typedef IfcParse::EntityPtr IfcEntity; typedef IfcParse::EntitiesPtr IfcEntities; +typedef std::map MapEntitiesByType; +typedef std::map MapEntityById; +typedef std::map MapEntitiesByRef; +typedef std::map MapOffsetById; -float UnitPrefixToValue(const std::string& s); - +// +// Several static convenience functions and variables +// class Ifc { private: - static IfcParse::File* f; + static MapEntitiesByType bytype; + static MapEntityById byid; + static MapEntitiesByRef byref; + static MapOffsetById offsets; + static unsigned int lastId; public: + static IfcParse::File* file; + static IfcParse::Tokens* tokens; static IfcEntities EntitiesByType(IfcSchema::Enum::IfcTypes t); static IfcEntities EntitiesByReference(int id); static IfcEntity EntityById(int id); @@ -193,4 +290,6 @@ public: static int CircleSegments; }; +float UnitPrefixToValue(const std::string& s); + #endif diff --git a/src/ifcparse/IfcSchema.h b/src/ifcparse/IfcSchema.h index 8b7f83c444..c696ba624e 100644 --- a/src/ifcparse/IfcSchema.h +++ b/src/ifcparse/IfcSchema.h @@ -92,7 +92,7 @@ IFC_REF(BooleanClippingResult,First,1) IFC_REF(BooleanClippingResult,Second,2) IFC_END_CLASS -IFC_CLASS(Face,TopoDS_Face) +IFC_FACE_CLASS(Face) IFC_REFS(Face,Bounds,0) IFC_END_CLASS @@ -181,7 +181,7 @@ IFC_FLT_SUB(CartesianPoint,Y,0,1) IFC_FLT_SUB(CartesianPoint,Z,0,2) IFC_END_CLASS -IFC_CLASS(Direction,gp_Vec) +IFC_CLASS(Direction,gp_Dir) IFC_FLT_SUB(Direction,X,0,0) IFC_FLT_SUB(Direction,Y,0,1) IFC_FLT_SUB(Direction,Z,0,2) @@ -288,11 +288,81 @@ IFC_END_CLASS IFC_HELPER_CLASS(OpeningElement) IFC_END_CLASS -IFC_SKIP_CLASS(PropertySingleValue) -IFC_SKIP_CLASS(PropertySet) -IFC_SKIP_CLASS(ComplexProperty) -IFC_SKIP_CLASS(RelDefinesByProperty) -IFC_SKIP_CLASS(MaterialLayer) -IFC_SKIP_CLASS(MaterialLayerSet) -IFC_SKIP_CLASS(MaterialLayerSetUsage) -IFC_SKIP_CLASS(PresentationLayerAssignment) \ No newline at end of file + +IFC_RENDER_CLASS(BuildingElementProxy) +IFC_END_CLASS +IFC_RENDER_CLASS(Covering) +IFC_END_CLASS +IFC_RENDER_CLASS(Beam) +IFC_END_CLASS +IFC_RENDER_CLASS(Column) +IFC_END_CLASS +IFC_RENDER_CLASS(CurtainWall) +IFC_END_CLASS +IFC_RENDER_CLASS(Door) +IFC_END_CLASS +IFC_RENDER_CLASS(Member) +IFC_END_CLASS +IFC_RENDER_CLASS(Railing) +IFC_END_CLASS +IFC_RENDER_CLASS(Ramp) +IFC_END_CLASS +IFC_RENDER_CLASS(RampFlight) +IFC_END_CLASS +IFC_RENDER_CLASS(Wall) +IFC_END_CLASS +IFC_RENDER_CLASS(WallStandardCase) +IFC_END_CLASS +IFC_RENDER_CLASS(Slab) +IFC_END_CLASS +IFC_RENDER_CLASS(StairFlight) +IFC_END_CLASS +IFC_RENDER_CLASS(Window) +IFC_END_CLASS +IFC_RENDER_CLASS(Stair) +IFC_END_CLASS +IFC_RENDER_CLASS(Roof) +IFC_END_CLASS +IFC_RENDER_CLASS(Pile) +IFC_END_CLASS +IFC_RENDER_CLASS(Footing) +IFC_END_CLASS +IFC_RENDER_CLASS(BuildingElementComponent) +IFC_END_CLASS +IFC_RENDER_CLASS(Plate) +IFC_END_CLASS + +IFC_RENDER_CLASS(IfcFlowFitting) +IFC_END_CLASS +IFC_RENDER_CLASS(IfcFlowSegment) +IFC_END_CLASS +IFC_RENDER_CLASS(IfcFlowController) +IFC_END_CLASS +IFC_RENDER_CLASS(IfcFlowTerminal) +IFC_END_CLASS +IFC_RENDER_CLASS(IfcFlowMovingDevice) +IFC_END_CLASS +IFC_RENDER_CLASS(IfcEnergyConversionDevice) +IFC_END_CLASS +IFC_RENDER_CLASS(IfcFlowStorageDevice) +IFC_END_CLASS +IFC_RENDER_CLASS(IfcFlowTreatmentDevice) +IFC_END_CLASS +IFC_RENDER_CLASS(IfcDistributionChamberElement) +IFC_END_CLASS +IFC_RENDER_CLASS(DistributionControlElement) +IFC_END_CLASS + +IFC_RENDER_CLASS(Site) +IFC_END_CLASS +IFC_RENDER_CLASS(Space) +IFC_END_CLASS + +IFC_RENDER_CLASS(FurnishingElement) +IFC_END_CLASS + +IFC_RENDER_CLASS(TransportElement) +IFC_END_CLASS + +IFC_RENDER_CLASS(GeographicElement) // 2x4 compatibility +IFC_END_CLASS diff --git a/src/ifcparse/IfcTypes.cpp b/src/ifcparse/IfcTypes.cpp index cc866077b1..9640f424c1 100644 --- a/src/ifcparse/IfcTypes.cpp +++ b/src/ifcparse/IfcTypes.cpp @@ -28,22 +28,47 @@ using namespace IfcSchema; #include "../ifcparse/IfcSchema.h" #undef IFC_PARSE_SOURCE +namespace IfcGeom { + namespace Cache { + std::map Shape; + std::map Face; + std::map Wire; + std::map Curve; + void PurgeShapeCache() { + Shape.clear(); + Face.clear(); + Wire.clear(); + Curve.clear(); + } + } +} + bool IfcGeom::convert_shape(const IfcEntity L, TopoDS_Shape &result) { if ( ! L ) return false; + bool r = false; + std::map::const_iterator it = Cache::Shape.find(L->id); + if ( it != Cache::Shape.end() ) { result = it->second; r = true; /*std::cout << "Read #" << L->id << " from cache" << std::endl;*/} + if ( false ) {} #define IFC_SHAPE_SRC #include "../ifcparse/IfcSchema.h" #undef IFC_SHAPE_SRC - std::cout << "[Error] Failed to interpret:" << std::endl << L->toString() << std::endl; - return false; + else std::cout << "[Error] Failed to interpret:" << std::endl << L->toString() << std::endl; + if ( r ) Cache::Shape[L->id] = result; + return r; } bool IfcGeom::convert_wire(const IfcEntity L, TopoDS_Wire &result) { if ( ! L ) return false; + bool r = false; + std::map::const_iterator it = Cache::Wire.find(L->id); + if ( it != Cache::Wire.end() ) { result = it->second; r = true; /*std::cout << "Read #" << L->id << " from cache" << std::endl;*/} + if ( false ) {} #define IFC_WIRE_SRC #include "../ifcparse/IfcSchema.h" #undef IFC_WIRE_SRC - std::cout << "[Error] Failed to interpret:" << std::endl << L->toString() << std::endl; - return false; + else std::cout << "[Error] Failed to interpret:" << std::endl << L->toString() << std::endl; + if ( r ) Cache::Wire[L->id] = result; + return r; } bool IfcGeom::convert_curve(const IfcEntity L, Handle(Geom_Curve) &result) { @@ -57,10 +82,14 @@ bool IfcGeom::convert_curve(const IfcEntity L, Handle(Geom_Curve) &result) { bool IfcGeom::convert_face(const IfcEntity L, TopoDS_Face &result) { if ( ! L ) return false; - TopoDS_Wire wire; + bool r = false; + std::map::const_iterator it = Cache::Face.find(L->id); + if ( it != Cache::Face.end() ) { result = it->second; r = true; /*std::cout << "Read #" << L->id << " from cache" << std::endl;*/} + if ( false ) {} #define IFC_FACE_SRC #include "../ifcparse/IfcSchema.h" #undef IFC_FACE_SRC - std::cout << "[Error] Failed to interpret:" << std::endl << L->toString() << std::endl; - return false; + else std::cout << "[Error] Failed to interpret:" << std::endl << L->toString() << std::endl; + if ( r ) Cache::Face[L->id] = result; + return r; } diff --git a/src/ifcparse/IfcTypes.h b/src/ifcparse/IfcTypes.h index 29d3436ece..4669e0ca89 100644 --- a/src/ifcparse/IfcTypes.h +++ b/src/ifcparse/IfcTypes.h @@ -26,7 +26,9 @@ #include #include #include +#include #include +#include #include "../ifcparse/IfcParse.h" @@ -47,6 +49,10 @@ namespace IfcGeom { 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); bool profile_helper(int numVerts, float* verts, int numFillets, int* filletIndices, float* filletRadii, gp_Trsf2d trsf, TopoDS_Face& face); + namespace Cache { + void Purge(); + void PurgeShapeCache(); + } } #endif