mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-19 14:41:25 +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 = (
|
classes = (
|
||||||
operator.AssignContainer,
|
operator.AssignContainer,
|
||||||
operator.ChangeSpatialLevel,
|
operator.ChangeSpatialLevel,
|
||||||
|
operator.ContractContainer,
|
||||||
operator.CopyToContainer,
|
operator.CopyToContainer,
|
||||||
|
operator.DeleteContainer,
|
||||||
operator.DereferenceStructure,
|
operator.DereferenceStructure,
|
||||||
operator.DisableEditingContainer,
|
operator.DisableEditingContainer,
|
||||||
|
operator.EditContainerAttributes,
|
||||||
operator.EnableEditingContainer,
|
operator.EnableEditingContainer,
|
||||||
|
operator.ExpandContainer,
|
||||||
|
operator.LoadContainerManager,
|
||||||
operator.ReferenceStructure,
|
operator.ReferenceStructure,
|
||||||
operator.RemoveContainer,
|
operator.RemoveContainer,
|
||||||
operator.SelectContainer,
|
operator.SelectContainer,
|
||||||
operator.SelectSimilarContainer,
|
|
||||||
operator.SelectProduct,
|
|
||||||
operator.LoadContainerManager,
|
|
||||||
operator.EditContainerAttributes,
|
|
||||||
operator.AddBuildingStorey,
|
|
||||||
operator.ContractContainer,
|
|
||||||
operator.ExpandContainer,
|
|
||||||
operator.DeleteContainer,
|
|
||||||
operator.SelectDecomposedElements,
|
operator.SelectDecomposedElements,
|
||||||
|
operator.SelectProduct,
|
||||||
|
operator.SelectSimilarContainer,
|
||||||
prop.SpatialElement,
|
prop.SpatialElement,
|
||||||
|
prop.Element,
|
||||||
prop.BIMSpatialProperties,
|
prop.BIMSpatialProperties,
|
||||||
prop.BIMObjectSpatialProperties,
|
prop.BIMObjectSpatialProperties,
|
||||||
prop.BIMContainer,
|
prop.BIMContainer,
|
||||||
@@ -46,6 +46,7 @@ classes = (
|
|||||||
ui.BIM_PT_spatial,
|
ui.BIM_PT_spatial,
|
||||||
ui.BIM_UL_containers,
|
ui.BIM_UL_containers,
|
||||||
ui.BIM_UL_containers_manager,
|
ui.BIM_UL_containers_manager,
|
||||||
|
ui.BIM_UL_elements,
|
||||||
ui.BIM_PT_project_tree,
|
ui.BIM_PT_project_tree,
|
||||||
workspace.Hotkey,
|
workspace.Hotkey,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -227,26 +227,6 @@ class DeleteContainer(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
core.delete_container(tool.Ifc, tool.Spatial, tool.Geometry, container=tool.Ifc.get().by_id(self.container))
|
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):
|
class SelectDecomposedElements(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
bl_idname = "bim.select_decomposed_elements"
|
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)
|
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):
|
def update_relating_container_from_object(self, context):
|
||||||
if self.relating_container_object is None or context.active_object is None:
|
if self.relating_container_object is None or context.active_object is None:
|
||||||
return
|
return
|
||||||
@@ -105,13 +109,23 @@ class BIMContainer(PropertyGroup):
|
|||||||
ifc_definition_id: IntProperty(name="IFC Definition ID")
|
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):
|
class BIMProjectTreeProperties(PropertyGroup):
|
||||||
containers: CollectionProperty(name="Containers", type=BIMContainer)
|
containers: CollectionProperty(name="Containers", type=BIMContainer)
|
||||||
contracted_containers: StringProperty(name="Contracted containers", default="[]")
|
contracted_containers: StringProperty(name="Contracted containers", default="[]")
|
||||||
expanded_containers: StringProperty(name="Expanded 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
|
@property
|
||||||
def active_container(self):
|
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]
|
return self.containers[self.active_container_index]
|
||||||
|
|||||||
@@ -102,23 +102,30 @@ class BIM_PT_project_tree(Panel):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
return tool.Ifc.get() and tool.Ifc.schema().name() != "IFC2X3"
|
return tool.Ifc.get()
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
if not ProjectTreeData.is_loaded:
|
if not ProjectTreeData.is_loaded:
|
||||||
ProjectTreeData.load()
|
ProjectTreeData.load()
|
||||||
self.props = context.scene.BIMProjectTreeProperties
|
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:
|
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 = self.layout.row(align=True)
|
||||||
row.alignment = "RIGHT"
|
row.label(
|
||||||
row.operator("bim.select_decomposed_elements", icon="RESTRICT_SELECT_OFF", text="")
|
text=f"Active {self.props.active_container.ifc_class}: {self.props.active_container.name}",
|
||||||
spatial_data = ProjectTreeData.data["containers"].get(ifc_definition_id, None)
|
icon="OUTLINER_COLLECTION",
|
||||||
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.select_decomposed_elements", icon="HIDE_OFF", text="")
|
||||||
row.operator("bim.delete_container", icon="X", text="").container = ifc_definition_id
|
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(
|
self.layout.template_list(
|
||||||
"BIM_UL_containers_manager",
|
"BIM_UL_containers_manager",
|
||||||
"",
|
"",
|
||||||
@@ -126,6 +133,32 @@ class BIM_PT_project_tree(Panel):
|
|||||||
"containers",
|
"containers",
|
||||||
self.props,
|
self.props,
|
||||||
"active_container_index",
|
"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:
|
if item:
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
self.draw_hierarchy(row, item)
|
self.draw_hierarchy(row, item)
|
||||||
split1 = row.split(factor=0.7)
|
row.prop(item, "name", emboss=False, text="")
|
||||||
split1.prop(item, "name", emboss=False, text="")
|
row.prop(item, "long_name", emboss=False, text="")
|
||||||
split2 = row.split(factor=1)
|
col = row.column()
|
||||||
split2.alignment = "RIGHT"
|
col.alignment = "RIGHT"
|
||||||
split2.prop(item, "elevation", emboss=False, text="")
|
col.prop(item, "elevation", emboss=False, text="")
|
||||||
|
|
||||||
def draw_hierarchy(self, row, item):
|
def draw_hierarchy(self, row, item):
|
||||||
for i in range(0, item.level_index):
|
for i in range(0, item.level_index):
|
||||||
@@ -164,3 +197,22 @@ class BIM_UL_containers_manager(UIList):
|
|||||||
row.label(text="", icon="ANTIALIASED")
|
row.label(text="", icon="ANTIALIASED")
|
||||||
else:
|
else:
|
||||||
row.label(text="", icon="META_PLANE")
|
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 can_reference(cls, structure, element): pass
|
||||||
def contract_container(cls, container): pass
|
def contract_container(cls, container): pass
|
||||||
def copy_xy(cls, src_obj, destination_obj): 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 deselect_objects(cls): pass
|
||||||
def disable_editing(cls, obj): pass
|
def disable_editing(cls, obj): pass
|
||||||
def duplicate_object_and_data(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]
|
z = src_obj.location[2]
|
||||||
src_obj.location = (destination_obj.location[0], destination_obj.location[1], z)
|
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
|
@classmethod
|
||||||
def load_container_manager(cls):
|
def load_container_manager(cls):
|
||||||
props = bpy.context.scene.BIMProjectTreeProperties
|
props = bpy.context.scene.BIMProjectTreeProperties
|
||||||
|
|||||||
Reference in New Issue
Block a user