adjust obstruction position on changing segment length

Now when you change the segment's length connected obstructions will adjust. Same for changing obstruction's length. You can also move obstructions/segment around and then use "Regenerate" to make them fit.
Small demo - https://imgur.com/a/atm8Mdx
This commit is contained in:
Andrej730
2023-08-02 16:28:45 +05:00
parent 92df1b351c
commit 45f81b4780
4 changed files with 74 additions and 14 deletions
@@ -41,6 +41,7 @@ float_is_zero = lambda f: 0.0001 >= f >= -0.0001
class FitFlowSegments(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.fit_flow_segments"
bl_description = "Add a fitting based on currently selected elements and cursor"
bl_label = "Fit Flow Segments"
bl_options = {"REGISTER", "UNDO"}
@@ -135,24 +136,69 @@ class MEPGenerator:
self.file = tool.Ifc.get()
self.collection = bpy.context.view_layer.active_layer_collection.collection
element = tool.Ifc.get_entity(obj)
representation = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
segment = tool.Ifc.get_entity(obj)
representation = ifcopenshell.util.representation.get_representation(segment, "Model", "Body", "MODEL_VIEW")
extrusion = tool.Model.get_extrusion(representation)
si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
length = extrusion.Depth * si_conversion
end_port_matrix = Matrix.Translation((0, 0, length))
start_port_matrix = obj.matrix_world @ Matrix()
end_port_matrix = obj.matrix_world @ Matrix.Translation((0, 0, length))
ports = tool.System.get_ports(element)
if not ports:
start_port_matrix = Matrix()
ports = tool.System.get_ports(segment)
if segment.is_a("IfcFlowSegment") and not ports:
for mat in [start_port_matrix, end_port_matrix]:
port = tool.Ifc.run("system.add_port", element=element)
# TODO: specify PredefinedType based on the segment type
port = tool.Ifc.run("system.add_port", element=segment)
port.FlowDirection = "NOTDEFINED"
tool.Ifc.run("geometry.edit_object_placement", product=port, matrix=obj.matrix_world @ mat, is_si=True)
tool.Ifc.run("geometry.edit_object_placement", product=port, matrix=mat, is_si=True)
return
end_port = self.get_segment_data(element)["end_port"]
tool.Model.edit_element_placement(end_port, obj.matrix_world @ end_port_matrix)
# adjust current segment ports and related flow segments
segment_data = self.get_segment_data(segment)
for port_position in ("start_port", "end_port"):
port = segment_data.get(port_position, None)
if not port:
continue
# no need to correct start port position - it's corrected automatically
# as DumbProfileJoiner already moved the general segment position in that case
if port_position == "end_port":
tool.Model.edit_element_placement(port, end_port_matrix)
connected_port = tool.System.get_connected_port(port)
if not connected_port:
continue
# handle only obstructions for now
connected_element = tool.System.get_port_relating_element(connected_port)
def get_predefined_type(element):
element_type = ifcopenshell.util.element.get_type(element)
if element_type:
return element_type.PredefinedType
return element.PredefinedType
connected_obj = tool.Ifc.get_object(connected_element)
connected_element_length = connected_obj.dimensions.z
if (segment.is_a("IfcFlowSegment") and get_predefined_type(connected_element) == "OBSTRUCTION") or (
segment.is_a("IfcFlowFitting") and connected_element.is_a("IfcFlowSegment")
):
if port_position == "start_port":
if segment.is_a("IfcFlowFitting"):
profile_joiner = DumbProfileJoiner()
connected_element_length = (
tool.Model.get_flow_segment_axis(connected_obj)[0]
- tool.Model.get_flow_segment_axis(obj)[0]
).length
connected_port_matrix = start_port_matrix @ Matrix.Translation((0, 0, -connected_element_length))
else:
connected_port_matrix = end_port_matrix
connected_obj.matrix_world = connected_port_matrix
if port_position == "start_port" and segment.is_a("IfcFlowFitting"):
profile_joiner = DumbProfileJoiner()
profile_joiner.set_depth(connected_obj, connected_element_length)
def get_segment_data(self, segment):
ports = tool.System.get_ports(segment)
@@ -275,6 +321,7 @@ class MEPGenerator:
profile_joiner.set_depth(obstruction_obj, length)
obstruction = tool.Ifc.get_entity(obstruction_obj)
# TODO: specify PredefinedType based on the segment type
obstruction_port = tool.Ifc.run("system.add_port", element=obstruction)
port_local_position = Matrix.Translation((0, 0, length)) if at_segment_start else Matrix()
tool.Ifc.run(
@@ -491,7 +491,7 @@ class DumbProfileJoiner:
should_sync_changes_first=False,
)
tool.Geometry.record_object_materials(obj)
if element.is_a("IfcFlowSegment"):
if element.is_a("IfcFlowSegment") or element.is_a("IfcFlowFitting"):
# lazy import to avoid circular import errors
from blenderbim.bim.module.model.mep import MEPGenerator
@@ -803,14 +803,23 @@ class RecalculateProfile(bpy.types.Operator, tool.Ifc.Operator):
class DumbProfileRecalculator:
def recalculate(self, profiles):
"`profiles` is a list of blender profile objects"
queue = set()
# also recalculate all connected elements
for profile in profiles:
element = tool.Ifc.get_entity(profile)
queue.add((element, profile))
connected_elements = []
for rel in getattr(element, "ConnectedTo", []):
queue.add((rel.RelatedElement, tool.Ifc.get_object(rel.RelatedElement)))
connected_elements.append(rel.RelatedElement)
for rel in getattr(element, "ConnectedFrom", []):
queue.add((rel.RelatingElement, tool.Ifc.get_object(rel.RelatingElement)))
connected_elements.append(rel.RelatingElement)
for element in connected_elements:
queue.add((element, tool.Ifc.get_object(element)))
joiner = DumbProfileJoiner()
for element, profile in queue:
if profile:
@@ -168,6 +168,7 @@ class HidePorts(bpy.types.Operator, Operator):
class AddPort(bpy.types.Operator, Operator):
bl_idname = "bim.add_port"
bl_description = "Add port at current cursor position"
bl_label = "Add Port"
bl_options = {"REGISTER", "UNDO"}
+4 -1
View File
@@ -64,6 +64,10 @@ class System(blenderbim.core.tool.System):
def get_ports(cls, element):
return ifcopenshell.util.system.get_ports(element)
@classmethod
def get_port_relating_element(cls, port):
return port.Nests[0].RelatingObject
@classmethod
def import_system_attributes(cls, system):
props = bpy.context.scene.BIMSystemProperties
@@ -129,7 +133,6 @@ class System(blenderbim.core.tool.System):
ifc_representation_class=ifc_representation_class,
)
@classmethod
def select_system_products(cls, system):
tool.Spatial.select_products(ifcopenshell.util.system.get_system_elements(system))