diff --git a/src/ifcblender/io_import_scene_ifc/__init__.py b/src/ifcblender/io_import_scene_ifc/__init__.py index 04bad62b5f..13f96866b1 100644 --- a/src/ifcblender/io_import_scene_ifc/__init__.py +++ b/src/ifcblender/io_import_scene_ifc/__init__.py @@ -46,9 +46,18 @@ if "bpy" in locals(): import bpy import mathutils -from bpy.props import StringProperty +from bpy.props import StringProperty, IntProperty, BoolProperty from bpy_extras.io_utils import ImportHelper +bpy.types.Object.ifc_id = IntProperty(name="IFC Entity ID", + description="The STEP entity instance name") +bpy.types.Object.ifc_guid = StringProperty(name="IFC Entity GUID", + description="The IFC Globally Unique Identifier") +bpy.types.Object.ifc_name = StringProperty(name="IFC Entity Name", + description="The optional name attribute") +bpy.types.Object.ifc_type = StringProperty(name="IFC Entity Type", + description="The STEP Datatype keyword") + class ImportIFC(bpy.types.Operator, ImportHelper): bl_idname = "import_scene.ifc" @@ -57,46 +66,100 @@ class ImportIFC(bpy.types.Operator, ImportHelper): filename_ext = ".ifc" filter_glob = StringProperty(default="*.ifc", options={'HIDDEN'}) + use_names = BoolProperty(name="Use entity names", + description="Use entity names rather than GlobalIds for objects", + default=True) + process_relations = BoolProperty(name="Process relations", + description="Convert containment and aggregation relations to parenting", + default=True) + def execute(self, context): from . import IfcImport if not IfcImport.Init(self.filepath): return {'FINISHED'} - ids = {} + id_to_object = {} + id_to_parent = {} while True: ob = IfcImport.Get() - if not ob.type in ['IfcSpace', 'IfcOpeningElement']: + if ob.type != 'IfcOpeningElement': f = ob.mesh.faces v = ob.mesh.verts m = ob.matrix t = ob.type[0:21] - if ob.mesh.id in ids: - me = ids[ob.mesh.id] + nm = ob.name if len(ob.name) and self.use_names else ob.guid + + verts = [[v[i], v[i + 1], v[i + 2]] \ + for i in range(0, len(v), 3)] + faces = [[f[i], f[i + 1], f[i + 2]] \ + for i in range(0, len(f), 3)] + + me = bpy.data.meshes.new('mesh%d' % ob.mesh.id) + me.from_pydata(verts, [], faces) + if t in bpy.data.materials: + mat = bpy.data.materials[t] + mat.use_fake_user = True else: - verts = [[v[i],v[i+1],v[i+2]] for i in range(0,len(v),3)] - faces = [[f[i],f[i+1],f[i+2]] for i in range(0,len(f),3)] - me = bpy.data.meshes.new('mesh%d' % ob.mesh.id) - me.from_pydata(verts, [], faces) - if t in bpy.data.materials: - mat = bpy.data.materials[t] - mat.use_fake_user = True - else: - mat = bpy.data.materials.new(t) - me.materials.append(mat) - ids[ob.mesh.id] = me - bob = bpy.data.objects.new(ob.name, me) + mat = bpy.data.materials.new(t) + me.materials.append(mat) + + bob = bpy.data.objects.new(nm, me) bob.matrix_world = mathutils.Matrix(([m[0], m[1], m[2], 0], [m[3], m[4], m[5], 0], [m[6], m[7], m[8], 0], [m[9], m[10], m[11], 1])) bpy.context.scene.objects.link(bob) - #me.update() + bpy.ops.object.select_all(action='DESELECT') bpy.ops.object.select_name(name=bob.name) bpy.ops.object.mode_set(mode='EDIT') bpy.ops.mesh.normals_make_consistent() bpy.ops.object.mode_set(mode='OBJECT') + + bob.ifc_id, bob.ifc_guid, bob.ifc_name, bob.ifc_type = \ + ob.id, ob.guid, ob.name, ob.type + + bob.hide = ob.type == 'IfcSpace' + id_to_object[ob.id] = bob + + if ob.parent_id > 0: + id_to_parent[ob.id] = ob.parent_id if not IfcImport.Next(): break + + while len(id_to_parent) and self.process_relations: + id, parent_id = id_to_parent.popitem() + + if parent_id in id_to_object: + bob = id_to_object[parent_id] + else: + parent_ob = IfcImport.GetObject(parent_id) + if parent_ob.id == -1: + bob = None + else: + m = parent_ob.matrix + nm = parent_ob.name if len(parent_ob.name) and self.use_names \ + else parent_ob.guid + bob = bpy.data.objects.new(nm, None) + bob.matrix_world = mathutils.Matrix(([m[0], m[1], m[2], 0], + [m[3], m[4], m[5], 0], + [m[6], m[7], m[8], 0], + [m[9], m[10], m[11], 1])) + bpy.context.scene.objects.link(bob) + + bob.ifc_id = parent_ob.id + bob.ifc_guid = parent_ob.guid + bob.ifc_name = parent_ob.name + bob.ifc_type = parent_ob.type + + if parent_ob.parent_id > 0: + id_to_parent[parent_id] = parent_ob.parent_id + id_to_object[parent_id] = bob + if bob: + ob = id_to_object[id] + ob.matrix_world = bob.matrix_world.inverted() * ob.matrix_world + ob.parent = bob + + IfcImport.CleanUp() return {'FINISHED'} diff --git a/src/ifcgeom/IfcGeomObjects.cpp b/src/ifcgeom/IfcGeomObjects.cpp index f24b0d2af1..a45f4bb72a 100644 --- a/src/ifcgeom/IfcGeomObjects.cpp +++ b/src/ifcgeom/IfcGeomObjects.cpp @@ -104,15 +104,33 @@ IfcGeomObjects::IfcMesh::IfcMesh(int i, TopoDS_Shape s) { } } -IfcGeomObjects::IfcGeomObject::IfcGeomObject(int my_id, const std::string& n, const std::string& t, gp_Trsf trsf, IfcMesh* m) { +IfcGeomObjects::IfcObject::IfcObject(int my_id, + int p_id, + const std::string& n, + const std::string& t, + const std::string& g, + const gp_Trsf& trsf) { + // Convert the gp_Trsf into a 4x3 Matrix for( int i = 1; i < 5; ++ i ) for ( int j = 1; j < 4; ++ j ) matrix.push_back((float)trsf.Value(j,i)); id = my_id; + parent_id = p_id; name = n; type = t; + guid = g; +} + +IfcGeomObjects::IfcGeomObject::IfcGeomObject(int my_id, + int p_id, + const std::string& n, + const std::string& t, + const std::string& g, + const gp_Trsf& trsf, + IfcMesh* m) : IfcObject(my_id,p_id,n,t,g,trsf) { + mesh = m; } @@ -194,7 +212,9 @@ IfcGeomObjects::IfcGeomObject* _get() { } } Ifc2x3::IfcProduct::ptr ifc_product = *inner; - const std::string name = ifc_product->hasName() ? ifc_product->Name() : ifc_product->GlobalId(); + int parent_id = -1; + const std::string name = ifc_product->hasName() ? ifc_product->Name() : ""; + const std::string guid = ifc_product->GlobalId(); gp_Trsf trsf; try { @@ -220,13 +240,37 @@ IfcGeomObjects::IfcGeomObject* _get() { } } + if ( ifc_product->is(Ifc2x3::Type::IfcElement ) ) { + Ifc2x3::IfcElement::ptr element = reinterpret_pointer_cast(ifc_product); + Ifc2x3::IfcRelContainedInSpatialStructure::list parents = element->ContainedInStructure(); + if ( parents->Size() ) { + Ifc2x3::IfcRelContainedInSpatialStructure::ptr parent = *parents->begin(); + parent_id = parent->RelatingStructure()->entity->id(); + } + } + if ( parent_id == -1 ) { + Ifc2x3::IfcRelDecomposes::list decomposes = ifc_product->IsDecomposedBy(); + // This is a bug in IfcParse IsDecomposedBy() and Decomposes() are mixed + for ( Ifc2x3::IfcRelDecomposes::it it = decomposes->begin(); it != decomposes->end(); ++ it ) { + Ifc2x3::IfcRelDecomposes::ptr decompose = *it; + Ifc2x3::IfcObjectDefinition* ifc_objectdef = decompose->RelatingObject(); + if ( ifc_product == ifc_objectdef ) continue; + parent_id = ifc_objectdef->entity->id(); + } + } + if ( (openings && openings->Size()) || use_world_coords ) { if ( shape ) delete shape; TopoDS_Shape temp_shape = shapes.Moved(gp_Trsf()); try { - if (openings && openings->Size()) IfcGeom::convert_openings(ifc_product,openings,temp_shape,trsf); - } catch( IfcParse::IfcException& e ) {Ifc::LogMessage("Warning",e.what()); } - catch(...) { Ifc::LogMessage("Error","Error processing openings for:",ifc_product->entity); } + if (openings && openings->Size()) { + IfcGeom::convert_openings(ifc_product,openings,temp_shape,trsf); + } + } catch( IfcParse::IfcException& e ) { + Ifc::LogMessage("Warning",e.what()); + } catch(...) { + Ifc::LogMessage("Error","Error processing openings for:",ifc_product->entity); + } if ( use_world_coords ) { shape = new IfcGeomObjects::IfcMesh(shaperep->entity->id(),temp_shape.Moved(trsf)); trsf = gp_Trsf(); @@ -237,12 +281,13 @@ IfcGeomObjects::IfcGeomObject* _get() { shape = new IfcGeomObjects::IfcMesh(shaperep->entity->id(),shapes); } - return new IfcGeomObjects::IfcGeomObject(ifc_product->entity->id(), name, Ifc2x3::Type::ToString(ifc_product->type()), trsf, shape); + return new IfcGeomObjects::IfcGeomObject(ifc_product->entity->id(), parent_id, name, + Ifc2x3::Type::ToString(ifc_product->type()), guid, trsf, shape); } } -extern bool IfcGeomObjects::Next() { +bool IfcGeomObjects::Next() { if ( entities ) { ++inner; } @@ -250,20 +295,67 @@ extern bool IfcGeomObjects::Next() { currentGeomObj = _get(); if ( ! currentGeomObj ) { delete shape; - Ifc::Dispose(); - IfcGeom::Cache::Purge(); return false; } else { return true; } } -extern const IfcGeomObjects::IfcGeomObject* IfcGeomObjects::Get() { +std::vector returned_objects; +bool IfcGeomObjects::CleanUp() { + Ifc::Dispose(); + IfcGeom::Cache::Purge(); + for ( std::vector::const_iterator it = returned_objects.begin(); + it != returned_objects.end(); + ++ it ) { + delete *it; + } + return true; +} +const IfcGeomObjects::IfcObject* IfcGeomObjects::GetObject(int id) { + IfcObject* ifc_object = 0; + try { + const IfcEntity& ifc_entity = Ifc::EntityById(id); + if ( ifc_entity->is(Ifc2x3::Type::IfcProduct) ) { + Ifc2x3::IfcProduct::ptr ifc_product = reinterpret_pointer_cast(ifc_entity); + int parent_id = -1; + if ( ifc_product->is(Ifc2x3::Type::IfcElement ) ) { + Ifc2x3::IfcElement::ptr element = reinterpret_pointer_cast(ifc_product); + Ifc2x3::IfcRelContainedInSpatialStructure::list parents = element->ContainedInStructure(); + if ( parents->Size() ) { + Ifc2x3::IfcRelContainedInSpatialStructure::ptr parent = *parents->begin(); + parent_id = parent->RelatingStructure()->entity->id(); + } + } + if ( parent_id == -1 ) { + Ifc2x3::IfcRelDecomposes::list decomposes = ifc_product->IsDecomposedBy(); + // This is a bug in IfcParse IsDecomposedBy() and Decomposes() are mixed + for ( Ifc2x3::IfcRelDecomposes::it it = decomposes->begin(); it != decomposes->end(); ++ it ) { + Ifc2x3::IfcRelDecomposes::ptr decompose = *it; + Ifc2x3::IfcObjectDefinition* ifc_objectdef = decompose->RelatingObject(); + if ( ifc_product == ifc_objectdef ) continue; + parent_id = ifc_objectdef->entity->id(); + } + } + const std::string name = ifc_product->hasName() ? ifc_product->Name() : ""; + gp_Trsf trsf; + try { + IfcGeom::convert(ifc_product->ObjectPlacement(),trsf); + } catch (...) {} + ifc_object = new IfcObject(ifc_product->entity->id(),parent_id,name, + Ifc2x3::Type::ToString(ifc_product->type()),ifc_product->GlobalId(),trsf); + } + } catch(...) {} + if ( !ifc_object ) ifc_object = new IfcObject(-1,-1,"","","",gp_Trsf()); + returned_objects.push_back(ifc_object); + return ifc_object; +} +const IfcGeomObjects::IfcGeomObject* IfcGeomObjects::Get() { return currentGeomObj; } -extern bool IfcGeomObjects::Init(const char* fn, bool world_coords) { +bool IfcGeomObjects::Init(const char* fn, bool world_coords) { return IfcGeomObjects::Init(fn, world_coords, 0, 0); } -extern bool IfcGeomObjects::Init(const char* fn, bool world_coords, std::ostream* log1, std::ostream* log2) { +bool IfcGeomObjects::Init(const char* fn, bool world_coords, std::ostream* log1, std::ostream* log2) { if ( log1 || log2 ) Ifc::SetOutput(log1,log2); use_world_coords = world_coords; if ( !Ifc::Init(fn) ) return false; @@ -281,7 +373,7 @@ extern bool IfcGeomObjects::Init(const char* fn, bool world_coords, std::ostream total = shapereps->Size(); return true; } -extern bool IfcGeomObjects::Init(std::istream& f, int len, bool world_coords, std::ostream* log1, std::ostream* log2) { +bool IfcGeomObjects::Init(std::istream& f, int len, bool world_coords, std::ostream* log1, std::ostream* log2) { if ( log1 || log2 ) Ifc::SetOutput(log1,log2); use_world_coords = world_coords; if ( !Ifc::Init(f, len) ) return false; @@ -299,6 +391,6 @@ extern bool IfcGeomObjects::Init(std::istream& f, int len, bool world_coords, st total = shapereps->Size(); return true; } -extern int IfcGeomObjects::Progress() { +int IfcGeomObjects::Progress() { return 100 * done / total; } diff --git a/src/ifcgeom/IfcGeomObjects.h b/src/ifcgeom/IfcGeomObjects.h index b81ed6d678..42169ae500 100644 --- a/src/ifcgeom/IfcGeomObjects.h +++ b/src/ifcgeom/IfcGeomObjects.h @@ -88,22 +88,31 @@ namespace IfcGeomObjects { } }; - class IfcGeomObject { + class IfcObject { public: int id; + int parent_id; std::string name; std::string type; + std::string guid; std::vector matrix; - IfcMesh* mesh; - IfcGeomObject(int i, const std::string& n, const std::string& t, gp_Trsf trsf, IfcMesh* m); + IfcObject(int my_id, int p_id, const std::string& n, const std::string& t, const std::string& g, const gp_Trsf& trsf); }; - extern bool Init(const char* fn, bool world_coords = false); - extern bool Init(const char* fn, bool world_coords = false, std::ostream* log1= 0, std::ostream* log2= 0); - extern bool Init(std::istream& f, int len, bool world_coords = false, std::ostream* log1= 0, std::ostream* log2= 0); - extern const IfcGeomObject* Get(); - extern bool Next(); - extern int Progress(); + class IfcGeomObject : public IfcObject { + public: + IfcMesh* mesh; + IfcGeomObject(int my_id, int p_id, const std::string& n, const std::string& t, const std::string& g, const gp_Trsf& trsf, IfcMesh* m); + }; + + bool Init(const char* fn, bool world_coords = false); + bool Init(const char* fn, bool world_coords = false, std::ostream* log1= 0, std::ostream* log2= 0); + bool Init(std::istream& f, int len, bool world_coords = false, std::ostream* log1= 0, std::ostream* log2= 0); + bool CleanUp(); + const IfcGeomObject* Get(); + bool Next(); + int Progress(); + const IfcObject* GetObject(int id); } diff --git a/src/ifcmax/IfcMax.cpp b/src/ifcmax/IfcMax.cpp index e245927f82..77a02a6d22 100644 --- a/src/ifcmax/IfcMax.cpp +++ b/src/ifcmax/IfcMax.cpp @@ -27,7 +27,7 @@ #include "../ifcmax/IfcMax.h" #include "../ifcmax/MaxMaterials.h" -#include "../ifcparse/IfcGeomObjects.h" +#include "../ifcgeom/IfcGeomObjects.h" int controlsInit = false; @@ -109,7 +109,7 @@ int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc, itfc->ProgressStart("Importing file...", TRUE, fn, NULL); - if ( ! IfcGeomObjects::Init((char*)name) ) return false; + if ( ! IfcGeomObjects::Init((char*)name,false,0,0) ) return false; std::map dict; MtlBaseLib* mats = itfc->GetSceneMtls(); @@ -158,7 +158,7 @@ int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc, ImpNode* node = impitfc->CreateNode(); node->Reference(tri); - node->SetName(o->name.c_str()); + node->SetName(o->guid.c_str()); node->GetINode()->SetMtl(m); node->SetTransform(0,Matrix3 ( Point3(o->matrix[0],o->matrix[1],o->matrix[2]),Point3(o->matrix[3],o->matrix[4],o->matrix[5]), Point3(o->matrix[6],o->matrix[7],o->matrix[8]),Point3(o->matrix[9],o->matrix[10],o->matrix[11]) )); @@ -168,6 +168,8 @@ int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc, } while ( IfcGeomObjects::Next() ); + IfcGeomObjects::CleanUp(); + itfc->ProgressEnd(); return true; diff --git a/src/ifcwrap/Interface.h b/src/ifcwrap/Interface.h index c72718e49c..908592449c 100644 --- a/src/ifcwrap/Interface.h +++ b/src/ifcwrap/Interface.h @@ -26,17 +26,25 @@ namespace IfcGeomObjects { std::vector edges; }; - class IfcGeomObject { + class IfcObject { public: int id; + int parent_id; std::string name; std::string type; + std::string guid; std::vector matrix; + }; + + class IfcGeomObject : public IfcObject { + public: IfcMesh* mesh; }; - extern bool Next(); - extern const IfcGeomObject* Get(); - extern bool Init(const char* fn, bool world_coords = false); - extern int Progress(); + bool Next(); + const IfcGeomObject* Get(); + bool Init(const char* fn, bool world_coords = false); + int Progress(); + const IfcObject* GetObject(int id); + bool CleanUp(); }; \ No newline at end of file