Prototype Building Storey Manager #3246

This commit is contained in:
Sigma Dimensions
2023-06-03 21:07:20 +01:00
parent 607172c51d
commit f8f1ba0ae8
12 changed files with 344 additions and 7 deletions
@@ -115,6 +115,8 @@ classes = (
ui.BIM_PT_roof,
ui.LaunchTypeManager,
ui.BIM_MT_model,
ui.BIM_PT_GridsSpatialManager,
ui.BIM_PT_Grids,
grid.BIM_OT_add_object,
stair.BIM_OT_add_object,
stair.BIM_OT_add_clever_stair,
@@ -96,7 +96,7 @@ def add_object(self, context):
obj.BIMObjectProperties.ifc_definition_id = result.id()
class BIM_OT_add_object(Operator):
class BIM_OT_add_object(Operator, tool.Ifc.Operator):
bl_idname = "mesh.add_grid"
bl_label = "IFC Grid"
bl_options = {"REGISTER", "UNDO"}
@@ -108,10 +108,7 @@ class BIM_OT_add_object(Operator):
@classmethod
def poll(cls, context):
return IfcStore.get_file()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
return tool.Ifc.get()
def _execute(self, context):
add_object(self, context)
@@ -137,6 +137,30 @@ class BIM_PT_authoring(Panel):
row.operator("bim.generate_spaces_from_walls")
class BIM_PT_GridsSpatialManager(Panel):
bl_label = "Grids and Containers"
bl_idname = "BIM_PT_GridsSpatialManager"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_options = {"DEFAULT_CLOSED"}
bl_category = "BlenderBIM"
def draw(self, context):
pass
class BIM_PT_Grids(Panel):
bl_label = "Grid Creator"
bl_idname = "BIM_PT_Grids"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_options = {"DEFAULT_CLOSED"}
bl_parent_id = "BIM_PT_GridsSpatialManager"
def draw(self, context):
self.animation_props = context.scene.BIMAnimationProperties
row = self.layout.row()
row.operator("mesh.add_grid", icon="ADD", text="Add Grids")
class BIM_PT_array(bpy.types.Panel):
bl_label = "IFC Array"
bl_idname = "BIM_PT_array"
@@ -31,11 +31,21 @@ classes = (
operator.SelectContainer,
operator.SelectSimilarContainer,
operator.SelectProduct,
operator.LoadContainerManager,
operator.EditContainerAttributes,
operator.AddBuildingStorey,
operator.ContractContainer,
operator.ExpandContainer,
operator.DeleteContainer,
prop.SpatialElement,
prop.BIMSpatialProperties,
prop.BIMObjectSpatialProperties,
prop.BIMContainer,
prop.BIMSpatialManagerProperties,
ui.BIM_PT_spatial,
ui.BIM_UL_containers,
ui.BIM_UL_containers_manager,
ui.BIM_PT_Storeys,
workspace.Hotkey,
)
@@ -45,8 +55,10 @@ def register():
bpy.utils.register_tool(workspace.SpatialTool, after={"bim.annotation_tool"}, separator=False, group=True)
bpy.types.Scene.BIMSpatialProperties = bpy.props.PointerProperty(type=prop.BIMSpatialProperties)
bpy.types.Object.BIMObjectSpatialProperties = bpy.props.PointerProperty(type=prop.BIMObjectSpatialProperties)
bpy.types.Scene.BIMSpatialManagerProperties = bpy.props.PointerProperty(type=prop.BIMSpatialManagerProperties)
def unregister():
del bpy.types.Scene.BIMSpatialProperties
del bpy.types.Object.BIMObjectSpatialProperties
del bpy.types.Scene.BIMSpatialManagerProperties
@@ -36,9 +36,20 @@ class SpatialData:
"is_directly_contained": cls.is_directly_contained(),
"label": cls.label(),
"references": cls.references(),
"containers": cls.containers(),
}
cls.is_loaded = True
@classmethod
def containers(cls):
results = {}
for container in tool.Ifc.get().by_type("IfcSpatialElement"):
results[container.id()] = {
"type": container.is_a(),
"id": container.id(),
}
return results
@classmethod
def get_parent_container_id(cls):
container_id = bpy.context.scene.BIMSpatialProperties.active_container_id
@@ -21,6 +21,8 @@ import ifcopenshell.api
import ifcopenshell.util.element
import blenderbim.tool as tool
import blenderbim.core.spatial as core
import blenderbim.core.geometry
import blenderbim.core.aggregate
import blenderbim.core.root
import blenderbim.bim.handler
from blenderbim.bim.ifc import IfcStore
@@ -171,3 +173,76 @@ class SelectProduct(bpy.types.Operator):
def execute(self, context):
core.select_product(tool.Spatial, product=tool.Ifc.get().by_id(self.product))
return {"FINISHED"}
class LoadContainerManager(bpy.types.Operator):
bl_idname = "bim.load_container_manager"
bl_label = "Load Container Manager"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
core.load_container_manager(tool.Spatial)
return {"FINISHED"}
class EditContainerAttributes(bpy.types.Operator):
bl_idname = "bim.edit_container_attributes"
bl_label = "Edit container attributes"
bl_options = {"REGISTER", "UNDO"}
container: bpy.props.IntProperty()
def execute(self, context):
core.edit_container_attributes(tool.Spatial, entity=tool.Ifc.get().by_id(self.container))
return {"FINISHED"}
class ContractContainer(bpy.types.Operator):
bl_idname = "bim.contract_container"
bl_label = "Contract Container"
bl_options = {"REGISTER", "UNDO"}
container: bpy.props.IntProperty()
def execute(self, context):
core.contract_container(tool.Spatial, container=tool.Ifc.get().by_id(self.container))
return {"FINISHED"}
class ExpandContainer(bpy.types.Operator):
bl_idname = "bim.expand_container"
bl_label = "Expand Container"
bl_options = {"REGISTER", "UNDO"}
container: bpy.props.IntProperty()
def execute(self, context):
core.expand_container(tool.Spatial, container=tool.Ifc.get().by_id(self.container))
return {"FINISHED"}
class DeleteContainer(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.delete_container"
bl_label = "Delete Container"
bl_options = {"REGISTER", "UNDO"}
container: bpy.props.IntProperty()
def _execute(self, context):
core.delete_container(tool.Ifc, tool.Spatial, tool.Geometry, container=tool.Ifc.get().by_id(self.container))
class AddBuildingStorey(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.add_building_storey"
bl_label = "Add Storey"
bl_options = {"REGISTER", "UNDO"}
part_class: bpy.props.StringProperty()
def _execute(self, context):
active_container = tool.Spatial.get_active_container()
obj = tool.Ifc.get_object(active_container)
blenderbim.core.aggregate.add_part_to_object(
tool.Ifc,
tool.Aggregate,
tool.Collector,
tool.Blender,
obj=obj,
part_class=self.part_class,
part_name="Unnamed",
)
core.load_container_manager(tool.Spatial)
@@ -30,6 +30,30 @@ from bpy.props import (
FloatVectorProperty,
CollectionProperty,
)
import blenderbim.tool as tool
import blenderbim.core.geometry
def update_elevation(self, context):
entity = tool.Ifc.get().by_id(self.active_container_id)
obj = tool.Ifc.get_object(entity)
if not obj:
return
obj.location.z = self.elevation
def update_active_container_index(self, context):
self.active_container_id = self.containers[self.active_container_index].ifc_definition_id
self.container_name = self.containers[self.active_container_index].name
self.elevation = self.containers[self.active_container_index].elevation
def updateContainerName(self, context):
props = context.scene.BIMSpatialManagerProperties
if not props.is_container_update_enabled or self.name == "Unnamed":
return
tool.Spatial.edit_container_name(tool.Ifc.get().by_id(props.active_container_id), self.name)
props.container_name = self.name
class SpatialElement(PropertyGroup):
@@ -48,3 +72,23 @@ class BIMSpatialProperties(PropertyGroup):
class BIMObjectSpatialProperties(PropertyGroup):
is_editing: BoolProperty(name="Is Editing")
class BIMContainer(PropertyGroup):
name: StringProperty(name="Name", update=updateContainerName)
elevation: FloatProperty(name="Elevation")
level_index: IntProperty(name="Level Index")
has_children: BoolProperty(name="Has Children")
is_expanded: BoolProperty(name="Is Expanded")
ifc_definition_id: IntProperty(name="IFC Definition ID")
class BIMSpatialManagerProperties(PropertyGroup):
containers: CollectionProperty(name="Containers", type=BIMContainer)
contracted_containers: StringProperty(name="Contracted containers", default="[]")
expanded_containers: StringProperty(name="Expanded containers", default="[]")
active_container_index: IntProperty(name="Active Container Index", update=update_active_container_index)
active_container_id: IntProperty(name="Active Container Id")
container_name: StringProperty(name="Container Name")
elevation: FloatProperty(name="Elevation", update=update_elevation)
is_container_update_enabled: BoolProperty(name="Is Container Update Enabled", default=True) # TODO:review
@@ -19,6 +19,7 @@
from bpy.types import Panel, UIList
from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.module.spatial.data import SpatialData
import blenderbim.tool as tool
class BIM_PT_spatial(Panel):
@@ -93,3 +94,70 @@ class BIM_UL_containers(UIList):
text="",
emboss=False,
)
class BIM_PT_Storeys(Panel):
bl_label = "Spatial Manager"
bl_idname = "BIM_PT_Storeys"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_options = {"DEFAULT_CLOSED"}
bl_parent_id = "BIM_PT_GridsSpatialManager"
@classmethod
def poll(cls, context):
return tool.Ifc.get()
def draw(self, context):
if not SpatialData.is_loaded:
SpatialData.load()
self.props = context.scene.BIMSpatialManagerProperties
row = self.layout.row()
row.operator("bim.load_container_manager", icon="FILE_REFRESH", text="Load Spatial Structure")
if self.props.active_container_index < len(self.props.containers):
ifc_definition_id = self.props.containers[self.props.active_container_index].ifc_definition_id
row = self.layout.row()
row.alignment = "RIGHT"
if SpatialData.data["containers"][ifc_definition_id]["type"] in ["IfcBuildingStorey", "IfcBuilding"]:
row.operator("bim.add_building_storey", icon="ADD", text="Add storey").part_class = "IfcBuildingStorey"
row.operator("bim.delete_container", icon="X", text="Delete").container = ifc_definition_id
self.layout.template_list(
"BIM_UL_containers_manager",
"",
self.props,
"containers",
self.props,
"active_container_index",
)
row = self.layout.row()
if self.props.active_container_index < len(self.props.containers):
row.prop(self.props, "container_name", text="")
row.prop(self.props, "elevation", text="")
op = row.operator("bim.edit_container_attributes", icon="CHECKMARK", text="Apply")
op.container = self.props.containers[self.props.active_container_index].ifc_definition_id
class BIM_UL_containers_manager(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
if item:
row = layout.row(align=True)
self.draw_hierarchy(row, item)
split1 = row.split(factor=0.7)
split1.prop(item, "name", emboss=False, text="")
split2 = row.split(factor=1)
split2.label(text=str(item.elevation), icon="BLANK1")
def draw_hierarchy(self, row, item):
for i in range(0, item.level_index):
row.label(text="", icon="BLANK1")
if item.has_children:
if item.is_expanded:
row.operator(
"bim.contract_container", text="", emboss=False, icon="DISCLOSURE_TRI_DOWN"
).container = item.ifc_definition_id
else:
row.operator(
"bim.expand_container", text="", emboss=False, icon="DISCLOSURE_TRI_RIGHT"
).container = item.ifc_definition_id
else:
row.label(text="", icon="DOT")
+19
View File
@@ -96,3 +96,22 @@ def select_similar_container(ifc, spatial, obj=None):
def select_product(spatial, product):
spatial.select_products([product])
def load_container_manager(spatial):
spatial.load_container_manager()
def edit_container_attributes(spatial, entity=None):
spatial.edit_container_attributes(entity)
spatial.load_container_manager()
def contract_container(spatial, container=None):
spatial.contract_container(container)
spatial.load_container_manager()
def expand_container(spatial, container=None):
spatial.expand_container(container)
spatial.load_container_manager()
def delete_container(ifc, spatial, geometry, container=None):
geometry.delete_ifc_object(ifc.get_object(container))
spatial.load_container_manager()
+8
View File
@@ -747,12 +747,18 @@ class Sequence:
class Spatial:
def can_contain(cls, structure_obj, element_obj): pass
def can_reference(cls, structure, element): pass
def contract_container(cls, container): pass
def copy_xy(cls, src_obj, destination_obj): pass
def create_new_storey_li(cls, element, level_index): pass
def deselect_objects(cls): pass
def disable_editing(cls, obj): pass
def duplicate_object_and_data(cls, obj): pass
def edit_container_attributes(cls, entity): pass
def edit_container_name(cls, container, name): pass
def enable_editing(cls, obj): pass
def expand_container(cls, container): pass
def filter_products(cls, products, action): pass
def get_active_container(cls): pass
def get_container(cls, element): pass
def get_decomposed_elements(cls, container): pass
def get_object_matrix(cls, obj): pass
@@ -760,6 +766,7 @@ class Spatial:
def get_selected_product_types(cls): pass
def get_selected_products(cls): pass
def import_containers(cls, parent=None): pass
def load_container_manager(cls): pass
def run_root_copy_class(cls, obj=None): pass
def run_spatial_assign_container(cls, structure_obj=None, element_obj=None): pass
def select_object(cls, obj): pass
@@ -768,6 +775,7 @@ class Spatial:
def set_relative_object_matrix(cls, target_obj, relative_to_obj, matrix): pass
def show_scene_objects(cls): pass
@interface
class Structural:
def disable_editing_structural_analysis_model(cls): pass
@@ -24,6 +24,7 @@ import numpy as np
import ifcopenshell
import blenderbim.core.tool
import blenderbim.core.style
import blenderbim.core.spatial
import blenderbim.tool as tool
import blenderbim.bim.import_ifc
from mathutils import Vector
@@ -97,12 +98,15 @@ class Geometry(blenderbim.core.tool.Geometry):
if element.VoidsElements:
bpy.ops.bim.remove_opening(opening_id=element.id())
else:
is_spatial = element.is_a("IfcSpatialElement")
if getattr(element, "HasOpenings", None):
for rel in element.HasOpenings:
bpy.ops.bim.remove_opening(opening_id=rel.RelatedOpeningElement.id())
for port in ifcopenshell.util.system.get_ports(element):
blenderbim.core.system.remove_port(tool.Ifc, tool.System, port=port)
ifcopenshell.api.run("root.remove_product", tool.Ifc.get(), product=element)
if is_spatial:
blenderbim.core.spatial.load_container_manager(tool.Spatial)
try:
obj.name
bpy.data.objects.remove(obj)
+75 -2
View File
@@ -22,6 +22,7 @@ import blenderbim.core.tool
import blenderbim.core.root
import blenderbim.core.spatial
import blenderbim.tool as tool
import json
class Spatial(blenderbim.core.tool.Spatial):
@@ -110,6 +111,7 @@ class Spatial(blenderbim.core.tool.Spatial):
new.long_name = element.LongName or ""
new.has_decomposition = bool(element.IsDecomposedBy)
new.ifc_definition_id = element.id()
new.elevation = element[1]
@classmethod
def run_root_copy_class(cls, obj=None):
@@ -151,7 +153,11 @@ class Spatial(blenderbim.core.tool.Spatial):
[obj.select_set(True) for obj in objects]
elif action == "isolate":
[obj.hide_set(False) for obj in objects if bpy.context.view_layer.objects.get(obj.name)]
[obj.hide_set(True) for obj in bpy.context.visible_objects if not obj in objects and bpy.context.view_layer.objects.get(obj.name)] # this is slow
[
obj.hide_set(True)
for obj in bpy.context.visible_objects
if not obj in objects and bpy.context.view_layer.objects.get(obj.name)
] # this is slow
elif action == "unhide":
[obj.hide_set(False) for obj in objects if bpy.context.view_layer.objects.get(obj.name)]
elif action == "hide":
@@ -164,7 +170,11 @@ class Spatial(blenderbim.core.tool.Spatial):
@classmethod
def show_scene_objects(cls):
[obj.hide_set(False) for obj in bpy.data.scenes["Scene"].objects if bpy.context.view_layer.objects.get(obj.name)]
[
obj.hide_set(False)
for obj in bpy.data.scenes["Scene"].objects
if bpy.context.view_layer.objects.get(obj.name)
]
@classmethod
def get_selected_products(cls):
@@ -185,3 +195,66 @@ class Spatial(blenderbim.core.tool.Spatial):
z = src_obj.location[2]
src_obj.location = (destination_obj.location[0], destination_obj.location[1], z)
@classmethod
def load_container_manager(cls):
cls.props = bpy.context.scene.BIMSpatialManagerProperties
cls.props.containers.clear()
cls.contracted_containers = json.loads(cls.props.contracted_containers)
cls.props.is_container_update_enabled = False
parent = tool.Ifc.get().by_type("IfcProject")[0]
for object in ifcopenshell.util.element.get_parts(parent):
if object.is_a("IfcSpatialElement"):
cls.create_new_storey_li(object, 0)
cls.props.is_container_update_enabled = True
@classmethod
def create_new_storey_li(cls, element, level_index):
new = cls.props.containers.add()
new.name = element.Name or "Unnamed"
new.long_name = element.LongName or ""
new.has_decomposition = bool(element.IsDecomposedBy)
new.ifc_definition_id = element.id()
new.elevation = ifcopenshell.util.placement.get_storey_elevation(element)
new.is_expanded = element.id() not in cls.contracted_containers
new.level_index = level_index
if new.has_decomposition:
new.has_children = True
if new.is_expanded:
for related_object in ifcopenshell.util.element.get_parts(element):
if related_object.is_a("IfcSpatialElement"):
cls.create_new_storey_li(related_object, level_index + 1)
@classmethod
def edit_container_attributes(cls, entity):
obj = tool.Ifc.get_object(entity)
blenderbim.core.geometry.edit_object_placement(tool.Ifc, tool.Geometry, tool.Surveyor, obj=obj)
name = bpy.context.scene.BIMSpatialManagerProperties.container_name
if name != entity.Name:
cls.edit_container_name(entity, name)
@classmethod
def edit_container_name(cls, container, name):
tool.Ifc.run("attribute.edit_attributes", product=container, attributes={"Name": name})
@classmethod
def get_active_container(cls):
props = bpy.context.scene.BIMSpatialManagerProperties
if props.active_container_index < len(props.containers):
container = tool.Ifc.get().by_id(props.containers[props.active_container_index].ifc_definition_id)
return container
@classmethod
def contract_container(cls, container):
props = bpy.context.scene.BIMSpatialManagerProperties
contracted_containers = json.loads(props.contracted_containers)
contracted_containers.append(container.id())
props.contracted_containers = json.dumps(contracted_containers)
@classmethod
def expand_container(cls, container):
props = bpy.context.scene.BIMSpatialManagerProperties
contracted_containers = json.loads(props.contracted_containers)
contracted_containers.remove(container.id())
props.contracted_containers = json.dumps(contracted_containers)