Spatial manager now shows aggregated objects inside selected space

This commit is contained in:
Dion Moult
2024-06-05 13:04:35 +10:00
parent dc8ea31138
commit 05ec36a37d
6 changed files with 127 additions and 46 deletions
@@ -22,23 +22,23 @@ from . import ui, prop, operator, workspace
classes = (
operator.AssignContainer,
operator.ChangeSpatialLevel,
operator.ContractContainer,
operator.CopyToContainer,
operator.DeleteContainer,
operator.DereferenceStructure,
operator.DisableEditingContainer,
operator.EditContainerAttributes,
operator.EnableEditingContainer,
operator.ExpandContainer,
operator.LoadContainerManager,
operator.ReferenceStructure,
operator.RemoveContainer,
operator.SelectContainer,
operator.SelectSimilarContainer,
operator.SelectProduct,
operator.LoadContainerManager,
operator.EditContainerAttributes,
operator.AddBuildingStorey,
operator.ContractContainer,
operator.ExpandContainer,
operator.DeleteContainer,
operator.SelectDecomposedElements,
operator.SelectProduct,
operator.SelectSimilarContainer,
prop.SpatialElement,
prop.Element,
prop.BIMSpatialProperties,
prop.BIMObjectSpatialProperties,
prop.BIMContainer,
@@ -46,6 +46,7 @@ classes = (
ui.BIM_PT_spatial,
ui.BIM_UL_containers,
ui.BIM_UL_containers_manager,
ui.BIM_UL_elements,
ui.BIM_PT_project_tree,
workspace.Hotkey,
)
@@ -227,26 +227,6 @@ class DeleteContainer(bpy.types.Operator, tool.Ifc.Operator):
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)
class SelectDecomposedElements(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.select_decomposed_elements"
@@ -49,6 +49,10 @@ def update_name(self, context):
tool.Spatial.edit_container_name(tool.Ifc.get().by_id(ifc_definition_id), self.name)
def update_active_container_index(self, context):
tool.Spatial.load_contained_elements()
def update_relating_container_from_object(self, context):
if self.relating_container_object is None or context.active_object is None:
return
@@ -105,13 +109,23 @@ class BIMContainer(PropertyGroup):
ifc_definition_id: IntProperty(name="IFC Definition ID")
class Element(PropertyGroup):
name: StringProperty(name="Name")
is_class: BoolProperty(name="Is Class", default=False)
is_type: BoolProperty(name="Is Type", default=False)
total: IntProperty(name="Total")
class BIMProjectTreeProperties(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")
active_container_index: IntProperty(name="Active Container Index", update=update_active_container_index)
elements: CollectionProperty(name="Elements", type=Element)
active_element_index: IntProperty(name="Active Element Index")
total_elements: IntProperty(name="Total Elements")
@property
def active_container(self):
if self.active_container_index < len(self.containers):
if self.containers and self.active_container_index < len(self.containers):
return self.containers[self.active_container_index]
@@ -102,23 +102,30 @@ class BIM_PT_project_tree(Panel):
@classmethod
def poll(cls, context):
return tool.Ifc.get() and tool.Ifc.schema().name() != "IFC2X3"
return tool.Ifc.get()
def draw(self, context):
if not ProjectTreeData.is_loaded:
ProjectTreeData.load()
self.props = context.scene.BIMProjectTreeProperties
row = self.layout.row()
row.operator("bim.load_container_manager", icon="FILE_REFRESH", text="Load Spatial Structure")
if self.props.active_container:
ifc_definition_id = self.props.containers[self.props.active_container_index].ifc_definition_id
row = self.layout.row(align=True)
row.alignment = "RIGHT"
row.operator("bim.select_decomposed_elements", icon="RESTRICT_SELECT_OFF", text="")
spatial_data = ProjectTreeData.data["containers"].get(ifc_definition_id, None)
if spatial_data and spatial_data["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="").container = ifc_definition_id
row.label(
text=f"Active {self.props.active_container.ifc_class}: {self.props.active_container.name}",
icon="OUTLINER_COLLECTION",
)
row.operator("bim.select_decomposed_elements", icon="HIDE_OFF", text="")
row.operator("bim.delete_container", icon="X", text="").container = (
self.props.active_container.ifc_definition_id
)
row.operator("bim.load_container_manager", icon="FILE_REFRESH", text="")
else:
row = self.layout.row(align=True)
row.label(text="Warning: No Active Container", icon="ERROR")
row.operator("bim.load_container_manager", icon="FILE_REFRESH", text="")
self.layout.template_list(
"BIM_UL_containers_manager",
"",
@@ -126,6 +133,32 @@ class BIM_PT_project_tree(Panel):
"containers",
self.props,
"active_container_index",
rows=10,
)
if not self.props.active_container:
return
# spatial_data = ProjectTreeData.data["containers"].get(ifc_definition_id, None)
# if spatial_data and spatial_data["type"] in ["IfcBuildingStorey", "IfcBuilding"]:
# row.operator("bim.add_building_storey", icon="ADD", text="Add storey").part_class = "IfcBuildingStorey"
if not self.props.total_elements:
row = self.layout.row()
row.label(text="No Contained Elements", icon="FILE_3D")
return
row = self.layout.row(align=True)
row.label(text=f"{self.props.total_elements} Contained Elements", icon="FILE_3D")
row.operator("bim.select_decomposed_elements", icon="RESTRICT_SELECT_OFF", text="")
self.layout.template_list(
"BIM_UL_elements",
"",
self.props,
"elements",
self.props,
"active_element_index",
)
@@ -134,11 +167,11 @@ class BIM_UL_containers_manager(UIList):
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.alignment = "RIGHT"
split2.prop(item, "elevation", emboss=False, text="")
row.prop(item, "name", emboss=False, text="")
row.prop(item, "long_name", emboss=False, text="")
col = row.column()
col.alignment = "RIGHT"
col.prop(item, "elevation", emboss=False, text="")
def draw_hierarchy(self, row, item):
for i in range(0, item.level_index):
@@ -164,3 +197,22 @@ class BIM_UL_containers_manager(UIList):
row.label(text="", icon="ANTIALIASED")
else:
row.label(text="", icon="META_PLANE")
class BIM_UL_elements(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
if item:
row = layout.row(align=True)
if item.is_class:
row.label(text="", icon="DISCLOSURE_TRI_DOWN")
row.label(text=item.name)
col = row.column()
col.alignment = "RIGHT"
col.label(text=str(item.total))
elif item.is_type:
row.label(text="", icon="BLANK1")
row.label(text="", icon="DISCLOSURE_TRI_DOWN")
row.label(text=item.name)
col = row.column()
col.alignment = "RIGHT"
col.label(text=str(item.total))
+1 -1
View File
@@ -831,7 +831,7 @@ class Spatial:
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 import_spatial_structure(cls, element, level_index): pass
def deselect_objects(cls): pass
def disable_editing(cls, obj): pass
def duplicate_object_and_data(cls, obj): pass
+34
View File
@@ -206,6 +206,40 @@ 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_contained_elements(cls):
props = bpy.context.scene.BIMProjectTreeProperties
props.elements.clear()
if not (container := props.active_container):
return
container = tool.Ifc.get().by_id(container.ifc_definition_id)
results = {}
for element in ifcopenshell.util.element.get_contained(container):
element_type = ifcopenshell.util.element.get_type(element)
ifc_class = element.is_a()
type_name = element_type.Name or "Unnamed" if element_type else "Untyped"
results.setdefault(ifc_class, {}).setdefault(type_name, 0)
results[ifc_class][type_name] += 1
total_elements = 0
for ifc_class in sorted(results.keys()):
new = props.elements.add()
new.name = ifc_class
new.is_class = True
total = 0
for type_name in sorted(results[ifc_class].keys()):
new2 = props.elements.add()
new2.name = type_name
new2.is_type = True
new2.total = results[ifc_class][type_name]
total += new2.total
new.total = total
total_elements += total
props.total_elements = total_elements
@classmethod
def load_container_manager(cls):
props = bpy.context.scene.BIMProjectTreeProperties