mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 09:48:32 +00:00
system decorations - live time update
Decoration data is now updating in live time, caching some parts in Data for performance. Real time update is needed because Data doesn't allow update on objects positions change and later will need real time update for viewport orientation data.
This commit is contained in:
@@ -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 = []
|
||||
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user