mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-29 11:46:33 +00:00
Construction Types - Attempt to solve repeated object creation (#2450)
* Constr types dicts to Blender props * Reduce update interval * Base for not linking dummy asset objects to collections
This commit is contained in:
committed by
GitHub
parent
d4d923e51b
commit
05070c3758
@@ -47,8 +47,9 @@ classes = (
|
|||||||
slab.EnableEditingSketchExtrusionProfile,
|
slab.EnableEditingSketchExtrusionProfile,
|
||||||
slab.ResetVertex,
|
slab.ResetVertex,
|
||||||
slab.SetArcIndex,
|
slab.SetArcIndex,
|
||||||
prop.BIMModelProperties,
|
|
||||||
prop.ConstrTypeInfo,
|
prop.ConstrTypeInfo,
|
||||||
|
prop.ConstrClassInfo,
|
||||||
|
prop.BIMModelProperties,
|
||||||
ui.BIM_PT_authoring,
|
ui.BIM_PT_authoring,
|
||||||
ui.DisplayConstrTypesUI,
|
ui.DisplayConstrTypesUI,
|
||||||
ui.HelpConstrTypes,
|
ui.HelpConstrTypes,
|
||||||
@@ -69,7 +70,6 @@ def register():
|
|||||||
if not bpy.app.background:
|
if not bpy.app.background:
|
||||||
bpy.utils.register_tool(workspace.BimTool, after={"builtin.scale_cage"}, separator=True, group=True)
|
bpy.utils.register_tool(workspace.BimTool, after={"builtin.scale_cage"}, separator=True, group=True)
|
||||||
bpy.types.Scene.BIMModelProperties = bpy.props.PointerProperty(type=prop.BIMModelProperties)
|
bpy.types.Scene.BIMModelProperties = bpy.props.PointerProperty(type=prop.BIMModelProperties)
|
||||||
bpy.types.Scene.ConstrTypeInfo = bpy.props.CollectionProperty(type=prop.ConstrTypeInfo)
|
|
||||||
bpy.types.VIEW3D_MT_mesh_add.append(grid.add_object_button)
|
bpy.types.VIEW3D_MT_mesh_add.append(grid.add_object_button)
|
||||||
bpy.types.VIEW3D_MT_mesh_add.append(stair.add_object_button)
|
bpy.types.VIEW3D_MT_mesh_add.append(stair.add_object_button)
|
||||||
bpy.types.VIEW3D_MT_mesh_add.append(opening.add_object_button)
|
bpy.types.VIEW3D_MT_mesh_add.append(opening.add_object_button)
|
||||||
@@ -87,7 +87,6 @@ def unregister():
|
|||||||
if not bpy.app.background:
|
if not bpy.app.background:
|
||||||
bpy.utils.unregister_tool(workspace.BimTool)
|
bpy.utils.unregister_tool(workspace.BimTool)
|
||||||
del bpy.types.Scene.BIMModelProperties
|
del bpy.types.Scene.BIMModelProperties
|
||||||
del bpy.types.Scene.ConstrTypeInfo
|
|
||||||
bpy.app.handlers.load_post.remove(handler.load_post)
|
bpy.app.handlers.load_post.remove(handler.load_post)
|
||||||
bpy.types.VIEW3D_MT_mesh_add.remove(grid.add_object_button)
|
bpy.types.VIEW3D_MT_mesh_add.remove(grid.add_object_button)
|
||||||
bpy.types.VIEW3D_MT_mesh_add.remove(stair.add_object_button)
|
bpy.types.VIEW3D_MT_mesh_add.remove(stair.add_object_button)
|
||||||
|
|||||||
@@ -20,10 +20,7 @@ import functools
|
|||||||
import bpy
|
import bpy
|
||||||
import blenderbim.tool as tool
|
import blenderbim.tool as tool
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
|
from blenderbim.bim.module.model.root import ConstrTypeEntityNotFound
|
||||||
|
|
||||||
preview_icon_ids = {}
|
|
||||||
attempts = 0
|
|
||||||
|
|
||||||
|
|
||||||
def refresh():
|
def refresh():
|
||||||
@@ -43,7 +40,6 @@ class AuthoringData:
|
|||||||
cls.load_ifc_classes()
|
cls.load_ifc_classes()
|
||||||
cls.load_relating_types()
|
cls.load_relating_types()
|
||||||
cls.load_relating_types_browser()
|
cls.load_relating_types_browser()
|
||||||
cls.load_preview_constr_types()
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load_ifc_classes(cls):
|
def load_ifc_classes(cls):
|
||||||
@@ -57,10 +53,6 @@ class AuthoringData:
|
|||||||
def load_relating_types_browser(cls):
|
def load_relating_types_browser(cls):
|
||||||
cls.data["relating_types_ids_browser"] = cls.relating_types_browser()
|
cls.data["relating_types_ids_browser"] = cls.relating_types_browser()
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def load_preview_constr_types(cls):
|
|
||||||
cls.data["preview_constr_types"] = preview_icon_ids
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def ifc_classes(cls):
|
def ifc_classes(cls):
|
||||||
results = []
|
results = []
|
||||||
@@ -97,11 +89,11 @@ class AuthoringData:
|
|||||||
def relating_types_browser(cls):
|
def relating_types_browser(cls):
|
||||||
return cls.relating_types(ifc_class=cls.props.ifc_class_browser)
|
return cls.relating_types(ifc_class=cls.props.ifc_class_browser)
|
||||||
|
|
||||||
@staticmethod
|
@classmethod
|
||||||
def new_relating_type_info(ifc_class):
|
def new_constr_class_info(cls, ifc_class):
|
||||||
relating_type_info = bpy.context.scene.ConstrTypeInfo.add()
|
if ifc_class not in cls.props.constr_classes:
|
||||||
relating_type_info.name = ifc_class
|
cls.props.constr_classes.add().name = ifc_class
|
||||||
return relating_type_info
|
return cls.props.constr_classes[ifc_class]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def assetize_constr_class(cls, ifc_class=None):
|
def assetize_constr_class(cls, ifc_class=None):
|
||||||
@@ -109,21 +101,19 @@ class AuthoringData:
|
|||||||
selected_relating_type_id = cls.props.relating_type_id
|
selected_relating_type_id = cls.props.relating_type_id
|
||||||
if ifc_class is None:
|
if ifc_class is None:
|
||||||
ifc_class = cls.props.ifc_class_browser
|
ifc_class = cls.props.ifc_class_browser
|
||||||
relating_type_info = cls.relating_type_info(ifc_class)
|
if cls.constr_class_info(ifc_class) is None:
|
||||||
_ = cls.new_relating_type_info(ifc_class) if relating_type_info is None else relating_type_info
|
cls.new_constr_class_info(ifc_class)
|
||||||
constr_class_occurrences = cls.constr_class_entities(ifc_class)
|
constr_class_occurrences = cls.constr_class_entities(ifc_class)
|
||||||
preview_constr_types = cls.data["preview_constr_types"]
|
constr_classes = cls.props.constr_classes
|
||||||
for constr_class_entity in constr_class_occurrences:
|
|
||||||
|
|
||||||
### handle asset regeneration when library entity is updated ¿?
|
for constr_class_entity in constr_class_occurrences:
|
||||||
if (
|
if (
|
||||||
ifc_class not in preview_constr_types
|
ifc_class not in constr_classes
|
||||||
or str(constr_class_entity.id()) not in preview_constr_types[ifc_class]
|
or constr_class_entity.Name not in constr_classes[ifc_class].constr_types
|
||||||
):
|
):
|
||||||
obj = tool.Ifc.get_object(constr_class_entity)
|
obj = tool.Ifc.get_object(constr_class_entity)
|
||||||
cls.assetize_object(obj, ifc_class, constr_class_entity)
|
cls.assetize_object(obj, ifc_class, constr_class_entity)
|
||||||
relating_type_info = cls.relating_type_info(ifc_class)
|
cls.constr_class_info(ifc_class).fully_loaded = True
|
||||||
relating_type_info.fully_loaded = True
|
|
||||||
cls.props.updating = True
|
cls.props.updating = True
|
||||||
cls.props.ifc_class = selected_ifc_class
|
cls.props.ifc_class = selected_ifc_class
|
||||||
cls.props.relating_type_id = selected_relating_type_id
|
cls.props.relating_type_id = selected_relating_type_id
|
||||||
@@ -144,21 +134,25 @@ class AuthoringData:
|
|||||||
obj.asset_mark()
|
obj.asset_mark()
|
||||||
obj.asset_generate_preview()
|
obj.asset_generate_preview()
|
||||||
|
|
||||||
def wait_for_asset_previews_generation(check_interval_seconds=0.001):
|
def wait_for_asset_previews_generation(check_interval_seconds=0.0001):
|
||||||
if bpy.app.is_job_running("RENDER_PREVIEW"):
|
if bpy.app.is_job_running("RENDER_PREVIEW"):
|
||||||
return check_interval_seconds
|
return check_interval_seconds
|
||||||
else:
|
else:
|
||||||
icon_id = obj.preview.icon_id
|
if ifc_class not in cls.props.constr_classes:
|
||||||
if ifc_class not in cls.data["preview_constr_types"]:
|
cls.props.constr_classes.add().name = ifc_class
|
||||||
cls.data["preview_constr_types"][ifc_class] = {}
|
constr_class_info = cls.props.constr_classes[ifc_class]
|
||||||
cls.data["preview_constr_types"][ifc_class][str(relating_type_id)] = {"icon_id": icon_id, "object": obj}
|
# relating_type = cls.relating_type_name_by_id(ifc_class, relating_type_id)
|
||||||
|
if str(relating_type_id) not in constr_class_info.constr_types:
|
||||||
|
constr_class_info.constr_types.add().name = str(relating_type_id)
|
||||||
|
relating_type_info = constr_class_info.constr_types[str(relating_type_id)]
|
||||||
|
relating_type_info.object = obj
|
||||||
|
relating_type_info.icon_id = obj.preview.icon_id
|
||||||
|
|
||||||
if to_be_deleted:
|
if to_be_deleted:
|
||||||
element = tool.Ifc.get_entity(obj)
|
element = tool.Ifc.get_entity(obj)
|
||||||
if element:
|
if element:
|
||||||
tool.Ifc.delete(element)
|
tool.Ifc.delete(element)
|
||||||
tool.Ifc.unlink(obj=obj)
|
tool.Ifc.unlink(obj=obj)
|
||||||
# We do not delete the object from the scene, as that breaks Blender's asset system.
|
|
||||||
# Instead, we only "hide" it by unlinking it from all collections.
|
|
||||||
for collection in obj.users_collection:
|
for collection in obj.users_collection:
|
||||||
collection.objects.unlink(obj)
|
collection.objects.unlink(obj)
|
||||||
return None
|
return None
|
||||||
@@ -174,31 +168,29 @@ class AuthoringData:
|
|||||||
entity for entity in constr_class_occurrences if entity.id() == int(relating_type_id)
|
entity for entity in constr_class_occurrences if entity.id() == int(relating_type_id)
|
||||||
]
|
]
|
||||||
if len(constr_class_occurrences) == 0:
|
if len(constr_class_occurrences) == 0:
|
||||||
return False
|
raise ConstrTypeEntityNotFound()
|
||||||
constr_class_entity = constr_class_occurrences[0]
|
constr_class_entity = constr_class_occurrences[0]
|
||||||
obj = tool.Ifc.get_object(constr_class_entity)
|
if (obj := tool.Ifc.get_object(constr_class_entity)) is None:
|
||||||
if obj is None:
|
raise ConstrTypeEntityNotFound()
|
||||||
return False
|
|
||||||
cls.assetize_object(obj, ifc_class, constr_class_entity, from_selection=True)
|
cls.assetize_object(obj, ifc_class, constr_class_entity, from_selection=True)
|
||||||
return True
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def relating_type_info(ifc_class):
|
def constr_class_info(ifc_class):
|
||||||
relating_type_infos = [element for element in bpy.context.scene.ConstrTypeInfo if element.name == ifc_class]
|
props = bpy.context.scene.BIMModelProperties
|
||||||
return None if len(relating_type_infos) == 0 else relating_type_infos[0]
|
return props.constr_classes[ifc_class] if ifc_class in props.constr_classes else None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def new_relating_type(cls, ifc_class=None, relating_type_id=None):
|
def new_relating_type(cls, ifc_class=None, relating_type_id=None):
|
||||||
if ifc_class is None:
|
if ifc_class is None:
|
||||||
bpy.ops.bim.add_constr_type_instance(
|
bpy.ops.bim.add_constr_type_instance(
|
||||||
ifc_class=cls.props.ifc_class, relating_type_id=int(cls.props.relating_type_id)
|
ifc_class=cls.props.ifc_class, relating_type_id=int(cls.props.relating_type_id), link_to_scene=True
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
cls.props.updating = True
|
cls.props.updating = True
|
||||||
cls.props.ifc_class = ifc_class
|
cls.props.ifc_class = ifc_class
|
||||||
cls.props.relating_type_id = str(relating_type_id)
|
cls.props.relating_type_id = str(relating_type_id)
|
||||||
cls.props.updating = False
|
cls.props.updating = False
|
||||||
bpy.ops.bim.add_constr_type_instance()
|
bpy.ops.bim.add_constr_type_instance(link_to_scene=True)
|
||||||
return bpy.context.selected_objects[-1]
|
return bpy.context.selected_objects[-1]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ class MepGenerator:
|
|||||||
def __init__(self, relating_type):
|
def __init__(self, relating_type):
|
||||||
self.relating_type = relating_type
|
self.relating_type = relating_type
|
||||||
|
|
||||||
def generate(self):
|
def generate(self, link_to_scene=True):
|
||||||
self.file = tool.Ifc.get()
|
self.file = tool.Ifc.get()
|
||||||
self.collection = bpy.context.view_layer.active_layer_collection.collection
|
self.collection = bpy.context.view_layer.active_layer_collection.collection
|
||||||
|
|
||||||
@@ -55,15 +55,15 @@ class MepGenerator:
|
|||||||
self.height = dimensions.get("NominalHeight")
|
self.height = dimensions.get("NominalHeight")
|
||||||
self.length = 1
|
self.length = 1
|
||||||
|
|
||||||
return self.derive_from_cursor()
|
return self.derive_from_cursor(link_to_scene=link_to_scene)
|
||||||
elif self.relating_type.is_a("IfcPipeSegmentType"):
|
elif self.relating_type.is_a("IfcPipeSegmentType"):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def derive_from_cursor(self):
|
def derive_from_cursor(self, link_to_scene):
|
||||||
self.location = bpy.context.scene.cursor.location
|
self.location = bpy.context.scene.cursor.location
|
||||||
return self.create_rectangle_segment()
|
return self.create_rectangle_segment(link_to_scene)
|
||||||
|
|
||||||
def create_rectangle_segment(self):
|
def create_rectangle_segment(self, link_to_scene):
|
||||||
verts = [
|
verts = [
|
||||||
Vector((-self.width / 2, self.height / 2, 0)),
|
Vector((-self.width / 2, self.height / 2, 0)),
|
||||||
Vector((-self.width / 2, -self.height / 2, 0)),
|
Vector((-self.width / 2, -self.height / 2, 0)),
|
||||||
@@ -89,10 +89,11 @@ class MepGenerator:
|
|||||||
ifc_class = ifc_classes[0]
|
ifc_class = ifc_classes[0]
|
||||||
|
|
||||||
obj = bpy.data.objects.new(tool.Model.generate_occurrence_name(self.relating_type, ifc_class), mesh)
|
obj = bpy.data.objects.new(tool.Model.generate_occurrence_name(self.relating_type, ifc_class), mesh)
|
||||||
obj.location = self.location
|
if link_to_scene:
|
||||||
obj.rotation_euler[0] = math.pi / 2
|
obj.location = self.location
|
||||||
obj.rotation_euler[2] = math.pi / 2
|
obj.rotation_euler[0] = math.pi / 2
|
||||||
self.collection.objects.link(obj)
|
obj.rotation_euler[2] = math.pi / 2
|
||||||
|
self.collection.objects.link(obj)
|
||||||
|
|
||||||
bpy.ops.bim.assign_class(
|
bpy.ops.bim.assign_class(
|
||||||
obj=obj.name,
|
obj=obj.name,
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ class AddConstrTypeInstance(bpy.types.Operator):
|
|||||||
ifc_class: bpy.props.StringProperty()
|
ifc_class: bpy.props.StringProperty()
|
||||||
relating_type_id: bpy.props.IntProperty()
|
relating_type_id: bpy.props.IntProperty()
|
||||||
from_invoke: bpy.props.BoolProperty(default=False)
|
from_invoke: bpy.props.BoolProperty(default=False)
|
||||||
|
link_to_scene: bpy.props.BoolProperty(default=True)
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
return self.execute(context)
|
return self.execute(context)
|
||||||
@@ -88,13 +89,13 @@ class AddConstrTypeInstance(bpy.types.Operator):
|
|||||||
material = ifcopenshell.util.element.get_material(relating_type)
|
material = ifcopenshell.util.element.get_material(relating_type)
|
||||||
|
|
||||||
if material and material.is_a("IfcMaterialProfileSet"):
|
if material and material.is_a("IfcMaterialProfileSet"):
|
||||||
if profile.DumbProfileGenerator(relating_type).generate():
|
if profile.DumbProfileGenerator(relating_type).generate(link_to_scene=self.link_to_scene):
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
elif material and material.is_a("IfcMaterialLayerSet"):
|
elif material and material.is_a("IfcMaterialLayerSet"):
|
||||||
if self.generate_layered_element(ifc_class, relating_type):
|
if self.generate_layered_element(ifc_class, relating_type, link_to_scene=self.link_to_scene):
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
if relating_type.is_a("IfcFlowSegmentType") and not relating_type.RepresentationMaps:
|
if relating_type.is_a("IfcFlowSegmentType") and not relating_type.RepresentationMaps:
|
||||||
if mep.MepGenerator(relating_type).generate():
|
if mep.MepGenerator(relating_type).generate(link_to_scene=self.link_to_scene):
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
building_obj = None
|
building_obj = None
|
||||||
@@ -125,15 +126,17 @@ class AddConstrTypeInstance(bpy.types.Operator):
|
|||||||
mesh = bpy.data.meshes.new(name="Instance")
|
mesh = bpy.data.meshes.new(name="Instance")
|
||||||
mesh.from_pydata(verts, edges, faces)
|
mesh.from_pydata(verts, edges, faces)
|
||||||
obj = bpy.data.objects.new(tool.Model.generate_occurrence_name(relating_type, instance_class), mesh)
|
obj = bpy.data.objects.new(tool.Model.generate_occurrence_name(relating_type, instance_class), mesh)
|
||||||
obj.location = context.scene.cursor.location
|
if self.link_to_scene:
|
||||||
collection = context.view_layer.active_layer_collection.collection
|
obj.location = context.scene.cursor.location
|
||||||
collection.objects.link(obj)
|
collection = context.view_layer.active_layer_collection.collection
|
||||||
collection_obj = bpy.data.objects.get(collection.name)
|
collection.objects.link(obj)
|
||||||
|
collection_obj = bpy.data.objects.get(collection.name)
|
||||||
bpy.ops.bim.assign_class(obj=obj.name, ifc_class=instance_class)
|
bpy.ops.bim.assign_class(obj=obj.name, ifc_class=instance_class)
|
||||||
element = tool.Ifc.get_entity(obj)
|
element = tool.Ifc.get_entity(obj)
|
||||||
blenderbim.core.type.assign_type(tool.Ifc, tool.Type, element=element, type=relating_type)
|
blenderbim.core.type.assign_type(tool.Ifc, tool.Type, element=element, type=relating_type)
|
||||||
# Update required as core.type.assign_type may change obj.data
|
if self.link_to_scene:
|
||||||
bpy.context.view_layer.update()
|
# Update required as core.type.assign_type may change obj.data
|
||||||
|
bpy.context.view_layer.update()
|
||||||
|
|
||||||
if (
|
if (
|
||||||
building_obj
|
building_obj
|
||||||
@@ -145,9 +148,9 @@ class AddConstrTypeInstance(bpy.types.Operator):
|
|||||||
bpy.ops.bim.add_element_opening(
|
bpy.ops.bim.add_element_opening(
|
||||||
voided_building_element=building_obj.name, filling_building_element=obj.name
|
voided_building_element=building_obj.name, filling_building_element=obj.name
|
||||||
)
|
)
|
||||||
if instance_class == "IfcDoor":
|
if instance_class == "IfcDoor" and self.link_to_scene:
|
||||||
obj.location[2] = building_obj.location[2] - min([v[2] for v in obj.bound_box])
|
obj.location[2] = building_obj.location[2] - min([v[2] for v in obj.bound_box])
|
||||||
else:
|
elif self.link_to_scene:
|
||||||
if collection_obj and collection_obj.BIMObjectProperties.ifc_definition_id:
|
if collection_obj and collection_obj.BIMObjectProperties.ifc_definition_id:
|
||||||
obj.location[2] = collection_obj.location[2] - min([v[2] for v in obj.bound_box])
|
obj.location[2] = collection_obj.location[2] - min([v[2] for v in obj.bound_box])
|
||||||
|
|
||||||
@@ -168,7 +171,7 @@ class AddConstrTypeInstance(bpy.types.Operator):
|
|||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def generate_layered_element(ifc_class, relating_type):
|
def generate_layered_element(ifc_class, relating_type, link_to_scene=True):
|
||||||
layer_set_direction = None
|
layer_set_direction = None
|
||||||
|
|
||||||
parametric = ifcopenshell.util.element.get_psets(relating_type).get("EPset_Parametric")
|
parametric = ifcopenshell.util.element.get_psets(relating_type).get("EPset_Parametric")
|
||||||
@@ -181,10 +184,10 @@ class AddConstrTypeInstance(bpy.types.Operator):
|
|||||||
layer_set_direction = "AXIS2"
|
layer_set_direction = "AXIS2"
|
||||||
|
|
||||||
if layer_set_direction == "AXIS3":
|
if layer_set_direction == "AXIS3":
|
||||||
if slab.DumbSlabGenerator(relating_type).generate():
|
if slab.DumbSlabGenerator(relating_type).generate(link_to_scene=link_to_scene):
|
||||||
return True
|
return True
|
||||||
elif layer_set_direction == "AXIS2":
|
elif layer_set_direction == "AXIS2":
|
||||||
if wall.DumbWallGenerator(relating_type).generate():
|
if wall.DumbWallGenerator(relating_type).generate(link_to_scene=link_to_scene):
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
pass # Dumb block generator? Eh? :)
|
pass # Dumb block generator? Eh? :)
|
||||||
@@ -201,8 +204,8 @@ class DisplayConstrTypes(bpy.types.Operator):
|
|||||||
AuthoringData.load()
|
AuthoringData.load()
|
||||||
props = context.scene.BIMModelProperties
|
props = context.scene.BIMModelProperties
|
||||||
ifc_class = props.ifc_class
|
ifc_class = props.ifc_class
|
||||||
relating_type_info = AuthoringData.relating_type_info(ifc_class)
|
constr_class_info = AuthoringData.constr_class_info(ifc_class)
|
||||||
if relating_type_info is None or not relating_type_info.fully_loaded:
|
if constr_class_info is None or not constr_class_info.fully_loaded:
|
||||||
AuthoringData.assetize_constr_class(ifc_class)
|
AuthoringData.assetize_constr_class(ifc_class)
|
||||||
bpy.ops.bim.display_constr_types_ui("INVOKE_DEFAULT")
|
bpy.ops.bim.display_constr_types_ui("INVOKE_DEFAULT")
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ class DumbProfileGenerator:
|
|||||||
def __init__(self, relating_type):
|
def __init__(self, relating_type):
|
||||||
self.relating_type = relating_type
|
self.relating_type = relating_type
|
||||||
|
|
||||||
def generate(self):
|
def generate(self, link_to_scene=True):
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(IfcStore.get_file())
|
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(IfcStore.get_file())
|
||||||
material = ifcopenshell.util.element.get_material(self.relating_type)
|
material = ifcopenshell.util.element.get_material(self.relating_type)
|
||||||
@@ -114,13 +114,13 @@ class DumbProfileGenerator:
|
|||||||
self.rotation = 0
|
self.rotation = 0
|
||||||
self.location = Vector((0, 0, 0))
|
self.location = Vector((0, 0, 0))
|
||||||
self.cardinal_point = int(bpy.context.scene.BIMModelProperties.cardinal_point)
|
self.cardinal_point = int(bpy.context.scene.BIMModelProperties.cardinal_point)
|
||||||
return self.derive_from_cursor()
|
return self.derive_from_cursor(link_to_scene=link_to_scene)
|
||||||
|
|
||||||
def derive_from_cursor(self):
|
def derive_from_cursor(self, link_to_scene):
|
||||||
self.location = bpy.context.scene.cursor.location
|
self.location = bpy.context.scene.cursor.location
|
||||||
return self.create_profile()
|
return self.create_profile(link_to_scene)
|
||||||
|
|
||||||
def create_profile(self):
|
def create_profile(self, link_to_scene):
|
||||||
ifc_classes = ifcopenshell.util.type.get_applicable_entities(self.relating_type.is_a(), self.file.schema)
|
ifc_classes = ifcopenshell.util.type.get_applicable_entities(self.relating_type.is_a(), self.file.schema)
|
||||||
# Standard cases are deprecated, so let's cull them
|
# Standard cases are deprecated, so let's cull them
|
||||||
ifc_class = [c for c in ifc_classes if "StandardCase" not in c][0]
|
ifc_class = [c for c in ifc_classes if "StandardCase" not in c][0]
|
||||||
@@ -128,10 +128,11 @@ class DumbProfileGenerator:
|
|||||||
mesh = bpy.data.meshes.new("Dummy")
|
mesh = bpy.data.meshes.new("Dummy")
|
||||||
obj = bpy.data.objects.new(tool.Model.generate_occurrence_name(self.relating_type, ifc_class), mesh)
|
obj = bpy.data.objects.new(tool.Model.generate_occurrence_name(self.relating_type, ifc_class), mesh)
|
||||||
obj.location = self.location
|
obj.location = self.location
|
||||||
if self.collection_obj and self.collection_obj.BIMObjectProperties.ifc_definition_id:
|
if link_to_scene and self.collection_obj and self.collection_obj.BIMObjectProperties.ifc_definition_id:
|
||||||
obj.location[2] = self.collection_obj.location[2]
|
obj.location[2] = self.collection_obj.location[2]
|
||||||
bpy.context.view_layer.update()
|
bpy.context.view_layer.update()
|
||||||
self.collection.objects.link(obj)
|
if link_to_scene:
|
||||||
|
self.collection.objects.link(obj)
|
||||||
|
|
||||||
element = blenderbim.core.root.assign_class(
|
element = blenderbim.core.root.assign_class(
|
||||||
tool.Ifc,
|
tool.Ifc,
|
||||||
@@ -186,7 +187,8 @@ class DumbProfileGenerator:
|
|||||||
ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"Engine": "BlenderBIM.DumbProfile"})
|
ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"Engine": "BlenderBIM.DumbProfile"})
|
||||||
MaterialData.load(self.file)
|
MaterialData.load(self.file)
|
||||||
|
|
||||||
obj.select_set(True)
|
if link_to_scene:
|
||||||
|
obj.select_set(True)
|
||||||
|
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
from blenderbim.bim.module.model.data import AuthoringData
|
from blenderbim.bim.module.model.data import AuthoringData
|
||||||
|
from blenderbim.bim.module.model.root import ConstrTypeEntityNotFound
|
||||||
from bpy.types import PropertyGroup
|
from bpy.types import PropertyGroup
|
||||||
|
|
||||||
|
|
||||||
@@ -42,14 +43,21 @@ def get_relating_type_browser(self, context):
|
|||||||
def update_icon_id(self, context, browser=False):
|
def update_icon_id(self, context, browser=False):
|
||||||
ifc_class = self.ifc_class_browser if browser else self.ifc_class
|
ifc_class = self.ifc_class_browser if browser else self.ifc_class
|
||||||
relating_type_id = self.relating_type_id_browser if browser else self.relating_type_id
|
relating_type_id = self.relating_type_id_browser if browser else self.relating_type_id
|
||||||
relating_type = AuthoringData.relating_type_name_by_id(ifc_class, relating_type_id)
|
# relating_type = AuthoringData.relating_type_name_by_id(ifc_class, relating_type_id)
|
||||||
if (
|
|
||||||
ifc_class not in AuthoringData.data["preview_constr_types"]
|
if ifc_class not in self.constr_classes or relating_type_id not in self.constr_classes[ifc_class].constr_types:
|
||||||
or relating_type_id not in AuthoringData.data["preview_constr_types"][ifc_class]
|
try:
|
||||||
) and relating_type is not None:
|
AuthoringData.assetize_relating_type_from_selection(browser=browser)
|
||||||
if not AuthoringData.assetize_relating_type_from_selection(browser=browser):
|
except ConstrTypeEntityNotFound:
|
||||||
return
|
return
|
||||||
self.icon_id = AuthoringData.data["preview_constr_types"][ifc_class][relating_type_id]["icon_id"]
|
|
||||||
|
def set_icon(update_interval_seconds=0.0001):
|
||||||
|
if ifc_class not in self.constr_classes or relating_type_id not in self.constr_classes[ifc_class].constr_types:
|
||||||
|
return update_interval_seconds
|
||||||
|
else:
|
||||||
|
self.icon_id = self.constr_classes[ifc_class].constr_types[relating_type_id].icon_id
|
||||||
|
|
||||||
|
bpy.app.timers.register(set_icon)
|
||||||
|
|
||||||
|
|
||||||
def update_ifc_class(self, context):
|
def update_ifc_class(self, context):
|
||||||
@@ -65,8 +73,9 @@ def update_ifc_class_browser(self, context):
|
|||||||
if self.updating:
|
if self.updating:
|
||||||
return
|
return
|
||||||
ifc_class = self.ifc_class_browser
|
ifc_class = self.ifc_class_browser
|
||||||
relating_type_info = AuthoringData.relating_type_info(ifc_class)
|
constr_class_info = AuthoringData.constr_class_info(ifc_class)
|
||||||
if relating_type_info is None or not relating_type_info.fully_loaded:
|
|
||||||
|
if constr_class_info is None or not constr_class_info.fully_loaded:
|
||||||
AuthoringData.assetize_constr_class(ifc_class)
|
AuthoringData.assetize_constr_class(ifc_class)
|
||||||
|
|
||||||
|
|
||||||
@@ -89,16 +98,32 @@ def update_relating_type_by_name(self, context):
|
|||||||
self.relating_type_id = relating_type_id
|
self.relating_type_id = relating_type_id
|
||||||
|
|
||||||
|
|
||||||
|
def get_constr_class_info(props, ifc_class):
|
||||||
|
return props.constr_classes[ifc_class] if ifc_class in props.constr_classes else None
|
||||||
|
|
||||||
|
|
||||||
def update_preview_multiple(self, context):
|
def update_preview_multiple(self, context):
|
||||||
if self.preview_multiple_constr_types:
|
if self.preview_multiple_constr_types:
|
||||||
ifc_class = self.ifc_class
|
ifc_class = self.ifc_class
|
||||||
relating_type_info = AuthoringData.relating_type_info(ifc_class)
|
constr_class_info = get_constr_class_info(self, ifc_class)
|
||||||
if relating_type_info is None or not relating_type_info.fully_loaded:
|
if constr_class_info is None or not constr_class_info.fully_loaded:
|
||||||
AuthoringData.assetize_constr_class(ifc_class)
|
AuthoringData.assetize_constr_class(ifc_class)
|
||||||
else:
|
else:
|
||||||
update_relating_type(self, context)
|
update_relating_type(self, context)
|
||||||
|
|
||||||
|
|
||||||
|
class ConstrTypeInfo(PropertyGroup):
|
||||||
|
name: bpy.props.StringProperty(name="Construction type ID")
|
||||||
|
icon_id: bpy.props.IntProperty(name="Icon ID")
|
||||||
|
object: bpy.props.PointerProperty(name="Object", type=bpy.types.Object)
|
||||||
|
|
||||||
|
|
||||||
|
class ConstrClassInfo(PropertyGroup):
|
||||||
|
name: bpy.props.StringProperty(name="Construction class")
|
||||||
|
constr_types: bpy.props.CollectionProperty(type=ConstrTypeInfo)
|
||||||
|
fully_loaded: bpy.props.BoolProperty(default=False)
|
||||||
|
|
||||||
|
|
||||||
class BIMModelProperties(PropertyGroup):
|
class BIMModelProperties(PropertyGroup):
|
||||||
ifc_class: bpy.props.EnumProperty(items=get_ifc_class, name="Construction Class", update=update_ifc_class)
|
ifc_class: bpy.props.EnumProperty(items=get_ifc_class, name="Construction Class", update=update_ifc_class)
|
||||||
ifc_class_browser: bpy.props.EnumProperty(
|
ifc_class_browser: bpy.props.EnumProperty(
|
||||||
@@ -120,6 +145,7 @@ class BIMModelProperties(PropertyGroup):
|
|||||||
)
|
)
|
||||||
occurrence_name_function: bpy.props.StringProperty(name="Occurrence Name Function")
|
occurrence_name_function: bpy.props.StringProperty(name="Occurrence Name Function")
|
||||||
getter_enum = {"ifc_class": get_ifc_class, "relating_type": get_relating_type}
|
getter_enum = {"ifc_class": get_ifc_class, "relating_type": get_relating_type}
|
||||||
|
constr_classes: bpy.props.CollectionProperty(type=ConstrClassInfo)
|
||||||
extrusion_depth: bpy.props.FloatProperty(default=42.0)
|
extrusion_depth: bpy.props.FloatProperty(default=42.0)
|
||||||
cardinal_point: bpy.props.EnumProperty(
|
cardinal_point: bpy.props.EnumProperty(
|
||||||
items=(
|
items=(
|
||||||
@@ -148,13 +174,3 @@ class BIMModelProperties(PropertyGroup):
|
|||||||
default="5",
|
default="5",
|
||||||
)
|
)
|
||||||
length: bpy.props.FloatProperty(default=42.0)
|
length: bpy.props.FloatProperty(default=42.0)
|
||||||
|
|
||||||
|
|
||||||
def get_relating_type_info(self, context):
|
|
||||||
return AuthoringData.relating_types(ifc_class=self.name)
|
|
||||||
|
|
||||||
|
|
||||||
class ConstrTypeInfo(PropertyGroup):
|
|
||||||
name: bpy.props.StringProperty(name="Construction class")
|
|
||||||
relating_type: bpy.props.EnumProperty(name="Construction type", items=get_relating_type_info)
|
|
||||||
fully_loaded: bpy.props.BoolProperty(default=False)
|
|
||||||
|
|||||||
@@ -48,3 +48,8 @@ def sync_name(usecase_path, ifc_file, settings):
|
|||||||
collection.name = new_name
|
collection.name = new_name
|
||||||
obj.name = new_name
|
obj.name = new_name
|
||||||
blenderbim.bim.handler.refresh_ui_data()
|
blenderbim.bim.handler.refresh_ui_data()
|
||||||
|
|
||||||
|
|
||||||
|
class ConstrTypeEntityNotFound(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ class DumbSlabGenerator:
|
|||||||
def __init__(self, relating_type):
|
def __init__(self, relating_type):
|
||||||
self.relating_type = relating_type
|
self.relating_type = relating_type
|
||||||
|
|
||||||
def generate(self):
|
def generate(self, link_to_scene=True):
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(IfcStore.get_file())
|
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(IfcStore.get_file())
|
||||||
thicknesses = []
|
thicknesses = []
|
||||||
@@ -204,13 +204,13 @@ class DumbSlabGenerator:
|
|||||||
self.length = 3
|
self.length = 3
|
||||||
self.rotation = 0
|
self.rotation = 0
|
||||||
self.location = Vector((0, 0, 0))
|
self.location = Vector((0, 0, 0))
|
||||||
return self.derive_from_cursor()
|
return self.derive_from_cursor(link_to_scene=link_to_scene)
|
||||||
|
|
||||||
def derive_from_cursor(self):
|
def derive_from_cursor(self, link_to_scene):
|
||||||
self.location = bpy.context.scene.cursor.location
|
self.location = bpy.context.scene.cursor.location
|
||||||
return self.create_slab()
|
return self.create_slab(link_to_scene)
|
||||||
|
|
||||||
def create_slab(self):
|
def create_slab(self, link_to_scene):
|
||||||
verts = [
|
verts = [
|
||||||
Vector((0, 0, 0)),
|
Vector((0, 0, 0)),
|
||||||
Vector((0, self.width, 0)),
|
Vector((0, self.width, 0)),
|
||||||
@@ -232,12 +232,13 @@ class DumbSlabGenerator:
|
|||||||
modifier.offset = 1
|
modifier.offset = 1
|
||||||
modifier.thickness = self.depth
|
modifier.thickness = self.depth
|
||||||
|
|
||||||
obj.location = self.location
|
if link_to_scene:
|
||||||
if self.collection_obj and self.collection_obj.BIMObjectProperties.ifc_definition_id:
|
obj.location = self.location
|
||||||
obj.location[2] = self.collection_obj.location[2] - self.depth
|
if self.collection_obj and self.collection_obj.BIMObjectProperties.ifc_definition_id:
|
||||||
else:
|
obj.location[2] = self.collection_obj.location[2] - self.depth
|
||||||
obj.location[2] -= self.depth
|
else:
|
||||||
self.collection.objects.link(obj)
|
obj.location[2] -= self.depth
|
||||||
|
self.collection.objects.link(obj)
|
||||||
bpy.ops.bim.assign_class(
|
bpy.ops.bim.assign_class(
|
||||||
obj=obj.name,
|
obj=obj.name,
|
||||||
ifc_class=ifc_class,
|
ifc_class=ifc_class,
|
||||||
|
|||||||
@@ -69,11 +69,10 @@ class DisplayConstrTypesUI(Operator):
|
|||||||
row.label(text=name, icon="FILE_3D")
|
row.label(text=name, icon="FILE_3D")
|
||||||
row.alignment = "CENTER"
|
row.alignment = "CENTER"
|
||||||
row = box.row()
|
row = box.row()
|
||||||
preview_constr_types = AuthoringData.data["preview_constr_types"]
|
if ifc_class in props.constr_classes:
|
||||||
if ifc_class in preview_constr_types:
|
constr_class_info = props.constr_classes[ifc_class]
|
||||||
preview_ifc_class = preview_constr_types[ifc_class]
|
if relating_type_id in constr_class_info.constr_types:
|
||||||
if relating_type_id in preview_ifc_class:
|
icon_id = constr_class_info.constr_types[relating_type_id].icon_id
|
||||||
icon_id = preview_ifc_class[relating_type_id]["icon_id"]
|
|
||||||
row.template_icon(icon_value=icon_id, scale=6.0)
|
row.template_icon(icon_value=icon_id, scale=6.0)
|
||||||
row = box.row()
|
row = box.row()
|
||||||
op = row.operator("bim.add_constr_type_instance", icon="ADD")
|
op = row.operator("bim.add_constr_type_instance", icon="ADD")
|
||||||
|
|||||||
@@ -413,7 +413,7 @@ class DumbWallGenerator:
|
|||||||
def __init__(self, relating_type):
|
def __init__(self, relating_type):
|
||||||
self.relating_type = relating_type
|
self.relating_type = relating_type
|
||||||
|
|
||||||
def generate(self):
|
def generate(self, link_to_scene=True):
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
self.layers = get_material_layer_parameters(self.relating_type)
|
self.layers = get_material_layer_parameters(self.relating_type)
|
||||||
if not self.layers["thickness"]:
|
if not self.layers["thickness"]:
|
||||||
@@ -433,7 +433,7 @@ class DumbWallGenerator:
|
|||||||
if self.has_sketch():
|
if self.has_sketch():
|
||||||
return # For now
|
return # For now
|
||||||
return self.derive_from_sketch()
|
return self.derive_from_sketch()
|
||||||
return self.derive_from_cursor()
|
return self.derive_from_cursor(link_to_scene)
|
||||||
|
|
||||||
def has_sketch(self):
|
def has_sketch(self):
|
||||||
return (
|
return (
|
||||||
@@ -511,7 +511,7 @@ class DumbWallGenerator:
|
|||||||
def is_near(self, point1, point2):
|
def is_near(self, point1, point2):
|
||||||
return (point1 - point2).length < 0.1
|
return (point1 - point2).length < 0.1
|
||||||
|
|
||||||
def derive_from_cursor(self):
|
def derive_from_cursor(self, link_to_scene):
|
||||||
self.location = bpy.context.scene.cursor.location
|
self.location = bpy.context.scene.cursor.location
|
||||||
if self.collection:
|
if self.collection:
|
||||||
for sibling_obj in self.collection.objects:
|
for sibling_obj in self.collection.objects:
|
||||||
@@ -537,18 +537,19 @@ class DumbWallGenerator:
|
|||||||
normal = (sibling_obj.matrix_world.to_quaternion() @ face.normal).normalized()
|
normal = (sibling_obj.matrix_world.to_quaternion() @ face.normal).normalized()
|
||||||
self.rotation = math.atan2(normal[1], normal[0])
|
self.rotation = math.atan2(normal[1], normal[0])
|
||||||
break
|
break
|
||||||
return self.create_wall()
|
return self.create_wall(link_to_scene)
|
||||||
|
|
||||||
def create_wall(self):
|
def create_wall(self, link_to_scene):
|
||||||
ifc_class = self.get_relating_type_class(self.relating_type)
|
ifc_class = self.get_relating_type_class(self.relating_type)
|
||||||
mesh = bpy.data.meshes.new("Dummy")
|
mesh = bpy.data.meshes.new("Dummy")
|
||||||
obj = bpy.data.objects.new(tool.Model.generate_occurrence_name(self.relating_type, ifc_class), mesh)
|
obj = bpy.data.objects.new(tool.Model.generate_occurrence_name(self.relating_type, ifc_class), mesh)
|
||||||
obj.location = self.location
|
if link_to_scene:
|
||||||
obj.rotation_euler[2] = self.rotation
|
obj.location = self.location
|
||||||
if self.collection_obj and self.collection_obj.BIMObjectProperties.ifc_definition_id:
|
obj.rotation_euler[2] = self.rotation
|
||||||
obj.location[2] = self.collection_obj.location[2]
|
if self.collection_obj and self.collection_obj.BIMObjectProperties.ifc_definition_id:
|
||||||
bpy.context.view_layer.update()
|
obj.location[2] = self.collection_obj.location[2]
|
||||||
self.collection.objects.link(obj)
|
bpy.context.view_layer.update()
|
||||||
|
self.collection.objects.link(obj)
|
||||||
|
|
||||||
element = blenderbim.core.root.assign_class(
|
element = blenderbim.core.root.assign_class(
|
||||||
tool.Ifc,
|
tool.Ifc,
|
||||||
|
|||||||
Reference in New Issue
Block a user