@@ -198,7 +198,16 @@ def poll(cls, context):
198198
199199 def _execute (self , context ):
200200 # Ifc.Operator - as operator will sync object's position with IFC.
201- core .show_ports (tool .Ifc , tool .System , tool .Spatial , element = tool .Ifc .get_entity (context .active_object ))
201+ element = tool .Ifc .get_entity (context .active_object )
202+ core .show_ports (tool .Ifc , tool .System , tool .Spatial , element = element )
203+
204+ for port in tool .System .get_ports (element ):
205+ connected_port = tool .System .get_connected_port (port )
206+ if connected_port :
207+ connected_port_obj = tool .Ifc .get_object (connected_port )
208+ if not connected_port_obj :
209+ parent_element = tool .System .get_port_relating_element (connected_port )
210+ core .show_ports (tool .Ifc , tool .System , tool .Spatial , element = parent_element )
202211
203212
204213class HidePorts (bpy .types .Operator , tool .Ifc .Operator ):
@@ -217,7 +226,7 @@ def _execute(self, context):
217226
218227class AddPort (bpy .types .Operator , tool .Ifc .Operator ):
219228 bl_idname = "bim.add_port"
220- bl_description = "Add port at current cursor position"
229+ bl_description = "Add USERDEFINED port at current cursor position"
221230 bl_label = "Add Port"
222231 bl_options = {"REGISTER" , "UNDO" }
223232
@@ -246,7 +255,41 @@ def poll(cls, context):
246255 def _execute (self , context ):
247256 obj1 = context .active_object
248257 obj2 = context .selected_objects [0 ] if context .selected_objects [1 ] == obj1 else context .selected_objects [1 ]
249- core .connect_port (tool .Ifc , port1 = tool .Ifc .get_entity (obj1 ), port2 = tool .Ifc .get_entity (obj2 ))
258+ direction = tool .Ifc .get_entity (obj1 ).FlowDirection or "NOTDEFINED"
259+ core .connect_port (
260+ tool .Ifc , port1 = tool .Ifc .get_entity (obj1 ), port2 = tool .Ifc .get_entity (obj2 ), direction = direction
261+ )
262+
263+
264+ class AddRelatedPortConnection (bpy .types .Operator , tool .Ifc .Operator ):
265+ bl_idname = "bim.add_related_port_connection"
266+ bl_label = "Connect Port"
267+ bl_options = {"REGISTER" , "UNDO" }
268+
269+ relating_port_id : bpy .props .IntProperty ()
270+
271+ def invoke (self , context , event ):
272+ return context .window_manager .invoke_props_dialog (self )
273+
274+ def draw (self , context ):
275+ props = tool .System .get_system_props ()
276+ self .layout .prop (props , "related_port" , text = "Select Port" )
277+
278+ def _execute (self , context ):
279+ props = tool .System .get_system_props ()
280+
281+ if not props .related_port or props .related_port == "NONE" :
282+ return {"CANCELLED" }
283+
284+ port_obj = bpy .data .objects .get (props .related_port )
285+ related_port = tool .Ifc .get_entity (port_obj )
286+ relating_port = tool .Ifc .get ().by_id (self .relating_port_id )
287+
288+ direction = relating_port .FlowDirection or "NOTDEFINED"
289+ core .connect_port (tool .Ifc , port1 = relating_port , port2 = related_port , direction = direction )
290+ PortData .is_loaded = False
291+
292+ return {"FINISHED" }
250293
251294
252295class DisconnectPort (bpy .types .Operator , tool .Ifc .Operator ):
@@ -256,6 +299,9 @@ class DisconnectPort(bpy.types.Operator, tool.Ifc.Operator):
256299
257300 element_id : bpy .props .IntProperty (default = 0 , options = {"SKIP_SAVE" })
258301
302+ def invoke (self , context , event ):
303+ return context .window_manager .invoke_confirm (self , event )
304+
259305 def _execute (self , context ):
260306 if self .element_id != 0 :
261307 element = tool .Ifc .get ().by_id (self .element_id )
@@ -310,7 +356,8 @@ def _execute(self, context):
310356 ports_distance [(port1 , port2 )] = distance
311357
312358 closest_ports = min (ports_distance , key = lambda x : ports_distance [x ])
313- core .connect_port (tool .Ifc , * closest_ports )
359+ direction = closest_ports [0 ].FlowDirection or "NOTDEFINED"
360+ core .connect_port (tool .Ifc , * closest_ports , direction = direction )
314361 bpy .ops .bim .regenerate_distribution_element ()
315362 return {"FINISHED" }
316363
@@ -379,6 +426,55 @@ def _execute(self, context):
379426 return {"CANCELLED" }
380427
381428
429+ class CycleFlowDirection (bpy .types .Operator , tool .Ifc .Operator ):
430+ bl_idname = "bim.cycle_flow_direction"
431+ bl_label = "Cycle Flow Direction"
432+ bl_options = {"REGISTER" , "UNDO" }
433+ port_id : bpy .props .IntProperty ()
434+
435+ @classmethod
436+ def description (cls , context , operator ):
437+ port = tool .Ifc .get ().by_id (operator .port_id )
438+ if port and port .is_a ("IfcDistributionPort" ):
439+ current_direction = port .FlowDirection or "NOTDEFINED"
440+ return f"Current flow direction: { current_direction } . Click to cycle: SOURCE → SINK → SOURCEANDSINK → NOTDEFINED"
441+ return "Cycle through flow directions: SOURCE → SINK → SOURCEANDSINK → NOTDEFINED → SOURCE..."
442+
443+ def _execute (self , context ):
444+ port = tool .Ifc .get ().by_id (self .port_id )
445+ if not port or not port .is_a ("IfcDistributionPort" ):
446+ return {"CANCELLED" }
447+
448+ current_direction = port .FlowDirection or "NOTDEFINED"
449+
450+ flow_cycle_map = {
451+ "SOURCE" : "SINK" ,
452+ "SINK" : "SOURCEANDSINK" ,
453+ "SOURCEANDSINK" : "NOTDEFINED" ,
454+ "NOTDEFINED" : "SOURCE" ,
455+ }
456+ next_direction = flow_cycle_map .get (current_direction , "SOURCE" )
457+
458+ tool .Ifc .run ("attribute.edit_attributes" , product = port , attributes = {"FlowDirection" : next_direction })
459+
460+ connected_port = tool .System .get_connected_port (port )
461+ if connected_port :
462+ connected_direction_map = {
463+ "SOURCE" : "SINK" ,
464+ "SINK" : "SOURCE" ,
465+ "SOURCEANDSINK" : "SOURCEANDSINK" ,
466+ "NOTDEFINED" : "NOTDEFINED" ,
467+ }
468+ connected_direction = connected_direction_map .get (next_direction , "NOTDEFINED" )
469+ tool .Ifc .run (
470+ "attribute.edit_attributes" , product = connected_port , attributes = {"FlowDirection" : connected_direction }
471+ )
472+
473+ PortData .is_loaded = False
474+
475+ return {"FINISHED" }
476+
477+
382478class LoadZones (bpy .types .Operator ):
383479 bl_idname = "bim.load_zones"
384480 bl_label = "Load Zones"
0 commit comments