mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-18 22:33:33 +00:00
Simplified handling of Ports in MEP
This commit is contained in:
@@ -21,11 +21,13 @@ from . import ui, prop, operator, decorator
|
|||||||
|
|
||||||
classes = (
|
classes = (
|
||||||
operator.AddPort,
|
operator.AddPort,
|
||||||
|
operator.AddRelatedPortConnection,
|
||||||
operator.AddSystem,
|
operator.AddSystem,
|
||||||
operator.AddZone,
|
operator.AddZone,
|
||||||
operator.AssignSystem,
|
operator.AssignSystem,
|
||||||
operator.AssignUnassignFlowControl,
|
operator.AssignUnassignFlowControl,
|
||||||
operator.ConnectPort,
|
operator.ConnectPort,
|
||||||
|
operator.CycleFlowDirection,
|
||||||
operator.DisableEditingSystem,
|
operator.DisableEditingSystem,
|
||||||
operator.DisableEditingZone,
|
operator.DisableEditingZone,
|
||||||
operator.DisableSystemEditingUI,
|
operator.DisableSystemEditingUI,
|
||||||
@@ -43,6 +45,7 @@ classes = (
|
|||||||
operator.RemoveZone,
|
operator.RemoveZone,
|
||||||
operator.SelectSystemProducts,
|
operator.SelectSystemProducts,
|
||||||
operator.SetFlowDirection,
|
operator.SetFlowDirection,
|
||||||
|
operator.ShowPortFlowError,
|
||||||
operator.ShowPorts,
|
operator.ShowPorts,
|
||||||
operator.UnassignSystem,
|
operator.UnassignSystem,
|
||||||
operator.UnloadZones,
|
operator.UnloadZones,
|
||||||
|
|||||||
@@ -217,7 +217,7 @@ class HidePorts(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
|
|
||||||
class AddPort(bpy.types.Operator, tool.Ifc.Operator):
|
class AddPort(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
bl_idname = "bim.add_port"
|
bl_idname = "bim.add_port"
|
||||||
bl_description = "Add port at current cursor position"
|
bl_description = "Add USERDEFINED port at current cursor position"
|
||||||
bl_label = "Add Port"
|
bl_label = "Add Port"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
@@ -249,6 +249,42 @@ class ConnectPort(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
core.connect_port(tool.Ifc, port1=tool.Ifc.get_entity(obj1), port2=tool.Ifc.get_entity(obj2))
|
core.connect_port(tool.Ifc, port1=tool.Ifc.get_entity(obj1), port2=tool.Ifc.get_entity(obj2))
|
||||||
|
|
||||||
|
|
||||||
|
class AddRelatedPortConnection(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
|
bl_idname = "bim.add_related_port_connection"
|
||||||
|
bl_label = "Connect Port"
|
||||||
|
bl_description = "Click to select a port to connect to"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
|
element_id: bpy.props.IntProperty(default=0, options={"SKIP_SAVE"})
|
||||||
|
|
||||||
|
def invoke(self, context, event):
|
||||||
|
if self.element_id == 0:
|
||||||
|
self.report({'ERROR'}, "No port specified")
|
||||||
|
return {'CANCELLED'}
|
||||||
|
context.window_manager.modal_handler_add(self)
|
||||||
|
return {'RUNNING_MODAL'}
|
||||||
|
|
||||||
|
def modal(self, context, event):
|
||||||
|
if event.type == 'LEFTMOUSE' and event.value == 'PRESS':
|
||||||
|
if context.active_object:
|
||||||
|
target_element = tool.Ifc.get_entity(context.active_object)
|
||||||
|
if target_element and target_element.is_a("IfcDistributionPort"):
|
||||||
|
source_element = tool.Ifc.get().by_id(self.element_id)
|
||||||
|
core.connect_port(tool.Ifc, port1=source_element, port2=target_element)
|
||||||
|
self.report({'INFO'}, "Ports connected")
|
||||||
|
return {'FINISHED'}
|
||||||
|
else:
|
||||||
|
self.report({'WARNING'}, "Selected object is not a port")
|
||||||
|
return {'RUNNING_MODAL'}
|
||||||
|
elif event.type in {'RIGHTMOUSE', 'ESC'}:
|
||||||
|
self.report({'INFO'}, "Cancelled")
|
||||||
|
return {'CANCELLED'}
|
||||||
|
return {'RUNNING_MODAL'}
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
|
return {'CANCELLED'}
|
||||||
|
|
||||||
|
|
||||||
class DisconnectPort(bpy.types.Operator, tool.Ifc.Operator):
|
class DisconnectPort(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
bl_idname = "bim.disconnect_port"
|
bl_idname = "bim.disconnect_port"
|
||||||
bl_label = "Disconnect Ports"
|
bl_label = "Disconnect Ports"
|
||||||
@@ -256,6 +292,9 @@ class DisconnectPort(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
|
|
||||||
element_id: bpy.props.IntProperty(default=0, options={"SKIP_SAVE"})
|
element_id: bpy.props.IntProperty(default=0, options={"SKIP_SAVE"})
|
||||||
|
|
||||||
|
def invoke(self, context, event):
|
||||||
|
return context.window_manager.invoke_confirm(self, event)
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
if self.element_id != 0:
|
if self.element_id != 0:
|
||||||
element = tool.Ifc.get().by_id(self.element_id)
|
element = tool.Ifc.get().by_id(self.element_id)
|
||||||
@@ -379,6 +418,61 @@ class SetFlowDirection(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
return {"CANCELLED"}
|
return {"CANCELLED"}
|
||||||
|
|
||||||
|
|
||||||
|
class CycleFlowDirection(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
|
bl_idname = "bim.cycle_flow_direction"
|
||||||
|
bl_label = "Cycle Flow Direction"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
port_id: bpy.props.IntProperty()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def description(cls, context, operator):
|
||||||
|
try:
|
||||||
|
port = tool.Ifc.get().by_id(operator.port_id)
|
||||||
|
if port and port.is_a("IfcDistributionPort"):
|
||||||
|
current_direction = port.FlowDirection or "NOTDEFINED"
|
||||||
|
return f"Current flow direction: {current_direction}. Click to cycle: SOURCE → SINK → SOURCEANDSINK → NOTDEFINED"
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return "Cycle through flow directions: SOURCE → SINK → SOURCEANDSINK → NOTDEFINED → SOURCE..."
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
|
port = tool.Ifc.get().by_id(self.port_id)
|
||||||
|
if not port or not port.is_a("IfcDistributionPort"):
|
||||||
|
return {"CANCELLED"}
|
||||||
|
|
||||||
|
current_direction = port.FlowDirection or "NOTDEFINED"
|
||||||
|
flow_cycle = ["SOURCE", "SINK", "SOURCEANDSINK", "NOTDEFINED"]
|
||||||
|
|
||||||
|
try:
|
||||||
|
current_index = flow_cycle.index(current_direction)
|
||||||
|
next_direction = flow_cycle[(current_index + 1) % len(flow_cycle)]
|
||||||
|
except ValueError:
|
||||||
|
next_direction = "SOURCE"
|
||||||
|
|
||||||
|
tool.Ifc.run("attribute.edit_attributes", product=port, attributes={"FlowDirection": next_direction})
|
||||||
|
|
||||||
|
PortData.is_loaded = False
|
||||||
|
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
|
class ShowPortFlowError(bpy.types.Operator):
|
||||||
|
bl_idname = "bim.show_port_flow_error"
|
||||||
|
bl_label = ""
|
||||||
|
bl_options = {"REGISTER"}
|
||||||
|
port_flow: bpy.props.StringProperty()
|
||||||
|
connected_flow: bpy.props.StringProperty()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def description(cls, context, operator):
|
||||||
|
if operator.port_flow and operator.connected_flow:
|
||||||
|
return f"Semantic error: Incompatible flow directions ({operator.port_flow} connected to {operator.connected_flow})"
|
||||||
|
return "Semantic error: Incompatible flow directions"
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class LoadZones(bpy.types.Operator):
|
class LoadZones(bpy.types.Operator):
|
||||||
bl_idname = "bim.load_zones"
|
bl_idname = "bim.load_zones"
|
||||||
bl_label = "Load Zones"
|
bl_label = "Load Zones"
|
||||||
|
|||||||
@@ -19,7 +19,8 @@
|
|||||||
import bpy
|
import bpy
|
||||||
import bonsai.bim.handler
|
import bonsai.bim.handler
|
||||||
import bonsai.tool as tool
|
import bonsai.tool as tool
|
||||||
from bonsai.bim.module.system.data import SystemData
|
import bonsai.core.system as core
|
||||||
|
from bonsai.bim.module.system.data import SystemData, PortData
|
||||||
import bonsai.bim.module.system.decorator as decorator
|
import bonsai.bim.module.system.decorator as decorator
|
||||||
from bonsai.bim.prop import StrProperty, Attribute
|
from bonsai.bim.prop import StrProperty, Attribute
|
||||||
from bpy.types import PropertyGroup
|
from bpy.types import PropertyGroup
|
||||||
@@ -92,6 +93,56 @@ def toggle_decorations(self: "BIMSystemProperties", context: bpy.types.Context)
|
|||||||
decorator.SystemDecorator.uninstall()
|
decorator.SystemDecorator.uninstall()
|
||||||
|
|
||||||
|
|
||||||
|
def is_port_available_for_connection(self: "BIMSystemProperties", obj: bpy.types.Object) -> bool:
|
||||||
|
element = tool.Ifc.get_entity(obj)
|
||||||
|
if not element or not element.is_a("IfcDistributionPort"):
|
||||||
|
return False
|
||||||
|
connected_port = tool.System.get_connected_port(element)
|
||||||
|
if connected_port is not None:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if bpy.context.active_object:
|
||||||
|
active_element = tool.Ifc.get_entity(bpy.context.active_object)
|
||||||
|
if active_element:
|
||||||
|
active_ports = tool.System.get_ports(active_element)
|
||||||
|
if element in active_ports:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def update_related_port_object(self: "BIMSystemProperties", context: bpy.types.Context) -> None:
|
||||||
|
if self.related_port_object is None:
|
||||||
|
return
|
||||||
|
if not context.active_object:
|
||||||
|
return
|
||||||
|
|
||||||
|
source_element = tool.Ifc.get_entity(context.active_object)
|
||||||
|
target_element = tool.Ifc.get_entity(self.related_port_object)
|
||||||
|
|
||||||
|
if not source_element or not target_element:
|
||||||
|
self.related_port_object = None
|
||||||
|
return
|
||||||
|
|
||||||
|
if not target_element.is_a("IfcDistributionPort"):
|
||||||
|
self.related_port_object = None
|
||||||
|
return
|
||||||
|
|
||||||
|
source_port = None
|
||||||
|
for port in tool.System.get_ports(source_element):
|
||||||
|
if not tool.System.get_connected_port(port):
|
||||||
|
source_port = port
|
||||||
|
break
|
||||||
|
|
||||||
|
if not source_port:
|
||||||
|
self.related_port_object = None
|
||||||
|
return
|
||||||
|
|
||||||
|
core.connect_port(tool.Ifc, port1=source_port, port2=target_element)
|
||||||
|
self.related_port_object = None
|
||||||
|
PortData.is_loaded = False
|
||||||
|
|
||||||
|
|
||||||
class BIMSystemProperties(PropertyGroup):
|
class BIMSystemProperties(PropertyGroup):
|
||||||
system_attributes: CollectionProperty(name="System Attributes", type=Attribute)
|
system_attributes: CollectionProperty(name="System Attributes", type=Attribute)
|
||||||
is_editing: BoolProperty(name="Is Editing", default=False)
|
is_editing: BoolProperty(name="Is Editing", default=False)
|
||||||
@@ -107,6 +158,12 @@ class BIMSystemProperties(PropertyGroup):
|
|||||||
should_draw_decorations: BoolProperty(
|
should_draw_decorations: BoolProperty(
|
||||||
name="Should Draw Decorations", description="Toggle system decorations", update=toggle_decorations
|
name="Should Draw Decorations", description="Toggle system decorations", update=toggle_decorations
|
||||||
)
|
)
|
||||||
|
related_port_object: PointerProperty(
|
||||||
|
type=bpy.types.Object,
|
||||||
|
name="Connect To Port",
|
||||||
|
update=update_related_port_object,
|
||||||
|
poll=is_port_available_for_connection,
|
||||||
|
)
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
system_attributes: bpy.types.bpy_prop_collection_idprop[Attribute]
|
system_attributes: bpy.types.bpy_prop_collection_idprop[Attribute]
|
||||||
@@ -119,6 +176,7 @@ class BIMSystemProperties(PropertyGroup):
|
|||||||
edited_system_id: int
|
edited_system_id: int
|
||||||
system_class: str
|
system_class: str
|
||||||
should_draw_decorations: bool
|
should_draw_decorations: bool
|
||||||
|
related_port_object: Union[bpy.types.Object, None]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def active_system_ui_item(self) -> Union[System, None]:
|
def active_system_ui_item(self) -> Union[System, None]:
|
||||||
|
|||||||
@@ -162,45 +162,75 @@ class BIM_PT_ports(Panel):
|
|||||||
if total_ports == 0:
|
if total_ports == 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
row = self.layout.row(align=True)
|
props = tool.System.get_system_props()
|
||||||
row.label(text="Change Flow Direction:")
|
|
||||||
|
|
||||||
current_flow_direction = PortData.data["selected_objects_flow_direction"]
|
|
||||||
for flow_direction in FLOW_DIRECTION_TO_ICON.keys():
|
|
||||||
row.operator(
|
|
||||||
"bim.set_flow_direction",
|
|
||||||
icon=FLOW_DIRECTION_TO_ICON[flow_direction],
|
|
||||||
depress=flow_direction == current_flow_direction,
|
|
||||||
text="",
|
|
||||||
).direction = flow_direction
|
|
||||||
row.enabled = len(context.selected_objects) == 2
|
|
||||||
|
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
row.label(text="Ports located on object and connected objects:")
|
row.label(text="Ports located on object and connected Port/Objects:")
|
||||||
|
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
cols = [row.column(align=True) for i in range(6)]
|
cols = [row.column(align=True) for i in range(10)]
|
||||||
|
|
||||||
for port_data in PortData.data["located_ports_data"]:
|
for port_data in PortData.data["located_ports_data"]:
|
||||||
flow_direction_icon = FLOW_DIRECTION_TO_ICON[port_data["FlowDirection"] or "NOTDEFINED"]
|
flow_direction_icon = FLOW_DIRECTION_TO_ICON[port_data["FlowDirection"] or "NOTDEFINED"]
|
||||||
if port_data["port_obj_name"]:
|
|
||||||
cols[0].label(text="", icon=flow_direction_icon)
|
if port_data["connected_obj_name"]:
|
||||||
cols[1].operator("bim.select_entity", text="", icon="RESTRICT_SELECT_OFF").ifc_id = port_data["id"]
|
cols[0].operator("bim.disconnect_port", text="", icon="UNLINKED").element_id = port_data["id"]
|
||||||
cols[2].label(text=port_data["port_obj_name"])
|
op = cols[1].operator("bim.cycle_flow_direction", text="", icon=flow_direction_icon, emboss=True)
|
||||||
|
op.port_id = port_data["id"]
|
||||||
else:
|
else:
|
||||||
cols[0].label(text="", icon=flow_direction_icon)
|
cols[0].label(text="", icon="BLANK1")
|
||||||
cols[1].label(text="", icon="HIDE_ON")
|
op = cols[1].operator("bim.cycle_flow_direction", text="", icon=flow_direction_icon, emboss=True)
|
||||||
cols[2].label(text="Port is hidden")
|
op.port_id = port_data["id"]
|
||||||
|
|
||||||
|
# Port information
|
||||||
|
if port_data["port_obj_name"]:
|
||||||
|
cols[2].operator("bim.select_entity", text="", icon="RESTRICT_SELECT_OFF").ifc_id = port_data["id"]
|
||||||
|
cols[3].label(text=port_data["port_obj_name"])
|
||||||
|
else:
|
||||||
|
cols[2].label(text="", icon="HIDE_ON")
|
||||||
|
cols[3].label(text="Port is hidden")
|
||||||
|
|
||||||
if port_data["connected_obj_name"]:
|
if port_data["connected_obj_name"]:
|
||||||
connected_obj = bpy.data.objects[port_data["connected_obj_name"]]
|
connected_obj = bpy.data.objects[port_data["connected_obj_name"]]
|
||||||
cols[3].operator("bim.disconnect_port", text="", icon="UNLINKED").element_id = port_data["id"]
|
|
||||||
|
port = tool.Ifc.get().by_id(port_data["id"])
|
||||||
|
connected_port = tool.System.get_connected_port(port)
|
||||||
|
if connected_port:
|
||||||
|
connected_port_flow_dir = FLOW_DIRECTION_TO_ICON[connected_port.FlowDirection or "NOTDEFINED"]
|
||||||
|
op = cols[4].operator("bim.cycle_flow_direction", text="", icon=connected_port_flow_dir, emboss=True)
|
||||||
|
op.port_id = connected_port.id()
|
||||||
|
cols[5].operator("bim.select_entity", text="", icon="RESTRICT_SELECT_OFF").ifc_id = connected_port.id()
|
||||||
|
connected_port_obj = tool.Ifc.get_object(connected_port)
|
||||||
|
cols[6].label(text=connected_port_obj.name if connected_port_obj else "Hidden Port")
|
||||||
|
else:
|
||||||
|
cols[4].label(text="", icon="BLANK1")
|
||||||
|
cols[5].label(text="", icon="BLANK1")
|
||||||
|
cols[6].label(text="")
|
||||||
|
|
||||||
ifc_id = tool.Blender.get_ifc_definition_id(connected_obj)
|
ifc_id = tool.Blender.get_ifc_definition_id(connected_obj)
|
||||||
cols[4].operator("bim.select_entity", text="", icon="RESTRICT_SELECT_OFF").ifc_id = ifc_id
|
cols[7].operator("bim.select_entity", text="", icon="RESTRICT_SELECT_OFF").ifc_id = ifc_id
|
||||||
cols[5].label(text=port_data["connected_obj_name"])
|
cols[8].label(text=port_data["connected_obj_name"])
|
||||||
|
|
||||||
|
if connected_port:
|
||||||
|
port_flow = port.FlowDirection or "NOTDEFINED"
|
||||||
|
connected_flow = connected_port.FlowDirection or "NOTDEFINED"
|
||||||
|
if (port_flow == "SOURCE" and connected_flow == "SOURCE") or \
|
||||||
|
(port_flow == "SINK" and connected_flow == "SINK"):
|
||||||
|
op = cols[9].operator("bim.show_port_flow_error", text="", icon="ERROR", emboss=False)
|
||||||
|
op.port_flow = port_flow
|
||||||
|
op.connected_flow = connected_flow
|
||||||
|
else:
|
||||||
|
cols[9].label(text="", icon="BLANK1")
|
||||||
|
else:
|
||||||
|
cols[9].label(text="", icon="BLANK1")
|
||||||
else:
|
else:
|
||||||
cols[3].label(text="", icon="UNLINKED")
|
|
||||||
cols[4].label(text="", icon="BLANK1")
|
cols[4].label(text="", icon="BLANK1")
|
||||||
cols[5].label(text="Port is disconnected")
|
cols[5].label(text="", icon="BLANK1")
|
||||||
|
cols[6].alignment = 'LEFT'
|
||||||
|
cols[6].prop(props, "related_port_object", text="")
|
||||||
|
cols[7].label(text="", icon="BLANK1")
|
||||||
|
cols[8].label(text="Port is disconnected")
|
||||||
|
cols[9].label(text="", icon="BLANK1")
|
||||||
|
|
||||||
|
|
||||||
class BIM_PT_port(Panel):
|
class BIM_PT_port(Panel):
|
||||||
@@ -227,7 +257,12 @@ class BIM_PT_port(Panel):
|
|||||||
|
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
row.label(text="IfcDistributionPort")
|
|
||||||
|
if not PortData.is_loaded:
|
||||||
|
PortData.load()
|
||||||
|
|
||||||
|
relating_object_name = PortData.data["port_relating_object_name"] if PortData.data["is_port"] else ""
|
||||||
|
row.label(text=f"IfcDistributionPort located in: {relating_object_name}")
|
||||||
row.operator("bim.connect_port", icon="PLUGIN", text="")
|
row.operator("bim.connect_port", icon="PLUGIN", text="")
|
||||||
row.operator("bim.disconnect_port", icon="UNLINKED", text="")
|
row.operator("bim.disconnect_port", icon="UNLINKED", text="")
|
||||||
row.operator("bim.remove_port", icon="X", text="")
|
row.operator("bim.remove_port", icon="X", text="")
|
||||||
@@ -239,41 +274,61 @@ class BIM_PT_port(Panel):
|
|||||||
return
|
return
|
||||||
|
|
||||||
element = tool.Ifc.get_entity(context.active_object)
|
element = tool.Ifc.get_entity(context.active_object)
|
||||||
current_flow_direction = str(element.FlowDirection)
|
props = tool.System.get_system_props()
|
||||||
row = layout.row(align=True)
|
|
||||||
row.label(text="Flow Direction:")
|
|
||||||
row.label(text=current_flow_direction)
|
|
||||||
|
|
||||||
# port located on
|
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
relating_object_name = PortData.data["port_relating_object_name"]
|
cols = [row.column(align=True) for i in range(10)]
|
||||||
relating_object = bpy.data.objects[relating_object_name]
|
|
||||||
row.label(text="Port located on:")
|
|
||||||
row.label(text=relating_object_name)
|
|
||||||
ifc_id = tool.Blender.get_ifc_definition_id(relating_object)
|
|
||||||
row.operator("bim.select_entity", text="", icon="RESTRICT_SELECT_OFF").ifc_id = ifc_id
|
|
||||||
|
|
||||||
# object connected to the port
|
flow_direction_icon = FLOW_DIRECTION_TO_ICON[element.FlowDirection or "NOTDEFINED"]
|
||||||
row = layout.row(align=True)
|
connected_port = tool.System.get_connected_port(element)
|
||||||
connected_object_name = PortData.data["port_connected_object_name"]
|
|
||||||
if connected_object_name:
|
if connected_port:
|
||||||
connected_object = bpy.data.objects[connected_object_name]
|
cols[0].operator("bim.disconnect_port", text="", icon="UNLINKED")
|
||||||
row.label(text="Port connected to:")
|
op = cols[1].operator("bim.cycle_flow_direction", text="", icon=flow_direction_icon, emboss=True)
|
||||||
row.label(text=connected_object_name)
|
op.port_id = element.id()
|
||||||
ifc_id = tool.Blender.get_ifc_definition_id(connected_object)
|
|
||||||
row.operator("bim.select_entity", text="", icon="RESTRICT_SELECT_OFF").ifc_id = ifc_id
|
|
||||||
else:
|
else:
|
||||||
row.label(text="Port is not connected to any element")
|
cols[0].label(text="", icon="BLANK1")
|
||||||
|
op = cols[1].operator("bim.cycle_flow_direction", text="", icon=flow_direction_icon, emboss=True)
|
||||||
|
op.port_id = element.id()
|
||||||
|
|
||||||
row = layout.row(align=True)
|
cols[2].operator("bim.select_entity", text="", icon="RESTRICT_SELECT_OFF").ifc_id = element.id()
|
||||||
row.label(text="Change Flow Direction:")
|
cols[3].label(text=context.active_object.name)
|
||||||
for flow_direction in FLOW_DIRECTION_TO_ICON.keys():
|
|
||||||
row.operator(
|
if connected_port:
|
||||||
"bim.set_flow_direction",
|
connected_port_flow_dir = FLOW_DIRECTION_TO_ICON[connected_port.FlowDirection or "NOTDEFINED"]
|
||||||
icon=FLOW_DIRECTION_TO_ICON[flow_direction],
|
op = cols[4].operator("bim.cycle_flow_direction", text="", icon=connected_port_flow_dir, emboss=True)
|
||||||
depress=flow_direction == current_flow_direction,
|
op.port_id = connected_port.id()
|
||||||
text="",
|
cols[5].operator("bim.select_entity", text="", icon="RESTRICT_SELECT_OFF").ifc_id = connected_port.id()
|
||||||
).direction = flow_direction
|
connected_port_obj = tool.Ifc.get_object(connected_port)
|
||||||
|
cols[6].label(text=connected_port_obj.name if connected_port_obj else "Hidden Port")
|
||||||
|
|
||||||
|
connected_object_name = PortData.data["port_connected_object_name"]
|
||||||
|
if connected_object_name:
|
||||||
|
connected_obj = bpy.data.objects[connected_object_name]
|
||||||
|
ifc_id = tool.Blender.get_ifc_definition_id(connected_obj)
|
||||||
|
cols[7].operator("bim.select_entity", text="", icon="RESTRICT_SELECT_OFF").ifc_id = ifc_id
|
||||||
|
cols[8].label(text=connected_object_name)
|
||||||
|
else:
|
||||||
|
cols[7].label(text="", icon="BLANK1")
|
||||||
|
cols[8].label(text="")
|
||||||
|
|
||||||
|
port_flow = element.FlowDirection or "NOTDEFINED"
|
||||||
|
connected_flow = connected_port.FlowDirection or "NOTDEFINED"
|
||||||
|
if (port_flow == "SOURCE" and connected_flow == "SOURCE") or \
|
||||||
|
(port_flow == "SINK" and connected_flow == "SINK"):
|
||||||
|
op = cols[9].operator("bim.show_port_flow_error", text="", icon="ERROR", emboss=False)
|
||||||
|
op.port_flow = port_flow
|
||||||
|
op.connected_flow = connected_flow
|
||||||
|
else:
|
||||||
|
cols[9].label(text="", icon="BLANK1")
|
||||||
|
else:
|
||||||
|
cols[4].label(text="", icon="BLANK1")
|
||||||
|
cols[5].label(text="", icon="BLANK1")
|
||||||
|
cols[6].alignment = 'LEFT'
|
||||||
|
cols[6].prop(props, "related_port_object", text="")
|
||||||
|
cols[7].label(text="", icon="BLANK1")
|
||||||
|
cols[8].label(text="Port is disconnected")
|
||||||
|
cols[9].label(text="", icon="BLANK1")
|
||||||
|
|
||||||
|
|
||||||
class BIM_PT_flow_controls(Panel):
|
class BIM_PT_flow_controls(Panel):
|
||||||
|
|||||||
@@ -123,9 +123,8 @@ def hide_ports(ifc: type[tool.Ifc], system: type[tool.System], element: ifcopens
|
|||||||
|
|
||||||
def add_port(ifc: type[tool.Ifc], system: type[tool.System], element: ifcopenshell.entity_instance) -> None:
|
def add_port(ifc: type[tool.Ifc], system: type[tool.System], element: ifcopenshell.entity_instance) -> None:
|
||||||
system.load_ports(element, system.get_ports(element))
|
system.load_ports(element, system.get_ports(element))
|
||||||
obj = system.create_empty_at_cursor_with_element_orientation(element)
|
port = system.create_port_at_cursor(element)
|
||||||
port = system.run_root_assign_class(obj=obj, ifc_class="IfcDistributionPort", should_add_representation=False)
|
system.load_ports(element, [port])
|
||||||
ifc.run("system.assign_port", element=element, port=port)
|
|
||||||
|
|
||||||
|
|
||||||
def remove_port(ifc: type[tool.Ifc], system: type[tool.System], port: ifcopenshell.entity_instance) -> None:
|
def remove_port(ifc: type[tool.Ifc], system: type[tool.System], port: ifcopenshell.entity_instance) -> None:
|
||||||
|
|||||||
@@ -107,6 +107,32 @@ class System(bonsai.core.tool.System):
|
|||||||
bpy.context.scene.collection.objects.link(obj)
|
bpy.context.scene.collection.objects.link(obj)
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create_port_at_cursor(cls, element: ifcopenshell.entity_instance) -> ifcopenshell.entity_instance:
|
||||||
|
ifc_file = tool.Ifc.get()
|
||||||
|
element_obj = tool.Ifc.get_object(element)
|
||||||
|
|
||||||
|
port = ifcopenshell.api.system.add_port(ifc_file, element=element)
|
||||||
|
port.FlowDirection = "NOTDEFINED"
|
||||||
|
port.PredefinedType = "USERDEFINED"
|
||||||
|
|
||||||
|
systems = ifcopenshell.util.system.get_element_systems(element)
|
||||||
|
if systems:
|
||||||
|
system = systems[0]
|
||||||
|
if hasattr(system, "PredefinedType") and system.PredefinedType:
|
||||||
|
port.SystemType = system.PredefinedType
|
||||||
|
else:
|
||||||
|
port.SystemType = "USERDEFINED"
|
||||||
|
else:
|
||||||
|
port.SystemType = "USERDEFINED"
|
||||||
|
|
||||||
|
matrix = element_obj.matrix_world.copy()
|
||||||
|
matrix.translation = bpy.context.scene.cursor.matrix.translation
|
||||||
|
|
||||||
|
ifcopenshell.api.geometry.edit_object_placement(ifc_file, product=port, matrix=matrix, is_si=True)
|
||||||
|
|
||||||
|
return port
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def delete_element_objects(cls, elements: list[ifcopenshell.entity_instance]) -> None:
|
def delete_element_objects(cls, elements: list[ifcopenshell.entity_instance]) -> None:
|
||||||
for element in elements:
|
for element in elements:
|
||||||
|
|||||||
Reference in New Issue
Block a user