mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 09:21:46 +00:00
Spatial manager now shows aggregated objects inside selected space
This commit is contained in:
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user