From fed98451d47957f930106d39c778b7da922b3e38 Mon Sep 17 00:00:00 2001 From: falken10vdl Date: Tue, 27 Jan 2026 01:32:06 +0100 Subject: [PATCH 1/2] connect the ports when creating several conected IfcFlowSegment with polyline --- src/bonsai/bonsai/bim/module/model/profile.py | 6 ++++++ .../bonsai/bim/module/system/operator.py | 20 ++++++++++--------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/model/profile.py b/src/bonsai/bonsai/bim/module/model/profile.py index 9271f2acc1..0a11fa191b 100644 --- a/src/bonsai/bonsai/bim/module/model/profile.py +++ b/src/bonsai/bonsai/bim/module/model/profile.py @@ -1131,8 +1131,14 @@ class DrawPolylineProfile(bpy.types.Operator, PolylineOperator, tool.Ifc.Operato MEPGenerator().setup_ports(profile1["obj"]) else: + connect_IfcFlowSegments = tool.Ifc.get_entity(profiles[0]["obj"]).is_a("IfcFlowSegment") for profile1, profile2 in zip(profiles[:-1], profiles[1:]): DumbProfileJoiner().join_V(profile2["obj"], profile1["obj"]) + if connect_IfcFlowSegments: + bpy.ops.bim.mep_connect_elements( + obj1_name=profile1["obj"].name, + obj2_name=profile2["obj"].name + ) def modal(self, context, event): return IfcStore.execute_ifc_operator(self, context, event, method="MODAL") diff --git a/src/bonsai/bonsai/bim/module/system/operator.py b/src/bonsai/bonsai/bim/module/system/operator.py index 8dd6724de3..5fecd05ffb 100644 --- a/src/bonsai/bonsai/bim/module/system/operator.py +++ b/src/bonsai/bonsai/bim/module/system/operator.py @@ -317,17 +317,19 @@ class MEPConnectElements(bpy.types.Operator, tool.Ifc.Operator): bl_label = "Connect MEP Elements" bl_description = "Connects two selected elements by their closest located ports and adjusts them" bl_options = {"REGISTER", "UNDO"} - - @classmethod - def poll(cls, context): - if not len(context.selected_objects) == 2: - cls.poll_message_set("Need to select 2 objects.") - return False - return True + obj1_name: bpy.props.StringProperty(name="Object 1") + obj2_name: bpy.props.StringProperty(name="Object 2") def _execute(self, context): - obj1 = context.active_object - obj2 = next(o for o in context.selected_objects if o != obj1) + if self.obj1_name and self.obj2_name: + obj1 = bpy.data.objects.get(self.obj1_name) + obj2 = bpy.data.objects.get(self.obj2_name) + else: + if not context.selected_objects or len(context.selected_objects) != 2: + self.report({"ERROR"}, "Need to select 2 objects.") + return {"CANCELLED"} + obj1 = context.active_object + obj2 = next(o for o in context.selected_objects if o != obj1) tool.Model.sync_object_ifc_position(obj1) tool.Model.sync_object_ifc_position(obj2) From 8a32d7bea0fca29699688cbed53e2eb8a0318e14 Mon Sep 17 00:00:00 2001 From: falken10vdl Date: Tue, 27 Jan 2026 18:05:19 +0100 Subject: [PATCH 2/2] Add EstablishPathDirection operator and update UI to integrate it --- .../bonsai/bim/module/system/__init__.py | 1 + .../bonsai/bim/module/system/operator.py | 50 +++++++++++++++++++ src/bonsai/bonsai/bim/module/system/ui.py | 4 +- 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/src/bonsai/bonsai/bim/module/system/__init__.py b/src/bonsai/bonsai/bim/module/system/__init__.py index d08046ee8f..36901100f6 100644 --- a/src/bonsai/bonsai/bim/module/system/__init__.py +++ b/src/bonsai/bonsai/bim/module/system/__init__.py @@ -37,6 +37,7 @@ classes = ( operator.EditZone, operator.EnableEditingSystem, operator.EnableEditingZone, + operator.EstablishPathDirection, operator.HidePorts, operator.LoadSystems, operator.LoadZones, diff --git a/src/bonsai/bonsai/bim/module/system/operator.py b/src/bonsai/bonsai/bim/module/system/operator.py index 5fecd05ffb..18e8d91d88 100644 --- a/src/bonsai/bonsai/bim/module/system/operator.py +++ b/src/bonsai/bonsai/bim/module/system/operator.py @@ -479,6 +479,56 @@ class CycleFlowDirection(bpy.types.Operator, tool.Ifc.Operator): return {"FINISHED"} +class EstablishPathDirection(bpy.types.Operator, tool.Ifc.Operator): + bl_idname = "bim.establish_path_direction" + bl_label = "Establish Path Direction" + bl_description = "Propagates flow direction through connected flow segments with two ports" + bl_options = {"REGISTER", "UNDO"} + port_id: bpy.props.IntProperty() + + def _execute(self, context): + connected_port = tool.Ifc.get().by_id(self.port_id) + + + if not connected_port or not connected_port.is_a("IfcDistributionPort"): + self.report({"ERROR"}, "Invalid port specified.") + return {"CANCELLED"} + + direction_map = { + "SOURCE": "SINK", + "SINK": "SOURCE", + "SOURCEANDSINK": "SOURCEANDSINK", + "NOTDEFINED": "NOTDEFINED", + } + next_element = tool.System.get_port_relating_element(connected_port) + ports = tool.System.get_ports(next_element) + segments_processed = 0 + while (len(ports) == 2): + if ports[0].id() == connected_port.id(): + other_port = ports[1] + else: + other_port = ports[0] + + new_direction = direction_map.get(connected_port.FlowDirection, "NOTDEFINED") + other_port.FlowDirection = new_direction + segments_processed += 1 + + connected_port = tool.System.get_connected_port(other_port) + if not connected_port: + break + connected_port.FlowDirection = direction_map.get(other_port.FlowDirection, "NOTDEFINED") + next_element = tool.System.get_port_relating_element(connected_port) + + if not next_element.is_a("IfcFlowSegment"): + print(f"DEBUG: next_element is not IfcFlowSegment, stopping") + break + + ports = tool.System.get_ports(next_element) + + self.report({"INFO"}, f"Established path direction through {segments_processed} flow segment(s).") + return {"FINISHED"} + + class LoadZones(bpy.types.Operator): bl_idname = "bim.load_zones" bl_label = "Load Zones" diff --git a/src/bonsai/bonsai/bim/module/system/ui.py b/src/bonsai/bonsai/bim/module/system/ui.py index d621adc02b..a3d73c10f6 100644 --- a/src/bonsai/bonsai/bim/module/system/ui.py +++ b/src/bonsai/bonsai/bim/module/system/ui.py @@ -296,7 +296,7 @@ class BIM_PT_port(Panel): element = tool.Ifc.get_entity(context.active_object) row = layout.row(align=True) - cols = [row.column(align=True) for i in range(9)] + cols = [row.column(align=True) for i in range(10)] cols[3].scale_x = 1.0 cols[6].scale_x = 1.0 cols[8].scale_x = 1.33 @@ -333,12 +333,14 @@ class BIM_PT_port(Panel): else: cols[7].label(text="", icon="BLANK1") cols[8].label(text="") + cols[9].operator("bim.establish_path_direction", text="", icon="CON_FOLLOWPATH").port_id = connected_port.id() else: cols[4].label(text="", icon="BLANK1") cols[5].label(text="", icon="BLANK1") cols[6].label(text="Port is disconnected") cols[7].label(text="", icon="BLANK1") cols[8].label(text="") + cols[9].label(text="", icon="BLANK1") class BIM_PT_flow_controls(Panel):