mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-17 14:02:27 +00:00
Merge pull request #641 from elmopl/blender_ifc_280rc1
Blender ifc 2.80rc1 collections enhancement
This commit is contained in:
@@ -41,10 +41,17 @@ if "bpy" in locals():
|
|||||||
if "ifcopenshell" in locals():
|
if "ifcopenshell" in locals():
|
||||||
importlib.reload(ifcopenshell)
|
importlib.reload(ifcopenshell)
|
||||||
|
|
||||||
import bpy
|
from bpy.props import (
|
||||||
import mathutils
|
BoolProperty,
|
||||||
from bpy.props import StringProperty, IntProperty, BoolProperty
|
IntProperty,
|
||||||
|
StringProperty,
|
||||||
|
)
|
||||||
from bpy_extras.io_utils import ImportHelper
|
from bpy_extras.io_utils import ImportHelper
|
||||||
|
from collections import defaultdict
|
||||||
|
import bpy
|
||||||
|
import logging
|
||||||
|
import mathutils
|
||||||
|
import os
|
||||||
|
|
||||||
major, minor = bpy.app.version[0:2]
|
major, minor = bpy.app.version[0:2]
|
||||||
transpose_matrices = minor >= 62
|
transpose_matrices = minor >= 62
|
||||||
@@ -62,6 +69,25 @@ bpy.types.Object.ifc_type = StringProperty(
|
|||||||
name="IFC Entity Type",
|
name="IFC Entity Type",
|
||||||
description="The STEP Datatype keyword")
|
description="The STEP Datatype keyword")
|
||||||
|
|
||||||
|
def _get_parent(instance):
|
||||||
|
"""This is based on ifcopenshell.app.geom"""
|
||||||
|
if instance.is_a("IfcOpeningElement"):
|
||||||
|
# We skip opening elements as they are nameless.
|
||||||
|
# We use this function to get usable collections.
|
||||||
|
return _get_parent(instance.VoidsElements[0].RelatingBuildingElement)
|
||||||
|
if instance.is_a("IfcElement"):
|
||||||
|
fills = instance.FillsVoids
|
||||||
|
if len(fills):
|
||||||
|
return fills[0].RelatingOpeningElement
|
||||||
|
containments = instance.ContainedInStructure
|
||||||
|
if len(containments):
|
||||||
|
return containments[0].RelatingStructure
|
||||||
|
if instance.is_a("IfcObjectDefinition"):
|
||||||
|
decompositions = instance.Decomposes
|
||||||
|
if len(decompositions):
|
||||||
|
return decompositions[0].RelatingObject
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def import_ifc(filename, use_names, process_relations, blender_booleans):
|
def import_ifc(filename, use_names, process_relations, blender_booleans):
|
||||||
from . import ifcopenshell
|
from . import ifcopenshell
|
||||||
@@ -69,22 +95,60 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
|
|||||||
print(f"Reading {bpy.path.basename(filename)}...")
|
print(f"Reading {bpy.path.basename(filename)}...")
|
||||||
settings = ifcopenshell_geom.settings()
|
settings = ifcopenshell_geom.settings()
|
||||||
settings.set(settings.DISABLE_OPENING_SUBTRACTIONS, blender_booleans)
|
settings.set(settings.DISABLE_OPENING_SUBTRACTIONS, blender_booleans)
|
||||||
iterator = ifcopenshell_geom.iterator(settings, filename)
|
assert os.path.exists(filename), filename
|
||||||
|
ifc_file = ifcopenshell.open(filename)
|
||||||
|
iterator = ifcopenshell_geom.iterator(settings, ifc_file)
|
||||||
valid_file = iterator.initialize()
|
valid_file = iterator.initialize()
|
||||||
if not valid_file:
|
if not valid_file:
|
||||||
return False
|
return False
|
||||||
print("Done reading file")
|
print("Done reading file")
|
||||||
id_to_object = {}
|
id_to_object = defaultdict(list)
|
||||||
id_to_parent = {}
|
id_to_parent = {}
|
||||||
id_to_matrix = {}
|
id_to_matrix = {}
|
||||||
openings = []
|
openings = []
|
||||||
old_progress = -1
|
old_progress = -1
|
||||||
print("Creating geometry...")
|
print("Creating geometry...")
|
||||||
collection = bpy.data.collections.new(f"{bpy.path.basename(filename)}")
|
root_collection = bpy.data.collections.new(f"{bpy.path.basename(filename)}")
|
||||||
bpy.context.scene.collection.children.link(collection)
|
bpy.context.scene.collection.children.link(root_collection)
|
||||||
|
|
||||||
|
collections = {
|
||||||
|
0: root_collection
|
||||||
|
}
|
||||||
|
def get_collection(cid):
|
||||||
|
if cid == 0:
|
||||||
|
return root_collection
|
||||||
|
|
||||||
|
collection = collections.get(cid)
|
||||||
|
if collection is None:
|
||||||
|
try:
|
||||||
|
ifc_object = ifc_file.by_id(cid)
|
||||||
|
except Exception as exc:
|
||||||
|
logging.exception(exc)
|
||||||
|
ifc_object = None
|
||||||
|
|
||||||
|
if ifc_object is not None:
|
||||||
|
# FIXME: I am really unsure if that is correct way to get parent object
|
||||||
|
ifc_parent_object = _get_parent(ifc_object)
|
||||||
|
parent_id = ifc_parent_object.id() if ifc_parent_object is not None else 0
|
||||||
|
parent_collection = get_collection(parent_id)
|
||||||
|
name = ifc_object.Name or f'{ifc_object.is_a()}[{cid}]'
|
||||||
|
else:
|
||||||
|
parent_collection = get_collection(0)
|
||||||
|
name = f'unresolved_{cid}'
|
||||||
|
|
||||||
|
collection = bpy.data.collections.new(name)
|
||||||
|
parent_collection.children.link(collection)
|
||||||
|
collections[cid] = collection
|
||||||
|
|
||||||
|
|
||||||
|
return collection
|
||||||
|
|
||||||
if process_relations:
|
if process_relations:
|
||||||
rel_collection = bpy.data.collections.new("Relations")
|
rel_collection = bpy.data.collections.new("Relations")
|
||||||
collection.children.link(rel_collection)
|
collection.children.link(rel_collection)
|
||||||
|
|
||||||
|
project_meshes = dict()
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
ob = iterator.get()
|
ob = iterator.get()
|
||||||
|
|
||||||
@@ -98,9 +162,9 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
|
|||||||
# MESH CREATION
|
# MESH CREATION
|
||||||
# Depending on version, geometry.id will be either int or str
|
# Depending on version, geometry.id will be either int or str
|
||||||
mesh_name = 'mesh-%r' % ob.geometry.id
|
mesh_name = 'mesh-%r' % ob.geometry.id
|
||||||
if mesh_name in bpy.data.meshes:
|
|
||||||
me = bpy.data.meshes[mesh_name]
|
me = project_meshes.get(mesh_name)
|
||||||
else:
|
if me is None:
|
||||||
verts = [[v[i], v[i + 1], v[i + 2]]
|
verts = [[v[i], v[i + 1], v[i + 2]]
|
||||||
for i in range(0, len(v), 3)]
|
for i in range(0, len(v), 3)]
|
||||||
faces = [[f[i], f[i + 1], f[i + 2]]
|
faces = [[f[i], f[i + 1], f[i + 2]]
|
||||||
@@ -163,7 +227,8 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
|
|||||||
id_to_matrix[ob.id] = mat
|
id_to_matrix[ob.id] = mat
|
||||||
else:
|
else:
|
||||||
bob.matrix_world = mat
|
bob.matrix_world = mat
|
||||||
collection.objects.link(bob)
|
|
||||||
|
get_collection(ob.parent_id).objects.link(bob)
|
||||||
|
|
||||||
bpy.context.view_layer.objects.active = bob
|
bpy.context.view_layer.objects.active = bob
|
||||||
bpy.ops.object.mode_set(mode='EDIT')
|
bpy.ops.object.mode_set(mode='EDIT')
|
||||||
@@ -178,8 +243,6 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
|
|||||||
bob.hide_viewport = bob.hide_render = True
|
bob.hide_viewport = bob.hide_render = True
|
||||||
bob.display_type = 'WIRE'
|
bob.display_type = 'WIRE'
|
||||||
|
|
||||||
if ob.id not in id_to_object:
|
|
||||||
id_to_object[ob.id] = []
|
|
||||||
id_to_object[ob.id].append(bob)
|
id_to_object[ob.id].append(bob)
|
||||||
|
|
||||||
if ob.parent_id > 0:
|
if ob.parent_id > 0:
|
||||||
@@ -201,45 +264,43 @@ def import_ifc(filename, use_names, process_relations, blender_booleans):
|
|||||||
|
|
||||||
if process_relations:
|
if process_relations:
|
||||||
print("Processing relations...")
|
print("Processing relations...")
|
||||||
|
while len(id_to_parent_temp):
|
||||||
|
id, parent_id = id_to_parent_temp.popitem()
|
||||||
|
|
||||||
while len(id_to_parent_temp) and process_relations:
|
if parent_id in id_to_object:
|
||||||
id, parent_id = id_to_parent_temp.popitem()
|
bob = id_to_object[parent_id][0]
|
||||||
|
|
||||||
if parent_id in id_to_object:
|
|
||||||
bob = id_to_object[parent_id][0]
|
|
||||||
else:
|
|
||||||
parent_ob = iterator.getObject(parent_id)
|
|
||||||
if parent_ob.id == -1:
|
|
||||||
bob = None
|
|
||||||
else:
|
else:
|
||||||
m = parent_ob.transformation.matrix.data
|
parent_ob = iterator.getObject(parent_id)
|
||||||
nm = parent_ob.name if len(parent_ob.name) and use_names \
|
if parent_ob.id == -1:
|
||||||
else parent_ob.guid
|
bob = None
|
||||||
bob = bpy.data.objects.new(nm, None)
|
else:
|
||||||
|
m = parent_ob.transformation.matrix.data
|
||||||
|
nm = parent_ob.name if len(parent_ob.name) and use_names \
|
||||||
|
else parent_ob.guid
|
||||||
|
bob = bpy.data.objects.new(nm, None)
|
||||||
|
|
||||||
mat = mathutils.Matrix((
|
mat = mathutils.Matrix((
|
||||||
[m[0], m[1], m[2], 0],
|
[m[0], m[1], m[2], 0],
|
||||||
[m[3], m[4], m[5], 0],
|
[m[3], m[4], m[5], 0],
|
||||||
[m[6], m[7], m[8], 0],
|
[m[6], m[7], m[8], 0],
|
||||||
[m[9], m[10], m[11], 1]))
|
[m[9], m[10], m[11], 1]))
|
||||||
if transpose_matrices:
|
if transpose_matrices:
|
||||||
mat.transpose()
|
mat.transpose()
|
||||||
id_to_matrix[parent_ob.id] = mat
|
id_to_matrix[parent_ob.id] = mat
|
||||||
|
|
||||||
rel_collection.objects.link(bob)
|
rel_collection.objects.link(bob)
|
||||||
|
|
||||||
bob.ifc_id = parent_ob.id
|
bob.ifc_id = parent_ob.id
|
||||||
bob.ifc_name, bob.ifc_type, bob.ifc_guid = \
|
bob.ifc_name, bob.ifc_type, bob.ifc_guid = \
|
||||||
parent_ob.name, parent_ob.type, parent_ob.guid
|
parent_ob.name, parent_ob.type, parent_ob.guid
|
||||||
|
|
||||||
if parent_ob.parent_id > 0:
|
if parent_ob.parent_id > 0:
|
||||||
id_to_parent[parent_id] = parent_ob.parent_id
|
id_to_parent[parent_id] = parent_ob.parent_id
|
||||||
id_to_parent_temp[parent_id] = parent_ob.parent_id
|
id_to_parent_temp[parent_id] = parent_ob.parent_id
|
||||||
if parent_id not in id_to_object: id_to_object[parent_id] = []
|
id_to_object[parent_id].append(bob)
|
||||||
id_to_object[parent_id].append(bob)
|
if bob:
|
||||||
if bob:
|
for ob in id_to_object[id]:
|
||||||
for ob in id_to_object[id]:
|
ob.parent = bob
|
||||||
ob.parent = bob
|
|
||||||
|
|
||||||
id_to_matrix_temp = dict(id_to_matrix)
|
id_to_matrix_temp = dict(id_to_matrix)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user