mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-06 07:51:47 +00:00
Support adding a child space using the rules of spatial decomposition for each schema
This commit is contained in:
@@ -36,7 +36,6 @@ class AggregateData:
|
||||
"relating_object_label": cls.get_relating_object_label(),
|
||||
"has_related_objects": cls.has_related_objects(),
|
||||
"total_parts": cls.total_parts(),
|
||||
"ifc_class": cls.ifc_class(),
|
||||
"total_linked_aggregate": cls.total_linked_aggregate(),
|
||||
}
|
||||
cls.is_loaded = True
|
||||
@@ -68,12 +67,6 @@ class AggregateData:
|
||||
def has_related_objects(cls) -> bool:
|
||||
return bool(cls.get_related_objects())
|
||||
|
||||
@classmethod
|
||||
def ifc_class(cls) -> str:
|
||||
element = tool.Ifc.get_entity(bpy.context.active_object)
|
||||
if element:
|
||||
return element.is_a()
|
||||
|
||||
@classmethod
|
||||
def total_linked_aggregate(cls):
|
||||
element = tool.Ifc.get_entity(bpy.context.active_object)
|
||||
|
||||
@@ -275,23 +275,23 @@ class BIM_OT_add_part_to_object(bpy.types.Operator, Operator):
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
part_class: bpy.props.StringProperty(name="Class", options={"HIDDEN"})
|
||||
part_name: bpy.props.StringProperty(name="Name")
|
||||
obj: bpy.props.StringProperty(options={"HIDDEN"})
|
||||
element: bpy.props.IntProperty(options={"HIDDEN"})
|
||||
|
||||
def invoke(self, context, event):
|
||||
self.part_name = "My " + self.part_class.lstrip("Ifc")
|
||||
return context.window_manager.invoke_props_dialog(self)
|
||||
|
||||
def _execute(self, context):
|
||||
obj = bpy.data.objects.get(self.obj) or context.active_object
|
||||
core.add_part_to_object(
|
||||
tool.Ifc,
|
||||
tool.Aggregate,
|
||||
tool.Collector,
|
||||
tool.Blender,
|
||||
obj=obj,
|
||||
obj=tool.Ifc.get_object(tool.Ifc.get().by_id(self.element)) if self.element else context.active_object,
|
||||
part_class=self.part_class,
|
||||
part_name=self.part_name,
|
||||
)
|
||||
tool.Spatial.load_container_manager()
|
||||
|
||||
|
||||
class BIM_OT_break_link_to_other_aggregates(bpy.types.Operator, Operator):
|
||||
|
||||
@@ -99,19 +99,6 @@ class BIM_PT_aggregate(Panel):
|
||||
op = row.operator("bim.select_parts", icon="RESTRICT_SELECT_OFF", text="")
|
||||
op.obj = context.active_object.name
|
||||
|
||||
ifc_class = AggregateData.data["ifc_class"]
|
||||
part_class = ""
|
||||
if ifc_class == "IfcBuilding":
|
||||
part_class = "IfcBuildingStorey"
|
||||
elif ifc_class == "IfcSite":
|
||||
part_class = "IfcBuilding"
|
||||
elif ifc_class == "IfcProject":
|
||||
part_class = "IfcSite"
|
||||
if part_class != "":
|
||||
op = layout.operator("bim.add_part_to_object", text="Add " + part_class.lstrip("Ifc"))
|
||||
op.part_class = part_class
|
||||
op.obj = context.active_object.name
|
||||
|
||||
|
||||
class BIM_PT_linked_aggregate(Panel):
|
||||
bl_label = "Linked Aggregates"
|
||||
|
||||
@@ -92,19 +92,71 @@ class ProjectTreeData:
|
||||
def load(cls):
|
||||
cls.is_loaded = True
|
||||
cls.data = {
|
||||
"containers": cls.containers(),
|
||||
"subelement_class": cls.subelement_class(),
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def containers(cls):
|
||||
results = {}
|
||||
def subelement_class(cls):
|
||||
results = []
|
||||
props = bpy.context.scene.BIMProjectTreeProperties
|
||||
if not (container := props.active_container):
|
||||
return results
|
||||
container_class = tool.Ifc.get().by_id(container.ifc_definition_id).is_a()
|
||||
if tool.Ifc.get_schema() == "IFC2X3":
|
||||
spatial_elements = tool.Ifc.get().by_type("IfcSpatialStructureElement")
|
||||
else:
|
||||
spatial_elements = tool.Ifc.get().by_type("IfcSpatialElement")
|
||||
for container in spatial_elements:
|
||||
results[container.id()] = {
|
||||
"type": container.is_a(),
|
||||
"id": container.id(),
|
||||
}
|
||||
return results
|
||||
results = {
|
||||
"IfcBuilding": ["IfcBuilding", "IfcBuildingStorey", "IfcSpace"],
|
||||
"IfcBuildingStorey": ["IfcBuildingStorey", "IfcSpace"],
|
||||
"IfcProject": ["IfcBuilding", "IfcSite", "IfcSpace"],
|
||||
"IfcSite": ["IfcBuilding", "IfcSite", "IfcSpace"],
|
||||
"IfcSpace": ["IfcSpace"],
|
||||
}[container_class]
|
||||
elif tool.Ifc.get_schema() == "IFC4":
|
||||
results = {
|
||||
"IfcBuilding": ["IfcBuilding", "IfcBuildingStorey", "IfcSpace"],
|
||||
"IfcBuildingStorey": ["IfcBuildingStorey", "IfcSpace"],
|
||||
"IfcExternalSpatialElement": ["IfcExternalSpatialElement"],
|
||||
"IfcProject": ["IfcBuilding", "IfcExternalSpatialElement", "IfcSite", "IfcSpace"],
|
||||
"IfcSite": ["IfcBuilding", "IfcExternalSpatialElement", "IfcSite", "IfcSpace"],
|
||||
"IfcSpace": ["IfcSpace"],
|
||||
}[container_class]
|
||||
elif tool.Ifc.get_schema() == "IFC4X3":
|
||||
results = {
|
||||
"IfcBridge": ["IfcBridge", "IfcBridgePart", "IfcSpace"],
|
||||
"IfcBridgePart": ["IfcSpace"],
|
||||
"IfcBuilding": ["IfcBuilding", "IfcBuildingStorey", "IfcSpace"],
|
||||
"IfcBuildingStorey": ["IfcBuildingStorey", "IfcSpace"],
|
||||
"IfcExternalSpatialElement": ["IfcExternalSpatialElement"],
|
||||
"IfcFacility": ["IfcFacility", "IfcFacilityPartCommon", "IfcSpace"],
|
||||
"IfcFacilityPartCommon": ["IfcSpace"],
|
||||
"IfcMarineFacility": ["IfcMarineFacility", "IfcMarinePart", "IfcSpace"],
|
||||
"IfcMarinePart": ["IfcSpace"],
|
||||
"IfcProject": [
|
||||
"IfcBridge",
|
||||
"IfcBuilding",
|
||||
"IfcExternalSpatialElement",
|
||||
"IfcFacility",
|
||||
"IfcMarineFacility",
|
||||
"IfcRailway",
|
||||
"IfcRoad",
|
||||
"IfcSite",
|
||||
"IfcSpace",
|
||||
],
|
||||
"IfcRailway": ["IfcRailway", "IfcRailwayPart", "IfcSpace"],
|
||||
"IfcRailwayPart": ["IfcSpace"],
|
||||
"IfcRoad": ["IfcRoad", "IfcRoadPart", "IfcSpace"],
|
||||
"IfcRoadPart": ["IfcSpace"],
|
||||
"IfcSite": [
|
||||
"IfcBridge",
|
||||
"IfcBuilding",
|
||||
"IfcExternalSpatialElement",
|
||||
"IfcFacility",
|
||||
"IfcMarineFacility",
|
||||
"IfcRailway",
|
||||
"IfcRoad",
|
||||
"IfcSite",
|
||||
"IfcSpace",
|
||||
],
|
||||
"IfcSpace": ["IfcSpace"],
|
||||
}[container_class]
|
||||
|
||||
return [(r, r, "") for r in results]
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
import bpy
|
||||
from blenderbim.bim.prop import StrProperty, Attribute
|
||||
from blenderbim.bim.module.spatial.data import SpatialData
|
||||
from blenderbim.bim.module.spatial.data import ProjectTreeData
|
||||
from bpy.types import PropertyGroup
|
||||
from bpy.props import (
|
||||
PointerProperty,
|
||||
@@ -31,10 +31,15 @@ from bpy.props import (
|
||||
CollectionProperty,
|
||||
)
|
||||
import blenderbim.tool as tool
|
||||
import blenderbim.core.geometry
|
||||
import ifcopenshell
|
||||
|
||||
|
||||
def get_subelement_class(self, context):
|
||||
if not ProjectTreeData.is_loaded:
|
||||
ProjectTreeData.load()
|
||||
return ProjectTreeData.data["subelement_class"]
|
||||
|
||||
|
||||
def update_elevation(self, context):
|
||||
if ifc_definition_id := self.ifc_definition_id:
|
||||
entity = tool.Ifc.get().by_id(ifc_definition_id)
|
||||
@@ -50,6 +55,7 @@ def update_name(self, context):
|
||||
|
||||
|
||||
def update_active_container_index(self, context):
|
||||
ProjectTreeData.data["subelement_class"] = ProjectTreeData.subelement_class()
|
||||
tool.Spatial.load_contained_elements()
|
||||
|
||||
|
||||
@@ -124,6 +130,7 @@ class BIMProjectTreeProperties(PropertyGroup):
|
||||
elements: CollectionProperty(name="Elements", type=Element)
|
||||
active_element_index: IntProperty(name="Active Element Index")
|
||||
total_elements: IntProperty(name="Total Elements")
|
||||
subelement_class: bpy.props.EnumProperty(items=get_subelement_class, name="Subelement Class")
|
||||
|
||||
@property
|
||||
def active_container(self):
|
||||
|
||||
@@ -112,15 +112,23 @@ class BIM_PT_project_tree(Panel):
|
||||
if self.props.active_container:
|
||||
row = self.layout.row(align=True)
|
||||
row.label(
|
||||
text=f"Active {self.props.active_container.ifc_class}: {self.props.active_container.name}",
|
||||
text=f"Active: {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="")
|
||||
|
||||
if self.props.active_container.ifc_class != "IfcProject":
|
||||
row = self.layout.row(align=True)
|
||||
row.operator("bim.select_decomposed_elements", icon="HIDE_OFF", text=f"Isolate {self.props.active_container.ifc_class}")
|
||||
row.operator("bim.delete_container", icon="X", text="").container = (
|
||||
self.props.active_container.ifc_definition_id
|
||||
)
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(self.props, "subelement_class", text="")
|
||||
op = row.operator("bim.add_part_to_object", icon="ADD", text="")
|
||||
op.element = self.props.active_container.ifc_definition_id
|
||||
op.part_class = self.props.subelement_class
|
||||
else:
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="Warning: No Active Container", icon="ERROR")
|
||||
@@ -139,10 +147,6 @@ class BIM_PT_project_tree(Panel):
|
||||
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")
|
||||
@@ -168,7 +172,8 @@ class BIM_UL_containers_manager(UIList):
|
||||
row = layout.row(align=True)
|
||||
self.draw_hierarchy(row, item)
|
||||
row.prop(item, "name", emboss=False, text="")
|
||||
row.prop(item, "long_name", emboss=False, text="")
|
||||
if item.long_name:
|
||||
row.prop(item, "long_name", emboss=False, text="")
|
||||
col = row.column()
|
||||
col.alignment = "RIGHT"
|
||||
col.prop(item, "elevation", emboss=False, text="")
|
||||
@@ -187,7 +192,9 @@ class BIM_UL_containers_manager(UIList):
|
||||
)
|
||||
else:
|
||||
row.label(text="", icon="BLANK1")
|
||||
if item.ifc_class == "IfcSite":
|
||||
if item.ifc_class == "IfcProject":
|
||||
row.label(text="", icon="FILE")
|
||||
elif item.ifc_class == "IfcSite":
|
||||
row.label(text="", icon="WORLD")
|
||||
elif item.ifc_class == "IfcBuilding":
|
||||
row.label(text="", icon="HOME")
|
||||
@@ -195,6 +202,8 @@ class BIM_UL_containers_manager(UIList):
|
||||
row.label(text="", icon="LINENUMBERS_OFF")
|
||||
elif item.ifc_class == "IfcSpace":
|
||||
row.label(text="", icon="ANTIALIASED")
|
||||
elif "Part" in item.ifc_class:
|
||||
row.label(text="", icon="MOD_FLUID")
|
||||
else:
|
||||
row.label(text="", icon="META_PLANE")
|
||||
|
||||
|
||||
@@ -246,14 +246,7 @@ class Spatial(blenderbim.core.tool.Spatial):
|
||||
previous_container_index = props.active_container_index
|
||||
props.containers.clear()
|
||||
cls.contracted_containers = json.loads(props.contracted_containers)
|
||||
props.is_container_update_enabled = False
|
||||
parent = tool.Ifc.get().by_type("IfcProject")[0]
|
||||
|
||||
for subelement in ifcopenshell.util.element.get_parts(parent) or []:
|
||||
if subelement.is_a("IfcSpatialElement") or subelement.is_a("IfcSpatialStructureElement"):
|
||||
cls.import_spatial_structure(subelement, 0)
|
||||
props.is_container_update_enabled = True
|
||||
# triggers spatial manager props setup
|
||||
cls.import_spatial_structure(tool.Ifc.get().by_type("IfcProject")[0], 0)
|
||||
props.active_container_index = min(previous_container_index, len(props.containers) - 1)
|
||||
|
||||
@classmethod
|
||||
@@ -264,7 +257,8 @@ class Spatial(blenderbim.core.tool.Spatial):
|
||||
new.name = element.Name or "Unnamed"
|
||||
new.description = element.Description or ""
|
||||
new.long_name = element.LongName or ""
|
||||
new.elevation = ifcopenshell.util.placement.get_storey_elevation(element)
|
||||
if not element.is_a("IfcProject"):
|
||||
new.elevation = ifcopenshell.util.placement.get_storey_elevation(element)
|
||||
new.is_expanded = element.id() not in cls.contracted_containers
|
||||
new.level_index = level_index
|
||||
children = ifcopenshell.util.element.get_parts(element)
|
||||
|
||||
Reference in New Issue
Block a user