UI for assigning controls to flow elements #3981

Example - https://imgur.com/a/CZQIoHp
This commit is contained in:
Andrej730
2023-11-09 17:16:32 +05:00
parent 72b3f1e967
commit fd69d91776
7 changed files with 214 additions and 0 deletions
@@ -24,6 +24,7 @@ classes = (
operator.AddSystem,
operator.AddZone,
operator.AssignSystem,
operator.AssignUnassignFlowControl,
operator.ConnectPort,
operator.DisableEditingSystem,
operator.DisableEditingZone,
@@ -54,6 +55,7 @@ classes = (
ui.BIM_PT_active_object_zones,
ui.BIM_PT_ports,
ui.BIM_PT_port,
ui.BIM_PT_flow_controls,
ui.BIM_UL_systems,
ui.BIM_UL_zones,
)
@@ -72,6 +72,7 @@ class ObjectSystemData:
"systems": cls.systems(),
# AFTER SYSTEMS
"connected_elements": cls.connected_elements(),
"flow_controls_data": cls.flow_controls_data(),
}
cls.is_loaded = True
@@ -91,6 +92,26 @@ class ObjectSystemData:
return set()
return tool.System.get_connected_elements(cls.element)
@classmethod
def flow_controls_data(cls):
flow_controls_data = {}
if not cls.element or not (
cls.element.is_a("IfcDistributionControlElement") or cls.element.is_a("IfcDistributionFlowElement")
):
return flow_controls_data
if cls.element.is_a("IfcDistributionControlElement"):
flow_controls_data["type"] = "IfcDistributionControlElement"
flow_element = tool.System.get_flow_control_flow_element(cls.element)
flow_element_obj = tool.Ifc.get_object(flow_element).name if flow_element else None
flow_controls_data["flow_element"] = flow_element, flow_element_obj
else:
flow_controls_data["type"] = "IfcDistributionFlowElement"
controls = [(c, tool.Ifc.get_object(c).name) for c in tool.System.get_flow_element_controls(cls.element)]
flow_controls_data["controls"] = controls
return flow_controls_data
class PortData:
data = {}
@@ -421,3 +421,67 @@ class RemoveZone(bpy.types.Operator, Operator):
def _execute(self, context):
ifcopenshell.api.run("system.remove_system", tool.Ifc.get(), system=tool.Ifc.get().by_id(self.zone))
bpy.ops.bim.load_zones()
class AssignUnassignFlowControl(bpy.types.Operator, Operator):
bl_idname = "bim.assign_unassign_flow_control"
bl_label = "Assign/Unassign Flow Control"
bl_options = {"REGISTER", "UNDO"}
flow_element: bpy.props.IntProperty(options={"SKIP_SAVE"})
flow_control: bpy.props.IntProperty(options={"SKIP_SAVE"})
assign: bpy.props.BoolProperty(name="Assign/Unassign", default=True, options={"SKIP_SAVE"})
def _execute(self, context):
ifc_file = tool.Ifc.get()
flow_element = None
flow_controls = []
from_selected_objects = False
if self.flow_element != 0:
flow_element = ifc_file.by_id(self.flow_element)
if self.flow_control != 0:
flow_controls = [ifc_file.by_id(self.flow_control)]
# if not provided as arguments tried to get them from
# the selected objects
if not flow_element or flow_controls:
from_selected_objects = True
for obj in context.selected_objects:
element = tool.Ifc.get_entity(obj)
if not element:
continue
if element.is_a("IfcDistributionControlElement") and self.flow_control == 0:
flow_controls.append(element)
elif element.is_a("IfcDistributionFlowElement") and self.flow_element == 0:
if flow_element:
self.report(
{"ERROR"},
"More than one flow element selected. Control can be assigned to only 1 flow element.",
)
return {"CANCELLED"}
flow_element = element
if not flow_element:
self.report({"ERROR"}, "No flow element selected.")
return {"CANCELLED"}
if not flow_controls:
self.report({"ERROR"}, "No flow controls selected.")
return {"CANCELLED"}
for control in flow_controls:
if self.assign:
tool.Ifc.run(
"system.assign_flow_control", relating_flow_element=flow_element, related_flow_control=control
)
else:
tool.Ifc.run(
"system.unassign_flow_control", relating_flow_element=flow_element, related_flow_control=control
)
if from_selected_objects:
self.report(
{"INFO"}, f"{len(flow_controls)} flow controls were {'assigned' if self.assign else 'unassigned'}."
)
return {"FINISHED"}
@@ -16,6 +16,7 @@
# You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import bpy
import blenderbim.bim.helper
import blenderbim.tool as tool
from blenderbim.bim.helper import prop_with_search
@@ -272,6 +273,68 @@ class BIM_PT_port(Panel):
).direction = flow_direction
class BIM_PT_flow_controls(Panel):
bl_label = "Flow Controls"
bl_idname = "BIM_PT_flow_controls"
bl_options = {"DEFAULT_CLOSED"}
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "object"
bl_order = 1
bl_parent_id = "BIM_PT_tab_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("IfcDistributionControlElement") or element.is_a("IfcDistributionFlowElement")
):
return False
return True
def draw(self, context):
if not ObjectSystemData.is_loaded:
ObjectSystemData.load()
def display_element(control_id, flow_element_id, displayed_object_name):
displayed_object = bpy.data.objects[displayed_object_name]
row = self.layout.row(align=True)
op = row.operator("bim.assign_unassign_flow_control", text="", icon="X")
op.flow_control = control_id
op.flow_element = flow_element_id
op.assign = False
row.operator(
"bim.select_entity", text="", icon="RESTRICT_SELECT_OFF"
).ifc_id = displayed_object.BIMObjectProperties.ifc_definition_id
row.label(text=f"{displayed_object_name}")
element = tool.Ifc.get_entity(context.active_object)
flow_controls_data = ObjectSystemData.data["flow_controls_data"]
if flow_controls_data["type"] == "IfcDistributionFlowElement":
controls = flow_controls_data["controls"]
row = self.layout.row(align=True)
if controls:
row.label(text="Controls assigned to the element:")
else:
row.label(text="No controls assigned to the flow element")
row.operator("bim.assign_unassign_flow_control", text="", icon="ADD").assign = True
if controls:
for control_data in controls:
control, control_obj_name = control_data
display_element(control.id(), element.id(), control_obj_name)
else:
flow_element, flow_element_obj_name = flow_controls_data["flow_element"]
row = self.layout.row(align=True)
if flow_element:
row.label(text="Flow element controlled by the flow control:")
display_element(element.id(), flow_element.id(), flow_element_obj_name)
else:
row.label(text="No flow element controlled by the flow control")
row.operator("bim.assign_unassign_flow_control", text="", icon="ADD").assign = True
class BIM_PT_zones(Panel):
bl_label = "Zones"
bl_idname = "BIM_PT_zones"
+12
View File
@@ -368,3 +368,15 @@ class System(blenderbim.core.tool.System):
@classmethod
def is_mep_element(cls, element):
return element.is_a("IfcFlowSegment") or element.is_a("IfcFlowFitting")
@classmethod
def get_flow_element_controls(cls, element):
if not element.HasControlElements:
return []
return [control for control in element.HasControlElements[0].RelatedControlElements]
@classmethod
def get_flow_control_flow_element(cls, element):
if not element.AssignedToFlowElement:
return
return element.AssignedToFlowElement[0].RelatingFlowElement
@@ -101,3 +101,28 @@ Scenario: Select system products
And I press "bim.assign_system(system={system})"
When I press "bim.select_system_products(system={system})"
Then nothing happens
Scenario: Assign flow controls to flow element_type
Given an empty IFC project
And I add an empty
And the object "Empty" is selected
And I set "scene.BIMRootProperties.ifc_product" to "IfcElement"
And I set "scene.BIMRootProperties.ifc_class" to "IfcActuator"
And I press "bim.assign_class"
And I add an empty
And the object "Empty" is selected
And I set "scene.BIMRootProperties.ifc_product" to "IfcElement"
And I set "scene.BIMRootProperties.ifc_class" to "IfcActuator"
And I press "bim.assign_class"
And I add an empty
And the object "Empty" is selected
And I set "scene.BIMRootProperties.ifc_product" to "IfcElement"
And I set "scene.BIMRootProperties.ifc_class" to "IfcFlowSegment"
And I press "bim.assign_class"
And the object "IfcActuator/Empty" is selected
And additionally the object "IfcActuator/Empty.001" is selected
And additionally the object "IfcFlowSegment/Empty" is selected
When I press "bim.assign_unassign_flow_control(assign=True)"
And the variable "assigned_controls" is "set(tool.System.get_flow_element_controls({ifc}.by_type('IfcFlowSegment')[0]))"
Then the variable "assigned_controls" is "set[{ifc}.by_type('IfcActuator')]"
+27
View File
@@ -277,3 +277,30 @@ class TestSetActiveSystem(NewFile):
system = ifcopenshell.api.run("system.add_system", ifc, ifc_class="IfcSystem")
subject.set_active_edited_system(system)
assert bpy.context.scene.BIMSystemProperties.edited_system_id == system.id()
class TestFlowElementAndControls(NewFile):
def test_run(self):
ifc = ifcopenshell.file()
flow_element = ifc.createIfcFlowSegment()
flow_control = ifc.createIfcController()
flow_control1 = ifc.createIfcController()
assert len(subject.get_flow_element_controls(flow_element)) == 0
assert subject.get_flow_control_flow_element(flow_control) == None
ifcopenshell.api.run(
"system.assign_flow_control",
ifc,
related_flow_control=flow_control,
relating_flow_element=flow_element,
)
ifcopenshell.api.run(
"system.assign_flow_control",
ifc,
related_flow_control=flow_control1,
relating_flow_element=flow_element,
)
controls = subject.get_flow_element_controls(flow_element)
assert set(controls) == set((flow_control, flow_control1))
assert subject.get_flow_control_flow_element(flow_control) == flow_element