diff --git a/src/blenderbim/blenderbim/bim/module/drawing/decoration.py b/src/blenderbim/blenderbim/bim/module/drawing/decoration.py index ebff8b188d..2c0bf10b1f 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/decoration.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/decoration.py @@ -52,15 +52,20 @@ class profile_consequential: cls.test_name = test_name @classmethod - def log(cls): + def log(cls, args=[]): if cls.start_time is not None: - cls.lines.append(f"{cls.test_name}\t{timer() - cls.start_time:.10f}") + args = "" if not args else "\t" + "\t".join(args) + cls.lines.append(f"{cls.test_name}\t{timer() - cls.start_time:.10f}{args}") @classmethod def stop(cls): cls.log() cls.start_time = None - print("\n".join(cls.lines)) + lines = "\n".join(cls.lines) + print(lines) + import pyperclip + + pyperclip.copy(lines) cls.lines = [] diff --git a/src/blenderbim/blenderbim/bim/module/system/data.py b/src/blenderbim/blenderbim/bim/module/system/data.py index 3ba63ae1f7..6955fcdbbf 100644 --- a/src/blenderbim/blenderbim/bim/module/system/data.py +++ b/src/blenderbim/blenderbim/bim/module/system/data.py @@ -68,16 +68,18 @@ class ObjectSystemData: cls.data = { "systems": cls.systems(), "total_systems": cls.total_systems(), + # AFTER SYSTEMS + "connected_elements": cls.connected_elements(), } cls.is_loaded = True @classmethod def systems(cls): results = [] - element = tool.Ifc.get_entity(bpy.context.active_object) - if not element: + cls.element = tool.Ifc.get_entity(bpy.context.active_object) + if not cls.element: return results - for system in ifcopenshell.util.system.get_element_systems(element): + for system in ifcopenshell.util.system.get_element_systems(cls.element): results.append({"id": system.id(), "name": system.Name or "Unnamed", "ifc_class": system.is_a()}) return results @@ -85,6 +87,12 @@ class ObjectSystemData: def total_systems(cls): return len(tool.Ifc.get().by_type("IfcSystem")) + @classmethod + def connected_elements(cls): + if not cls.element: + return set() + return tool.System.get_connected_elements(cls.element) + class PortData: data = {} @@ -151,15 +159,34 @@ class PortData: class SystemDecorationData: data = {} + elements_ports_positions = {} is_loaded = False @classmethod def load(cls): - cls.data = { - "decoration_data": cls.decoration_data(), - } + cls.data = {} cls.is_loaded = True + cls.elements_ports_positions = {} @classmethod - def decoration_data(cls): - return tool.System.get_decoration_data() + def get_element_ports_data(cls, element): + """returns element's port data, caches the data until UI update + + Port data includes: + - local port position in SI units + - port flow direction + + """ + if element not in cls.elements_ports_positions: + ports = tool.System.get_ports(element) + si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get()) + ports_data = [] + for port in ports: + position = tool.Model.get_element_matrix(port, keep_local=True).translation * si_conversion + port_data = { + "position": position, + "flow_direction": port.FlowDirection, + } + ports_data.append(port_data) + cls.elements_ports_positions[element] = ports_data + return cls.elements_ports_positions[element] diff --git a/src/blenderbim/blenderbim/bim/module/system/decorator.py b/src/blenderbim/blenderbim/bim/module/system/decorator.py index 8cebbae4f3..e3e8518f79 100644 --- a/src/blenderbim/blenderbim/bim/module/system/decorator.py +++ b/src/blenderbim/blenderbim/bim/module/system/decorator.py @@ -111,11 +111,9 @@ class SystemDecorator: roof_angle_edges = [] preview_edges = [] - # NOTE: using .data here doesn't allow having live viewport orientation for the calculations - # but not using .data seems to be performance heavy - if not SystemDecorationData.is_loaded: - SystemDecorationData.load() - decoration_data = SystemDecorationData.data["decoration_data"] + # NOTE: using live update because Data wouldn't allow + # live time update of objects positions + decoration_data = tool.System.get_decoration_data() all_vertices = decoration_data["all_vertices"] preview_edges = decoration_data["preview_edges"] diff --git a/src/blenderbim/blenderbim/tool/model.py b/src/blenderbim/blenderbim/tool/model.py index e2a2c29773..47ae276c3a 100644 --- a/src/blenderbim/blenderbim/tool/model.py +++ b/src/blenderbim/blenderbim/tool/model.py @@ -31,6 +31,7 @@ from blenderbim.bim.module.geometry.helper import Helper from blenderbim.bim.module.model.data import AuthoringData, RailingData, RoofData, WindowData, DoorData import collections import json +import numpy as np class Model(blenderbim.core.tool.Model): @@ -815,8 +816,12 @@ class Model(blenderbim.core.tool.Model): tool.Ifc.run("geometry.edit_object_placement", product=element, matrix=matrix, is_si=True) @classmethod - def get_element_matrix(cls, element): - placement = ifcopenshell.util.placement.get_local_placement(element.ObjectPlacement) + def get_element_matrix(cls, element, keep_local=False): + placement = element.ObjectPlacement + if keep_local: + placement = ifcopenshell.util.placement.get_axis2placement(placement.RelativePlacement) + else: + placement = ifcopenshell.util.placement.get_local_placement(placement) return Matrix(placement) @classmethod diff --git a/src/blenderbim/blenderbim/tool/system.py b/src/blenderbim/blenderbim/tool/system.py index 9688875b89..6a0cd8b080 100644 --- a/src/blenderbim/blenderbim/tool/system.py +++ b/src/blenderbim/blenderbim/tool/system.py @@ -24,6 +24,8 @@ from blenderbim.bim import import_ifc import re from math import pi, cos, sin from mathutils import Matrix, Vector +from blenderbim.bim.module.system.data import ObjectSystemData, SystemDecorationData +from blenderbim.bim.module.drawing.decoration import profile_consequential class System(blenderbim.core.tool.System): @@ -204,13 +206,16 @@ class System(blenderbim.core.tool.System): def most_aligned_vector(a, vectors): return max(vectors, key=lambda v: abs(a.dot(v))) - si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get()) start_vert_i = 0 - if bpy.context.active_object and (active_element := tool.Ifc.get_entity(bpy.context.active_object)): - selected_elements = cls.get_connected_elements(active_element) - else: - selected_elements = set() + if not ObjectSystemData.is_loaded: + ObjectSystemData.load() + + if not SystemDecorationData.is_loaded: + SystemDecorationData.load() + + object_system_data = ObjectSystemData.data + selected_elements = object_system_data["connected_elements"] # TODO: get only objects visible in viewport objects = set(bpy.data.objects) - set(bpy.data.collections["Types"].objects) @@ -230,19 +235,17 @@ class System(blenderbim.core.tool.System): continue selected_element = element in selected_elements - ports = tool.System.get_ports(element) verts_pos = [] - for port in ports: - position = tool.Model.get_element_matrix(port).translation * si_conversion - verts_pos.append(position) + port_data = SystemDecorationData.get_element_ports_data(element) + verts_pos.extend([obj.matrix_world @ data["position"] for data in port_data]) - verts = range(start_vert_i, start_vert_i + len(ports)) - edges = [(i, i + 1) for i in range(start_vert_i, start_vert_i + len(ports) - 1)] + verts = range(start_vert_i, start_vert_i + len(port_data)) + edges = [(i, i + 1) for i in range(start_vert_i, start_vert_i + len(port_data) - 1)] - def get_flow_direction(ports): + def get_flow_direction(port_data): # diagram - https://i.imgur.com/ioYL7bZ.png - flow_dirs = [p.FlowDirection for p in ports] + flow_dirs = [p["flow_direction"] for p in port_data] unique = set(flow_dirs) if len(unique) == 1: return 0 @@ -256,7 +259,7 @@ class System(blenderbim.core.tool.System): return -1 return 0 - if len(ports) == 2 and selected_element and (flow_direction := get_flow_direction(ports)): + if len(port_data) == 2 and selected_element and (flow_direction := get_flow_direction(port_data)): edge_verts = verts_pos.copy() edge_verts = edge_verts[::flow_direction] @@ -284,7 +287,7 @@ class System(blenderbim.core.tool.System): n_direction_lines = int(n_direction_lines) + 1 start_offset /= 2 start_offset = edge_dir * start_offset + base_vert - cur_vert_index = start_vert_i + len(ports) + cur_vert_index = start_vert_i + len(port_data) for i in range(n_direction_lines): cur_offset = start_offset + edge_dir * i * direction_lines_offset