mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-06 07:51:47 +00:00
Process IfcRelAggregates and IfcRelContainedInSpatialStructure to enable IfcBlender to build a parenting graph
This commit is contained in:
@@ -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'}
|
||||
|
||||
|
||||
|
||||
+106
-14
@@ -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<Ifc2x3::IfcProduct,Ifc2x3::IfcElement>(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<IfcGeomObjects::IfcObject*> returned_objects;
|
||||
bool IfcGeomObjects::CleanUp() {
|
||||
Ifc::Dispose();
|
||||
IfcGeom::Cache::Purge();
|
||||
for ( std::vector<IfcGeomObjects::IfcObject*>::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<IfcUtil::IfcBaseClass,Ifc2x3::IfcProduct>(ifc_entity);
|
||||
int parent_id = -1;
|
||||
if ( ifc_product->is(Ifc2x3::Type::IfcElement ) ) {
|
||||
Ifc2x3::IfcElement::ptr element = reinterpret_pointer_cast<Ifc2x3::IfcProduct,Ifc2x3::IfcElement>(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;
|
||||
}
|
||||
|
||||
@@ -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<float> 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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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<int, TriObject*> 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;
|
||||
|
||||
+13
-5
@@ -26,17 +26,25 @@ namespace IfcGeomObjects {
|
||||
std::vector<int> edges;
|
||||
};
|
||||
|
||||
class IfcGeomObject {
|
||||
class IfcObject {
|
||||
public:
|
||||
int id;
|
||||
int parent_id;
|
||||
std::string name;
|
||||
std::string type;
|
||||
std::string guid;
|
||||
std::vector<float> 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();
|
||||
};
|
||||
Reference in New Issue
Block a user