mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-25 17:57:02 +00:00
You can now connect, disconnect, and set flow directions of distribution ports in Blender.
This commit is contained in:
@@ -23,14 +23,17 @@ classes = (
|
|||||||
operator.AddPort,
|
operator.AddPort,
|
||||||
operator.AddSystem,
|
operator.AddSystem,
|
||||||
operator.AssignSystem,
|
operator.AssignSystem,
|
||||||
|
operator.ConnectPort,
|
||||||
operator.DisableEditingSystem,
|
operator.DisableEditingSystem,
|
||||||
operator.DisableSystemEditingUI,
|
operator.DisableSystemEditingUI,
|
||||||
|
operator.DisconnectPort,
|
||||||
operator.EditSystem,
|
operator.EditSystem,
|
||||||
operator.EnableEditingSystem,
|
operator.EnableEditingSystem,
|
||||||
operator.HidePorts,
|
operator.HidePorts,
|
||||||
operator.LoadSystems,
|
operator.LoadSystems,
|
||||||
operator.RemoveSystem,
|
operator.RemoveSystem,
|
||||||
operator.SelectSystemProducts,
|
operator.SelectSystemProducts,
|
||||||
|
operator.SetFlowDirection,
|
||||||
operator.ShowPorts,
|
operator.ShowPorts,
|
||||||
operator.UnassignSystem,
|
operator.UnassignSystem,
|
||||||
prop.System,
|
prop.System,
|
||||||
@@ -38,6 +41,7 @@ classes = (
|
|||||||
ui.BIM_PT_systems,
|
ui.BIM_PT_systems,
|
||||||
ui.BIM_PT_object_systems,
|
ui.BIM_PT_object_systems,
|
||||||
ui.BIM_PT_ports,
|
ui.BIM_PT_ports,
|
||||||
|
ui.BIM_PT_port,
|
||||||
ui.BIM_UL_systems,
|
ui.BIM_UL_systems,
|
||||||
ui.BIM_UL_object_systems,
|
ui.BIM_UL_object_systems,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -159,3 +159,39 @@ class AddPort(bpy.types.Operator, Operator):
|
|||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
core.add_port(tool.Ifc, tool.System, element=tool.Ifc.get_entity(context.active_object))
|
core.add_port(tool.Ifc, tool.System, element=tool.Ifc.get_entity(context.active_object))
|
||||||
|
|
||||||
|
|
||||||
|
class ConnectPort(bpy.types.Operator, Operator):
|
||||||
|
bl_idname = "bim.connect_port"
|
||||||
|
bl_label = "Connect Ports"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
return len(context.selected_objects) == 2
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
|
obj1 = context.active_object
|
||||||
|
obj2 = context.selected_objects[0] if context.selected_objects[1] == obj1 else context.selected_objects[1]
|
||||||
|
core.connect_port(tool.Ifc, port1=tool.Ifc.get_entity(obj1), port2=tool.Ifc.get_entity(obj2))
|
||||||
|
|
||||||
|
|
||||||
|
class DisconnectPort(bpy.types.Operator, Operator):
|
||||||
|
bl_idname = "bim.disconnect_port"
|
||||||
|
bl_label = "Disconnect Ports"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
|
core.disconnect_port(tool.Ifc, port=tool.Ifc.get_entity(context.active_object))
|
||||||
|
|
||||||
|
|
||||||
|
class SetFlowDirection(bpy.types.Operator, Operator):
|
||||||
|
bl_idname = "bim.set_flow_direction"
|
||||||
|
bl_label = "Set Flow Direction"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
direction: bpy.props.StringProperty()
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
|
core.set_flow_direction(
|
||||||
|
tool.Ifc, tool.System, port=tool.Ifc.get_entity(context.active_object), direction=self.direction
|
||||||
|
)
|
||||||
|
|||||||
@@ -156,6 +156,35 @@ class BIM_PT_ports(Panel):
|
|||||||
row.operator("bim.add_port", icon="ADD", text="")
|
row.operator("bim.add_port", icon="ADD", text="")
|
||||||
|
|
||||||
|
|
||||||
|
class BIM_PT_port(Panel):
|
||||||
|
bl_label = "IFC Port"
|
||||||
|
bl_idname = "BIM_PT_port"
|
||||||
|
bl_options = {"DEFAULT_CLOSED"}
|
||||||
|
bl_space_type = "PROPERTIES"
|
||||||
|
bl_region_type = "WINDOW"
|
||||||
|
bl_context = "object"
|
||||||
|
bl_parent_id = "BIM_PT_services_object"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
if not context.active_object:
|
||||||
|
return False
|
||||||
|
element = tool.Ifc.get_entity(context.active_object)
|
||||||
|
if not element or not element.is_a("IfcPort"):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
self.props = context.scene.BIMSystemProperties
|
||||||
|
row = self.layout.row(align=True)
|
||||||
|
row.operator("bim.connect_port", icon="PLUGIN", text="")
|
||||||
|
row.operator("bim.disconnect_port", icon="UNLINKED", text="")
|
||||||
|
row.operator("bim.set_flow_direction", icon="FORWARD", text="").direction = "SOURCE"
|
||||||
|
row.operator("bim.set_flow_direction", icon="BACK", text="").direction = "SINK"
|
||||||
|
row.operator("bim.set_flow_direction", icon="ARROW_LEFTRIGHT", text="").direction = "SOURCEANDSINK"
|
||||||
|
row.operator("bim.set_flow_direction", icon="RESTRICT_INSTANCED_ON", text="").direction = "NOTDEFINED"
|
||||||
|
|
||||||
|
|
||||||
class BIM_UL_systems(UIList):
|
class BIM_UL_systems(UIList):
|
||||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
||||||
system_icons = {
|
system_icons = {
|
||||||
|
|||||||
@@ -81,3 +81,18 @@ def add_port(ifc, system, element=None):
|
|||||||
obj = system.create_empty_at_cursor_with_element_orientation(element)
|
obj = system.create_empty_at_cursor_with_element_orientation(element)
|
||||||
port = system.run_root_assign_class(obj=obj, ifc_class="IfcDistributionPort")
|
port = system.run_root_assign_class(obj=obj, ifc_class="IfcDistributionPort")
|
||||||
ifc.run("system.assign_port", element=element, port=port)
|
ifc.run("system.assign_port", element=element, port=port)
|
||||||
|
|
||||||
|
|
||||||
|
def connect_port(ifc, port1=None, port2=None):
|
||||||
|
ifc.run("system.connect_port", port1=port1, port2=port2)
|
||||||
|
|
||||||
|
|
||||||
|
def disconnect_port(ifc, port=None):
|
||||||
|
ifc.run("system.disconnect_port", port=port)
|
||||||
|
|
||||||
|
|
||||||
|
def set_flow_direction(ifc, system, port=None, direction=None):
|
||||||
|
port2 = system.get_connected_port(port)
|
||||||
|
if not port2:
|
||||||
|
return
|
||||||
|
ifc.run("system.connect_port", port1=port, port2=port2, direction=direction)
|
||||||
|
|||||||
@@ -390,6 +390,7 @@ class System:
|
|||||||
def disable_system_editing_ui(cls): pass
|
def disable_system_editing_ui(cls): pass
|
||||||
def enable_system_editing_ui(cls): pass
|
def enable_system_editing_ui(cls): pass
|
||||||
def export_system_attributes(cls): pass
|
def export_system_attributes(cls): pass
|
||||||
|
def get_connected_port(cls, port): pass
|
||||||
def get_ports(cls, element): pass
|
def get_ports(cls, element): pass
|
||||||
def import_system_attributes(cls, system): pass
|
def import_system_attributes(cls, system): pass
|
||||||
def import_systems(cls): pass
|
def import_systems(cls): pass
|
||||||
|
|||||||
@@ -56,6 +56,10 @@ class System(blenderbim.core.tool.System):
|
|||||||
def export_system_attributes(cls):
|
def export_system_attributes(cls):
|
||||||
return blenderbim.bim.helper.export_attributes(bpy.context.scene.BIMSystemProperties.system_attributes)
|
return blenderbim.bim.helper.export_attributes(bpy.context.scene.BIMSystemProperties.system_attributes)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_connected_port(cls, port):
|
||||||
|
return ifcopenshell.util.system.get_connected_port(port)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_ports(cls, element):
|
def get_ports(cls, element):
|
||||||
return ifcopenshell.util.system.get_ports(element)
|
return ifcopenshell.util.system.get_ports(element)
|
||||||
|
|||||||
@@ -113,3 +113,14 @@ class TestAddPort:
|
|||||||
system.run_root_assign_class(obj="obj", ifc_class="IfcDistributionPort").should_be_called().will_return("port")
|
system.run_root_assign_class(obj="obj", ifc_class="IfcDistributionPort").should_be_called().will_return("port")
|
||||||
ifc.run("system.assign_port", element="element", port="port").should_be_called()
|
ifc.run("system.assign_port", element="element", port="port").should_be_called()
|
||||||
subject.add_port(ifc, system, element="element")
|
subject.add_port(ifc, system, element="element")
|
||||||
|
|
||||||
|
|
||||||
|
class TestSetFlowDirection:
|
||||||
|
def test_run(self, ifc, system):
|
||||||
|
system.get_connected_port("port").should_be_called().will_return("port2")
|
||||||
|
ifc.run("system.connect_port", port1="port", port2="port2", direction="direction").should_be_called()
|
||||||
|
subject.set_flow_direction(ifc, system, port="port", direction="direction")
|
||||||
|
|
||||||
|
def test_do_not_set_a_direction_if_port_is_not_connected(self, ifc, system):
|
||||||
|
system.get_connected_port("port").should_be_called().will_return(None)
|
||||||
|
subject.set_flow_direction(ifc, system, port="port", direction="direction")
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
@@ -36,9 +36,8 @@ class TestCreateEmptyAtCursorWithElementOrientation(NewFile):
|
|||||||
obj = bpy.data.objects.new("Object", None)
|
obj = bpy.data.objects.new("Object", None)
|
||||||
element = ifc.createIfcWall()
|
element = ifc.createIfcWall()
|
||||||
tool.Ifc.link(element, obj)
|
tool.Ifc.link(element, obj)
|
||||||
bpy.context.scene.cursor.matrix.translation[0] = 5
|
|
||||||
obj = subject.create_empty_at_cursor_with_element_orientation(element)
|
obj = subject.create_empty_at_cursor_with_element_orientation(element)
|
||||||
assert obj.matrix_world.translation[0] == 5
|
assert obj.matrix_world == bpy.context.scene.cursor.matrix
|
||||||
|
|
||||||
|
|
||||||
class TestDeleteElementObjects(NewFile):
|
class TestDeleteElementObjects(NewFile):
|
||||||
@@ -83,6 +82,16 @@ class TestExportSystemAttributes(NewFile):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class TestGetConnectedPort(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
ifc = ifcopenshell.file()
|
||||||
|
port1 = ifcopenshell.api.run("system.add_port", ifc)
|
||||||
|
port2 = ifcopenshell.api.run("system.add_port", ifc)
|
||||||
|
ifcopenshell.api.run("system.connect_port", ifc, port1=port1, port2=port2)
|
||||||
|
assert subject.get_connected_port(port1) == port2
|
||||||
|
assert subject.get_connected_port(port2) == port1
|
||||||
|
|
||||||
|
|
||||||
class TestGetPorts(NewFile):
|
class TestGetPorts(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
ifc = ifcopenshell.file()
|
ifc = ifcopenshell.file()
|
||||||
|
|||||||
@@ -43,3 +43,28 @@ def get_ports(element):
|
|||||||
for rel in element.HasPorts or []:
|
for rel in element.HasPorts or []:
|
||||||
results.append(rel.RelatingPort)
|
results.append(rel.RelatingPort)
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
|
||||||
|
def get_connected_port(port):
|
||||||
|
for rel in port.ConnectedTo:
|
||||||
|
return rel.RelatedPort
|
||||||
|
for rel in port.ConnectedFrom:
|
||||||
|
return rel.RelatingPort
|
||||||
|
|
||||||
|
|
||||||
|
def get_connected_to(element):
|
||||||
|
# Note: this code is for IFC2X3. IFC4 has a different approach.
|
||||||
|
results = []
|
||||||
|
for rel in element.HasPorts:
|
||||||
|
for rel2 in rel.RelatingPort.ConnectedTo:
|
||||||
|
results.extend([r.RelatedElement for r in rel2.RelatedPort.ContainedIn if r.RelatedElement != element])
|
||||||
|
return results
|
||||||
|
|
||||||
|
|
||||||
|
def get_connected_from(element):
|
||||||
|
# Note: this code is for IFC2X3. IFC4 has a different approach.
|
||||||
|
results = []
|
||||||
|
for rel in element.HasPorts:
|
||||||
|
for rel2 in rel.RelatingPort.ConnectedFrom:
|
||||||
|
results.extend([r.RelatedElement for r in rel2.RelatingPort.ContainedIn if r.RelatedElement != element])
|
||||||
|
return results
|
||||||
|
|||||||
@@ -61,3 +61,12 @@ class TestGetPortsIFC2X3(test.bootstrap.IFC2X3):
|
|||||||
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcFlowSegment")
|
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcFlowSegment")
|
||||||
ifcopenshell.api.run("system.assign_port", self.file, element=element, port=port)
|
ifcopenshell.api.run("system.assign_port", self.file, element=element, port=port)
|
||||||
assert subject.get_ports(element) == [port]
|
assert subject.get_ports(element) == [port]
|
||||||
|
|
||||||
|
|
||||||
|
class TestGetConnectedPort(test.bootstrap.IFC4):
|
||||||
|
def test_run(self):
|
||||||
|
port1 = ifcopenshell.api.run("system.add_port", self.file)
|
||||||
|
port2 = ifcopenshell.api.run("system.add_port", self.file)
|
||||||
|
ifcopenshell.api.run("system.connect_port", self.file, port1=port1, port2=port2)
|
||||||
|
assert subject.get_connected_port(port1) == port2
|
||||||
|
assert subject.get_connected_port(port2) == port1
|
||||||
|
|||||||
Reference in New Issue
Block a user