diff --git a/src/ifcgeom/IfcGeom.h b/src/ifcgeom/IfcGeom.h index dbe9d78412..a0d0ece89f 100644 --- a/src/ifcgeom/IfcGeom.h +++ b/src/ifcgeom/IfcGeom.h @@ -50,7 +50,9 @@ // Specifies the treshold distance under which cartesian points are deemed equal #define POINT_EQUALITY_TOLERANCE 0.000001 -#define FACESET_AS_COMPOUND 1 +// Specifies maximum number of faces for a shell to be sewed. Sewing shells +// that consist of many faces is really detrimental for the performance. +#define MAX_FACES_TO_SEW 100 namespace IfcGeom { bool convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face); diff --git a/src/ifcgeom/IfcGeomObjects.cpp b/src/ifcgeom/IfcGeomObjects.cpp index 2e7b6058b4..86cf1dde2a 100644 --- a/src/ifcgeom/IfcGeomObjects.cpp +++ b/src/ifcgeom/IfcGeomObjects.cpp @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -522,6 +521,9 @@ void IfcGeomObjects::Settings(int setting, bool value) { case USE_BREP_DATA: use_brep_data = value; break; + case SEW_SHELLS: + Ifc::SewShells = value; + break; } } int IfcGeomObjects::Progress() { diff --git a/src/ifcgeom/IfcGeomObjects.h b/src/ifcgeom/IfcGeomObjects.h index 1018630972..611e9f1787 100644 --- a/src/ifcgeom/IfcGeomObjects.h +++ b/src/ifcgeom/IfcGeomObjects.h @@ -38,9 +38,7 @@ * 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) parses the IFC file in fn, returns true on succes. * * * * Get() returns a pointer to the current IfcGeomObject * * * @@ -69,13 +67,37 @@ namespace IfcGeomObjects { - const int WELD_VERTICES = 1; - const int USE_WORLD_COORDS = 2; - const int CONVERT_BACK_UNITS = 3; - const int USE_BREP_DATA = 4; + // Enumeration of setting identifiers. These settings define the + // behaviour of various aspects of IfcOpenShell. + // Specifies whether vertices are welded, meaning that the coordinates + // vector will only contain unique xyz-triplets. This results in a + // manifold mesh which is useful for modelling applications, but might + // result in unwanted shading artifacts in rendering applications. + const int WELD_VERTICES = 1; + // Specifies whether to apply the local placements of building elements + // directly to the coordinates of the representation mesh rather than + // to represent the local placement in the 4x3 matrix, which will in that + // case be the identity matrix. + const int USE_WORLD_COORDS = 2; + // Internally IfcOpenShell measures everything in meters. This settings + // specifies whether to convert IfcGeomObjects back to the units in which + // the geometry in the IFC file is specified. + const int CONVERT_BACK_UNITS = 3; + // Specifies whether to use the Open Cascade BREP format for representation + // items rather than to create triangle meshes. This is useful is IfcOpenShell + // is used as a library in an application that is also built on Open Cascade. + const int USE_BREP_DATA = 4; + // Specifies whether to sew IfcConnectedFaceSets (open and closed shells) to + // TopoDS_Shells or whether to keep them as a loose collection of faces. + const int SEW_SHELLS = 5; + + // End of settings enumeration. + + // Some typedefs for convenience typedef std::vector::const_iterator IntIt; typedef std::vector::const_iterator FltIt; + // A nested pair of doubles to be able to store an XYZ coordinate in a map. typedef std::pair< double,std::pair > VertKey; typedef std::map VertKeyMap; typedef std::pair Edge; diff --git a/src/ifcgeom/IfcGeomShapes.cpp b/src/ifcgeom/IfcGeomShapes.cpp index e0d2f200a7..0fe2105cae 100644 --- a/src/ifcgeom/IfcGeomShapes.cpp +++ b/src/ifcgeom/IfcGeomShapes.cpp @@ -71,8 +71,6 @@ #include #include -#include - #include #include @@ -293,41 +291,45 @@ bool IfcGeom::convert(const Ifc2x3::IfcBooleanClippingResult::ptr l, TopoDS_Shap } bool IfcGeom::convert(const Ifc2x3::IfcConnectedFaceSet::ptr l, TopoDS_Shape& shape) { -#ifdef FACESET_AS_COMPOUND - TopoDS_Compound compound; - BRep_Builder builder; - builder.MakeCompound(compound); -#else - BRepOffsetAPI_Sewing builder; - builder.SetTolerance(0.01); -#endif Ifc2x3::IfcFace::list faces = l->CfsFaces(); bool facesAdded = false; - for( Ifc2x3::IfcFace::it it = faces->begin(); it != faces->end(); ++ it ) { - TopoDS_Face face; - if ( IfcGeom::convert_face(*it,face) ) { -#ifdef FACESET_AS_COMPOUND - builder.Add(compound,face); -#else - builder.Add(face); -#endif - facesAdded = true; - } else { - Ifc::LogMessage("Warning","Invalid face:",(*it)->entity); + const unsigned int num_faces = faces->Size(); + if ( Ifc::SewShells && num_faces < MAX_FACES_TO_SEW ) { + BRepOffsetAPI_Sewing builder; + builder.SetTolerance(0.01); + for( Ifc2x3::IfcFace::it it = faces->begin(); it != faces->end(); ++ it ) { + TopoDS_Face face; + if ( IfcGeom::convert_face(*it,face) ) { + builder.Add(face); + facesAdded = true; + } else { + Ifc::LogMessage("Warning","Invalid face:",(*it)->entity); + } } + if ( ! facesAdded ) return false; + builder.Perform(); + shape = builder.SewedShape(); + try { + ShapeFix_Solid solid; + solid.LimitTolerance(0.01); + shape = solid.SolidFromShell(TopoDS::Shell(shape)); + } catch(...) {} + } else { + TopoDS_Compound compound; + BRep_Builder builder; + builder.MakeCompound(compound); + for( Ifc2x3::IfcFace::it it = faces->begin(); it != faces->end(); ++ it ) { + TopoDS_Face face; + if ( IfcGeom::convert_face(*it,face) ) { + builder.Add(compound,face); + facesAdded = true; + } else { + Ifc::LogMessage("Warning","Invalid face:",(*it)->entity); + } + } + if ( ! facesAdded ) return false; + shape = compound; } - if ( ! facesAdded ) return false; -#ifdef FACESET_AS_COMPOUND - shape = compound; -#else - builder.Perform(); - shape = builder.SewedShape(); - try { - ShapeFix_Solid solid; - solid.LimitTolerance(0.01); - shape = solid.SolidFromShell(TopoDS::Shell(shape)); - } catch(...) {} -#endif return true; } bool IfcGeom::convert(const Ifc2x3::IfcMappedItem::ptr l, ShapeList& shapes) { diff --git a/src/ifcmax/IfcMax.cpp b/src/ifcmax/IfcMax.cpp index 30b2139054..58344c4798 100644 --- a/src/ifcmax/IfcMax.cpp +++ b/src/ifcmax/IfcMax.cpp @@ -24,6 +24,7 @@ #include "../ifcmax/IfcMax.h" #include "../ifcmax/MaxMaterials.h" #include "../ifcgeom/IfcGeomObjects.h" + int controlsInit = false; BOOL WINAPI DllMain(HINSTANCE hinstDLL,ULONG fdwReason,LPVOID lpvReserved) { @@ -106,10 +107,11 @@ int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc, IfcGeomObjects::Settings(IfcGeomObjects::USE_WORLD_COORDS,false); IfcGeomObjects::Settings(IfcGeomObjects::WELD_VERTICES,true); + IfcGeomObjects::Settings(IfcGeomObjects::SEW_SHELLS,true); if ( ! IfcGeomObjects::Init((char*)name,0,0) ) return false; - std::map dict; + //std::map dict; MtlBaseLib* mats = itfc->GetSceneMtls(); int slot = mats->Count(); @@ -129,10 +131,14 @@ int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc, m = static_cast((*mats)[matIndex]); } - std::map::const_iterator it = dict.find(o->mesh->id); + // This mapping is useless for now, because this even in case + // meshes entities in IFC share the same representation elements + // they will never be given the same id. + // TODO: Fix this! + // std::map::const_iterator it = dict.find(o->mesh->id); TriObject* tri; - if ( it == dict.end() ) { + // if ( it == dict.end() ) { tri = CreateNewTriObject(); const int numVerts = o->mesh->verts.size()/3; tri->mesh.setNumVerts(numVerts); @@ -145,14 +151,21 @@ int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc, tri->mesh.faces[i].setVerts(o->mesh->faces[3*i+0],o->mesh->faces[3*i+1],o->mesh->faces[3*i+2]); tri->mesh.faces[i].setEdgeVisFlags(o->mesh->edges[3*i+0],o->mesh->edges[3*i+1],o->mesh->edges[3*i+2]); } - tri->mesh.InvalidateTopologyCache(); - tri->mesh.InvalidateGeomCache(); + tri->mesh.buildNormals(); + // Either use this or undefine the FACESETS_AS_COMPOUND option in IfcGeom.h to have + // properly oriented normals. Using only the line below will result in a consistent + // orientation of normals accross shells, but not always oriented towards the + // outside. + // tri->mesh.UnifyNormals(false); tri->mesh.BuildStripsAndEdges(); - dict[o->mesh->id] = tri; - } else { - tri = (*it).second; - } + tri->mesh.InvalidateTopologyCache(); + tri->mesh.InvalidateGeomCache(); + + // dict[o->mesh->id] = tri; + // } else { + // tri = (*it).second; + // } ImpNode* node = impitfc->CreateNode(); node->Reference(tri); diff --git a/src/ifcobj/IfcObj.cpp b/src/ifcobj/IfcObj.cpp index b3823442e0..f2627cb1c0 100644 --- a/src/ifcobj/IfcObj.cpp +++ b/src/ifcobj/IfcObj.cpp @@ -49,6 +49,7 @@ int main ( int argc, char** argv ) { IfcGeomObjects::Settings(IfcGeomObjects::USE_WORLD_COORDS,true); IfcGeomObjects::Settings(IfcGeomObjects::WELD_VERTICES,false); + IfcGeomObjects::Settings(IfcGeomObjects::SEW_SHELLS,true); // Stream for log messages, we don't want to interupt our new progress bar... std::stringstream ss; diff --git a/src/ifcparse/IfcParse.cpp b/src/ifcparse/IfcParse.cpp index 6f89f7ab74..6f4dba9cfa 100644 --- a/src/ifcparse/IfcParse.cpp +++ b/src/ifcparse/IfcParse.cpp @@ -822,6 +822,7 @@ Tokens* Ifc::tokens = 0; double Ifc::LengthUnit = 1.0f; double Ifc::PlaneAngleUnit = 1.0f; bool Ifc::hasPlaneAngleUnit = false; +bool Ifc::SewShells = false; int Ifc::CircleSegments = 32; MapEntitiesByType Ifc::bytype; MapEntityById Ifc::byid; diff --git a/src/ifcparse/IfcParse.h b/src/ifcparse/IfcParse.h index faf6662e9b..9e785cf15f 100644 --- a/src/ifcparse/IfcParse.h +++ b/src/ifcparse/IfcParse.h @@ -268,6 +268,7 @@ public: static std::string GetLog(); static void Dispose(); static bool hasPlaneAngleUnit; + static bool SewShells; static double LengthUnit; static double PlaneAngleUnit; static int CircleSegments; diff --git a/src/ifcwrap/Interface.h b/src/ifcwrap/Interface.h index c6e225b09d..4c9058848d 100644 --- a/src/ifcwrap/Interface.h +++ b/src/ifcwrap/Interface.h @@ -23,6 +23,7 @@ namespace IfcGeomObjects { const int USE_WORLD_COORDS = 2; const int CONVERT_BACK_UNITS = 3; const int USE_BREP_DATA = 4; + const int SEW_SHELLS = 5; class IfcMesh { public: