From 84931fbbd2a1c2ee2c5076dce3329a7a55823585 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Thu, 9 Jan 2025 17:40:52 +1100 Subject: [PATCH 01/61] See #5941. Don't show mode changes if an object is unselectable. Unselectable things should be uneditable. That's what the lock/unlock is for. --- src/bonsai/bonsai/bim/module/model/workspace.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/model/workspace.py b/src/bonsai/bonsai/bim/module/model/workspace.py index 5720c7df30..7e56054858 100644 --- a/src/bonsai/bonsai/bim/module/model/workspace.py +++ b/src/bonsai/bonsai/bim/module/model/workspace.py @@ -118,10 +118,6 @@ class BimTool(WorkSpaceTool): EditObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type) else: CreateObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type) - # Show some UI for spatial elements that are unselectable by default. - if active_ifc_object: - EditObjectUI.layout = layout # Prevent .draw_modes from using old layout and crash. - EditObjectUI.draw_modes(context) class WallTool(BimTool): From e220b6981ede44975f458938e475ba8ab10000a5 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Thu, 9 Jan 2025 18:24:09 +1100 Subject: [PATCH 02/61] See #5940. Fix bug where ODS and XLSX didn't correctly check for whether summaries existed and sometimes printed out "None" rows --- src/ifccsv/ifccsv.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/ifccsv/ifccsv.py b/src/ifccsv/ifccsv.py index 0030bc84d1..247946236a 100755 --- a/src/ifccsv/ifccsv.py +++ b/src/ifccsv/ifccsv.py @@ -296,12 +296,12 @@ class IfcCsv: writer.writerow(self.headers) for row in self.results: writer.writerow(row) - if any([s for s in self.summaries if s is not None]): + if self.has_summaries(): writer.writerow(self.summaries) def export_ods(self, output, should_preserve_existing=False): df = self.export_pd() - if self.summaries: + if self.has_summaries(): df.loc[df.shape[0]] = self.summaries if os.path.exists(output) and should_preserve_existing: @@ -362,9 +362,12 @@ class IfcCsv: row.addElement(new_cell) return new_cell + def has_summaries(self): + return any([s for s in self.summaries if s is not None]) + def export_xlsx(self, output, should_preserve_existing=False): df = self.export_pd() - if self.summaries: + if self.has_summaries(): df.loc[df.shape[0]] = self.summaries if os.path.exists(output): From 40dcfd450fafdff72eadcd4c88857ca40ac90698 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Thu, 9 Jan 2025 18:25:00 +1100 Subject: [PATCH 03/61] See #5940. Fix bug where using preserve existing in IfcCSV didn't fully purge extra rows, possibly leading to orphaned data (which LibreOffice will render as 0 if it is a number value type) --- src/ifccsv/ifccsv.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/ifccsv/ifccsv.py b/src/ifccsv/ifccsv.py index 247946236a..34e4b37b32 100755 --- a/src/ifccsv/ifccsv.py +++ b/src/ifccsv/ifccsv.py @@ -324,10 +324,9 @@ class IfcCsv: # If the DataFrame has fewer rows than the table, blank out the extra rows num_rows_table = len(first_table.getElementsByType(TableRow)) - 1 # Exclude header row if len(df) < num_rows_table: - for i in range(len(df) + 1, num_rows_table + 1): # +1 to account for header - for cell in first_table.getElementsByType(TableRow)[i].getElementsByType(TableCell): - for item in cell.childNodes: - cell.removeChild(item) + rows = first_table.getElementsByType(TableRow) + for i in reversed(range(len(df) + 1, num_rows_table + 1)): # +1 to account for header + first_table.removeChild(rows[i]) ods_document.save(output) else: From 8b1d4ca5d4a05820c9c49e34cb746d6652fb2597 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Perdig=C3=A3o?= Date: Wed, 8 Jan 2025 20:56:21 -0300 Subject: [PATCH 04/61] Implement polyline tool for profiles. --- .../bonsai/bim/module/model/__init__.py | 1 + .../bonsai/bim/module/model/decorator.py | 136 +++++++-------- src/bonsai/bonsai/bim/module/model/profile.py | 165 +++++++++++++++++- .../bonsai/bim/module/model/workspace.py | 4 + 4 files changed, 229 insertions(+), 77 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/model/__init__.py b/src/bonsai/bonsai/bim/module/model/__init__.py index 2be31b25c1..74dd0a2e7f 100644 --- a/src/bonsai/bonsai/bim/module/model/__init__.py +++ b/src/bonsai/bonsai/bim/module/model/__init__.py @@ -95,6 +95,7 @@ classes = ( profile.ChangeCardinalPoint, profile.ChangeProfileDepth, profile.DisableEditingExtrusionAxis, + profile.DrawPolylineProfile, profile.EditExtrusionAxis, profile.EnableEditingExtrusionAxis, profile.ExtendProfile, diff --git a/src/bonsai/bonsai/bim/module/model/decorator.py b/src/bonsai/bonsai/bim/module/model/decorator.py index 86c5e72e55..b426f42736 100644 --- a/src/bonsai/bonsai/bim/module/model/decorator.py +++ b/src/bonsai/bonsai/bim/module/model/decorator.py @@ -25,7 +25,7 @@ import bmesh import ifcopenshell import bonsai.tool as tool import math -from math import sin, cos, tan, radians +from math import sin, cos, tan, radians, atan2 from bpy.types import SpaceView3D from bpy_extras import view3d_utils from mathutils import Vector, Matrix, Quaternion @@ -981,22 +981,24 @@ class ProductDecorator: def get_profile_preview_data(self, context, relating_type): material = ifcopenshell.util.element.get_material(relating_type) try: - profile = material.MaterialProfiles[0].Profile + profile_curve = material.MaterialProfiles[0].Profile except: return {} model_props = context.scene.BIMModelProperties - extrusion_depth = model_props.extrusion_depth cardinal_point = model_props.cardinal_point - rot_mat = Quaternion() - if relating_type.is_a("IfcBeamType"): - y_rot = Quaternion((0.0, 1.0, 0.0), radians(90)) - z_rot = Quaternion((0.0, 0.0, 1.0), radians(90)) - rot_mat = y_rot @ z_rot - # Get profile data + + polyline_verts = [] + polyline_data = context.scene.BIMPolylineProperties.insertion_polyline + polyline_points = polyline_data[0].polyline_points if polyline_data else [] + if len(polyline_points) < 2: + return + for point in polyline_points: + polyline_verts.append(Vector((point.x, point.y, point.z))) + polyline_edges = [(i, i+1) for i in range(len(polyline_verts)-1)] settings = ifcopenshell.geom.settings() settings.set("dimensionality", ifcopenshell.ifcopenshell_wrapper.CURVES_SURFACES_AND_SOLIDS) - shape = ifcopenshell.geom.create_shape(settings, profile) + shape = ifcopenshell.geom.create_shape(settings, profile_curve) verts = shape.verts if not verts: @@ -1036,78 +1038,65 @@ class ProductDecorator: case "9": grouped_verts = [(v[0] + x_offset, v[1] - y_offset, v[2]) for v in grouped_verts] - # Create extrusion bmesh + + profile_curve = bpy.data.curves.new("Profile", type='CURVE') + profile_curve.dimensions = "2D" + profile_curve.splines.new('POLY') + profile_curve.splines[0].points.add(len(grouped_verts) - 1) + + for i, point in enumerate(profile_curve.splines[0].points): + point.co = Vector((*grouped_verts[i], 0)) + + profile_obj = bpy.data.objects.new("Profile", profile_curve) + + preview_curve = bpy.data.curves.new("Polyline", type='CURVE') + preview_curve.dimensions = "2D" + preview_curve.splines.new('POLY') + preview_curve.splines[0].points.add(len(polyline_verts) - 1) + for i, point in enumerate(preview_curve.splines[0].points): + point.co = Vector((*polyline_verts[i], 0)) + preview_curve.splines[0].use_smooth = False + preview_curve.bevel_mode = "OBJECT" + preview_curve.bevel_object = profile_obj + + preview_obj = bpy.data.objects.new("Preview", preview_curve) + context.scene.collection.objects.link(preview_obj) + bpy.context.view_layer.objects.active = preview_obj + selection = preview_obj.select_get() + bpy.ops.object.select_all(action="DESELECT") + preview_obj.select_set(True) + bpy.ops.object.convert(target="MESH") + preview_obj = bpy.data.objects["Preview"] + bm = bmesh.new() - - new_verts = [bm.verts.new(v) for v in grouped_verts] - new_edges = [bm.edges.new((new_verts[i], new_verts[i + 1])) for i in range(len(grouped_verts) - 1)] - - bm.verts.index_update() - bm.edges.index_update() - - new_faces = bmesh.ops.contextual_create(bm, geom=bm.edges) - - new_faces = bmesh.ops.extrude_face_region(bm, geom=bm.faces) - new_verts = [e for e in new_faces["geom"] if isinstance(e, bmesh.types.BMVert)] - new_faces = bmesh.ops.translate(bm, verts=new_verts, vec=(0.0, 0.0, extrusion_depth)) - + new_verts = [bm.verts.new(v.co) for v in preview_obj.data.vertices] + index = [[v for v in edge.vertices] for edge in preview_obj.data.edges] + new_edges = [bm.edges.new((new_verts[i[0]], new_verts[i[1]])) for i in index] + for face in preview_obj.data.polygons: + verts = [new_verts[i] for i in face.vertices] + bm.faces.new(verts) bm.verts.index_update() bm.edges.index_update() tris = [[loop.vert.index for loop in triangles] for triangles in bm.calc_loop_triangles()] - # Create bounding box - verts = bm.verts - i = len(verts) - - min_x = min(v.co.x for v in verts) - max_x = max(v.co.x for v in verts) - min_y = min(v.co.y for v in verts) - max_y = max(v.co.y for v in verts) - min_z = min(v.co.z for v in verts) - max_z = max(v.co.z for v in verts) - - bbox_verts = [ - (min_x, min_y, min_z), - (max_x, min_y, min_z), - (max_x, max_y, min_z), - (min_x, max_y, min_z), - (min_x, min_y, max_z), - (max_x, min_y, max_z), - (max_x, max_y, max_z), - (min_x, max_y, max_z), - ] - - bbox_edges = [ - (0 + i, 3 + i), - (3 + i, 7 + i), - (7 + i, 4 + i), - (4 + i, 0 + i), - (0 + i, 1 + i), - (3 + i, 2 + i), - (7 + i, 6 + i), - (4 + i, 5 + i), - (1 + i, 2 + i), - (2 + i, 6 + i), - (6 + i, 5 + i), - (5 + i, 1 + i), - ] - - # Calculate rotation, mouse position, angle and cardinal point - # TODO Angle - snap_prop = context.scene.BIMPolylineProperties.snap_mouse_point[0] - mouse_point = Vector((snap_prop.x, snap_prop.y, snap_prop.z)) data = {} - - verts = [tuple(v.co) for v in verts] - verts.extend(bbox_verts) - verts = [tuple(rot_mat @ Vector(v)) for v in verts] - verts = [tuple(Vector(v) + mouse_point) for v in verts] - data["verts"] = verts - data["edges"] = bbox_edges - # data["edges"] = [(edge.verts[0].index, edge.verts[1].index) for edge in bm.edges] + data["verts"] = [tuple(v.co) for v in bm.verts] + data["edges"] = [(edge.verts[0].index, edge.verts[1].index) for edge in bm.edges] data["tris"] = tris + bpy.data.objects.remove(bpy.data.objects[preview_obj.name], do_unlink=True) + bpy.data.objects.remove(bpy.data.objects[profile_obj.name], do_unlink=True) + try: + bpy.data.curves.remove(profile_obj.data, do_unlink=True) + except: + pass + try: + bpy.data.curves.remove(preview_obj.data, do_unlink=True) + except: + pass + bm.free() + return data def draw_product_preview(self, context): @@ -1152,6 +1141,7 @@ class ProductDecorator: ) # Profile type products + self.line_shader.uniform_float("lineWidth", 0.5) product_preview_data = self.get_profile_preview_data(context, self.relating_type) if product_preview_data: self.draw_batch("LINES", product_preview_data["verts"], decorator_color, product_preview_data["edges"]) diff --git a/src/bonsai/bonsai/bim/module/model/profile.py b/src/bonsai/bonsai/bim/module/model/profile.py index e10eb578bf..442b04efab 100644 --- a/src/bonsai/bonsai/bim/module/model/profile.py +++ b/src/bonsai/bonsai/bim/module/model/profile.py @@ -32,11 +32,13 @@ import bonsai.core.type import bonsai.core.geometry import bonsai.core.material import bonsai.core.root -from math import pi, degrees, inf +from math import pi, degrees, inf, atan2 from mathutils import Vector, Matrix, Quaternion from bonsai.bim.module.geometry.helper import Helper from bonsai.bim.module.model.wall import DumbWallRecalculator -from bonsai.bim.module.model.decorator import ProfileDecorator +from bonsai.bim.module.model.decorator import ProfileDecorator, PolylineDecorator, ProductDecorator +from bonsai.bim.module.model.polyline import PolylineOperator +from typing import Union, Any class DumbProfileGenerator: @@ -44,7 +46,7 @@ class DumbProfileGenerator: self.relating_type = relating_type self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get()) - def generate(self): + def generate(self, insertion_type="CURSOR"): self.file = tool.Ifc.get() self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get()) material = ifcopenshell.util.element.get_material(self.relating_type) @@ -67,7 +69,28 @@ class DumbProfileGenerator: self.rotation = 0 self.location = Vector((0, 0, 0)) self.cardinal_point = int(bpy.context.scene.BIMModelProperties.cardinal_point) - return self.derive_from_cursor() + if insertion_type == "POLYLINE": + return self.derive_from_polyline() + elif insertion_type == "CURSOR": + return self.derive_from_cursor() + + def derive_from_polyline(self) -> tuple[list[Union[dict[str, Any], None]], bool]: + polyline_data = bpy.context.scene.BIMPolylineProperties.insertion_polyline + polyline_points = polyline_data[0].polyline_points if polyline_data else [] + is_polyline_closed = False + if len(polyline_points) > 3: + first_vec = Vector((polyline_points[0].x, polyline_points[0].y, polyline_points[0].z)) + last_vec = Vector((polyline_points[-1].x, polyline_points[-1].y, polyline_points[-1].z)) + if first_vec == last_vec: + is_polyline_closed = True + + profiles = [] + for i in range(len(polyline_points) - 1): + vec1 = Vector((polyline_points[i].x, polyline_points[i].y, polyline_points[i].z)) + vec2 = Vector((polyline_points[i + 1].x, polyline_points[i + 1].y, polyline_points[i + 1].z)) + coords = (vec1, vec2) + profiles.append(self.create_profile_from_2_points(coords)) + return profiles, is_polyline_closed def derive_from_cursor(self): self.location = bpy.context.scene.cursor.location @@ -86,6 +109,9 @@ class DumbProfileGenerator: "IfcFlowSegmentType" ): matrix_world = Matrix.Rotation(pi / 2, 4, "Z") @ Matrix.Rotation(pi / 2, 4, "X") @ matrix_world + + matrix_world = Matrix.Rotation(self.rotation, 4, "Z") @ matrix_world + matrix_world.translation = self.location if self.container_obj: matrix_world.translation.z = self.container_obj.location.z @@ -146,6 +172,25 @@ class DumbProfileGenerator: return obj + def create_profile_from_2_points(self, coords, should_round=False) -> Union[dict[str, Any], None]: + direction = coords[1] - coords[0] + length = direction.length + if round(length, 4) < 0.1: + return + data = {"coords": coords} + + self.depth = length + self.rotation = atan2(direction[1], direction[0]) + if should_round: + # Round to nearest 50mm (yes, metric for now) + self.length = 0.05 * round(length / 0.05) + # Round to nearest 5 degrees + nearest_degree = (math.pi / 180) * 5 + self.rotation = nearest_degree * round(self.rotation / nearest_degree) + self.location = coords[0] + data["obj"] = self.create_profile() + return data + class DumbProfileRegenerator: def regenerate_from_profile_def(self, profile): @@ -1064,3 +1109,115 @@ class EditExtrusionAxis(bpy.types.Operator, tool.Ifc.Operator): joiner = DumbProfileJoiner() joiner.set_depth(obj, depth) return {"FINISHED"} + + +class DrawPolylineProfile(bpy.types.Operator, PolylineOperator): + bl_idname = "bim.draw_polyline_profile" + bl_label = "Draw Polyline Profile" + bl_options = {"REGISTER", "UNDO"} + + @classmethod + def poll(cls, context): + return context.space_data.type == "VIEW_3D" + + def __init__(self): + super().__init__() + self.relating_type = None + props = bpy.context.scene.BIMModelProperties + relating_type_id = props.relating_type_id + if relating_type_id: + self.relating_type = tool.Ifc.get().by_id(int(relating_type_id)) + + def create_profiles_from_polyline(self, context: bpy.types.Context) -> Union[set[str], None]: + if not self.relating_type: + return {"FINISHED"} + + model_props = context.scene.BIMModelProperties + direction_sense = model_props.direction_sense + offset = model_props.offset + + profiles, is_polyline_closed = DumbProfileGenerator(self.relating_type).generate("POLYLINE") + if profiles: + if is_polyline_closed: + for profile1, profile2 in zip(profiles, profiles[1:] + [profiles[0]]): + DumbProfileJoiner().join_V(profile2["obj"], profile1["obj"]) + else: + for profile1, profile2 in zip(profiles[:-1], profiles[1:]): + DumbProfileJoiner().join_V(profile2["obj"], profile1["obj"]) + + + def modal(self, context, event): + if not self.relating_type: + self.report({"WARNING"}, "You need to select a profile type.") + PolylineDecorator.uninstall() + tool.Blender.update_viewport() + return {"FINISHED"} + + PolylineDecorator.update(event, self.tool_state, self.input_ui, self.snapping_points[0]) + tool.Blender.update_viewport() + + self.handle_lock_axis(context, event) # Must come before "PASS_TRHOUGH" + + if event.type in {"MIDDLEMOUSE", "WHEELUPMOUSE", "WHEELDOWNMOUSE"}: + self.handle_mouse_move(context, event) + return {"PASS_THROUGH"} + + # Wall axis settings + if event.value == "RELEASE" and event.type == "F": + direction_sense = context.scene.BIMModelProperties.direction_sense + context.scene.BIMModelProperties.direction_sense = ( + "NEGATIVE" if direction_sense == "POSITIVE" else "POSITIVE" + ) + + if event.value == "RELEASE" and event.type == "O": + offset_type = context.scene.BIMModelProperties.offset_type + items = ["EXTERIOR", "CENTER", "INTERIOR"] + index = items.index(offset_type) + size = len(items) + context.scene.BIMModelProperties.offset_type = items[((index + 1) % size)] + + + props = bpy.context.scene.BIMModelProperties + wall_config = f"""Direction: {props.direction_sense} + Offset Type: {props.offset_type} + Offset Value: {props.offset} + """ + self.handle_instructions(context, wall_config) + + self.handle_mouse_move(context, event, should_round=True) + + self.choose_axis(event) + + self.handle_snap_selection(context, event) + + if ( + not self.tool_state.is_input_on + and event.value == "RELEASE" + and event.type in {"RET", "NUMPAD_ENTER", "RIGHTMOUSE"} + ): + self.create_profiles_from_polyline(context) + context.workspace.status_text_set(text=None) + ProductDecorator.uninstall() + PolylineDecorator.uninstall() + tool.Polyline.clear_polyline() + tool.Blender.update_viewport() + return {"FINISHED"} + + self.handle_keyboard_input(context, event) + + self.handle_inserting_polyline(context, event) + + cancel = self.handle_cancelation(context, event) + if cancel is not None: + ProductDecorator.uninstall() + return cancel + + return {"RUNNING_MODAL"} + + def invoke(self, context, event): + super().invoke(context, event) + ProductDecorator.install(context) + self.tool_state.use_default_container = True + self.tool_state.plane_method = "XY" + return {"RUNNING_MODAL"} + diff --git a/src/bonsai/bonsai/bim/module/model/workspace.py b/src/bonsai/bonsai/bim/module/model/workspace.py index 7e56054858..d02804ff6c 100644 --- a/src/bonsai/bonsai/bim/module/model/workspace.py +++ b/src/bonsai/bonsai/bim/module/model/workspace.py @@ -991,6 +991,10 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator): relating_type_id and tool.Model.get_usage_type(tool.Ifc.get().by_id(int(relating_type_id))) == "LAYER3" ): bpy.ops.bim.draw_polyline_slab("INVOKE_DEFAULT") + elif ( + relating_type_id and tool.Model.get_usage_type(tool.Ifc.get().by_id(int(relating_type_id))) == "PROFILE" + ): + bpy.ops.bim.draw_polyline_profile("INVOKE_DEFAULT") else: bpy.ops.bim.add_occurrence("INVOKE_DEFAULT") From 737402cae474879b9fb6e4dcc95ea159d51ad473 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Perdig=C3=A3o?= Date: Thu, 9 Jan 2025 08:45:03 -0300 Subject: [PATCH 05/61] Fix profile scale issue in profile preview decorator. --- src/bonsai/bonsai/bim/module/model/decorator.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bonsai/bonsai/bim/module/model/decorator.py b/src/bonsai/bonsai/bim/module/model/decorator.py index b426f42736..301f2d5edb 100644 --- a/src/bonsai/bonsai/bim/module/model/decorator.py +++ b/src/bonsai/bonsai/bim/module/model/decorator.py @@ -1039,6 +1039,8 @@ class ProductDecorator: grouped_verts = [(v[0] + x_offset, v[1] - y_offset, v[2]) for v in grouped_verts] + scale_mat = Matrix.Scale(-1, 4, (1.0, 0.0, 0.0)) + grouped_verts = [scale_mat @ Vector(v) for v in grouped_verts] profile_curve = bpy.data.curves.new("Profile", type='CURVE') profile_curve.dimensions = "2D" profile_curve.splines.new('POLY') From 0124b7a0e9c1f60ad4764e5331c06d42a4df3c94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Perdig=C3=A3o?= Date: Thu, 9 Jan 2025 08:45:40 -0300 Subject: [PATCH 06/61] Allow polyline profile for IfcCoveringType --- src/bonsai/bonsai/bim/module/model/profile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bonsai/bonsai/bim/module/model/profile.py b/src/bonsai/bonsai/bim/module/model/profile.py index 442b04efab..83fd9c97da 100644 --- a/src/bonsai/bonsai/bim/module/model/profile.py +++ b/src/bonsai/bonsai/bim/module/model/profile.py @@ -105,7 +105,7 @@ class DumbProfileGenerator: obj = bpy.data.objects.new(tool.Model.generate_occurrence_name(self.relating_type, ifc_class), mesh) matrix_world = Matrix() - if self.relating_type.is_a() in ["IfcBeamType", "IfcMemberType"] or self.relating_type.is_a( + if self.relating_type.is_a() in ["IfcBeamType", "IfcCoveringType", "IfcMemberType"] or self.relating_type.is_a( "IfcFlowSegmentType" ): matrix_world = Matrix.Rotation(pi / 2, 4, "Z") @ Matrix.Rotation(pi / 2, 4, "X") @ matrix_world From 66577fd30d2f81e9ce3faac74218738a658e1334 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Perdig=C3=A3o?= Date: Thu, 9 Jan 2025 13:18:44 -0300 Subject: [PATCH 07/61] Prevent polyline profile from being called by Column Tool --- src/bonsai/bonsai/bim/module/model/workspace.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bonsai/bonsai/bim/module/model/workspace.py b/src/bonsai/bonsai/bim/module/model/workspace.py index d02804ff6c..87f0602889 100644 --- a/src/bonsai/bonsai/bim/module/model/workspace.py +++ b/src/bonsai/bonsai/bim/module/model/workspace.py @@ -954,6 +954,7 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator): def hotkey_S_A(self): props = bpy.context.scene.BIMModelProperties relating_type_id = AuthoringData.data["relating_type_id_current"] + relating_type_class = AuthoringData.data["ifc_class_current"] if relating_type_id is None: self.report({"ERROR"}, "No relating type selected") return @@ -992,7 +993,7 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator): ): bpy.ops.bim.draw_polyline_slab("INVOKE_DEFAULT") elif ( - relating_type_id and tool.Model.get_usage_type(tool.Ifc.get().by_id(int(relating_type_id))) == "PROFILE" + relating_type_id and tool.Model.get_usage_type(tool.Ifc.get().by_id(int(relating_type_id))) == "PROFILE" and relating_type_class not in {"IfcColumnType"} ): bpy.ops.bim.draw_polyline_profile("INVOKE_DEFAULT") else: From 6b8024f83504c240cff172b7224bcf1c6af37b07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Perdig=C3=A3o?= Date: Thu, 9 Jan 2025 13:28:07 -0300 Subject: [PATCH 08/61] Refactor: Improve profile preview decorator to prevent GPU context errors --- .../bonsai/bim/module/model/__init__.py | 4 + .../bonsai/bim/module/model/decorator.py | 131 ++-------------- .../bonsai/bim/module/model/polyline.py | 148 ++++++++++++++++++ src/bonsai/bonsai/bim/module/model/profile.py | 2 + src/bonsai/bonsai/bim/module/model/prop.py | 10 ++ 5 files changed, 174 insertions(+), 121 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/model/__init__.py b/src/bonsai/bonsai/bim/module/model/__init__.py index 74dd0a2e7f..6bf42d99e9 100644 --- a/src/bonsai/bonsai/bim/module/model/__init__.py +++ b/src/bonsai/bonsai/bim/module/model/__init__.py @@ -128,6 +128,7 @@ classes = ( prop.SnapMousePoint, prop.PolylinePoint, prop.Polyline, + prop.ProductPreviewItem, prop.BIMModelProperties, prop.BIMArrayProperties, prop.BIMStairProperties, @@ -137,6 +138,7 @@ classes = ( prop.BIMRailingProperties, prop.BIMRoofProperties, prop.BIMPolylineProperties, + prop.BIMProductPreviewProperties, ui.BIM_PT_array, ui.BIM_PT_stair, ui.BIM_PT_sverchok, @@ -219,6 +221,7 @@ def register(): bpy.types.Scene.BIMModelProperties = bpy.props.PointerProperty(type=prop.BIMModelProperties) bpy.types.Scene.BIMPolylineProperties = bpy.props.PointerProperty(type=prop.BIMPolylineProperties) + bpy.types.Scene.BIMProductPreviewProperties = bpy.props.PointerProperty(type=prop.BIMProductPreviewProperties) bpy.types.Object.BIMArrayProperties = bpy.props.PointerProperty(type=prop.BIMArrayProperties) bpy.types.Object.BIMStairProperties = bpy.props.PointerProperty(type=prop.BIMStairProperties) bpy.types.Object.BIMSverchokProperties = bpy.props.PointerProperty(type=prop.BIMSverchokProperties) @@ -249,6 +252,7 @@ def unregister(): del bpy.types.Scene.BIMModelProperties del bpy.types.Scene.BIMPolylineProperties + del bpy.types.Scene.BIMProductPreviewProperties del bpy.types.Object.BIMArrayProperties del bpy.types.Object.BIMStairProperties del bpy.types.Object.BIMSverchokProperties diff --git a/src/bonsai/bonsai/bim/module/model/decorator.py b/src/bonsai/bonsai/bim/module/model/decorator.py index 301f2d5edb..5e3fc70e06 100644 --- a/src/bonsai/bonsai/bim/module/model/decorator.py +++ b/src/bonsai/bonsai/bim/module/model/decorator.py @@ -786,6 +786,10 @@ class ProductDecorator: @classmethod def uninstall(cls): + props = bpy.context.scene.BIMProductPreviewProperties # updated by model/polyline.py + props.verts.clear() + props.edges.clear() + props.tris.clear() for handler in cls.handlers: try: SpaceView3D.draw_handler_remove(handler, "WINDOW") @@ -978,127 +982,12 @@ class ProductDecorator: data["verts"] = [tuple(rot_mat @ (Vector((v[0], v[1], (v[2] + rl)))) + mouse_point) for v in data["verts"]] return data - def get_profile_preview_data(self, context, relating_type): - material = ifcopenshell.util.element.get_material(relating_type) - try: - profile_curve = material.MaterialProfiles[0].Profile - except: - return {} - - model_props = context.scene.BIMModelProperties - cardinal_point = model_props.cardinal_point - - polyline_verts = [] - polyline_data = context.scene.BIMPolylineProperties.insertion_polyline - polyline_points = polyline_data[0].polyline_points if polyline_data else [] - if len(polyline_points) < 2: - return - for point in polyline_points: - polyline_verts.append(Vector((point.x, point.y, point.z))) - polyline_edges = [(i, i+1) for i in range(len(polyline_verts)-1)] - settings = ifcopenshell.geom.settings() - settings.set("dimensionality", ifcopenshell.ifcopenshell_wrapper.CURVES_SURFACES_AND_SOLIDS) - shape = ifcopenshell.geom.create_shape(settings, profile_curve) - - verts = shape.verts - if not verts: - raise RuntimeError("Profile shape has no vertices, it probably is invalid.") - - edges = shape.edges - - grouped_verts = [[verts[i], verts[i + 1], 0] for i in range(0, len(verts), 3)] - grouped_edges = [[edges[i], edges[i + 1]] for i in range(0, len(edges), 2)] - - # Create offsets based on cardinal point - min_x = min(v[0] for v in grouped_verts) - max_x = max(v[0] for v in grouped_verts) - min_y = min(v[1] for v in grouped_verts) - max_y = max(v[1] for v in grouped_verts) - - x_offset = (max_x - min_x) / 2 - y_offset = (max_y - min_y) / 2 - - match cardinal_point: - case "1": - grouped_verts = [(v[0] - x_offset, v[1] + y_offset, v[2]) for v in grouped_verts] - case "2": - grouped_verts = [(v[0], v[1] + y_offset, v[2]) for v in grouped_verts] - case "3": - grouped_verts = [(v[0] + x_offset, v[1] + y_offset, v[2]) for v in grouped_verts] - case "4": - grouped_verts = [(v[0] - x_offset, v[1], v[2]) for v in grouped_verts] - case "5": - grouped_verts = [(v[0], v[1], v[2]) for v in grouped_verts] - case "6": - grouped_verts = [(v[0] + x_offset, v[1], v[2]) for v in grouped_verts] - case "7": - grouped_verts = [(v[0] - x_offset, v[1] - y_offset, v[2]) for v in grouped_verts] - case "8": - grouped_verts = [(v[0], v[1] - y_offset, v[2]) for v in grouped_verts] - case "9": - grouped_verts = [(v[0] + x_offset, v[1] - y_offset, v[2]) for v in grouped_verts] - - - scale_mat = Matrix.Scale(-1, 4, (1.0, 0.0, 0.0)) - grouped_verts = [scale_mat @ Vector(v) for v in grouped_verts] - profile_curve = bpy.data.curves.new("Profile", type='CURVE') - profile_curve.dimensions = "2D" - profile_curve.splines.new('POLY') - profile_curve.splines[0].points.add(len(grouped_verts) - 1) - - for i, point in enumerate(profile_curve.splines[0].points): - point.co = Vector((*grouped_verts[i], 0)) - - profile_obj = bpy.data.objects.new("Profile", profile_curve) - - preview_curve = bpy.data.curves.new("Polyline", type='CURVE') - preview_curve.dimensions = "2D" - preview_curve.splines.new('POLY') - preview_curve.splines[0].points.add(len(polyline_verts) - 1) - for i, point in enumerate(preview_curve.splines[0].points): - point.co = Vector((*polyline_verts[i], 0)) - preview_curve.splines[0].use_smooth = False - preview_curve.bevel_mode = "OBJECT" - preview_curve.bevel_object = profile_obj - - preview_obj = bpy.data.objects.new("Preview", preview_curve) - context.scene.collection.objects.link(preview_obj) - bpy.context.view_layer.objects.active = preview_obj - selection = preview_obj.select_get() - bpy.ops.object.select_all(action="DESELECT") - preview_obj.select_set(True) - bpy.ops.object.convert(target="MESH") - preview_obj = bpy.data.objects["Preview"] - - bm = bmesh.new() - new_verts = [bm.verts.new(v.co) for v in preview_obj.data.vertices] - index = [[v for v in edge.vertices] for edge in preview_obj.data.edges] - new_edges = [bm.edges.new((new_verts[i[0]], new_verts[i[1]])) for i in index] - for face in preview_obj.data.polygons: - verts = [new_verts[i] for i in face.vertices] - bm.faces.new(verts) - bm.verts.index_update() - bm.edges.index_update() - tris = [[loop.vert.index for loop in triangles] for triangles in bm.calc_loop_triangles()] - + def get_profile_preview_data(self, context): + props = context.scene.BIMProductPreviewProperties data = {} - data["verts"] = [tuple(v.co) for v in bm.verts] - data["edges"] = [(edge.verts[0].index, edge.verts[1].index) for edge in bm.edges] - data["tris"] = tris - - bpy.data.objects.remove(bpy.data.objects[preview_obj.name], do_unlink=True) - bpy.data.objects.remove(bpy.data.objects[profile_obj.name], do_unlink=True) - try: - bpy.data.curves.remove(profile_obj.data, do_unlink=True) - except: - pass - try: - bpy.data.curves.remove(preview_obj.data, do_unlink=True) - except: - pass - - bm.free() - + data["verts"] = [(*v.value,) for v in props.verts] + data["edges"] = [(int(e.tvalue[0]),int(e.tvalue[1])) for e in props.edges] + data["tris"] = [(int(t.value[0]), int(t.value[1]), int(t.value[2])) for t in props.tris] return data def draw_product_preview(self, context): @@ -1144,7 +1033,7 @@ class ProductDecorator: # Profile type products self.line_shader.uniform_float("lineWidth", 0.5) - product_preview_data = self.get_profile_preview_data(context, self.relating_type) + product_preview_data = self.get_profile_preview_data(context) if product_preview_data: self.draw_batch("LINES", product_preview_data["verts"], decorator_color, product_preview_data["edges"]) self.draw_batch( diff --git a/src/bonsai/bonsai/bim/module/model/polyline.py b/src/bonsai/bonsai/bim/module/model/polyline.py index 62c155ba98..168f0af08f 100644 --- a/src/bonsai/bonsai/bim/module/model/polyline.py +++ b/src/bonsai/bonsai/bim/module/model/polyline.py @@ -43,6 +43,150 @@ from typing import Optional, Union, Literal from lark import Lark, Transformer +def get_profile_preview_data(context, relating_type): + material = ifcopenshell.util.element.get_material(relating_type) + try: + profile_curve = material.MaterialProfiles[0].Profile + except: + return {} + + model_props = context.scene.BIMModelProperties + cardinal_point = model_props.cardinal_point + + polyline_verts = [] + polyline_data = context.scene.BIMPolylineProperties.insertion_polyline + polyline_points = polyline_data[0].polyline_points if polyline_data else [] + if len(polyline_points) < 2: + return + for point in polyline_points: + polyline_verts.append(Vector((point.x, point.y, point.z))) + polyline_edges = [(i, i+1) for i in range(len(polyline_verts)-1)] + + # Get profile shape + settings = ifcopenshell.geom.settings() + settings.set("dimensionality", ifcopenshell.ifcopenshell_wrapper.CURVES_SURFACES_AND_SOLIDS) + shape = ifcopenshell.geom.create_shape(settings, profile_curve) + + verts = shape.verts + if not verts: + raise RuntimeError("Profile shape has no vertices, it probably is invalid.") + + edges = shape.edges + + grouped_verts = [[verts[i], verts[i + 1], 0] for i in range(0, len(verts), 3)] + grouped_edges = [[edges[i], edges[i + 1]] for i in range(0, len(edges), 2)] + + # Create offsets based on cardinal point + min_x = min(v[0] for v in grouped_verts) + max_x = max(v[0] for v in grouped_verts) + min_y = min(v[1] for v in grouped_verts) + max_y = max(v[1] for v in grouped_verts) + + x_offset = (max_x - min_x) / 2 + y_offset = (max_y - min_y) / 2 + + match cardinal_point: + case "1": + grouped_verts = [(v[0] - x_offset, v[1] + y_offset, v[2]) for v in grouped_verts] + case "2": + grouped_verts = [(v[0], v[1] + y_offset, v[2]) for v in grouped_verts] + case "3": + grouped_verts = [(v[0] + x_offset, v[1] + y_offset, v[2]) for v in grouped_verts] + case "4": + grouped_verts = [(v[0] - x_offset, v[1], v[2]) for v in grouped_verts] + case "5": + grouped_verts = [(v[0], v[1], v[2]) for v in grouped_verts] + case "6": + grouped_verts = [(v[0] + x_offset, v[1], v[2]) for v in grouped_verts] + case "7": + grouped_verts = [(v[0] - x_offset, v[1] - y_offset, v[2]) for v in grouped_verts] + case "8": + grouped_verts = [(v[0], v[1] - y_offset, v[2]) for v in grouped_verts] + case "9": + grouped_verts = [(v[0] + x_offset, v[1] - y_offset, v[2]) for v in grouped_verts] + + + # Create profile curve + scale_mat = Matrix.Scale(-1, 4, (1.0, 0.0, 0.0)) + grouped_verts = [scale_mat @ Vector(v) for v in grouped_verts] + profile_curve = bpy.data.curves.new("Profile", type='CURVE') + profile_curve.dimensions = "2D" + profile_curve.splines.new('POLY') + profile_curve.splines[0].points.add(len(grouped_verts)) + + for i, point in enumerate(profile_curve.splines[0].points): + if i == len(grouped_verts): # Close curve + point.co = Vector((*grouped_verts[0], 0)) + continue + point.co = Vector((*grouped_verts[i], 0)) + profile_obj = bpy.data.objects.new("Profile", profile_curve) + + # Create path curve with profile object as bevel + path_curve = bpy.data.curves.new("Polyline", type='CURVE') + path_curve.dimensions = "2D" + path_curve.splines.new('POLY') + path_curve.splines[0].points.add(len(polyline_verts) - 1) + for i, point in enumerate(path_curve.splines[0].points): + point.co = Vector((*polyline_verts[i], 0)) + path_curve.splines[0].use_smooth = False + path_curve.bevel_mode = "OBJECT" + path_curve.bevel_object = profile_obj + + # Convert path curve to mesh + # This operation throws a warning when done during gpu drawing, so it was removed from the decorator file to be handled here + path_obj = bpy.data.objects.new("Preview", path_curve) + context.scene.collection.objects.link(path_obj) + bpy.context.view_layer.objects.active = path_obj + dg = context.evaluated_depsgraph_get() + path_obj = path_obj.evaluated_get(dg) + me = path_obj.to_mesh() + + # Create bmesh from path mesh + bm = bmesh.new() + new_verts = [bm.verts.new(v.co) for v in me.vertices] + index = [[v for v in edge.vertices] for edge in me.edges] + new_edges = [bm.edges.new((new_verts[i[0]], new_verts[i[1]])) for i in index] + for face in me.polygons: + verts = [new_verts[i] for i in face.vertices] + bm.faces.new(verts) + bm.verts.index_update() + bm.edges.index_update() + tris = [[loop.vert.index for loop in triangles] for triangles in bm.calc_loop_triangles()] + + bpy.data.objects.remove(bpy.data.objects[path_obj.name], do_unlink=True) + bpy.data.objects.remove(bpy.data.objects[profile_obj.name], do_unlink=True) + try: + bpy.data.curves.remove(profile_obj.data, do_unlink=True) + except: + pass + try: + bpy.data.curves.remove(path_obj.data, do_unlink=True) + except: + pass + + data = {} + data["verts"] = [tuple(v.co) for v in bm.verts] + data["edges"] = [(edge.verts[0].index, edge.verts[1].index) for edge in bm.edges] + data["tris"] = tris + + # Update properties so it can be used by the decorator + props = context.scene.BIMProductPreviewProperties + props.verts.clear() + props.edges.clear() + props.tris.clear() + + for vert in data["verts"]: + v = props.verts.add() + v.value = vert + for edge in data["edges"]: + e = props.edges.add() + e.tvalue = edge + for tri in data["tris"]: + t = props.tris.add() + t.value = tri + + bm.free() + class PolylineOperator: # TODO Fill doc strings """ """ @@ -387,6 +531,10 @@ class PolylineOperator: tool.Polyline.remove_last_polyline_point() tool.Blender.update_viewport() + def get_product_preview_data(self, context: bpy.types.Context, relating_type: ifcopenshell.entity_isntance): + if relating_type.is_a() in ["IfcBeamType", "IfcCoveringType", "IfcMemberType"]: + return get_profile_preview_data(context, relating_type) + def modal(self, context: bpy.types.Context, event: bpy.types.Event) -> Union[set[str], None]: PolylineDecorator.update(event, self.tool_state, self.input_ui, self.snapping_points[0]) tool.Blender.update_viewport() diff --git a/src/bonsai/bonsai/bim/module/model/profile.py b/src/bonsai/bonsai/bim/module/model/profile.py index 83fd9c97da..e9057b63f7 100644 --- a/src/bonsai/bonsai/bim/module/model/profile.py +++ b/src/bonsai/bonsai/bim/module/model/profile.py @@ -1207,6 +1207,8 @@ class DrawPolylineProfile(bpy.types.Operator, PolylineOperator): self.handle_inserting_polyline(context, event) + self.get_product_preview_data(context, self.relating_type) + cancel = self.handle_cancelation(context, event) if cancel is not None: ProductDecorator.uninstall() diff --git a/src/bonsai/bonsai/bim/module/model/prop.py b/src/bonsai/bonsai/bim/module/model/prop.py index 27aa3151a4..7809d5b2d1 100644 --- a/src/bonsai/bonsai/bim/module/model/prop.py +++ b/src/bonsai/bonsai/bim/module/model/prop.py @@ -820,3 +820,13 @@ class BIMPolylineProperties(PropertyGroup): snap_mouse_ref: bpy.props.CollectionProperty(type=SnapMousePoint) insertion_polyline: bpy.props.CollectionProperty(type=Polyline) measurement_polyline: bpy.props.CollectionProperty(type=Polyline) + +class ProductPreviewItem(PropertyGroup): + value: bpy.props.FloatVectorProperty() + tvalue: bpy.props.FloatVectorProperty(size=2) + +class BIMProductPreviewProperties(PropertyGroup): + verts: bpy.props.CollectionProperty(type=ProductPreviewItem) + edges: bpy.props.CollectionProperty(type=ProductPreviewItem) + tris: bpy.props.CollectionProperty(type=ProductPreviewItem) + From cf054e11a18dbe6ebf32bce93855c25c41308c15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Perdig=C3=A3o?= Date: Thu, 9 Jan 2025 15:52:33 -0300 Subject: [PATCH 09/61] Refactor: improve preview decorators for other products, following 420a4cfdc --- .../bonsai/bim/module/model/decorator.py | 213 +---------- .../bonsai/bim/module/model/polyline.py | 350 ++++++++++++++++-- src/bonsai/bonsai/bim/module/model/product.py | 2 + src/bonsai/bonsai/bim/module/model/prop.py | 4 +- src/bonsai/bonsai/bim/module/model/wall.py | 2 + 5 files changed, 342 insertions(+), 229 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/model/decorator.py b/src/bonsai/bonsai/bim/module/model/decorator.py index 5e3fc70e06..a11bd6efff 100644 --- a/src/bonsai/bonsai/bim/module/model/decorator.py +++ b/src/bonsai/bonsai/bim/module/model/decorator.py @@ -25,15 +25,14 @@ import bmesh import ifcopenshell import bonsai.tool as tool import math -from math import sin, cos, tan, radians, atan2 +from math import sin, cos, radians from bpy.types import SpaceView3D from bpy_extras import view3d_utils -from mathutils import Vector, Matrix, Quaternion +from mathutils import Vector, Matrix from gpu_extras.batch import batch_for_shader from gpu_extras.presets import draw_circle_2d from typing import Union from bonsai.bim.module.drawing.helper import format_distance -from bonsai.bim.module.geometry.decorator import ItemDecorator def transparent_color(color, alpha=0.1): @@ -803,191 +802,12 @@ class ProductDecorator: shader.uniform_float("color", color) batch.draw(shader) - def get_wall_preview_data(cls, context, relating_type): - def create_bmesh_from_vertices(vertices): - bm = bmesh.new() - - new_verts = [bm.verts.new(v) for v in polyline_vertices] - if is_closed: - new_edges = [bm.edges.new((new_verts[i], new_verts[i + 1])) for i in range(len(new_verts) - 1)] - new_edges.append( - bm.edges.new((new_verts[-1], new_verts[0])) - ) # Add an edge between the last an first point to make it closed. - else: - new_edges = [bm.edges.new((new_verts[i], new_verts[i + 1])) for i in range(len(new_verts) - 1)] - - bm.verts.index_update() - bm.edges.index_update() - return bm - - # Get properties from object type - layers = tool.Model.get_material_layer_parameters(relating_type) - if not layers["thickness"]: - return - thickness = layers["thickness"] - model_props = context.scene.BIMModelProperties - direction_sense = model_props.direction_sense - direction = 1 - if direction_sense == "NEGATIVE": - direction = -1 - offset_type = model_props.offset_type - offset = 0 - if offset_type == "CENTER": - offset = -thickness / 2 - elif offset_type == "INTERIOR": - offset = -thickness - - unit_system = tool.Drawing.get_unit_system() - factor = 1 - if unit_system == "IMPERIAL": - factor = 3.048 - if unit_system == "METRIC": - unit_length = context.scene.unit_settings.length_unit - if unit_length == "MILLIMETERS": - factor = 1000 - - # For the model properties, the offset value should just be converted - # However, for the wall preview logic that follows, offset and thickness must change direction - model_props.offset = offset * factor - thickness *= direction - offset *= direction - - height = float(model_props.extrusion_depth) - rl = float(model_props.rl1) - x_angle = float(model_props.x_angle) - angle_distortion = height * tan(x_angle) - - wall_preview_data = {} - wall_preview_data["verts"] = [] - - # Verts - polyline_vertices = [] - polyline_data = context.scene.BIMPolylineProperties.insertion_polyline - polyline_points = polyline_data[0].polyline_points if polyline_data else [] - if len(polyline_points) < 2: - wall_preview_data = [] - return - for point in polyline_points: - polyline_vertices.append(Vector((point.x, point.y, point.z))) - - is_closed = False - if ( - polyline_vertices[0].x == polyline_vertices[-1].x - and polyline_vertices[0].y == polyline_vertices[-1].y - and polyline_vertices[0].z == polyline_vertices[-1].z - ): - is_closed = True - polyline_vertices.pop(-1) # Remove the last point. The edges are going to inform that the shape is closed. - - bm_base = create_bmesh_from_vertices(polyline_vertices) - base_vertices = tool.Cad.offset_edges(bm_base, offset) - offset_base_verts = tool.Cad.offset_edges(bm_base, thickness + offset) - top_vertices = tool.Cad.offset_edges(bm_base, angle_distortion + offset) - offset_top_verts = tool.Cad.offset_edges(bm_base, angle_distortion + thickness + offset) - if is_closed: - base_vertices.append(base_vertices[0]) - offset_base_verts.append(offset_base_verts[0]) - top_vertices.append(top_vertices[0]) - offset_top_verts.append(offset_top_verts[0]) - - if offset_base_verts is not None: - for v in base_vertices: - wall_preview_data["verts"].append((v.co.x, v.co.y, v.co.z + rl)) - - for v in offset_base_verts[::-1]: - wall_preview_data["verts"].append((v.co.x, v.co.y, v.co.z + rl)) - - for v in top_vertices: - wall_preview_data["verts"].append((v.co.x, v.co.y, v.co.z + rl + height)) - - for v in offset_top_verts[::-1]: - wall_preview_data["verts"].append((v.co.x, v.co.y, v.co.z + rl + height)) - - bm_base.free() - - # Edges and Tris - points = [] - side_edges_1 = [] - side_edges_2 = [] - base_edges = [] - - for i in range(len(wall_preview_data["verts"])): - points.append(Vector(wall_preview_data["verts"][i])) - - n = len(points) // 2 - bottom_side_1 = [[i, (i + 1) % (n)] for i in range((n - 1) // 2)] - bottom_side_2 = [[i, (i + 1) % (n)] for i in range(n // 2, n - 1)] - bottom_connections = [[i, n - i - 1] for i in range(n // 2)] - bottom_loop = bottom_connections + bottom_side_1 + bottom_side_2 - side_edges_1.extend(bottom_side_1) - side_edges_2.extend(bottom_side_2) - base_edges.extend(bottom_loop) - - upper_side_1 = [[i + n for i in edges] for edges in bottom_side_1] - upper_side_2 = [[i + n for i in edges] for edges in bottom_side_2] - upper_loop = [[i + n for i in edges] for edges in bottom_loop] - side_edges_1.extend(upper_side_1) - side_edges_2.extend(upper_side_2) - base_edges.extend(upper_loop) - - loops = [side_edges_1, side_edges_2, base_edges] - - wall_preview_data["edges"] = [] - wall_preview_data["tris"] = [] - for i, group in enumerate(loops): - bm = bmesh.new() - - new_verts = [bm.verts.new(v) for v in points] - new_edges = [bm.edges.new((new_verts[e[0]], new_verts[e[1]])) for e in group] - - bm.verts.index_update() - bm.edges.index_update() - - if i == 2: - new_faces = bmesh.ops.contextual_create(bm, geom=bm.edges) - new_faces = bmesh.ops.bridge_loops(bm, edges=bm.edges, use_pairs=True, use_cyclic=True) - - bm.verts.index_update() - bm.edges.index_update() - edges = [[v.index for v in e.verts] for e in bm.edges] - tris = [[l.vert.index for l in loop] for loop in bm.calc_loop_triangles()] - wall_preview_data["edges"].extend(edges) - wall_preview_data["tris"].extend(tris) - - wall_preview_data["edges"] = list(set(tuple(e) for e in wall_preview_data["edges"])) - wall_preview_data["tris"] = list(set(tuple(t) for t in wall_preview_data["tris"])) - - return wall_preview_data - - def get_product_preview_data(cls, context, relating_type): - model_props = context.scene.BIMModelProperties - if relating_type.is_a("IfcDoorType"): - rl = float(model_props.rl1) - elif relating_type.is_a("IfcWindowType"): - rl = float(model_props.rl2) - else: - rl = 0 - snap_prop = context.scene.BIMPolylineProperties.snap_mouse_point[0] - mouse_point = Vector((snap_prop.x, snap_prop.y, snap_prop.z)) - snap_obj = bpy.data.objects.get(snap_prop.snap_object) - snap_element = tool.Ifc.get_entity(snap_obj) - rot_mat = Quaternion() - if snap_element and snap_element.is_a("IfcWall"): - rot_mat = snap_obj.matrix_world.to_quaternion() - - obj_type = tool.Ifc.get_object(relating_type) - if obj_type.data: - data = ItemDecorator.get_obj_data(obj_type) - data["verts"] = [tuple(obj_type.matrix_world.inverted() @ Vector(v)) for v in data["verts"]] - data["verts"] = [tuple(rot_mat @ (Vector((v[0], v[1], (v[2] + rl)))) + mouse_point) for v in data["verts"]] - return data - - def get_profile_preview_data(self, context): + def get_product_preview_data(self, context): props = context.scene.BIMProductPreviewProperties data = {} - data["verts"] = [(*v.value,) for v in props.verts] - data["edges"] = [(int(e.tvalue[0]),int(e.tvalue[1])) for e in props.edges] - data["tris"] = [(int(t.value[0]), int(t.value[1]), int(t.value[2])) for t in props.tris] + data["verts"] = [(*v.value_3d,) for v in props.verts] + data["edges"] = [(int(e.value_2d[0]),int(e.value_2d[1])) for e in props.edges] + data["tris"] = [(int(t.value_3d[0]), int(t.value_3d[1]), int(t.value_3d[2])) for t in props.tris] return data def draw_product_preview(self, context): @@ -1014,26 +834,7 @@ class ProductDecorator: else: return - # Wall - if self.relating_type.is_a("IfcWallType"): - wall_preview_data = self.get_wall_preview_data(context, self.relating_type) - if wall_preview_data: - self.draw_batch("LINES", wall_preview_data["verts"], decorator_color, wall_preview_data["edges"]) - self.draw_batch( - "TRIS", wall_preview_data["verts"], transparent_color(decorator_color), wall_preview_data["tris"] - ) - - # Mesh type products - product_preview_data = self.get_product_preview_data(context, self.relating_type) - if product_preview_data: - self.draw_batch("LINES", product_preview_data["verts"], decorator_color, product_preview_data["edges"]) - self.draw_batch( - "TRIS", product_preview_data["verts"], transparent_color(decorator_color), product_preview_data["tris"] - ) - - # Profile type products - self.line_shader.uniform_float("lineWidth", 0.5) - product_preview_data = self.get_profile_preview_data(context) + product_preview_data = self.get_product_preview_data(context) if product_preview_data: self.draw_batch("LINES", product_preview_data["verts"], decorator_color, product_preview_data["edges"]) self.draw_batch( diff --git a/src/bonsai/bonsai/bim/module/model/polyline.py b/src/bonsai/bonsai/bim/module/model/polyline.py index 168f0af08f..fbaa088003 100644 --- a/src/bonsai/bonsai/bim/module/model/polyline.py +++ b/src/bonsai/bonsai/bim/module/model/polyline.py @@ -35,15 +35,282 @@ import bonsai.core.geometry import bonsai.core.model as core import bonsai.tool as tool from bonsai.bim.ifc import IfcStore -from math import pi, sin, cos, degrees -from mathutils import Vector, Matrix +from math import pi, sin, cos, degrees, tan +from mathutils import Vector, Matrix, Quaternion from bonsai.bim.module.model.opening import FilledOpeningGenerator from bonsai.bim.module.model.decorator import PolylineDecorator +from bonsai.bim.module.geometry.decorator import ItemDecorator from typing import Optional, Union, Literal from lark import Lark, Transformer -def get_profile_preview_data(context, relating_type): +def get_wall_preview_data(context, relating_type): + def create_bmesh_from_vertices(vertices): + bm = bmesh.new() + + new_verts = [bm.verts.new(v) for v in polyline_vertices] + if is_closed: + new_edges = [bm.edges.new((new_verts[i], new_verts[i + 1])) for i in range(len(new_verts) - 1)] + new_edges.append( + bm.edges.new((new_verts[-1], new_verts[0])) + ) # Add an edge between the last an first point to make it closed. + else: + new_edges = [bm.edges.new((new_verts[i], new_verts[i + 1])) for i in range(len(new_verts) - 1)] + + bm.verts.index_update() + bm.edges.index_update() + return bm + + # Get properties from object type + layers = tool.Model.get_material_layer_parameters(relating_type) + if not layers["thickness"]: + return + thickness = layers["thickness"] + model_props = context.scene.BIMModelProperties + direction_sense = model_props.direction_sense + direction = 1 + if direction_sense == "NEGATIVE": + direction = -1 + offset_type = model_props.offset_type + offset = 0 + if offset_type == "CENTER": + offset = -thickness / 2 + elif offset_type == "INTERIOR": + offset = -thickness + + unit_system = tool.Drawing.get_unit_system() + factor = 1 + if unit_system == "IMPERIAL": + factor = 3.048 + if unit_system == "METRIC": + unit_length = context.scene.unit_settings.length_unit + if unit_length == "MILLIMETERS": + factor = 1000 + + # For the model properties, the offset value should just be converted + # However, for the wall preview logic that follows, offset and thickness must change direction + model_props.offset = offset * factor + thickness *= direction + offset *= direction + + height = float(model_props.extrusion_depth) + rl = float(model_props.rl1) + x_angle = float(model_props.x_angle) + angle_distortion = height * tan(x_angle) + + data = {} + data["verts"] = [] + + # Verts + polyline_vertices = [] + polyline_data = context.scene.BIMPolylineProperties.insertion_polyline + polyline_points = polyline_data[0].polyline_points if polyline_data else [] + if len(polyline_points) < 2: + data = [] + return + for point in polyline_points: + polyline_vertices.append(Vector((point.x, point.y, point.z))) + + is_closed = False + if ( + polyline_vertices[0].x == polyline_vertices[-1].x + and polyline_vertices[0].y == polyline_vertices[-1].y + and polyline_vertices[0].z == polyline_vertices[-1].z + ): + is_closed = True + polyline_vertices.pop(-1) # Remove the last point. The edges are going to inform that the shape is closed. + + bm_base = create_bmesh_from_vertices(polyline_vertices) + base_vertices = tool.Cad.offset_edges(bm_base, offset) + offset_base_verts = tool.Cad.offset_edges(bm_base, thickness + offset) + top_vertices = tool.Cad.offset_edges(bm_base, angle_distortion + offset) + offset_top_verts = tool.Cad.offset_edges(bm_base, angle_distortion + thickness + offset) + if is_closed: + base_vertices.append(base_vertices[0]) + offset_base_verts.append(offset_base_verts[0]) + top_vertices.append(top_vertices[0]) + offset_top_verts.append(offset_top_verts[0]) + + if offset_base_verts is not None: + for v in base_vertices: + data["verts"].append((v.co.x, v.co.y, v.co.z + rl)) + + for v in offset_base_verts[::-1]: + data["verts"].append((v.co.x, v.co.y, v.co.z + rl)) + + for v in top_vertices: + data["verts"].append((v.co.x, v.co.y, v.co.z + rl + height)) + + for v in offset_top_verts[::-1]: + data["verts"].append((v.co.x, v.co.y, v.co.z + rl + height)) + + bm_base.free() + + # Edges and Tris + points = [] + side_edges_1 = [] + side_edges_2 = [] + base_edges = [] + + for i in range(len(data["verts"])): + points.append(Vector(data["verts"][i])) + + n = len(points) // 2 + bottom_side_1 = [[i, (i + 1) % (n)] for i in range((n - 1) // 2)] + bottom_side_2 = [[i, (i + 1) % (n)] for i in range(n // 2, n - 1)] + bottom_connections = [[i, n - i - 1] for i in range(n // 2)] + bottom_loop = bottom_connections + bottom_side_1 + bottom_side_2 + side_edges_1.extend(bottom_side_1) + side_edges_2.extend(bottom_side_2) + base_edges.extend(bottom_loop) + + upper_side_1 = [[i + n for i in edges] for edges in bottom_side_1] + upper_side_2 = [[i + n for i in edges] for edges in bottom_side_2] + upper_loop = [[i + n for i in edges] for edges in bottom_loop] + side_edges_1.extend(upper_side_1) + side_edges_2.extend(upper_side_2) + base_edges.extend(upper_loop) + + loops = [side_edges_1, side_edges_2, base_edges] + + data["edges"] = [] + data["tris"] = [] + for i, group in enumerate(loops): + bm = bmesh.new() + + new_verts = [bm.verts.new(v) for v in points] + new_edges = [bm.edges.new((new_verts[e[0]], new_verts[e[1]])) for e in group] + + bm.verts.index_update() + bm.edges.index_update() + + if i == 2: + new_faces = bmesh.ops.contextual_create(bm, geom=bm.edges) + new_faces = bmesh.ops.bridge_loops(bm, edges=bm.edges, use_pairs=True, use_cyclic=True) + + bm.verts.index_update() + bm.edges.index_update() + edges = [[v.index for v in e.verts] for e in bm.edges] + tris = [[l.vert.index for l in loop] for loop in bm.calc_loop_triangles()] + data["edges"].extend(edges) + data["tris"].extend(tris) + + data["edges"] = list(set(tuple(e) for e in data["edges"])) + data["tris"] = list(set(tuple(t) for t in data["tris"])) + + return data + +def get_vertical_profile_preview_data(context, relating_type): + material = ifcopenshell.util.element.get_material(relating_type) + try: + profile = material.MaterialProfiles[0].Profile + except: + return {} + + model_props = context.scene.BIMModelProperties + extrusion_depth = model_props.extrusion_depth + cardinal_point = model_props.cardinal_point + rot_mat = Quaternion() + if relating_type.is_a("IfcBeamType"): + y_rot = Quaternion((0.0, 1.0, 0.0), radians(90)) + z_rot = Quaternion((0.0, 0.0, 1.0), radians(90)) + rot_mat = y_rot @ z_rot + # Get profile data + settings = ifcopenshell.geom.settings() + settings.set("dimensionality", ifcopenshell.ifcopenshell_wrapper.CURVES_SURFACES_AND_SOLIDS) + shape = ifcopenshell.geom.create_shape(settings, profile) + + verts = shape.verts + if not verts: + raise RuntimeError("Profile shape has no vertices, it probably is invalid.") + + edges = shape.edges + + grouped_verts = [[verts[i], verts[i + 1], 0] for i in range(0, len(verts), 3)] + grouped_edges = [[edges[i], edges[i + 1]] for i in range(0, len(edges), 2)] + + # Create offsets based on cardinal point + min_x = min(v[0] for v in grouped_verts) + max_x = max(v[0] for v in grouped_verts) + min_y = min(v[1] for v in grouped_verts) + max_y = max(v[1] for v in grouped_verts) + + x_offset = (max_x - min_x) / 2 + y_offset = (max_y - min_y) / 2 + + match cardinal_point: + case "1": + grouped_verts = [(v[0] - x_offset, v[1] + y_offset, v[2]) for v in grouped_verts] + case "2": + grouped_verts = [(v[0], v[1] + y_offset, v[2]) for v in grouped_verts] + case "3": + grouped_verts = [(v[0] + x_offset, v[1] + y_offset, v[2]) for v in grouped_verts] + case "4": + grouped_verts = [(v[0] - x_offset, v[1], v[2]) for v in grouped_verts] + case "5": + grouped_verts = [(v[0], v[1], v[2]) for v in grouped_verts] + case "6": + grouped_verts = [(v[0] + x_offset, v[1], v[2]) for v in grouped_verts] + case "7": + grouped_verts = [(v[0] - x_offset, v[1] - y_offset, v[2]) for v in grouped_verts] + case "8": + grouped_verts = [(v[0], v[1] - y_offset, v[2]) for v in grouped_verts] + case "9": + grouped_verts = [(v[0] + x_offset, v[1] - y_offset, v[2]) for v in grouped_verts] + + # Create extrusion bmesh + bm = bmesh.new() + + grouped_verts.append(grouped_verts[0]) # Close profile + new_verts = [bm.verts.new(v) for v in grouped_verts] + new_edges = [bm.edges.new((new_verts[i], new_verts[i + 1])) for i in range(len(grouped_verts) - 1)] + + bm.verts.index_update() + bm.edges.index_update() + + bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.001) + + new_faces = bmesh.ops.contextual_create(bm, geom=bm.edges) + + new_faces = bmesh.ops.extrude_face_region(bm, geom=bm.faces, use_dissolve_ortho_edges=True) + new_verts = [e for e in new_faces["geom"] if isinstance(e, bmesh.types.BMVert)] + new_faces = bmesh.ops.translate(bm, verts=new_verts, vec=(0.0, 0.0, extrusion_depth)) + + bm.verts.index_update() + bm.edges.index_update() + tris = [[loop.vert.index for loop in triangles] for triangles in bm.calc_loop_triangles()] + + # Calculate rotation, mouse position, angle and cardinal point + snap_prop = context.scene.BIMPolylineProperties.snap_mouse_point[0] + mouse_point = Vector((snap_prop.x, snap_prop.y, snap_prop.z)) + data = {} + + verts = [tuple(v.co) for v in bm.verts] + verts = [tuple(rot_mat @ Vector(v)) for v in verts] + verts = [tuple(Vector(v) + mouse_point) for v in verts] + min_z = min(v.co.z for v in bm.verts) + max_z = max(v.co.z for v in bm.verts) + # Add axis verts + verts.append(tuple(mouse_point)) + verts.append(tuple(mouse_point + Vector((0, 0, max_z)))) + # Add only profile edges + edges = [] + for edge in bm.edges: + if (edge.verts[0].co.z == min_z and edge.verts[1].co.z == min_z) or (edge.verts[0].co.z == max_z and edge.verts[1].co.z == max_z): + edges.append(edge) + # Add axis edge + edges = [(edge.verts[0].index, edge.verts[1].index) for edge in edges] + edges.append((len(verts)-1, len(verts)-2)) + data["verts"] = verts + data["edges"] = edges + data["tris"] = tris + + bm.free() + + return data + + +def get_horizontal_profile_preview_data(context, relating_type): material = ifcopenshell.util.element.get_material(relating_type) try: profile_curve = material.MaterialProfiles[0].Profile @@ -169,24 +436,37 @@ def get_profile_preview_data(context, relating_type): data["edges"] = [(edge.verts[0].index, edge.verts[1].index) for edge in bm.edges] data["tris"] = tris - # Update properties so it can be used by the decorator - props = context.scene.BIMProductPreviewProperties - props.verts.clear() - props.edges.clear() - props.tris.clear() - - for vert in data["verts"]: - v = props.verts.add() - v.value = vert - for edge in data["edges"]: - e = props.edges.add() - e.tvalue = edge - for tri in data["tris"]: - t = props.tris.add() - t.value = tri - bm.free() + return data + + +def get_product_preview_data(context, relating_type): + model_props = context.scene.BIMModelProperties + if relating_type.is_a("IfcDoorType"): + rl = float(model_props.rl1) + elif relating_type.is_a("IfcWindowType"): + rl = float(model_props.rl2) + else: + rl = 0 + snap_prop = context.scene.BIMPolylineProperties.snap_mouse_point[0] + default_container_elevation = tool.Ifc.get_object(tool.Root.get_default_container()).location.z + mouse_point = Vector((snap_prop.x, snap_prop.y, default_container_elevation)) + snap_obj = bpy.data.objects.get(snap_prop.snap_object) + snap_element = tool.Ifc.get_entity(snap_obj) + rot_mat = Quaternion() + if snap_element and snap_element.is_a("IfcWall"): + rot_mat = snap_obj.matrix_world.to_quaternion() + + obj_type = tool.Ifc.get_object(relating_type) + if obj_type.data: + data = ItemDecorator.get_obj_data(obj_type) + data["verts"] = [tuple(obj_type.matrix_world.inverted() @ Vector(v)) for v in data["verts"]] + data["verts"] = [tuple(rot_mat @ (Vector((v[0], v[1], (v[2] + rl)))) + mouse_point) for v in data["verts"]] + + return data + + class PolylineOperator: # TODO Fill doc strings """ """ @@ -532,8 +812,36 @@ class PolylineOperator: tool.Blender.update_viewport() def get_product_preview_data(self, context: bpy.types.Context, relating_type: ifcopenshell.entity_isntance): - if relating_type.is_a() in ["IfcBeamType", "IfcCoveringType", "IfcMemberType"]: - return get_profile_preview_data(context, relating_type) + if ( + tool.Model.get_usage_type(relating_type) == "PROFILE" and relating_type.is_a() not in {"IfcColumnType"} + ): + data = get_horizontal_profile_preview_data(context, relating_type) + elif ( + tool.Model.get_usage_type(relating_type) == "PROFILE" and relating_type.is_a() in {"IfcColumnType"} + ): + data = get_vertical_profile_preview_data(context, relating_type) + elif tool.Model.get_usage_type(relating_type) == "LAYER2": + data = get_wall_preview_data(context, relating_type) + else: + data = get_product_preview_data(context, relating_type) + + # Update properties so it can be used by the decorator + if not data: + return + props = context.scene.BIMProductPreviewProperties + props.verts.clear() + props.edges.clear() + props.tris.clear() + + for vert in data["verts"]: + v = props.verts.add() + v.value_3d = vert + for edge in data["edges"]: + e = props.edges.add() + e.value_2d = edge + for tri in data["tris"]: + t = props.tris.add() + t.value_3d = tri def modal(self, context: bpy.types.Context, event: bpy.types.Event) -> Union[set[str], None]: PolylineDecorator.update(event, self.tool_state, self.input_ui, self.snapping_points[0]) diff --git a/src/bonsai/bonsai/bim/module/model/product.py b/src/bonsai/bonsai/bim/module/model/product.py index efa39f3cbe..b4bec77d48 100644 --- a/src/bonsai/bonsai/bim/module/model/product.py +++ b/src/bonsai/bonsai/bim/module/model/product.py @@ -191,6 +191,8 @@ class AddOccurrence(bpy.types.Operator, PolylineOperator): if event.value == "RELEASE" and event.type == "LEFTMOUSE": self.create_occurrence(context, event) + self.get_product_preview_data(context, self.relating_type) + cancel = self.handle_cancelation(context, event) if cancel is not None: ProductDecorator.uninstall() diff --git a/src/bonsai/bonsai/bim/module/model/prop.py b/src/bonsai/bonsai/bim/module/model/prop.py index 7809d5b2d1..bda91f79f3 100644 --- a/src/bonsai/bonsai/bim/module/model/prop.py +++ b/src/bonsai/bonsai/bim/module/model/prop.py @@ -822,8 +822,8 @@ class BIMPolylineProperties(PropertyGroup): measurement_polyline: bpy.props.CollectionProperty(type=Polyline) class ProductPreviewItem(PropertyGroup): - value: bpy.props.FloatVectorProperty() - tvalue: bpy.props.FloatVectorProperty(size=2) + value_3d: bpy.props.FloatVectorProperty() + value_2d: bpy.props.FloatVectorProperty(size=2) class BIMProductPreviewProperties(PropertyGroup): verts: bpy.props.CollectionProperty(type=ProductPreviewItem) diff --git a/src/bonsai/bonsai/bim/module/model/wall.py b/src/bonsai/bonsai/bim/module/model/wall.py index 88db7f3a26..1988ab7864 100644 --- a/src/bonsai/bonsai/bim/module/model/wall.py +++ b/src/bonsai/bonsai/bim/module/model/wall.py @@ -421,6 +421,8 @@ class DrawPolylineWall(bpy.types.Operator, PolylineOperator): self.handle_inserting_polyline(context, event) + self.get_product_preview_data(context, self.relating_type) + cancel = self.handle_cancelation(context, event) if cancel is not None: ProductDecorator.uninstall() From 07bb7e68ddaefde0f50767ae1b8658d323dc0ba2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Perdig=C3=A3o?= Date: Thu, 9 Jan 2025 16:14:11 -0300 Subject: [PATCH 10/61] Fix #5932 --- src/bonsai/bonsai/tool/raycast.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bonsai/bonsai/tool/raycast.py b/src/bonsai/bonsai/tool/raycast.py index 852ae2f8c1..5c3d01ecea 100644 --- a/src/bonsai/bonsai/tool/raycast.py +++ b/src/bonsai/bonsai/tool/raycast.py @@ -206,7 +206,7 @@ class Raycast(bonsai.core.tool.Raycast): bm.free() snapping_points = [] - sorted_points = sorted(points) + sorted_points = sorted(points, key=lambda x : x[0]) for p in sorted_points: point = copy.deepcopy(p) snapping_points.append(point[1]) From 1e448cb1709806b04bc289c49896ae1ee5366f65 Mon Sep 17 00:00:00 2001 From: Stephen Boddy Date: Thu, 9 Jan 2025 21:49:13 +0000 Subject: [PATCH 11/61] Add mini-guide to setting up IDE for debugging --- .../docs/guides/development/debugging.rst | 110 ++++++++++++++++++ src/bonsai/docs/guides/development/index.rst | 1 + src/bonsai/docs/index.rst | 1 + 3 files changed, 112 insertions(+) create mode 100644 src/bonsai/docs/guides/development/debugging.rst diff --git a/src/bonsai/docs/guides/development/debugging.rst b/src/bonsai/docs/guides/development/debugging.rst new file mode 100644 index 0000000000..69bb2c6244 --- /dev/null +++ b/src/bonsai/docs/guides/development/debugging.rst @@ -0,0 +1,110 @@ +Debugging Bonsai +================ + +This is a mini-guide to setting up an IDE and configuring it to debug Bonsai more +easily. It is currently specific to this writers own system (Ubuntu) but this +can be expanded by others. + +1. **Install VSCodium**: This will be system specific. I used the available + snap package. + + .. code-block:: bash + + sudo snap install --classic codium + + I chose VSCodium to avoid Microsoft telemetry and data harvesting, but + VSCode is going to be similar, and even a bit easier (i.e. steps 3 & 4). + +2. **Activate Python language support**: Start VSCodium, open the Extensions, find the Python + language support and activate it. + +3. **Install Blender Addon**: It seems VSCodium is not allowed to directly access + the Marketplace, and this addon (and the next) is not available in + VSCodium's equivalent. (Or I'm an idiot... entirely possible). This means a + few more steps are needed. + + Download the Blender addon's ``.vsix`` file from marketplace (Under "Resources") + using your browser from `this `_ + page. + + Install it with "**...**" -> "**Install from VSIX...**" + +4. **Install ms-vscode.cpptools**: When trying to use the Blender addon I got + an error about a missing dependancy. I read somewhere that this addon was + not needed, but I can't currently find the reference. At least for me, it + needs to be added the same way as step 3, or the Blender addon fails to + start. + + Download the Cpp Tools addon's ``.vsix`` file from marketplace (Under "Resources") + using your browser from `this `_ + page. You will need to select the correct download for your system OS and + architecture. + + Install it with "**...**" -> "**Install from VSIX...**" + +5. **Set the Blender config directory**: In **Settings** -> **Extensions** -> **Blender** -> "**Environment Variables**" + edit the json file to set the ``BLENDER_USER_RESOURCE`` to the config folder + you installed Bonsai to. For me: + + .. code-block:: json + + { + "blender.environmentVariables": { + "BLENDER_USER_RESOURCES": "/home/steve/.config/blender/4.2bonsai" + } + } + + .. note:: + You `must` change that path to the correct value for your system. + +6. **Unset the Just My Code flag**: In **Settings** -> **Extensions** -> **Blender** -> "**Just My Code**" + by unchecking the box. + + Again, this was advice found searching around in a github issue. If not + done, the breakpoints do not work for me. + +7. **Open the folder in VSCodium**: This is the same folder set in step 5. + + ``/home/steve/.config/blender/4.2bonsai`` + + This was a key point for me. Do `not` go deeper in the folder structure - + that just doesn't work. (Thanks @theoryshaw) + +8. **Start Blender**: In VSCodium press ``Ctrl+Shift+P``, and search/select + **Blender: Start**. + +9. **Set the Blender binary path**: The first time you try to start Blender the + addon will ask for the path of the binary. Navigate to your Blender binary + and select it. For me: + + ``/home/steve/Software/blender-git/build_linux/bin/blender`` + + .. warning:: + Do `not` try to use a binary installed using snap - it will `not` work. + Either install a debian package of Blender, or build it from source, and + use that. + + All being well, Blender should start and show the usual Bonsai UI. + +10. **Ensure Blender is behaving**: Exercise the interface a bit to be sure + Bonsai is working normally. Add a demo project, add some walls, etc. + + One issue I ran in to was opening the wrong folder in step 7. Due to the + way VSCodium works, I was getting two Bonsai plugins conflicting, and + failing in interesting ways. One symptom of this was the modal user + interface when adding walls was completely missing. Oh, and the debugger + completely failed to work. + + If you are happy, quit Blender, and try setting some breakpoints in + VSCodium then run Blender again, and try to trigger them. I set one on + the ``bim.add_sheet`` operator at: + ``extensions/.local/lib/python3.11/site-packages/bonsai/bim/module/drawing/operator.py:1456`` + + .. note:: + I made the mistake of setting the breakpoint on the ``_execute`` + methods ``def`` line, which did not work. This probably helped confuse + me when trying to get the addon to work. + +If you get to this point, congratulations! You will now be 1000% more effective +when troubleshooting issues, and able to make many more contributions, fixes +and patches. \ No newline at end of file diff --git a/src/bonsai/docs/guides/development/index.rst b/src/bonsai/docs/guides/development/index.rst index d0a0e46bf5..009fc835be 100644 --- a/src/bonsai/docs/guides/development/index.rst +++ b/src/bonsai/docs/guides/development/index.rst @@ -15,3 +15,4 @@ This chapter covers how you can help contribute to Bonsai. translations undo_system writing_docs + debugging diff --git a/src/bonsai/docs/index.rst b/src/bonsai/docs/index.rst index 1775f95e35..f9a8c490ef 100644 --- a/src/bonsai/docs/index.rst +++ b/src/bonsai/docs/index.rst @@ -58,6 +58,7 @@ and data-rich OpenBIM with Blender :) guides/development/index guides/authoring/other_addons guides/troubleshooting + guides/debugging .. toctree:: :hidden: From 4a1422d2926a0f31005c970adebf0e31ed91459f Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Fri, 10 Jan 2025 14:13:24 +1100 Subject: [PATCH 12/61] New annotations should not go into the unsorted collection --- src/bonsai/bonsai/core/drawing.py | 2 +- src/bonsai/bonsai/tool/collector.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/bonsai/bonsai/core/drawing.py b/src/bonsai/bonsai/core/drawing.py index 0a1ec7d5eb..9dd4490e98 100644 --- a/src/bonsai/bonsai/core/drawing.py +++ b/src/bonsai/bonsai/core/drawing.py @@ -425,7 +425,7 @@ def add_annotation( ifc_representation_class=drawing_tool.get_ifc_representation_class(object_type), ) ifc.run("group.assign_group", group=drawing_tool.get_drawing_group(drawing), products=[element]) - collector.assign(obj) + collector.assign(obj, should_clean_users_collection=True) drawing_tool.enable_editing(obj) diff --git a/src/bonsai/bonsai/tool/collector.py b/src/bonsai/bonsai/tool/collector.py index 2754f708ad..e6400a3076 100644 --- a/src/bonsai/bonsai/tool/collector.py +++ b/src/bonsai/bonsai/tool/collector.py @@ -31,11 +31,11 @@ class Collector(bonsai.core.tool.Collector): for users_collection in obj.users_collection: if obj.BIMObjectProperties.collection == users_collection: continue - # Users are free to user extra collections for their own + # Users are free to use extra collections for their own # purposes except for the reserved keyword "Ifc" and # "Collection" (which is the default collection that comes with - # a Blender session) - if "Ifc" in users_collection.name or users_collection.name == "Collection": + # a Blender session) and "Unsorted" (our special collection). + if "Ifc" in users_collection.name or users_collection.name in ("Collection", "Unsorted"): users_collection.objects.unlink(obj) element = tool.Ifc.get_entity(obj) From e4412e2f51593c784a16bcb6a419ab140af6c455 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Fri, 10 Jan 2025 15:21:18 +1100 Subject: [PATCH 13/61] Black --- src/bonsai/bonsai/bim/import_ifc.py | 1 - .../bonsai/bim/module/aggregate/decorator.py | 14 +++----- .../bonsai/bim/module/aggregate/operator.py | 8 +++-- .../bonsai/bim/module/geometry/operator.py | 6 ++-- .../bonsai/bim/module/model/decorator.py | 6 ++-- .../bonsai/bim/module/model/polyline.py | 36 +++++++++---------- src/bonsai/bonsai/bim/module/model/profile.py | 3 -- src/bonsai/bonsai/bim/module/model/prop.py | 3 +- .../bonsai/bim/module/model/workspace.py | 8 +++-- src/bonsai/bonsai/bim/module/pset/ui.py | 4 ++- src/bonsai/bonsai/bim/ui.py | 16 +++++---- src/bonsai/bonsai/core/aggregate.py | 7 +++- src/bonsai/bonsai/tool/geometry.py | 4 +-- src/bonsai/bonsai/tool/loader.py | 3 +- src/bonsai/bonsai/tool/raycast.py | 2 +- src/bonsai/bonsai/tool/root.py | 1 - 16 files changed, 63 insertions(+), 59 deletions(-) diff --git a/src/bonsai/bonsai/bim/import_ifc.py b/src/bonsai/bonsai/bim/import_ifc.py index c30bbca3db..c2145b16fb 100644 --- a/src/bonsai/bonsai/bim/import_ifc.py +++ b/src/bonsai/bonsai/bim/import_ifc.py @@ -1129,7 +1129,6 @@ class IfcImporter: tool.Aggregate.constrain_all_parts_to_aggregate(relating_obj) bpy.context.scene.BIMAggregateProperties.aggregate_decorator = True - def lock_scales(self) -> None: elements = set(self.file.by_type("IfcProduct")) while elements: diff --git a/src/bonsai/bonsai/bim/module/aggregate/decorator.py b/src/bonsai/bonsai/bim/module/aggregate/decorator.py index 911fc86890..e1afe6b507 100644 --- a/src/bonsai/bonsai/bim/module/aggregate/decorator.py +++ b/src/bonsai/bonsai/bim/module/aggregate/decorator.py @@ -207,7 +207,6 @@ class AggregateDecorator: parts = ifcopenshell.util.element.get_parts(tool.Ifc.get_entity(aggregate)) parts_objs = [tool.Ifc.get_object(p) for p in parts] - indices, edges = create_bounding_box(parts_objs) self.line_shader.uniform_float("lineWidth", 0.5) self.draw_batch("LINES", indices, color, edges) @@ -230,9 +229,7 @@ class AggregateModeDecorator: cls.handlers.append( SpaceView3D.draw_handler_add(handler.draw_aggregate_empty, (context,), "WINDOW", "POST_VIEW") ) - cls.handlers.append( - SpaceView3D.draw_handler_add(handler.draw_new_objects, (context,), "WINDOW", "POST_VIEW") - ) + cls.handlers.append(SpaceView3D.draw_handler_add(handler.draw_new_objects, (context,), "WINDOW", "POST_VIEW")) cls.is_installed = True @classmethod @@ -352,12 +349,11 @@ class AggregateModeDecorator: new_objs = [o for o in new_objs if o.data] for obj in new_objs: element = tool.Ifc.get_entity(obj) - if (aggregate := ifcopenshell.util.element.get_aggregate(element)) == tool.Ifc.get_entity(props.editing_aggregate): + if (aggregate := ifcopenshell.util.element.get_aggregate(element)) == tool.Ifc.get_entity( + props.editing_aggregate + ): continue if element and element.is_a("IfcElement"): data = ItemDecorator.get_obj_data(obj) if data: - self.draw_batch( - "TRIS", data["verts"], transparent_color((1, 0, 0, 1)), data["tris"] - ) - + self.draw_batch("TRIS", data["verts"], transparent_color((1, 0, 0, 1)), data["tris"]) diff --git a/src/bonsai/bonsai/bim/module/aggregate/operator.py b/src/bonsai/bonsai/bim/module/aggregate/operator.py index 87b46412b7..49516d1f82 100644 --- a/src/bonsai/bonsai/bim/module/aggregate/operator.py +++ b/src/bonsai/bonsai/bim/module/aggregate/operator.py @@ -375,6 +375,7 @@ class BIM_OT_select_linked_aggregates(bpy.types.Operator): return {"FINISHED"} + class BIM_OT_disable_aggregate_mode(bpy.types.Operator): bl_idname = "bim.disable_aggregate_mode" bl_label = "Disable Aggregate Mode" @@ -385,6 +386,7 @@ class BIM_OT_disable_aggregate_mode(bpy.types.Operator): bonsai.core.aggregate.disable_aggregate_mode(tool.Aggregate) return {"FINISHED"} + class BIM_OT_toggle_aggregate_mode_local_view(bpy.types.Operator): bl_idname = "bim.toggle_aggregate_mode_local_view" bl_label = "Toggle Aggregate Mode Local View" @@ -403,6 +405,7 @@ class BIM_OT_toggle_aggregate_mode_local_view(bpy.types.Operator): return {"FINISHED"} + class BIM_OT_aggregate_assign_new_objects_in_aggregate_mode(bpy.types.Operator): bl_idname = "bim.aggregate_assign_new_objects_in_aggregate_mode" bl_label = "Aggregate Assign New Objects In Aggregate Mode" @@ -424,7 +427,9 @@ class BIM_OT_aggregate_assign_new_objects_in_aggregate_mode(bpy.types.Operator): new_objs = [o for o in new_objs if o.data] for obj in new_objs: element = tool.Ifc.get_entity(obj) - if (aggregate := ifcopenshell.util.element.get_aggregate(element)) == tool.Ifc.get_entity(props.editing_aggregate): + if (aggregate := ifcopenshell.util.element.get_aggregate(element)) == tool.Ifc.get_entity( + props.editing_aggregate + ): continue if element and element.is_a("IfcElement"): obj.select_set(True) @@ -439,4 +444,3 @@ class BIM_OT_aggregate_assign_new_objects_in_aggregate_mode(bpy.types.Operator): BIM_OT_aggregate_assign_object._execute(self, context) return {"FINISHED"} - diff --git a/src/bonsai/bonsai/bim/module/geometry/operator.py b/src/bonsai/bonsai/bim/module/geometry/operator.py index 9208ba302a..aac604fb48 100644 --- a/src/bonsai/bonsai/bim/module/geometry/operator.py +++ b/src/bonsai/bonsai/bim/module/geometry/operator.py @@ -1858,7 +1858,7 @@ class OverrideEscape(bpy.types.Operator): bpy.ops.bim.hide_all_openings() elif context.scene.BIMAggregateProperties.in_aggregate_mode: bpy.ops.bim.disable_aggregate_mode() - elif active_object:=context.active_object: + elif active_object := context.active_object: if tool.Blender.Modifier.try_canceling_editing_modifier_parameters_or_path(active_object): pass return {"FINISHED"} @@ -1902,7 +1902,9 @@ class OverrideModeSetEdit(bpy.types.Operator, tool.Ifc.Operator): self.report({"ERROR"}, f"Element '{obj.name}' is in item mode and cannot be edited directly") elif obj in [o.obj for o in context.scene.BIMAggregateProperties.not_editing_objects]: obj.select_set(False) - self.report({"ERROR"}, f"Element '{obj.name}' does not belong to this aggregate and cannot be edited directly") + self.report( + {"ERROR"}, f"Element '{obj.name}' does not belong to this aggregate and cannot be edited directly" + ) elif obj in bpy.context.scene.BIMProjectProperties.clipping_planes_objs: self.report({"ERROR"}, "Clipping planes cannot be edited") elif element: diff --git a/src/bonsai/bonsai/bim/module/model/decorator.py b/src/bonsai/bonsai/bim/module/model/decorator.py index a11bd6efff..0d1bd6079e 100644 --- a/src/bonsai/bonsai/bim/module/model/decorator.py +++ b/src/bonsai/bonsai/bim/module/model/decorator.py @@ -25,7 +25,7 @@ import bmesh import ifcopenshell import bonsai.tool as tool import math -from math import sin, cos, radians +from math import sin, cos, radians from bpy.types import SpaceView3D from bpy_extras import view3d_utils from mathutils import Vector, Matrix @@ -785,7 +785,7 @@ class ProductDecorator: @classmethod def uninstall(cls): - props = bpy.context.scene.BIMProductPreviewProperties # updated by model/polyline.py + props = bpy.context.scene.BIMProductPreviewProperties # updated by model/polyline.py props.verts.clear() props.edges.clear() props.tris.clear() @@ -806,7 +806,7 @@ class ProductDecorator: props = context.scene.BIMProductPreviewProperties data = {} data["verts"] = [(*v.value_3d,) for v in props.verts] - data["edges"] = [(int(e.value_2d[0]),int(e.value_2d[1])) for e in props.edges] + data["edges"] = [(int(e.value_2d[0]), int(e.value_2d[1])) for e in props.edges] data["tris"] = [(int(t.value_3d[0]), int(t.value_3d[1]), int(t.value_3d[2])) for t in props.tris] return data diff --git a/src/bonsai/bonsai/bim/module/model/polyline.py b/src/bonsai/bonsai/bim/module/model/polyline.py index fbaa088003..85ff369a43 100644 --- a/src/bonsai/bonsai/bim/module/model/polyline.py +++ b/src/bonsai/bonsai/bim/module/model/polyline.py @@ -200,6 +200,7 @@ def get_wall_preview_data(context, relating_type): return data + def get_vertical_profile_preview_data(context, relating_type): material = ifcopenshell.util.element.get_material(relating_type) try: @@ -261,7 +262,7 @@ def get_vertical_profile_preview_data(context, relating_type): # Create extrusion bmesh bm = bmesh.new() - grouped_verts.append(grouped_verts[0]) # Close profile + grouped_verts.append(grouped_verts[0]) # Close profile new_verts = [bm.verts.new(v) for v in grouped_verts] new_edges = [bm.edges.new((new_verts[i], new_verts[i + 1])) for i in range(len(grouped_verts) - 1)] @@ -296,11 +297,13 @@ def get_vertical_profile_preview_data(context, relating_type): # Add only profile edges edges = [] for edge in bm.edges: - if (edge.verts[0].co.z == min_z and edge.verts[1].co.z == min_z) or (edge.verts[0].co.z == max_z and edge.verts[1].co.z == max_z): + if (edge.verts[0].co.z == min_z and edge.verts[1].co.z == min_z) or ( + edge.verts[0].co.z == max_z and edge.verts[1].co.z == max_z + ): edges.append(edge) # Add axis edge edges = [(edge.verts[0].index, edge.verts[1].index) for edge in edges] - edges.append((len(verts)-1, len(verts)-2)) + edges.append((len(verts) - 1, len(verts) - 2)) data["verts"] = verts data["edges"] = edges data["tris"] = tris @@ -327,7 +330,7 @@ def get_horizontal_profile_preview_data(context, relating_type): return for point in polyline_points: polyline_verts.append(Vector((point.x, point.y, point.z))) - polyline_edges = [(i, i+1) for i in range(len(polyline_verts)-1)] + polyline_edges = [(i, i + 1) for i in range(len(polyline_verts) - 1)] # Get profile shape settings = ifcopenshell.geom.settings() @@ -372,26 +375,25 @@ def get_horizontal_profile_preview_data(context, relating_type): case "9": grouped_verts = [(v[0] + x_offset, v[1] - y_offset, v[2]) for v in grouped_verts] - # Create profile curve scale_mat = Matrix.Scale(-1, 4, (1.0, 0.0, 0.0)) grouped_verts = [scale_mat @ Vector(v) for v in grouped_verts] - profile_curve = bpy.data.curves.new("Profile", type='CURVE') + profile_curve = bpy.data.curves.new("Profile", type="CURVE") profile_curve.dimensions = "2D" - profile_curve.splines.new('POLY') + profile_curve.splines.new("POLY") profile_curve.splines[0].points.add(len(grouped_verts)) for i, point in enumerate(profile_curve.splines[0].points): - if i == len(grouped_verts): # Close curve + if i == len(grouped_verts): # Close curve point.co = Vector((*grouped_verts[0], 0)) continue point.co = Vector((*grouped_verts[i], 0)) profile_obj = bpy.data.objects.new("Profile", profile_curve) # Create path curve with profile object as bevel - path_curve = bpy.data.curves.new("Polyline", type='CURVE') + path_curve = bpy.data.curves.new("Polyline", type="CURVE") path_curve.dimensions = "2D" - path_curve.splines.new('POLY') + path_curve.splines.new("POLY") path_curve.splines[0].points.add(len(polyline_verts) - 1) for i, point in enumerate(path_curve.splines[0].points): point.co = Vector((*polyline_verts[i], 0)) @@ -400,12 +402,12 @@ def get_horizontal_profile_preview_data(context, relating_type): path_curve.bevel_object = profile_obj # Convert path curve to mesh - # This operation throws a warning when done during gpu drawing, so it was removed from the decorator file to be handled here + # This operation throws a warning when done during gpu drawing, so it was removed from the decorator file to be handled here path_obj = bpy.data.objects.new("Preview", path_curve) context.scene.collection.objects.link(path_obj) bpy.context.view_layer.objects.active = path_obj dg = context.evaluated_depsgraph_get() - path_obj = path_obj.evaluated_get(dg) + path_obj = path_obj.evaluated_get(dg) me = path_obj.to_mesh() # Create bmesh from path mesh @@ -812,13 +814,9 @@ class PolylineOperator: tool.Blender.update_viewport() def get_product_preview_data(self, context: bpy.types.Context, relating_type: ifcopenshell.entity_isntance): - if ( - tool.Model.get_usage_type(relating_type) == "PROFILE" and relating_type.is_a() not in {"IfcColumnType"} - ): + if tool.Model.get_usage_type(relating_type) == "PROFILE" and relating_type.is_a() not in {"IfcColumnType"}: data = get_horizontal_profile_preview_data(context, relating_type) - elif ( - tool.Model.get_usage_type(relating_type) == "PROFILE" and relating_type.is_a() in {"IfcColumnType"} - ): + elif tool.Model.get_usage_type(relating_type) == "PROFILE" and relating_type.is_a() in {"IfcColumnType"}: data = get_vertical_profile_preview_data(context, relating_type) elif tool.Model.get_usage_type(relating_type) == "LAYER2": data = get_wall_preview_data(context, relating_type) @@ -832,7 +830,7 @@ class PolylineOperator: props.verts.clear() props.edges.clear() props.tris.clear() - + for vert in data["verts"]: v = props.verts.add() v.value_3d = vert diff --git a/src/bonsai/bonsai/bim/module/model/profile.py b/src/bonsai/bonsai/bim/module/model/profile.py index e9057b63f7..0d0bfc0227 100644 --- a/src/bonsai/bonsai/bim/module/model/profile.py +++ b/src/bonsai/bonsai/bim/module/model/profile.py @@ -1145,7 +1145,6 @@ class DrawPolylineProfile(bpy.types.Operator, PolylineOperator): for profile1, profile2 in zip(profiles[:-1], profiles[1:]): DumbProfileJoiner().join_V(profile2["obj"], profile1["obj"]) - def modal(self, context, event): if not self.relating_type: self.report({"WARNING"}, "You need to select a profile type.") @@ -1176,7 +1175,6 @@ class DrawPolylineProfile(bpy.types.Operator, PolylineOperator): size = len(items) context.scene.BIMModelProperties.offset_type = items[((index + 1) % size)] - props = bpy.context.scene.BIMModelProperties wall_config = f"""Direction: {props.direction_sense} Offset Type: {props.offset_type} @@ -1222,4 +1220,3 @@ class DrawPolylineProfile(bpy.types.Operator, PolylineOperator): self.tool_state.use_default_container = True self.tool_state.plane_method = "XY" return {"RUNNING_MODAL"} - diff --git a/src/bonsai/bonsai/bim/module/model/prop.py b/src/bonsai/bonsai/bim/module/model/prop.py index bda91f79f3..4c972c657b 100644 --- a/src/bonsai/bonsai/bim/module/model/prop.py +++ b/src/bonsai/bonsai/bim/module/model/prop.py @@ -821,12 +821,13 @@ class BIMPolylineProperties(PropertyGroup): insertion_polyline: bpy.props.CollectionProperty(type=Polyline) measurement_polyline: bpy.props.CollectionProperty(type=Polyline) + class ProductPreviewItem(PropertyGroup): value_3d: bpy.props.FloatVectorProperty() value_2d: bpy.props.FloatVectorProperty(size=2) + class BIMProductPreviewProperties(PropertyGroup): verts: bpy.props.CollectionProperty(type=ProductPreviewItem) edges: bpy.props.CollectionProperty(type=ProductPreviewItem) tris: bpy.props.CollectionProperty(type=ProductPreviewItem) - diff --git a/src/bonsai/bonsai/bim/module/model/workspace.py b/src/bonsai/bonsai/bim/module/model/workspace.py index 87f0602889..dbfd571803 100644 --- a/src/bonsai/bonsai/bim/module/model/workspace.py +++ b/src/bonsai/bonsai/bim/module/model/workspace.py @@ -591,7 +591,7 @@ class EditObjectUI: op = row.operator("bim.disable_aggregate_mode", text="", icon="X") op = row.operator("bim.toggle_aggregate_mode_local_view", text="", icon="ZOOM_SELECTED") op = row.operator("bim.aggregate_assign_new_objects_in_aggregate_mode", text="", icon="CUBE") - + text = format_ifc_camel_case(AuthoringData.data["active_class"]) layout.label(text=f"{text} Edit Tools:", icon="RESTRICT_SELECT_OFF") cls.draw_parameter_adjustments(context) @@ -954,7 +954,7 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator): def hotkey_S_A(self): props = bpy.context.scene.BIMModelProperties relating_type_id = AuthoringData.data["relating_type_id_current"] - relating_type_class = AuthoringData.data["ifc_class_current"] + relating_type_class = AuthoringData.data["ifc_class_current"] if relating_type_id is None: self.report({"ERROR"}, "No relating type selected") return @@ -993,7 +993,9 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator): ): bpy.ops.bim.draw_polyline_slab("INVOKE_DEFAULT") elif ( - relating_type_id and tool.Model.get_usage_type(tool.Ifc.get().by_id(int(relating_type_id))) == "PROFILE" and relating_type_class not in {"IfcColumnType"} + relating_type_id + and tool.Model.get_usage_type(tool.Ifc.get().by_id(int(relating_type_id))) == "PROFILE" + and relating_type_class not in {"IfcColumnType"} ): bpy.ops.bim.draw_polyline_profile("INVOKE_DEFAULT") else: diff --git a/src/bonsai/bonsai/bim/module/pset/ui.py b/src/bonsai/bonsai/bim/module/pset/ui.py index 98839b66c3..119d4c2c83 100644 --- a/src/bonsai/bonsai/bim/module/pset/ui.py +++ b/src/bonsai/bonsai/bim/module/pset/ui.py @@ -197,7 +197,9 @@ def draw_psetqto_ui( row = box.row(align=True) row.scale_y = 0.8 row.label(text=prop["Name"]) - op = row.operator("bim.select_similar", text=get_display_value(nominal_value), icon="NONE", emboss=False) + op = row.operator( + "bim.select_similar", text=get_display_value(nominal_value), icon="NONE", emboss=False + ) op.key = '"' + pset["Name"].replace('"', '\\"') + '"."' + prop["Name"].replace('"', '\\"') + '"' # calculate sum of all selected objects if active_operator: diff --git a/src/bonsai/bonsai/bim/ui.py b/src/bonsai/bonsai/bim/ui.py index 69731dfdb9..88bcddcc09 100644 --- a/src/bonsai/bonsai/bim/ui.py +++ b/src/bonsai/bonsai/bim/ui.py @@ -246,9 +246,10 @@ class BIM_ADDON_preferences(bpy.types.AddonPreferences): ) should_play_chaching_sound: BoolProperty(name="Play A Cha-Ching Sound When Project Costs Updates", default=False) spatial_elements_unselectable: BoolProperty( - name="Make Spatial Elements Unselectable By Default", - default=True, - description="If disabled, it will be possible to select spatial elements in the 3D viewport.\nIt is recommended to keep this `Enabled`, as this can have unintended consequences") + name="Make Spatial Elements Unselectable By Default", + default=True, + description="If disabled, it will be possible to select spatial elements in the 3D viewport.\nIt is recommended to keep this `Enabled`, as this can have unintended consequences", + ) decorations_colour: bpy.props.FloatVectorProperty( name="Decorations Color", subtype="COLOR", default=(1, 1, 1, 1), min=0.0, max=1.0, size=4 ) @@ -1191,15 +1192,16 @@ def draw_custom_context_menu(self: bpy.types.Menu, context: bpy.types.Context) - url_op = layout.operator("bim.open_uri", icon="URL", text="Online IFC Documentation") url_op.uri = url + class BIM_PT_decorators_overlay(Panel): - bl_space_type = 'VIEW_3D' - bl_region_type = 'HEADER' - bl_parent_id = 'VIEW3D_PT_overlay' + bl_space_type = "VIEW_3D" + bl_region_type = "HEADER" + bl_parent_id = "VIEW3D_PT_overlay" bl_label = "Bonsai Decorators" @classmethod def poll(cls, context): - return context.mode == 'OBJECT' + return context.mode == "OBJECT" def draw(self, context): layout = self.layout diff --git a/src/bonsai/bonsai/core/aggregate.py b/src/bonsai/bonsai/core/aggregate.py index 30e2c14965..693063b602 100644 --- a/src/bonsai/bonsai/core/aggregate.py +++ b/src/bonsai/bonsai/core/aggregate.py @@ -86,12 +86,17 @@ def add_part_to_object( assign_object(ifc, aggregator, collector, relating_obj=obj, related_obj=part_obj) blender.set_active_object(obj) -def enable_aggregate_mode(aggregator: tool.Aggregate, obj: bpy.types.Object,): + +def enable_aggregate_mode( + aggregator: tool.Aggregate, + obj: bpy.types.Object, +): if aggregator.get_aggregate_mode(): disable_aggregate_mode(aggregator) aggregator.enable_aggregate_mode(obj) + def disable_aggregate_mode(aggregator: tool.Aggregate): aggregator.disable_aggregate_mode() diff --git a/src/bonsai/bonsai/tool/geometry.py b/src/bonsai/bonsai/tool/geometry.py index 5a49c948cd..faf228e286 100644 --- a/src/bonsai/bonsai/tool/geometry.py +++ b/src/bonsai/bonsai/tool/geometry.py @@ -1795,9 +1795,7 @@ class Geometry(bonsai.core.tool.Geometry): return False @classmethod - def get_bvh_tree(cls, obj:bpy.types.Object) -> BVHTree: + def get_bvh_tree(cls, obj: bpy.types.Object) -> BVHTree: bm = tool.Blender.get_bmesh_for_mesh(obj.data) bm.transform(obj.matrix_world) return BVHTree.FromBMesh(bm) - - \ No newline at end of file diff --git a/src/bonsai/bonsai/tool/loader.py b/src/bonsai/bonsai/tool/loader.py index 568bb7899b..6f9b8c84a5 100644 --- a/src/bonsai/bonsai/tool/loader.py +++ b/src/bonsai/bonsai/tool/loader.py @@ -983,8 +983,7 @@ class Loader(bonsai.core.tool.Loader): tool.Loader.load_indexed_colour_map(rep, mesh) ios_edges_values = [ - (e.vertices[0], e.vertices[1]) in ios_edges - or (e.vertices[1], e.vertices[0]) in ios_edges + (e.vertices[0], e.vertices[1]) in ios_edges or (e.vertices[1], e.vertices[0]) in ios_edges for e in mesh.edges ] tool.Blender.Attribute.fill_attribute(mesh, "ios_edges", "EDGE", "BOOLEAN", ios_edges_values) diff --git a/src/bonsai/bonsai/tool/raycast.py b/src/bonsai/bonsai/tool/raycast.py index 5c3d01ecea..4b2d16c4ea 100644 --- a/src/bonsai/bonsai/tool/raycast.py +++ b/src/bonsai/bonsai/tool/raycast.py @@ -206,7 +206,7 @@ class Raycast(bonsai.core.tool.Raycast): bm.free() snapping_points = [] - sorted_points = sorted(points, key=lambda x : x[0]) + sorted_points = sorted(points, key=lambda x: x[0]) for p in sorted_points: point = copy.deepcopy(p) snapping_points.append(point[1]) diff --git a/src/bonsai/bonsai/tool/root.py b/src/bonsai/bonsai/tool/root.py index a19bb227f5..ab5f0a6fc8 100644 --- a/src/bonsai/bonsai/tool/root.py +++ b/src/bonsai/bonsai/tool/root.py @@ -354,7 +354,6 @@ class Root(bonsai.core.tool.Root): tool.Aggregate.constrain_all_parts_to_aggregate(tool.Ifc.get_object(new_aggregate[0])) tool.Blender.select_and_activate_single_object(bpy.context, tool.Ifc.get_object(new_aggregate[0])) - @classmethod def run_geometry_add_representation( cls, From 83add56e6c0a8ede3bf1dd7e76dfa69c22d5b7bd Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Fri, 10 Jan 2025 15:22:53 +1100 Subject: [PATCH 14/61] Fix #5949. When duplicating objects, copy over IFC links (shape representation ID, item_ids, edge_item_ids) in a more reliable way --- src/bonsai/bonsai/core/root.py | 10 ++++------ src/bonsai/bonsai/core/tool.py | 2 +- src/bonsai/bonsai/tool/geometry.py | 26 ++++++++++++++++++-------- src/bonsai/bonsai/tool/ifc.py | 4 +++- src/bonsai/bonsai/tool/loader.py | 9 ++++----- src/bonsai/bonsai/tool/root.py | 18 ++++++++++++++---- 6 files changed, 44 insertions(+), 25 deletions(-) diff --git a/src/bonsai/bonsai/core/root.py b/src/bonsai/bonsai/core/root.py index f124951d53..7e0b9381ba 100644 --- a/src/bonsai/bonsai/core/root.py +++ b/src/bonsai/bonsai/core/root.py @@ -27,7 +27,7 @@ if TYPE_CHECKING: def copy_class( ifc: tool.Ifc, collector: tool.Collector, geometry: tool.Geometry, root: tool.Root, obj: bpy.types.Object -) -> ifcopenshell.entity_instance: +) -> ifcopenshell.entity_instance | None: element = ifc.get_entity(obj) if not element: return @@ -43,14 +43,12 @@ def copy_class( ifc.run("type.map_type_representations", related_object=new, relating_type=relating_type) root.link_object_data(ifc.get_object(relating_type), obj) elif representation: - root.copy_representation(element, new) - new_representation = root.get_element_representation(new, root.get_representation_context(representation)) + copied_entities = root.copy_representation(element, new) data = geometry.duplicate_object_data(obj) if data: + geometry.copy_data_links(data, copied_entities) geometry.change_object_data(obj, data, is_global=True) - geometry.rename_object(data, geometry.get_representation_name(new_representation)) - geometry.link(new_representation, data) - geometry.reload_representation_item_ids(new_representation, data) + geometry.rename_object(data, geometry.get_representation_name(ifc.get_entity(data))) root.assign_body_styles(new, obj) collector.assign(obj) if root.is_element_a(new, "IfcOpeningElement"): diff --git a/src/bonsai/bonsai/core/tool.py b/src/bonsai/bonsai/core/tool.py index 291e0b2890..1f673b9521 100644 --- a/src/bonsai/bonsai/core/tool.py +++ b/src/bonsai/bonsai/core/tool.py @@ -387,6 +387,7 @@ class Geometry: def clear_cache(cls, element): pass def clear_modifiers(cls, obj): pass def clear_scale(cls, obj): pass + def copy_data_links(cls, data, copied_entities) -> None: pass def delete_data(cls, data): pass def delete_ifc_object(cls, obj): pass def delete_opening_object_placement(cls, opening): pass @@ -420,7 +421,6 @@ class Geometry: def record_object_position(cls, obj): pass def recreate_object_with_data(cls, obj, data): pass def reimport_element_representations(cls, obj, representation, apply_openings=True): pass - def reload_representation_item_ids(cls, representation, data) -> None: pass def remove_connection(cls, connection): pass def rename_object(cls, obj, name): pass def replace_object_data_globally(cls, old_data, new_data): pass diff --git a/src/bonsai/bonsai/tool/geometry.py b/src/bonsai/bonsai/tool/geometry.py index faf228e286..ef6a141513 100644 --- a/src/bonsai/bonsai/tool/geometry.py +++ b/src/bonsai/bonsai/tool/geometry.py @@ -259,10 +259,14 @@ class Geometry(bonsai.core.tool.Geometry): # a cylinder) so dissolving edges should not be allowed. mesh_element = tool.Ifc.get().by_id(obj.data.BIMMeshProperties.ifc_definition_id) if ( - mesh_element.is_a("IfcShapeRepresentation") - and ifcopenshell.util.representation.resolve_representation(mesh_element).RepresentationType - == "AdvancedBrep" - ) or mesh_element.is_a("IfcAdvancedBrep") or not obj.data: + ( + mesh_element.is_a("IfcShapeRepresentation") + and ifcopenshell.util.representation.resolve_representation(mesh_element).RepresentationType + == "AdvancedBrep" + ) + or mesh_element.is_a("IfcAdvancedBrep") + or not obj.data + ): return if hasattr(obj.data, "attributes") and (ios_edges_attribute := obj.data.attributes.get("ios_edges")): # Edges from a forced triangulation are stored as True in a boolean attribute on the mesh @@ -612,7 +616,7 @@ class Geometry(bonsai.core.tool.Geometry): @classmethod def get_representation_name(cls, representation: ifcopenshell.entity_instance) -> str: - return tool.Loader.get_mesh_name(representation.ContextOfItems.id(), representation.id()) + return tool.Loader.get_mesh_name(representation) @classmethod def get_styles( @@ -719,7 +723,7 @@ class Geometry(bonsai.core.tool.Geometry): if not tool.Loader.is_native_swept_disk_solid(element, representation): continue if curve is None: - mesh_name = tool.Loader.get_mesh_name(context.id(), representation.id()) + mesh_name = tool.Loader.get_mesh_name(representation) native_data = { "representation": representation, # TODO: calculate mapped item matrix. @@ -1729,8 +1733,14 @@ class Geometry(bonsai.core.tool.Geometry): return results @classmethod - def reload_representation_item_ids(cls, representation: ifcopenshell.entity_instance, data: bpy.types.Mesh) -> None: - data["ios_item_ids"] = [i["item"].id() for i in ifcopenshell.util.representation.resolve_items(representation)] + def copy_data_links(cls, data: bpy.types.Mesh, copied_entities: dict[int, ifcopenshell.entity_instance]) -> None: + representation = tool.Ifc.get_entity(data) + representation = copied_entities.get(representation.id(), representation) + tool.Ifc.link(representation, data) + if item_ids := data.get("ios_item_ids"): + data["ios_item_ids"] = [copied_entities.get(i, tool.Ifc.get().by_id(i)).id() for i in item_ids] + if item_ids := data.get("ios_edges_item_ids"): + data["ios_edges_item_ids"] = [copied_entities.get(i, tool.Ifc.get().by_id(i)).id() for i in item_ids] @classmethod def export_mesh_to_tessellation( diff --git a/src/bonsai/bonsai/tool/ifc.py b/src/bonsai/bonsai/tool/ifc.py index c52c86bee4..8144325584 100644 --- a/src/bonsai/bonsai/tool/ifc.py +++ b/src/bonsai/bonsai/tool/ifc.py @@ -102,7 +102,7 @@ class Ifc(bonsai.core.tool.Ifc): Return None if object is not linked to IFC or it's linked to non-existent element. """ ifc = IfcStore.get_file() - if not ifc: + if not ifc or not obj: return props = None @@ -110,6 +110,8 @@ class Ifc(bonsai.core.tool.Ifc): props = obj.BIMObjectProperties elif isinstance(obj, bpy.types.Material): props = obj.BIMStyleProperties + else: + props = obj.BIMMeshProperties if props and (ifc_definition_id := props.ifc_definition_id): try: diff --git a/src/bonsai/bonsai/tool/loader.py b/src/bonsai/bonsai/tool/loader.py index 6f9b8c84a5..b558d75be5 100644 --- a/src/bonsai/bonsai/tool/loader.py +++ b/src/bonsai/bonsai/tool/loader.py @@ -84,13 +84,12 @@ class Loader(bonsai.core.tool.Loader): @classmethod def get_mesh_name_from_shape(cls, geometry: ifcopenshell.geom.ShapeType) -> str: representation_id = cls.get_representation_id_from_shape(geometry) - representation = tool.Ifc.get().by_id(representation_id) - context_id = representation.ContextOfItems.id() if hasattr(representation, "ContextOfItems") else 0 - return cls.get_mesh_name(context_id, representation_id) + return cls.get_mesh_name(tool.Ifc.get().by_id(representation_id)) @classmethod - def get_mesh_name(cls, context_id: int, representation_id: int) -> str: - return "{}/{}".format(context_id, representation_id) + def get_mesh_name(cls, representation: ifcopenshell.entity_instance) -> str: + context_id = representation.ContextOfItems.id() if hasattr(representation, "ContextOfItems") else 0 + return "{}/{}".format(context_id, representation.id()) @classmethod def get_name(cls, element: ifcopenshell.entity_instance) -> str: diff --git a/src/bonsai/bonsai/tool/root.py b/src/bonsai/bonsai/tool/root.py index ab5f0a6fc8..b2af1b50d5 100644 --- a/src/bonsai/bonsai/tool/root.py +++ b/src/bonsai/bonsai/tool/root.py @@ -55,28 +55,38 @@ class Root(bonsai.core.tool.Root): ) @classmethod - def copy_representation(cls, source: ifcopenshell.entity_instance, dest: ifcopenshell.entity_instance) -> None: + def copy_representation( + cls, source: ifcopenshell.entity_instance, dest: ifcopenshell.entity_instance + ) -> dict[int, ifcopenshell.entity_instance]: def exclude_callback(attribute): return attribute.is_a("IfcProfileDef") and attribute.ProfileName + copied_entities: dict[int, ifcopenshell.entity_instance] = {} + if dest.is_a("IfcProduct"): if not source.Representation: - return + return copied_entities dest.Representation = ifcopenshell.util.element.copy_deep( tool.Ifc.get(), source.Representation, exclude=["IfcGeometricRepresentationContext"], exclude_callback=exclude_callback, + copied_entities=copied_entities, ) elif dest.is_a("IfcTypeProduct"): if not source.RepresentationMaps: - return + return copied_entities dest.RepresentationMaps = [ ifcopenshell.util.element.copy_deep( - tool.Ifc.get(), m, exclude=["IfcGeometricRepresentationContext"], exclude_callback=exclude_callback + tool.Ifc.get(), + m, + exclude=["IfcGeometricRepresentationContext"], + exclude_callback=exclude_callback, + copied_entities=copied_entities, ) for m in source.RepresentationMaps ] + return copied_entities @classmethod def does_type_have_representations(cls, element: ifcopenshell.entity_instance) -> bool: From cac3d7f6997b40a97dc027b36c56f4e3980ba984 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Fri, 10 Jan 2025 16:59:45 +1100 Subject: [PATCH 15/61] Fix #5939. Fix #2751. IfcPatch no longer needs the (rarely used) input src arg by default. --- .../bonsai/bim/module/patch/operator.py | 6 ----- src/bonsai/bonsai/tool/patch.py | 6 ++--- src/ifcpatch/ifcpatch/__init__.py | 18 ++------------- .../ifcpatch/recipes/ConvertLengthUnit.py | 2 -- .../recipes/ConvertNestToAggregate.py | 3 +-- .../recipes/ConvertPropertiesToQuantities.py | 3 +-- .../recipes/DowngradeIndexedPolyCurve.py | 3 +-- .../ifcpatch/recipes/ExtractElements.py | 3 +-- .../recipes/ExtractPropertiesToSQLite.py | 2 -- .../recipes/FixArchiCADToRevitDoorSwings.py | 3 +-- .../recipes/FixArchiCADToRevitSpaces.py | 15 ++++++++----- .../FixRevitClassificationCodeTypes.py | 3 +-- src/ifcpatch/ifcpatch/recipes/FixRevitTINs.py | 15 ++++++++----- src/ifcpatch/ifcpatch/recipes/Ifc2Sql.py | 2 -- .../ifcpatch/recipes/MergeDuplicateTypes.py | 3 +-- .../ifcpatch/recipes/MergeProjects.py | 5 +---- src/ifcpatch/ifcpatch/recipes/Migrate.py | 2 -- .../recipes/OffsetObjectPlacements.py | 2 -- .../recipes/OffsetStoreyElevations.py | 3 +-- src/ifcpatch/ifcpatch/recipes/Optimise.py | 3 +-- src/ifcpatch/ifcpatch/recipes/PurgeData.py | 3 +-- .../recipes/RecycleNonRootedElements.py | 3 +-- .../ifcpatch/recipes/RegenerateGlobalIds.py | 3 +-- .../RemoveRevitUniformatClassification.py | 3 +-- .../recipes/RemoveSiteRepresentation.py | 3 +-- .../recipes/ResetAbsoluteCoordinates.py | 2 -- .../recipes/ResetSpatialElementLocations.py | 3 +-- .../ifcpatch/recipes/SetFalseOrigin.py | 5 +---- .../ifcpatch/recipes/SetRefElevation.py | 3 +-- .../recipes/SetWorldCoordinateSystem.py | 2 -- .../ifcpatch/recipes/SplitByBuildingStorey.py | 22 +++++-------------- .../ifcpatch/recipes/TessellateElements.py | 2 -- src/ifcpatch/ifcpatch/recipes/UnsharePsets.py | 21 ++++++++++-------- 33 files changed, 58 insertions(+), 119 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/patch/operator.py b/src/bonsai/bonsai/bim/module/patch/operator.py index fe2b021c1d..0a1f4049ca 100644 --- a/src/bonsai/bonsai/bim/module/patch/operator.py +++ b/src/bonsai/bonsai/bim/module/patch/operator.py @@ -98,12 +98,6 @@ class ExecuteIfcPatch(bpy.types.Operator): if props.should_load_from_memory and tool.Ifc.get(): args["file"] = tool.Ifc.get() - if ifcpatch.get_patch_input_argument_use(recipe_name) == "REQUIRED": - self.report( - {"ERROR"}, - f"The recipe '{recipe_name}' is not currently supported if file is loaded from memory.", - ) - return {"CANCELLED"} else: args["input"] = cast(str, props.ifc_patch_input) args["file"] = cast(ifcopenshell.file, ifcopenshell.open(props.ifc_patch_input)) diff --git a/src/bonsai/bonsai/tool/patch.py b/src/bonsai/bonsai/tool/patch.py index a178f99e2b..356a5001de 100644 --- a/src/bonsai/bonsai/tool/patch.py +++ b/src/bonsai/bonsai/tool/patch.py @@ -33,10 +33,8 @@ class Patch(bonsai.core.tool.Patch): @classmethod def is_filepath_argument(cls, recipe: str, arg_name: str) -> bool: - # TODO: Temporary hack to identify filepath arguments. - # Should mark them as such in the patches documentation - # and process it later. - return recipe == "SplitByBuildingStorey" and arg_name == "output_dir" + # There is probably a more explicit way to do this + return "filepath" in arg_name @classmethod def does_patch_has_output(cls, recipe: str) -> bool: diff --git a/src/ifcpatch/ifcpatch/__init__.py b/src/ifcpatch/ifcpatch/__init__.py index 907ab669fb..3112483785 100644 --- a/src/ifcpatch/ifcpatch/__init__.py +++ b/src/ifcpatch/ifcpatch/__init__.py @@ -95,30 +95,16 @@ def execute(args: ArgumentsDict) -> Union[ifcopenshell.file, str]: else: recipe = importlib.import_module(f"ifcpatch.recipes.{args['recipe']}") - # Ensure file or input is provided. - input_argument = get_patch_input_argument_use(args["recipe"]) - if input_argument == "REQUIRED": - if not args.get("input"): - raise ValueError(f"Recipe {args['recipe']} is requiring 'input' argument to be provided.") - elif "file" not in args: # SUPPORTED, IGNORED. - raise ValueError(f"Recipe {args['recipe']} is requiring 'file' argument to be provided.") - arguments = args.get("arguments", None) or [] if recipe.Patcher.__init__.__doc__ is not None: - patcher = recipe.Patcher(args.get("input"), args.get("file"), logger, *arguments) + patcher = recipe.Patcher(args.get("file"), logger, *arguments) else: - patcher = recipe.Patcher(args.get("input"), args.get("file"), logger, arguments) + patcher = recipe.Patcher(args.get("file"), logger, arguments) patcher.patch() output = getattr(patcher, "file_patched", patcher.file) return output -def get_patch_input_argument_use(recipe: str) -> Literal["REQUIRED", "SUPPORTED", "IGNORED"]: - # try out of tree and subpackage imports - recipe_module = sys.modules.get(f"ifcpatch.recipes.{recipe}") or sys.modules.get(recipe) - return getattr(recipe_module.Patcher, "input_argument", "IGNORED") - - def write(output: Union[ifcopenshell.file, str], filepath: str) -> None: """Write the output of an IFC patch to a file diff --git a/src/ifcpatch/ifcpatch/recipes/ConvertLengthUnit.py b/src/ifcpatch/ifcpatch/recipes/ConvertLengthUnit.py index c555a2035e..297cdfbda6 100644 --- a/src/ifcpatch/ifcpatch/recipes/ConvertLengthUnit.py +++ b/src/ifcpatch/ifcpatch/recipes/ConvertLengthUnit.py @@ -53,7 +53,6 @@ LengthUnit = typing.Literal[ class Patcher: def __init__( self, - src: str, file: ifcopenshell.file, logger: Logger, unit: LengthUnit = "METER", @@ -76,7 +75,6 @@ class Patcher: # Convert to feet model = ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "ConvertLengthUnit", "arguments": ["FOOT"]}) """ - self.src = src self.file = file self.logger = logger self.unit = unit diff --git a/src/ifcpatch/ifcpatch/recipes/ConvertNestToAggregate.py b/src/ifcpatch/ifcpatch/recipes/ConvertNestToAggregate.py index d9df05666d..8471ed28f3 100644 --- a/src/ifcpatch/ifcpatch/recipes/ConvertNestToAggregate.py +++ b/src/ifcpatch/ifcpatch/recipes/ConvertNestToAggregate.py @@ -21,7 +21,7 @@ import ifcopenshell.guid class Patcher: - def __init__(self, src, file, logger): + def __init__(self, file, logger): """Convert nesting relationships to aggregate relationships Some software like Revit won't load nested children elements because @@ -39,7 +39,6 @@ class Patcher: ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "ConvertNestToAggregate", "arguments": []}) """ - self.src = src self.file = file self.logger = logger diff --git a/src/ifcpatch/ifcpatch/recipes/ConvertPropertiesToQuantities.py b/src/ifcpatch/ifcpatch/recipes/ConvertPropertiesToQuantities.py index 48482821e2..969461ecc2 100644 --- a/src/ifcpatch/ifcpatch/recipes/ConvertPropertiesToQuantities.py +++ b/src/ifcpatch/ifcpatch/recipes/ConvertPropertiesToQuantities.py @@ -26,7 +26,7 @@ from typing import Union class Patcher: - def __init__(self, src: str, file: ifcopenshell.file, logger: Logger, property_name: str, quantity_name: str): + def __init__(self, file: ifcopenshell.file, logger: Logger, property_name: str, quantity_name: str): """Converts a property to a standardised quantity IFC can store arbitrary key value metadata associated with a elements @@ -59,7 +59,6 @@ class Patcher: # "NetSideArea", if that standardised quantity exists. ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "ConvertPropertiesToQuantities", "arguments": ["Area", "NetSideArea"]}) """ - self.src = src self.file = file self.logger = logger self.source_property_name = property_name diff --git a/src/ifcpatch/ifcpatch/recipes/DowngradeIndexedPolyCurve.py b/src/ifcpatch/ifcpatch/recipes/DowngradeIndexedPolyCurve.py index f9afbe6835..ea169f2967 100644 --- a/src/ifcpatch/ifcpatch/recipes/DowngradeIndexedPolyCurve.py +++ b/src/ifcpatch/ifcpatch/recipes/DowngradeIndexedPolyCurve.py @@ -21,7 +21,7 @@ import ifcopenshell.util.element class Patcher: - def __init__(self, src, file, logger): + def __init__(self, file, logger): """Downgrade indexed polycurves to simple polylines Low quality IFC viewers like Navisworks do not support various IFC4 @@ -39,7 +39,6 @@ class Patcher: ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "DowngradeIndexedPolyCurve", "arguments": []}) """ - self.src = src self.file = file self.logger = logger diff --git a/src/ifcpatch/ifcpatch/recipes/ExtractElements.py b/src/ifcpatch/ifcpatch/recipes/ExtractElements.py index 3947dd919d..e49f1b0af4 100644 --- a/src/ifcpatch/ifcpatch/recipes/ExtractElements.py +++ b/src/ifcpatch/ifcpatch/recipes/ExtractElements.py @@ -25,7 +25,7 @@ from logging import Logger class Patcher: - def __init__(self, src: str, file: ifcopenshell.file, logger: Logger, query: str = "IfcWall"): + def __init__(self, file: ifcopenshell.file, logger: Logger, query: str = "IfcWall"): """Extract certain elements into a new model Extract a subset of elements from an existing IFC data set and save it @@ -48,7 +48,6 @@ class Patcher: # Extract all walls and slabs ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "ExtractElements", "arguments": ["IfcWall, IfcSlab"]}) """ - self.src = src self.file = file self.logger = logger self.query = query diff --git a/src/ifcpatch/ifcpatch/recipes/ExtractPropertiesToSQLite.py b/src/ifcpatch/ifcpatch/recipes/ExtractPropertiesToSQLite.py index f9fdc9727a..226052ae19 100644 --- a/src/ifcpatch/ifcpatch/recipes/ExtractPropertiesToSQLite.py +++ b/src/ifcpatch/ifcpatch/recipes/ExtractPropertiesToSQLite.py @@ -34,7 +34,6 @@ except: class Patcher: def __init__( self, - src, file, logger, ): @@ -50,7 +49,6 @@ class Patcher: result = ifcpatch.execute({"input": fn, "file": model, "recipe": "ExtractPropertiesToSQLite"}) ifcpatch.write(result, "output.sqlite") """ - self.src = src self.file = file self.logger = logger diff --git a/src/ifcpatch/ifcpatch/recipes/FixArchiCADToRevitDoorSwings.py b/src/ifcpatch/ifcpatch/recipes/FixArchiCADToRevitDoorSwings.py index b087b4e6b8..54e3e32fec 100644 --- a/src/ifcpatch/ifcpatch/recipes/FixArchiCADToRevitDoorSwings.py +++ b/src/ifcpatch/ifcpatch/recipes/FixArchiCADToRevitDoorSwings.py @@ -27,7 +27,7 @@ import ifcopenshell.util.element class Patcher: - def __init__(self, src, file, logger): + def __init__(self, file, logger): """Fix missing door swings in Revit when viewing ArchiCAD IFCs ArchiCAD has the ability to store 2D data with objects like doors for @@ -56,7 +56,6 @@ class Patcher: ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "FixArchiCADToRevitDoorSwings", "arguments": []}) """ - self.src = src self.file = file self.logger = logger diff --git a/src/ifcpatch/ifcpatch/recipes/FixArchiCADToRevitSpaces.py b/src/ifcpatch/ifcpatch/recipes/FixArchiCADToRevitSpaces.py index 49b6507a7e..84941d2bd6 100644 --- a/src/ifcpatch/ifcpatch/recipes/FixArchiCADToRevitSpaces.py +++ b/src/ifcpatch/ifcpatch/recipes/FixArchiCADToRevitSpaces.py @@ -21,9 +21,7 @@ import ifcopenshell class Patcher: - input_argument = "REQUIRED" - - def __init__(self, src: str, file: None, logger: logging.Logger): + def __init__(self, file: None, logger: logging.Logger, filepath: str): """Allow ArchiCAD IFC spaces to open as Revit rooms The underlying problem is that Revit does not bring in IFC spaces as @@ -51,16 +49,21 @@ class Patcher: requires you to run it using Blender, as the geometric modification uses the Blender geometry engine. - `input` argument is required for this recipe, `file` argument is ignored. + `filepath` argument is required for this recipe, `file` argument is + ignored. + + :param filepath: The filepath of the IFC model. This is required to + load into Bonsai. + :filter_glob filepath: *.ifc;*.ifczip;*.ifcxml Example: .. code:: python ifcpatch.execute({"input": "input.ifc", "recipe": "FixArchiCADToRevitSpaces", "arguments": []}) """ - self.src = src self.file = file self.logger = logger + self.filepath = filepath def patch(self) -> None: import bpy @@ -74,7 +77,7 @@ class Patcher: bpy.data.batch_remove(bpy.data.objects) bpy.ops.outliner.orphans_purge(do_local_ids=True, do_linked_ids=True, do_recursive=True) - bpy.ops.bim.load_project(filepath=self.src) + bpy.ops.bim.load_project(filepath=self.filepath) def recalculate_origin(wall: bpy.types.Object) -> None: new_origin = wall.matrix_world @ Vector(wall.bound_box[0]) diff --git a/src/ifcpatch/ifcpatch/recipes/FixRevitClassificationCodeTypes.py b/src/ifcpatch/ifcpatch/recipes/FixRevitClassificationCodeTypes.py index 21a613c5f0..1ec5b331de 100644 --- a/src/ifcpatch/ifcpatch/recipes/FixRevitClassificationCodeTypes.py +++ b/src/ifcpatch/ifcpatch/recipes/FixRevitClassificationCodeTypes.py @@ -21,7 +21,7 @@ import ifcopenshell.util.element class Patcher: - def __init__(self, src, file, logger): + def __init__(self, file, logger): """Reassigns occurrence classifications to types Revit has a bug (see https://github.com/Autodesk/revit-ifc/issues/691) @@ -35,7 +35,6 @@ class Patcher: ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "FixRevitClassificationCodeTypes"}) """ - self.src = src self.file = file self.logger = logger diff --git a/src/ifcpatch/ifcpatch/recipes/FixRevitTINs.py b/src/ifcpatch/ifcpatch/recipes/FixRevitTINs.py index 60a08dd876..07184d1cb2 100644 --- a/src/ifcpatch/ifcpatch/recipes/FixRevitTINs.py +++ b/src/ifcpatch/ifcpatch/recipes/FixRevitTINs.py @@ -22,9 +22,7 @@ import logging class Patcher: - input_argument = "REQUIRED" - - def __init__(self, src: str, file: None, logger: logging.Logger, is_solid: bool = True): + def __init__(self, file: None, logger: logging.Logger, filepath: str, is_solid: bool = True): """Fix missing or spot-coordinate bugged TINs loading in Revit TINs exported from 12D or Civil 3D may contain dense or highly obtuse @@ -62,7 +60,12 @@ class Patcher: from civil software. It also requires you to run it using Blender, as the geometric modification uses the Blender geometry engine. - `input` argument is required for this recipe, `file` argument is ignored. + `filepath` argument is required for this recipe, `file` argument is + ignored. + + :param filepath: The filepath of the IFC model. This is required to + load into Bonsai. + :filter_glob filepath: *.ifc;*.ifczip;*.ifcxml Example: @@ -70,8 +73,8 @@ class Patcher: ifcpatch.execute({"input": "input.ifc", "recipe": "FixRevitTINs", "arguments": []}) """ - self.src = src self.file = file + self.filepath = filepath self.logger = logger self.is_solid = is_solid @@ -82,7 +85,7 @@ class Patcher: from math import degrees bpy.context.scene.BIMProjectProperties.should_use_native_meshes = True - bpy.ops.bim.load_project(filepath=self.src) + bpy.ops.bim.load_project(filepath=self.filepath) old_history_size = tool.Ifc.get().history_size old_undo_steps = bpy.context.preferences.edit.undo_steps diff --git a/src/ifcpatch/ifcpatch/recipes/Ifc2Sql.py b/src/ifcpatch/ifcpatch/recipes/Ifc2Sql.py index 3114d8620a..f382bc6a18 100644 --- a/src/ifcpatch/ifcpatch/recipes/Ifc2Sql.py +++ b/src/ifcpatch/ifcpatch/recipes/Ifc2Sql.py @@ -54,7 +54,6 @@ except: class Patcher: def __init__( self, - src, file, logger, sql_type: SQLTypes = "SQLite", @@ -98,7 +97,6 @@ class Patcher: {"input": "input.ifc", "file": model, "recipe": "Ifc2Sql", "arguments": ["sqlite"]} ) """ - self.src = src self.file = file self.logger = logger self.sql_type = sql_type.lower() diff --git a/src/ifcpatch/ifcpatch/recipes/MergeDuplicateTypes.py b/src/ifcpatch/ifcpatch/recipes/MergeDuplicateTypes.py index c26fa918c4..6b40b26fbc 100644 --- a/src/ifcpatch/ifcpatch/recipes/MergeDuplicateTypes.py +++ b/src/ifcpatch/ifcpatch/recipes/MergeDuplicateTypes.py @@ -23,7 +23,7 @@ from logging import Logger class Patcher: - def __init__(self, src: str, file: ifcopenshell.file, logger: Logger, attribute: str = "Tag"): + def __init__(self, file: ifcopenshell.file, logger: Logger, attribute: str = "Tag"): """Merge duplicate element types via the Tag or another attribute Revit is notorious for creating many duplicate element types. Element @@ -60,7 +60,6 @@ class Patcher: # Explicitly say we want to merge based on the Name attribute ifcpatch.execute({"file": model, "recipe": "MergeDuplicateTypes", "arguments": ["Name"]}) """ - self.src = src self.file = file self.logger = logger self.attribute = attribute diff --git a/src/ifcpatch/ifcpatch/recipes/MergeProjects.py b/src/ifcpatch/ifcpatch/recipes/MergeProjects.py index 7581f7259a..4e06b01274 100644 --- a/src/ifcpatch/ifcpatch/recipes/MergeProjects.py +++ b/src/ifcpatch/ifcpatch/recipes/MergeProjects.py @@ -27,9 +27,7 @@ from logging import Logger class Patcher: - def __init__( - self, src: str, file: ifcopenshell.file, logger: Logger, filepaths: list[Union[str, ifcopenshell.file]] - ): + def __init__(self, file: ifcopenshell.file, logger: Logger, filepaths: list[Union[str, ifcopenshell.file]]): """Merge two or more IFC models into one Note that other than combining the two (or more) IfcProject elements into @@ -50,7 +48,6 @@ class Patcher: ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "MergeProjects", "arguments": ["/path/to/model2.ifc"]}) """ - self.src = src self.file = file self.logger = logger self.filepaths = filepaths diff --git a/src/ifcpatch/ifcpatch/recipes/Migrate.py b/src/ifcpatch/ifcpatch/recipes/Migrate.py index 9938ddd754..cf90464678 100644 --- a/src/ifcpatch/ifcpatch/recipes/Migrate.py +++ b/src/ifcpatch/ifcpatch/recipes/Migrate.py @@ -25,7 +25,6 @@ from logging import Logger class Patcher: def __init__( self, - src: str, file: ifcopenshell.file, logger: Logger, schema: ifcopenshell.util.schema.IFC_SCHEMA = "IFC4", @@ -45,7 +44,6 @@ class Patcher: # Upgrade an IFC2X3 model to IFC4 ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "Migrate", "arguments": ["IFC4"]}) """ - self.src = src self.file = file self.logger = logger self.schema = schema diff --git a/src/ifcpatch/ifcpatch/recipes/OffsetObjectPlacements.py b/src/ifcpatch/ifcpatch/recipes/OffsetObjectPlacements.py index 55059e5283..765cef7336 100644 --- a/src/ifcpatch/ifcpatch/recipes/OffsetObjectPlacements.py +++ b/src/ifcpatch/ifcpatch/recipes/OffsetObjectPlacements.py @@ -26,7 +26,6 @@ import typing class Patcher: def __init__( self, - src, file, logger, x: typing.Union[str, float] = "0", @@ -89,7 +88,6 @@ class Patcher: # Some crazy 3D rotation and offset ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "OffsetObjectPlacements", "arguments": [12.5,5,2,False,90,90,45]}) """ - self.src = src self.file = file self.logger = logger self.x = float(x) diff --git a/src/ifcpatch/ifcpatch/recipes/OffsetStoreyElevations.py b/src/ifcpatch/ifcpatch/recipes/OffsetStoreyElevations.py index 5611b4a126..4b3efd7c71 100644 --- a/src/ifcpatch/ifcpatch/recipes/OffsetStoreyElevations.py +++ b/src/ifcpatch/ifcpatch/recipes/OffsetStoreyElevations.py @@ -20,7 +20,7 @@ import typing class Patcher: - def __init__(self, src, file, logger, z: typing.Union[str, float] = "0"): + def __init__(self, file, logger, z: typing.Union[str, float] = "0"): """Offset building storeys by a particular Z value All objects placed relative to the storeys will also be shifted. @@ -35,7 +35,6 @@ class Patcher: # Shift all storeys up by 42 units ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "OffsetStoreyElevations", "arguments": [42]}) """ - self.src = src self.file = file self.logger = logger self.z = float(z) diff --git a/src/ifcpatch/ifcpatch/recipes/Optimise.py b/src/ifcpatch/ifcpatch/recipes/Optimise.py index bca0c12ef7..79699ae2e6 100644 --- a/src/ifcpatch/ifcpatch/recipes/Optimise.py +++ b/src/ifcpatch/ifcpatch/recipes/Optimise.py @@ -21,7 +21,7 @@ import ifcopenshell.util.element class Patcher: - def __init__(self, src, file, logger): + def __init__(self, file, logger): """Optimise the filesize of an IFC model It is possible to non-losslessly optimise the filesize of an IFC model. @@ -46,7 +46,6 @@ class Patcher: ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "Optimise", "arguments": []}) """ - self.src = src self.file = file self.logger = logger self.optimized_file = ifcopenshell.file(schema=self.file.schema) diff --git a/src/ifcpatch/ifcpatch/recipes/PurgeData.py b/src/ifcpatch/ifcpatch/recipes/PurgeData.py index 9f55b47af9..871120840f 100644 --- a/src/ifcpatch/ifcpatch/recipes/PurgeData.py +++ b/src/ifcpatch/ifcpatch/recipes/PurgeData.py @@ -22,7 +22,7 @@ from logging import Logger class Patcher: - def __init__(self, src: str, file: ifcopenshell.file, logger: Logger): + def __init__(self, file: ifcopenshell.file, logger: Logger): """Purge IFC properties, relationships, and other data In some rare cases (i.e. "resetting" a model or for security purposes) @@ -51,7 +51,6 @@ class Patcher: # Watch the world burn ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "PurgeData", "arguments": []}) """ - self.src = src self.file = file self.logger = logger diff --git a/src/ifcpatch/ifcpatch/recipes/RecycleNonRootedElements.py b/src/ifcpatch/ifcpatch/recipes/RecycleNonRootedElements.py index c94ddfeb30..93ab762778 100644 --- a/src/ifcpatch/ifcpatch/recipes/RecycleNonRootedElements.py +++ b/src/ifcpatch/ifcpatch/recipes/RecycleNonRootedElements.py @@ -22,7 +22,7 @@ import ifcopenshell.util.element class Patcher: - def __init__(self, src: str, file: ifcopenshell.file, logger: logging.Logger): + def __init__(self, file: ifcopenshell.file, logger: logging.Logger): """Optimise the filesize of an IFC model by reusing non-rooted elements It is possible to non-losslessly optimise the filesize of an IFC model. @@ -46,7 +46,6 @@ class Patcher: ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "RecycleNonRootedElements", "arguments": []}) """ - self.src = src self.file = file self.logger = logger diff --git a/src/ifcpatch/ifcpatch/recipes/RegenerateGlobalIds.py b/src/ifcpatch/ifcpatch/recipes/RegenerateGlobalIds.py index 6a00e54e95..dec1a1db10 100644 --- a/src/ifcpatch/ifcpatch/recipes/RegenerateGlobalIds.py +++ b/src/ifcpatch/ifcpatch/recipes/RegenerateGlobalIds.py @@ -22,7 +22,7 @@ from logging import Logger class Patcher: - def __init__(self, src: str, file: ifcopenshell.file, logger: Logger, only_duplicates=False): + def __init__(self, file: ifcopenshell.file, logger: Logger, only_duplicates=False): """Regenerate GlobalIds in an IFC model All root elements in an IFC model must be identified by a unique Global @@ -48,7 +48,6 @@ class Patcher: # Regenerate only duplicate GlobalIds ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "RegenerateGlobalIds", "arguments": [True]}) """ - self.src = src self.file = file self.logger = logger self.only_duplicates = only_duplicates diff --git a/src/ifcpatch/ifcpatch/recipes/RemoveRevitUniformatClassification.py b/src/ifcpatch/ifcpatch/recipes/RemoveRevitUniformatClassification.py index 0a73508139..0d61bbd6c0 100644 --- a/src/ifcpatch/ifcpatch/recipes/RemoveRevitUniformatClassification.py +++ b/src/ifcpatch/ifcpatch/recipes/RemoveRevitUniformatClassification.py @@ -18,7 +18,7 @@ class Patcher: - def __init__(self, src, file, logger): + def __init__(self, file, logger): """Removes the built-in Revit Uniformat classification. Revit has a bug (see https://github.com/Autodesk/revit-ifc/issues/486) @@ -31,7 +31,6 @@ class Patcher: ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "RemoveRevitUniformatClassification"}) """ - self.src = src self.file = file self.logger = logger diff --git a/src/ifcpatch/ifcpatch/recipes/RemoveSiteRepresentation.py b/src/ifcpatch/ifcpatch/recipes/RemoveSiteRepresentation.py index 39b326a4c9..c5daea9868 100644 --- a/src/ifcpatch/ifcpatch/recipes/RemoveSiteRepresentation.py +++ b/src/ifcpatch/ifcpatch/recipes/RemoveSiteRepresentation.py @@ -18,7 +18,7 @@ class Patcher: - def __init__(self, src, file, logger): + def __init__(self, file, logger): """Removes any 3D geometry associated with a site or multiple sites If no sites or no site geometry is present, nothing happens. @@ -29,7 +29,6 @@ class Patcher: ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "RemoveSiteRepresentation", "arguments": []}) """ - self.src = src self.file = file self.logger = logger diff --git a/src/ifcpatch/ifcpatch/recipes/ResetAbsoluteCoordinates.py b/src/ifcpatch/ifcpatch/recipes/ResetAbsoluteCoordinates.py index 7f58e39694..ee0b4c1568 100644 --- a/src/ifcpatch/ifcpatch/recipes/ResetAbsoluteCoordinates.py +++ b/src/ifcpatch/ifcpatch/recipes/ResetAbsoluteCoordinates.py @@ -26,7 +26,6 @@ from typing import Literal, Optional, Union class Patcher: def __init__( self, - src: str, file: ifcopenshell.file, logger: logging.Logger, mode: Literal[ @@ -99,7 +98,6 @@ class Patcher: # Reset all coordinates with an ordinate larger than 1000 by -500,-200,0 ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "ResetAbsoluteCoordinates", "arguments": [False, 1000, -500,-200,0]}) """ - self.src = src self.file = file self.logger = logger self.mode = mode.lower() diff --git a/src/ifcpatch/ifcpatch/recipes/ResetSpatialElementLocations.py b/src/ifcpatch/ifcpatch/recipes/ResetSpatialElementLocations.py index f77516eb4b..aa335320ba 100644 --- a/src/ifcpatch/ifcpatch/recipes/ResetSpatialElementLocations.py +++ b/src/ifcpatch/ifcpatch/recipes/ResetSpatialElementLocations.py @@ -18,7 +18,7 @@ class Patcher: - def __init__(self, src, file, logger, ifc_class="IfcSite"): + def __init__(self, file, logger, ifc_class="IfcSite"): """Resets the location of a spatial element to 0,0,0 Another more specialised patch to fix incorrect coordinate usage is to @@ -35,7 +35,6 @@ class Patcher: # All IfcSites will shift back to 0,0,0. ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "ResetSpatialElementLocations", "arguments": ["IfcSite"]}) """ - self.src = src self.file = file self.logger = logger self.ifc_class = ifc_class diff --git a/src/ifcpatch/ifcpatch/recipes/SetFalseOrigin.py b/src/ifcpatch/ifcpatch/recipes/SetFalseOrigin.py index 8657890418..73008c8fdf 100644 --- a/src/ifcpatch/ifcpatch/recipes/SetFalseOrigin.py +++ b/src/ifcpatch/ifcpatch/recipes/SetFalseOrigin.py @@ -25,7 +25,6 @@ import typing class Patcher: def __init__( self, - src, file, logger, name: str = "EPSG:1234", @@ -59,7 +58,6 @@ class Patcher: # Set the current origin 0,0,0 to correlate to map coordinates 1000,1000,0 and a grid north of 15. ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "SetFalseOrigin", "arguments": ["EPSG:1234", 0, 0, 0, 1000, 1000, 0, 15, 0]}) """ - self.src = src self.file = file self.logger = logger self.name = name @@ -73,7 +71,7 @@ class Patcher: self.rotate_angle = float(rotate_angle) def patch(self): - SetWorldCoordinateSystem.Patcher(self.src, self.file, self.logger, x=0, y=0, z=0, ax=0, ay=0, az=0).patch() + SetWorldCoordinateSystem.Patcher(self.file, self.logger, x=0, y=0, z=0, ax=0, ay=0, az=0).patch() coordinate_operation = { "Eastings": self.e, "Northings": self.n, @@ -90,7 +88,6 @@ class Patcher: self.file, projected_crs={"Name": self.name}, coordinate_operation=coordinate_operation ) OffsetObjectPlacements.Patcher( - self.src, self.file, self.logger, x=-self.x, diff --git a/src/ifcpatch/ifcpatch/recipes/SetRefElevation.py b/src/ifcpatch/ifcpatch/recipes/SetRefElevation.py index cc1a092aff..a39b564cd9 100644 --- a/src/ifcpatch/ifcpatch/recipes/SetRefElevation.py +++ b/src/ifcpatch/ifcpatch/recipes/SetRefElevation.py @@ -20,7 +20,7 @@ import typing class Patcher: - def __init__(self, src, file, logger, elevation: typing.Union[str, float] = "0"): + def __init__(self, file, logger, elevation: typing.Union[str, float] = "0"): """Sets the reference elevation of all IfcSites To completely reference model coordinates, a reference elevation should @@ -41,7 +41,6 @@ class Patcher: # All IfcSites will have their reference elevation set to 42. ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "SetRefElevation", "arguments": [42]}) """ - self.src = src self.file = file self.logger = logger self.elevation = float(elevation) diff --git a/src/ifcpatch/ifcpatch/recipes/SetWorldCoordinateSystem.py b/src/ifcpatch/ifcpatch/recipes/SetWorldCoordinateSystem.py index ff8a4a4043..ba83d9a556 100644 --- a/src/ifcpatch/ifcpatch/recipes/SetWorldCoordinateSystem.py +++ b/src/ifcpatch/ifcpatch/recipes/SetWorldCoordinateSystem.py @@ -24,7 +24,6 @@ import typing class Patcher: def __init__( self, - src, file, logger, x: typing.Union[str, float] = "0", @@ -61,7 +60,6 @@ class Patcher: # Set the world coordinate system back to 0, 0, 0 ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "SetWorldCoordinateSystem", "arguments": [0,0,0,0,0,0]}) """ - self.src = src self.file = file self.logger = logger self.x = float(x) diff --git a/src/ifcpatch/ifcpatch/recipes/SplitByBuildingStorey.py b/src/ifcpatch/ifcpatch/recipes/SplitByBuildingStorey.py index 82f4e32fc4..a2cee58a08 100644 --- a/src/ifcpatch/ifcpatch/recipes/SplitByBuildingStorey.py +++ b/src/ifcpatch/ifcpatch/recipes/SplitByBuildingStorey.py @@ -24,18 +24,13 @@ from typing import Union class Patcher: - input_argument = "SUPPORTED" - - def __init__(self, src: str, file: ifcopenshell.file, logger: logging.Logger, output_dir: Union[str, None] = None): + def __init__(self, file: ifcopenshell.file, logger: logging.Logger, output_dir: Union[str, None] = None): """Split an IFC model into multiple models based on building storey The new IFC model names will be named after the storey name in the format of {i}-{name}.ifc, where {i} is an ascending number starting from 0 and {name} is the name of the storey. - `input` argument might be provided to ifcpatch - it will be used load file from disk - (otherwise `file` will be saved to a temporary file). - :param output_dir: Specifies an output directory where the new IFC models will be saved. Example: @@ -44,7 +39,6 @@ class Patcher: ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "SplitByBuildingStorey", "arguments": ["C:/.../output_files"]}) """ - self.src = src self.file = file self.logger = logger self.output_dir = output_dir @@ -60,17 +54,14 @@ class Patcher: output_dir = Path(self.output_dir) output_dir.mkdir(parents=True, exist_ok=True) - temp_file = None - if not self.src: - temp_file = tempfile.NamedTemporaryFile(suffix=".ifc", delete=False) - self.src = temp_file.name - self.file.write(self.src) + temp_file = tempfile.NamedTemporaryFile(suffix=".ifc", delete=False) + self.file.write(temp_file.name) storeys = self.file.by_type("IfcBuildingStorey") for i, storey in enumerate(storeys): filename = f"{i}-{storey.Name}.ifc" dest = filename if output_dir == None else output_dir / filename - copyfile(self.src, dest) + copyfile(temp_file.name, dest) old_ifc: ifcopenshell.file = ifcopenshell.open(dest) new_ifc = ifcopenshell.file(schema=self.file.schema) @@ -98,9 +89,8 @@ class Patcher: new_ifc.remove(element) new_ifc.write(dest) - if temp_file is not None: - temp_file.close() - os.unlink(temp_file.name) + temp_file.close() + os.unlink(temp_file.name) def is_in_storey(self, element: ifcopenshell.entity_instance, storey: ifcopenshell.entity_instance) -> bool: return ( diff --git a/src/ifcpatch/ifcpatch/recipes/TessellateElements.py b/src/ifcpatch/ifcpatch/recipes/TessellateElements.py index 06929cea59..5becec4264 100644 --- a/src/ifcpatch/ifcpatch/recipes/TessellateElements.py +++ b/src/ifcpatch/ifcpatch/recipes/TessellateElements.py @@ -30,7 +30,6 @@ from typing import Union class Patcher: def __init__( self, - src: str, file: ifcopenshell.file, logger: Logger, query: str = "IfcBeam", @@ -58,7 +57,6 @@ class Patcher: ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "TessellateElements", "arguments": ["IfcBeam", False]}) """ - self.src = src self.file = file self.logger = logger self.query = query diff --git a/src/ifcpatch/ifcpatch/recipes/UnsharePsets.py b/src/ifcpatch/ifcpatch/recipes/UnsharePsets.py index 7020a86504..fa7f1b083c 100644 --- a/src/ifcpatch/ifcpatch/recipes/UnsharePsets.py +++ b/src/ifcpatch/ifcpatch/recipes/UnsharePsets.py @@ -25,18 +25,22 @@ from logging import Logger class Patcher: - def __init__(self, src: str, file: ifcopenshell.file, logger: Logger, query: str = ""): + def __init__(self, file: ifcopenshell.file, logger: Logger, query: str = ""): """Create independent copies for shared psets in IFC file. - In IFC it's possible that same property set is shared by multiple elements, - so editing it's properties will automatically change their values for all those elements. + In IFC it's possible that same property set is shared by multiple + elements, so editing it's properties will automatically change their + values for all those elements. - Sometimes it's intended but sometimes it's not and it's just the way some other - software exports IFC (e.g. there is a known case when Tekla exports shared psets for all the occurrences). - While it is more optimized way to store data, it may lead to unexpected results when editing properties. + Sometimes it's intended but sometimes it's not and it's just the way + some other software exports IFC (e.g. there is a known case when Tekla + exports shared psets for all the occurrences). While it is more + optimized way to store data, it may lead to unexpected results when + editing properties. - This recipe creates independent copies of all shared psets (may be limited by the query) - and assigns them to the elements, so they can be edited without affecting any other elements. + This recipe creates independent copies of all shared psets (may be + limited by the query) and assigns them to the elements, so they can be + edited without affecting any other elements. :param query: A query to select the subset of IFC elements, optional. If not provided, patch will be applied to all shared property sets in the model. @@ -51,7 +55,6 @@ class Patcher: # Unshare psets on all IfcWalls. ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "UnsharePsets", "arguments": ["IfcWall"]}) """ - self.src = src self.file = file self.logger = logger self.query = query From 0a32149be308583fc32565c3f6d69e4785889c46 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Fri, 10 Jan 2025 19:49:04 +1100 Subject: [PATCH 16/61] Fix #5944. You can now tab / edit IfcAnnotationFillArea with the new item editing mode. --- .../bonsai/bim/module/geometry/operator.py | 32 ++++++++++++++++--- src/bonsai/bonsai/tool/model.py | 30 +++++++++++++++++ 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/geometry/operator.py b/src/bonsai/bonsai/bim/module/geometry/operator.py index aac604fb48..c27d4d25c5 100644 --- a/src/bonsai/bonsai/bim/module/geometry/operator.py +++ b/src/bonsai/bonsai/bim/module/geometry/operator.py @@ -1973,6 +1973,13 @@ class OverrideModeSetEdit(bpy.types.Operator, tool.Ifc.Operator): ProfileDecorator.install(context) if not bpy.app.background: tool.Blender.set_viewport_tool("bim.cad_tool") + elif item.is_a("IfcAnnotationFillArea"): + tool.Model.import_annotation_fill_area(item, obj=obj) + obj.data.BIMMeshProperties.ifc_definition_id = item.id() + self.enable_edit_mode(context) + ProfileDecorator.install(context) + if not bpy.app.background: + tool.Blender.set_viewport_tool("bim.cad_tool") elif tool.Geometry.is_curvelike_item(item): tool.Model.import_curve(item, obj=obj) obj.data.BIMMeshProperties.ifc_definition_id = item.id() @@ -2126,10 +2133,7 @@ class OverrideModeSetObject(bpy.types.Operator, tool.Ifc.Operator): tool.Geometry.import_item(obj) elif item.is_a("IfcSweptAreaSolid"): ProfileDecorator.uninstall() - - profile = tool.Model.export_profile(obj) - - if not profile: + if not (profile := tool.Model.export_profile(obj)): def msg(self, context): self.layout.label(text="INVALID PROFILE") @@ -2186,6 +2190,26 @@ class OverrideModeSetObject(bpy.types.Operator, tool.Ifc.Operator): product=element, representation=new_footprint, ) + elif item.is_a("IfcAnnotationFillArea"): + ProfileDecorator.uninstall() + if not (profile := tool.Model.export_annotation_fill_area(obj)): + + def msg(self, context): + self.layout.label(text="INVALID PROFILE") + + bpy.context.window_manager.popup_menu(msg, title="Error", icon="ERROR") + ProfileDecorator.install(bpy.context) + self.enable_edit_mode(bpy.context) + return + + for inverse in tool.Ifc.get().get_inverse(item): + ifcopenshell.util.element.replace_attribute(inverse, item, profile) + ifcopenshell.util.element.remove_deep2(tool.Ifc.get(), item) + obj.data.BIMMeshProperties.ifc_definition_id = profile.id() + + tool.Geometry.reload_representation(bpy.context.scene.BIMGeometryProperties.representation_obj) + tool.Geometry.import_item(obj) + tool.Geometry.import_item_attributes(obj) elif tool.Geometry.is_curvelike_item(item): ProfileDecorator.uninstall() new = tool.Model.export_curves(obj) diff --git a/src/bonsai/bonsai/tool/model.py b/src/bonsai/bonsai/tool/model.py index 2eb5be5aba..709f2403e9 100644 --- a/src/bonsai/bonsai/tool/model.py +++ b/src/bonsai/bonsai/tool/model.py @@ -131,6 +131,12 @@ class Model(bonsai.core.tool.Model): points.append(cls.convert_si_to_unit(list(local_point))) return tool.Ifc.get().createIfcCartesianPointList2D(points) + @classmethod + def export_annotation_fill_area(cls, obj: bpy.types.Object) -> ifcopenshell.entity_instance | None: + result = cls.auto_detect_annotation_fill_area(obj, obj.data) + if isinstance(result, dict) and result["annotation_fill_area"]: + return tool.Ifc.get().add(result["annotation_fill_area"]) + @classmethod def export_profile( cls, obj: bpy.types.Object, position: Optional[Matrix] = None @@ -268,6 +274,12 @@ class Model(bonsai.core.tool.Model): return obj + @classmethod + def import_annotation_fill_area( + cls, annotation_fill_area: ifcopenshell.entity_instance, obj: Optional[bpy.types.Object] = None + ) -> bpy.types.Object: + return cls.import_profile(annotation_fill_area, obj) + @classmethod def import_profile( cls, @@ -299,6 +311,10 @@ class Model(bonsai.core.tool.Model): cls.convert_curve_to_mesh(obj, position, inner_curve) elif profile.is_a() == "IfcRectangleProfileDef": cls.import_rectangle(obj, position, profile) + elif profile.is_a() == "IfcAnnotationFillArea": + cls.convert_curve_to_mesh(obj, position, profile.OuterBoundary) + for inner_boundary in profile.InnerBoundaries or []: + cls.convert_curve_to_mesh(obj, position, inner_boundary) mesh = bpy.data.meshes.new("Profile") mesh.from_pydata(cls.vertices, cls.edges, []) @@ -1575,6 +1591,20 @@ class Model(bonsai.core.tool.Model): ) tool.Model.replace_object_ifc_representation(body, obj, representation) + @classmethod + def auto_detect_annotation_fill_area(cls, obj: bpy.types.Object, mesh: bpy.types.Mesh) -> dict | None: + result = cls.auto_detect_profiles(obj, mesh) + fill_area = None + if isinstance(result, dict) and (profile_def := result["profile_def"]): + if profile_def.is_a("IfcArbitraryClosedProfileDef"): + fill_area = result["ifc_file"].createIfcAnnotationFillArea(profile_def.OuterCurve) + elif profile_def.is_a("IfcArbitraryProfileDefWithVoids"): + fill_area = result["ifc_file"].createIfcAnnotationFillArea( + profile_def.OuterCurve, profile_def.InnerCurves + ) + if fill_area: + return {"ifc_file": result["ifc_file"], "annotation_fill_area": fill_area} + @classmethod def auto_detect_profiles( cls, obj: bpy.types.Object, mesh: bpy.types.Mesh, position: Matrix | None = None From 956b7dcb92a3f641bc5dcc036c09a752885c0f78 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Fri, 10 Jan 2025 21:50:52 +1100 Subject: [PATCH 17/61] Fix #5941. Regression in ae22eec9 where active object wasn't considered when adding a parametric door. --- src/bonsai/bonsai/bim/module/model/door.py | 10 +++++----- src/bonsai/bonsai/tool/blender.py | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/model/door.py b/src/bonsai/bonsai/bim/module/model/door.py index a8aa7b66c2..94ba825413 100644 --- a/src/bonsai/bonsai/bim/module/model/door.py +++ b/src/bonsai/bonsai/bim/module/model/door.py @@ -572,7 +572,7 @@ class AddDoor(bpy.types.Operator, tool.Ifc.Operator): update_door_modifier_representation(obj) def _execute(self, context): - for obj in context.selected_objects: + for obj in tool.Blender.get_selected_objects(): if not tool.Blender.Modifier.is_eligible_for_door_modifier(obj): continue self.add_door_on_object(obj) @@ -610,7 +610,7 @@ class CancelEditingDoor(bpy.types.Operator, tool.Ifc.Operator): props.is_editing = False def _execute(self, context): - for obj in context.selected_objects: + for obj in tool.Blender.get_selected_objects(): self.cancel_editing_door_on_object(obj) return {"FINISHED"} @@ -642,7 +642,7 @@ class FinishEditingDoor(bpy.types.Operator, tool.Ifc.Operator): ifcopenshell.api.run("pset.edit_pset", tool.Ifc.get(), pset=pset, properties={"Data": door_data}) def _execute(self, context): - for obj in context.selected_objects: + for obj in tool.Blender.get_selected_objects(): self.finish_editing_door_on_object(obj) return {"FINISHED"} @@ -666,7 +666,7 @@ class EnableEditingDoor(bpy.types.Operator, tool.Ifc.Operator): props.is_editing = True def _execute(self, context): - for obj in context.selected_objects: + for obj in tool.Blender.get_selected_objects(): self.edit_door_on_obj(obj) return {"FINISHED"} @@ -686,6 +686,6 @@ class RemoveDoor(bpy.types.Operator, tool.Ifc.Operator): ifcopenshell.api.run("pset.remove_pset", tool.Ifc.get(), product=element, pset=pset) def _execute(self, context): - for obj in context.selected_objects: + for obj in tool.Blender.get_selected_objects(): self.remove_door_on_object(obj) return {"FINISHED"} diff --git a/src/bonsai/bonsai/tool/blender.py b/src/bonsai/bonsai/tool/blender.py index f6cb45e08e..b096903297 100644 --- a/src/bonsai/bonsai/tool/blender.py +++ b/src/bonsai/bonsai/tool/blender.py @@ -144,7 +144,7 @@ class Blender(bonsai.core.tool.Blender): @classmethod def get_active_object(cls) -> bpy.types.Object: - return bpy.context.view_layer.objects.active + return bpy.context.view_layer.objects.active or bpy.context.active_object @classmethod def get_selected_objects(cls) -> set[bpy.types.Object]: From d88adf2d02a93f11c25ab1a25c1fa2c41e459927 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Fri, 10 Jan 2025 22:48:11 +1100 Subject: [PATCH 18/61] See #5938. Correctly detect negative extrusion depths and directions. --- src/bonsai/bonsai/bim/handler.py | 2 +- src/bonsai/bonsai/bim/module/geometry/helper.py | 2 +- src/bonsai/bonsai/bim/module/model/prop.py | 8 +++++++- src/bonsai/bonsai/bim/module/type/operator.py | 8 +++++--- src/bonsai/bonsai/tool/blender.py | 2 +- 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/bonsai/bonsai/bim/handler.py b/src/bonsai/bonsai/bim/handler.py index e24d984757..1f63ff18b8 100644 --- a/src/bonsai/bonsai/bim/handler.py +++ b/src/bonsai/bonsai/bim/handler.py @@ -134,7 +134,7 @@ def update_bim_tool_props(): if AuthoringData.data["active_material_usage"] == "LAYER2": x_angle = get_x_angle(extrusion) axis = tool.Model.get_wall_axis(obj)["reference"] - props.extrusion_depth = extrusion.Depth * si_conversion * cos(x_angle) + props.extrusion_depth = abs(extrusion.Depth * si_conversion * cos(x_angle)) props.length = (axis[1] - axis[0]).length props.x_angle = x_angle diff --git a/src/bonsai/bonsai/bim/module/geometry/helper.py b/src/bonsai/bonsai/bim/module/geometry/helper.py index bee6593996..38ca24d15d 100644 --- a/src/bonsai/bonsai/bim/module/geometry/helper.py +++ b/src/bonsai/bonsai/bim/module/geometry/helper.py @@ -454,7 +454,7 @@ class Helper: x_axis = (mesh.vertices[loop[0]].co - center).normalized() else: x_axis = (mesh.vertices[loop[1]].co - mesh.vertices[loop[0]].co).normalized() - z_axis = profile_face.polygons[0].normal.normalized() * (-1) + z_axis = profile_face.polygons[0].normal.normalized() * -1 y_axis = z_axis.cross(x_axis).normalized() matrix = Matrix((x_axis, y_axis, z_axis)) matrix.normalize() diff --git a/src/bonsai/bonsai/bim/module/model/prop.py b/src/bonsai/bonsai/bim/module/model/prop.py index 4c972c657b..4325a3e9fb 100644 --- a/src/bonsai/bonsai/bim/module/model/prop.py +++ b/src/bonsai/bonsai/bim/module/model/prop.py @@ -97,6 +97,12 @@ def update_slab_direction_decorator(self, context): SlabDirectionDecorator.uninstall() +def update_x_angle(self, context): + angle_deg = math.degrees(self.x_angle) + if tool.Cad.is_x(angle_deg, -90, 0.5) or tool.Cad.is_x(angle_deg, 90, 0.5): + self.x_angle = 0 + + class BIMModelProperties(PropertyGroup): ifc_class: bpy.props.EnumProperty(items=get_ifc_class, name="Construction Class", update=update_ifc_class) relating_type_id: bpy.props.EnumProperty( @@ -161,7 +167,7 @@ class BIMModelProperties(PropertyGroup): rl2: bpy.props.FloatProperty(name="RL", default=1, subtype="DISTANCE", description="Z offset for windows") # Used for plan calculation points such as in room generation rl3: bpy.props.FloatProperty(name="RL", default=1, subtype="DISTANCE", description="Z offset for space calculation") - x_angle: bpy.props.FloatProperty(name="X Angle", default=0, subtype="ANGLE", min=-pi / 180 * 89, max=pi / 180 * 89) + x_angle: bpy.props.FloatProperty(name="X Angle", default=0, subtype="ANGLE", min=math.radians(-180), max=math.radians(180), update=update_x_angle) type_page: bpy.props.IntProperty(name="Type Page", default=1, update=update_type_page) type_name: bpy.props.StringProperty(name="Name", default="TYPEX") boundary_class: bpy.props.EnumProperty(items=get_boundary_class, name="Boundary Class") diff --git a/src/bonsai/bonsai/bim/module/type/operator.py b/src/bonsai/bonsai/bim/module/type/operator.py index cb5c1b6361..5b67d79957 100644 --- a/src/bonsai/bonsai/bim/module/type/operator.py +++ b/src/bonsai/bonsai/bim/module/type/operator.py @@ -40,7 +40,9 @@ class AssignType(bpy.types.Operator, tool.Ifc.Operator): related_object: bpy.props.StringProperty() def _execute(self, context): - type = tool.Ifc.get().by_id(self.relating_type or int(context.active_object.BIMTypeProperties.relating_type)) + relating_type = tool.Ifc.get().by_id( + self.relating_type or int(context.active_object.BIMTypeProperties.relating_type) + ) related_objects = ( [bpy.data.objects.get(self.related_object)] if self.related_object @@ -49,9 +51,9 @@ class AssignType(bpy.types.Operator, tool.Ifc.Operator): model_props = context.scene.BIMModelProperties for obj in related_objects: element = tool.Ifc.get_entity(obj) - core.assign_type(tool.Ifc, tool.Type, element=element, type=type) + core.assign_type(tool.Ifc, tool.Type, element=element, type=relating_type) if model_props.occurrence_name_style == "TYPE": - obj.name = tool.Model.generate_occurrence_name(type, element.is_a()) + obj.name = tool.Model.generate_occurrence_name(relating_type, element.is_a()) class UnassignType(bpy.types.Operator, tool.Ifc.Operator): diff --git a/src/bonsai/bonsai/tool/blender.py b/src/bonsai/bonsai/tool/blender.py index b096903297..8795f77155 100644 --- a/src/bonsai/bonsai/tool/blender.py +++ b/src/bonsai/bonsai/tool/blender.py @@ -144,7 +144,7 @@ class Blender(bonsai.core.tool.Blender): @classmethod def get_active_object(cls) -> bpy.types.Object: - return bpy.context.view_layer.objects.active or bpy.context.active_object + return bpy.context.view_layer.objects.active or getattr(bpy.context, "active_object", None) @classmethod def get_selected_objects(cls) -> set[bpy.types.Object]: From 2e7cbb759eb90ce166c2a964df34e420579710e9 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sat, 11 Jan 2025 14:51:18 +1100 Subject: [PATCH 19/61] Fix #5955. Regression in 0983f812fd where you couldn't remove a style that wasn't being edited. --- src/bonsai/bonsai/bim/module/style/operator.py | 1 - src/bonsai/bonsai/core/style.py | 2 ++ src/bonsai/bonsai/core/tool.py | 1 + src/bonsai/bonsai/tool/style.py | 4 ++++ 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/bonsai/bonsai/bim/module/style/operator.py b/src/bonsai/bonsai/bim/module/style/operator.py index b1b63ebca2..ba4b306af4 100644 --- a/src/bonsai/bonsai/bim/module/style/operator.py +++ b/src/bonsai/bonsai/bim/module/style/operator.py @@ -80,7 +80,6 @@ class RemoveStyle(bpy.types.Operator, tool.Ifc.Operator): style: bpy.props.IntProperty() def _execute(self, context): - core.disable_editing_style(tool.Style) # So we don't end up soft-locking style edition core.remove_style(tool.Ifc, tool.Style, style=tool.Ifc.get().by_id(self.style), reload_styles_ui=True) diff --git a/src/bonsai/bonsai/core/style.py b/src/bonsai/bonsai/core/style.py index 685cc2cf88..b555a311e2 100644 --- a/src/bonsai/bonsai/core/style.py +++ b/src/bonsai/bonsai/core/style.py @@ -65,6 +65,8 @@ def remove_style( avoid unnecessary reloads. """ obj = ifc.get_object(style) + if style_tool.is_editing_style() and obj == style_tool.get_currently_edited_material(): + style_tool.disable_editing() # Get style_type before removing object as later StylesData might fail to load # due object not yet removed completely. style_type = style_tool.get_active_style_type() diff --git a/src/bonsai/bonsai/core/tool.py b/src/bonsai/bonsai/core/tool.py index 1f673b9521..4e10708786 100644 --- a/src/bonsai/bonsai/core/tool.py +++ b/src/bonsai/bonsai/core/tool.py @@ -1013,6 +1013,7 @@ class Style: def get_uv_maps(cls, representation): pass def import_presentation_styles(cls, style_type): pass def import_surface_attributes(cls, style): pass + def is_editing_style(cls): pass def is_editing_styles(cls): pass def reload_material_from_ifc(cls, obj): pass def is_style_side_attribute_edited(cls, style, new_attributes): pass diff --git a/src/bonsai/bonsai/tool/style.py b/src/bonsai/bonsai/tool/style.py index 359386b25a..7c6b7fd602 100644 --- a/src/bonsai/bonsai/tool/style.py +++ b/src/bonsai/bonsai/tool/style.py @@ -550,6 +550,10 @@ class Style(bonsai.core.tool.Style): def is_editing_styles(cls) -> bool: return bpy.context.scene.BIMStylesProperties.is_editing + @classmethod + def is_editing_style(cls) -> bool: + return bpy.context.scene.BIMStylesProperties.is_editing_style + @classmethod def select_elements(cls, elements: list[ifcopenshell.entity_instance]) -> None: for element in elements: From c446aab9a048b1eddf1cdb75e0b86e746f6620c2 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sat, 11 Jan 2025 15:39:13 +1100 Subject: [PATCH 20/61] Fix #5951. Regression when removing mathutils dependency from shape builder and parametric stairs were expecting Vector and instead got numpy. --- src/bonsai/bonsai/tool/model.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/bonsai/bonsai/tool/model.py b/src/bonsai/bonsai/tool/model.py index 709f2403e9..e69531cce4 100644 --- a/src/bonsai/bonsai/tool/model.py +++ b/src/bonsai/bonsai/tool/model.py @@ -1264,7 +1264,9 @@ class Model(bonsai.core.tool.Model): if stair_type == "WOOD/STEEL": builder = ShapeBuilder(None) # full tread rectangle - get_tread_verts = partial(builder.get_rectangle_coords, position=V_(0, -(tread_depth - tread_rise))) + def get_tread_verts(*args, **kwargs): + fn = partial(builder.get_rectangle_coords, position=V_(0, -(tread_depth - tread_rise))) + return [Vector(x) for x in fn(*args, **kwargs)] default_tread_verts = get_tread_verts(size=V_(tread_run + nosing_overlap, tread_depth)) default_tread_offset = V_(tread_run + nosing_tread_gap, tread_rise) From 0a4ab32810973110e577ba5440a78a1fddc0124a Mon Sep 17 00:00:00 2001 From: Bruno Postle Date: Sat, 11 Jan 2025 13:36:54 +0000 Subject: [PATCH 21/61] Fix missing carriage return SyntaxWarning: invalid escape sequence '\I' --- src/bonsai/bonsai/bim/ui.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bonsai/bonsai/bim/ui.py b/src/bonsai/bonsai/bim/ui.py index 88bcddcc09..42742fb1de 100644 --- a/src/bonsai/bonsai/bim/ui.py +++ b/src/bonsai/bonsai/bim/ui.py @@ -237,7 +237,7 @@ class BIM_ADDON_preferences(bpy.types.AddonPreferences): activate_workspace: BoolProperty( name="Activate BIM Workspace on Startup", default=True, - description="If enabled, this will automatically activate the BIM workspace when opening a project.\It is recommended to keep this `Enabled`", + description="If enabled, this will automatically activate the BIM workspace when opening a project.\nIt is recommended to keep this `Enabled`", ) should_setup_toolbar: BoolProperty( name="Always Show Toolbar In 3D Viewport", From 02632440b0efa674538dbb5f687aa75fb439a5d1 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sun, 12 Jan 2025 15:42:25 +1100 Subject: [PATCH 22/61] See #5949. Only show material psets and classifications if actually editing in the material manager. Previously, you could disable editing and it would still show irrelevant psets or classifications. --- src/bonsai/bonsai/bim/module/classification/ui.py | 6 ++---- src/bonsai/bonsai/bim/module/material/prop.py | 5 +++++ src/bonsai/bonsai/bim/module/pset/ui.py | 6 ++---- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/classification/ui.py b/src/bonsai/bonsai/bim/module/classification/ui.py index 300cfc5b8c..fcef0ad4bd 100644 --- a/src/bonsai/bonsai/bim/module/classification/ui.py +++ b/src/bonsai/bonsai/bim/module/classification/ui.py @@ -313,10 +313,8 @@ class BIM_PT_material_classifications(Panel, ReferenceUI): if not tool.Ifc.get(): return False props = context.scene.BIMMaterialProperties - if props.materials and props.active_material_index < len(props.materials): - material = props.materials[props.active_material_index] - if material.ifc_definition_id: - return True + if props.is_editing and (material := props.active_material) and material.ifc_definition_id: + return True return False def draw(self, context): diff --git a/src/bonsai/bonsai/bim/module/material/prop.py b/src/bonsai/bonsai/bim/module/material/prop.py index e6cf5ae827..b623083d5f 100644 --- a/src/bonsai/bonsai/bim/module/material/prop.py +++ b/src/bonsai/bonsai/bim/module/material/prop.py @@ -124,6 +124,11 @@ class BIMMaterialProperties(PropertyGroup): styles: EnumProperty(items=get_styles, name="Styles") contexts: EnumProperty(items=get_contexts, name="Contexts") + @property + def active_material(self): + if self.active_material_index < len(self.materials): + return self.materials[self.active_material_index] + class BIMObjectMaterialProperties(PropertyGroup): material_type: EnumProperty(items=get_object_material_type, name="Material Type") diff --git a/src/bonsai/bonsai/bim/module/pset/ui.py b/src/bonsai/bonsai/bim/module/pset/ui.py index 119d4c2c83..69333ac9b4 100644 --- a/src/bonsai/bonsai/bim/module/pset/ui.py +++ b/src/bonsai/bonsai/bim/module/pset/ui.py @@ -402,10 +402,8 @@ class BIM_PT_material_psets(Panel): if not ifc_file or ifc_file.schema == "IFC2X3": return False # We don't support material psets in IFC2X3 because they suck props = context.scene.BIMMaterialProperties - if props.materials and props.active_material_index < len(props.materials): - material = props.materials[props.active_material_index] - if material.ifc_definition_id: - return True + if props.is_editing and (material := props.active_material) and material.ifc_definition_id: + return True return False def draw(self, context): From 8e77011dda56b7134f574782bf1c8030027f18b5 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sun, 12 Jan 2025 15:44:57 +1100 Subject: [PATCH 23/61] Fix #5949. Remove material set psets panel in favour of merging into material manager psets panel. Previously, to edit a single IfcMaterial pset, you'd do so in the material manager. In contrast, to edit a IfcMaterialSet pset, you'd do so only when assigned to an object. Not only is it bad to edit psets in two locations, it also means you can't edit psets until you've first assigned the material set to an object which is bad. Now it's less code, and material / material set psets are in the same spot. There still more consolidation work to do, to allow editing of sets in the material manager and to figure out how to show item psets, but it's a step in the right direction. --- src/bonsai/bonsai/bim/module/pset/__init__.py | 3 -- src/bonsai/bonsai/bim/module/pset/data.py | 19 +------- src/bonsai/bonsai/bim/module/pset/ui.py | 43 +------------------ src/bonsai/bonsai/tool/blender.py | 4 -- src/bonsai/bonsai/tool/ifc.py | 1 - src/bonsai/bonsai/tool/pset.py | 2 - 6 files changed, 2 insertions(+), 70 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/pset/__init__.py b/src/bonsai/bonsai/bim/module/pset/__init__.py index 5e53bde928..0ab35183e4 100644 --- a/src/bonsai/bonsai/bim/module/pset/__init__.py +++ b/src/bonsai/bonsai/bim/module/pset/__init__.py @@ -47,7 +47,6 @@ classes = ( ui.BIM_PT_object_psets, ui.BIM_PT_object_qtos, ui.BIM_PT_material_psets, - ui.BIM_PT_material_set_psets, ui.BIM_PT_material_set_item_psets, ui.BIM_PT_task_qtos, ui.BIM_PT_resource_qtos, @@ -66,7 +65,6 @@ classes = ( def register(): bpy.types.Object.PsetProperties = bpy.props.PointerProperty(type=prop.PsetProperties) bpy.types.Scene.MaterialPsetProperties = bpy.props.PointerProperty(type=prop.PsetProperties) - bpy.types.Object.MaterialSetPsetProperties = bpy.props.PointerProperty(type=prop.PsetProperties) bpy.types.Object.MaterialSetItemPsetProperties = bpy.props.PointerProperty(type=prop.PsetProperties) bpy.types.Scene.TaskPsetProperties = bpy.props.PointerProperty(type=prop.PsetProperties) bpy.types.Scene.ResourcePsetProperties = bpy.props.PointerProperty(type=prop.PsetProperties) @@ -82,7 +80,6 @@ def register(): def unregister(): del bpy.types.Object.PsetProperties del bpy.types.Scene.MaterialPsetProperties - del bpy.types.Object.MaterialSetPsetProperties del bpy.types.Object.MaterialSetItemPsetProperties del bpy.types.Scene.TaskPsetProperties del bpy.types.Scene.ResourcePsetProperties diff --git a/src/bonsai/bonsai/bim/module/pset/data.py b/src/bonsai/bonsai/bim/module/pset/data.py index 7f1e391629..6506f7cce7 100644 --- a/src/bonsai/bonsai/bim/module/pset/data.py +++ b/src/bonsai/bonsai/bim/module/pset/data.py @@ -33,7 +33,6 @@ def refresh(): ObjectPsetsData.is_loaded = False ObjectQtosData.is_loaded = False MaterialPsetsData.is_loaded = False - MaterialSetPsetsData.is_loaded = False MaterialSetItemPsetsData.is_loaded = False TaskQtosData.is_loaded = False ResourceQtosData.is_loaded = False @@ -185,7 +184,7 @@ class MaterialPsetsData(Data): if material.ifc_definition_id: material = tool.Ifc.get().by_id(material.ifc_definition_id) category = getattr(material, "Category", None) or None - psets = bonsai.bim.schema.ifc.psetqto.get_applicable("IfcMaterial", category, pset_only=True) + psets = bonsai.bim.schema.ifc.psetqto.get_applicable(props.material_type, category, pset_only=True) psetnames = cls.format_pset_enum(psets) assigned_names = ifcopenshell.util.element.get_psets( material, psets_only=True, should_inherit=False @@ -194,22 +193,6 @@ class MaterialPsetsData(Data): return [] -class MaterialSetPsetsData(Data): - data = {} - is_loaded = False - - @classmethod - def load(cls): - psets = {} - element = tool.Ifc.get_entity(bpy.context.active_object) - if element: - material = ifcopenshell.util.element.get_material(element, should_skip_usage=True) - if material and "Set" in material.is_a(): - psets = cls.psetqtos(material) - cls.data = {"psets": psets} - cls.is_loaded = True - - class MaterialSetItemPsetsData(Data): data = {} is_loaded = False diff --git a/src/bonsai/bonsai/bim/module/pset/ui.py b/src/bonsai/bonsai/bim/module/pset/ui.py index 69333ac9b4..93d087c54e 100644 --- a/src/bonsai/bonsai/bim/module/pset/ui.py +++ b/src/bonsai/bonsai/bim/module/pset/ui.py @@ -25,7 +25,6 @@ from bonsai.bim.module.pset.data import ( ObjectPsetsData, ObjectQtosData, MaterialPsetsData, - MaterialSetPsetsData, MaterialSetItemPsetsData, TaskQtosData, ResourceQtosData, @@ -88,7 +87,7 @@ def draw_enumerated_property( def get_active_pset_obj_name(context: bpy.types.Context, obj_type: tool.Ifc.OBJECT_TYPE) -> str: - if obj_type in ("Object", "MaterialSet", "MaterialSetItem"): + if obj_type in ("Object", "MaterialSetItem"): return context.active_object.name return "" @@ -430,46 +429,6 @@ class BIM_PT_material_psets(Panel): draw_psetqto_ui(context, pset["id"], pset, props, self.layout, "Material") -class BIM_PT_material_set_psets(Panel): - bl_label = "Material Set Property Sets" - bl_idname = "BIM_PT_material_set_psets" - bl_options = {"DEFAULT_CLOSED"} - bl_space_type = "PROPERTIES" - bl_region_type = "WINDOW" - bl_context = "object" - bl_parent_id = "BIM_PT_object_material" - - @classmethod - def poll(cls, context): - if not context.active_object: - return False - if not tool.Ifc.get() or tool.Ifc.get().schema == "IFC2X3": - return False # We don't support material psets in IFC2X3 because they suck - if not tool.Ifc.get_entity(context.active_object): - return False - if not ObjectMaterialData.is_loaded: - ObjectMaterialData.load() - ifc_class = ObjectMaterialData.data["material_class"] - return bool(ifc_class and "Set" in ifc_class) - - def draw(self, context): - if not MaterialSetPsetsData.is_loaded: - MaterialSetPsetsData.load() - - props = context.active_object.MaterialSetPsetProperties - row = self.layout.row(align=True) - prop_with_search(row, props, "pset_name", text="") - op = row.operator("bim.add_pset", icon="ADD", text="") - op.obj = context.active_object.name - op.obj_type = "MaterialSet" - - if not props.active_pset_id and props.active_pset_name and props.active_pset_type == "PSET": - draw_psetqto_ui(context, 0, {}, props, self.layout, "MaterialSet") - - for pset in MaterialSetPsetsData.data["psets"]: - draw_psetqto_ui(context, pset["id"], pset, props, self.layout, "MaterialSet") - - class BIM_PT_material_set_item_psets(Panel): bl_label = "Material Set Item Property Sets" bl_idname = "BIM_PT_material_set_item_psets" diff --git a/src/bonsai/bonsai/tool/blender.py b/src/bonsai/bonsai/tool/blender.py index 8795f77155..d736599384 100644 --- a/src/bonsai/bonsai/tool/blender.py +++ b/src/bonsai/bonsai/tool/blender.py @@ -185,10 +185,6 @@ class Blender(bonsai.core.tool.Blender): return context.scene.BIMMaterialProperties.materials[ context.scene.BIMMaterialProperties.active_material_index ].ifc_definition_id - elif obj_type == "MaterialSet": - return ifcopenshell.util.element.get_material( - tool.Ifc.get_entity(bpy.data.objects.get(obj)), should_skip_usage=True - ).id() elif obj_type == "MaterialSetItem": return bpy.data.objects.get(obj).BIMObjectMaterialProperties.active_material_set_item_id elif obj_type == "Task": diff --git a/src/bonsai/bonsai/tool/ifc.py b/src/bonsai/bonsai/tool/ifc.py index 8144325584..502903601d 100644 --- a/src/bonsai/bonsai/tool/ifc.py +++ b/src/bonsai/bonsai/tool/ifc.py @@ -34,7 +34,6 @@ class Ifc(bonsai.core.tool.Ifc): OBJECT_TYPE = Literal[ "Object", "Material", - "MaterialSet", "MaterialSetItem", "Task", "Cost", diff --git a/src/bonsai/bonsai/tool/pset.py b/src/bonsai/bonsai/tool/pset.py index 9d37115aa4..7c07010fa8 100644 --- a/src/bonsai/bonsai/tool/pset.py +++ b/src/bonsai/bonsai/tool/pset.py @@ -45,8 +45,6 @@ class Pset(bonsai.core.tool.Pset): return bpy.data.objects.get(obj).PsetProperties elif obj_type == "Material": return bpy.context.scene.MaterialPsetProperties - elif obj_type == "MaterialSet": - return bpy.data.objects.get(obj).MaterialSetPsetProperties elif obj_type == "MaterialSetItem": return bpy.data.objects.get(obj).MaterialSetItemPsetProperties elif obj_type == "Task": From 41362e1582b90cc46f922d0e64c0da56a8cae190 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sun, 12 Jan 2025 16:28:14 +1100 Subject: [PATCH 24/61] Fix #5950. IfcTester now considers optional requirement facets as per latest documentation. The IDS documentation used to state that "optional" on requirement facets was "for information only" and didn't affect the pass / fail state. This was changed a while ago (which I missed) to a new behaviour: both no values and passing values will pass. --- src/ifctester/ifctester/facet.py | 24 +++++++------- src/ifctester/test/test_facet.py | 56 +++++++++++++++++++++++++++----- src/ifctester/test/test_ids.py | 2 +- 3 files changed, 60 insertions(+), 22 deletions(-) diff --git a/src/ifctester/ifctester/facet.py b/src/ifctester/ifctester/facet.py index f84f4821af..92104af211 100644 --- a/src/ifctester/ifctester/facet.py +++ b/src/ifctester/ifctester/facet.py @@ -279,16 +279,13 @@ class Attribute(Facet): return results def __call__(self, inst: ifcopenshell.entity_instance, logger: Optional[Logger] = None) -> AttributeResult: - if self.cardinality == "optional": - return AttributeResult(True) - if isinstance(self.name, str): names = [self.name] attribute_type = inst.wrapped_data.get_attribute_category(self.name) if attribute_type == 1: # Forward attribute values = [getattr(inst, self.name, None)] else: - values = [None] + values = [] else: info = inst.get_info() names = [] @@ -304,6 +301,8 @@ class Attribute(Facet): reason = None if not is_pass: + if self.cardinality == "optional": + return AttributeResult(True) reason = {"type": "NOVALUE"} if is_pass: @@ -394,9 +393,6 @@ class Classification(Facet): return ifc_file.by_type("IfcObjectDefinition") def __call__(self, inst: ifcopenshell.entity_instance, logger: Optional[Logger] = None) -> ClassificationResult: - if self.cardinality == "optional": - return ClassificationResult(True) # Is this really the correct behaviour? - leaf_references = ifcopenshell.util.classification.get_references(inst) references = leaf_references.copy() @@ -407,6 +403,8 @@ class Classification(Facet): reason = None if not is_pass: + if self.cardinality == "optional": + return ClassificationResult(True) reason = {"type": "NOVALUE"} if is_pass and self.value: @@ -657,9 +655,6 @@ class Property(Facet): ) def __call__(self, inst: ifcopenshell.entity_instance, logger: Optional[Logger] = None) -> PropertyResult: - if self.cardinality == "optional": - return PropertyResult(True) - if isinstance(self.propertySet, str): pset = get_pset(inst, self.propertySet) psets = {self.propertySet: pset} if pset else {} @@ -671,6 +666,8 @@ class Property(Facet): reason = None if not is_pass: + if self.cardinality == "optional": + return PropertyResult(True) reason = {"type": "NOPSET"} if is_pass: @@ -691,6 +688,8 @@ class Property(Facet): props[pset_name] = {k: v for k, v in pset_props.items() if k == self.baseName} if not bool(props[pset_name]): + if self.cardinality == "optional": + return PropertyResult(True) is_pass = False reason = {"type": "NOVALUE"} break @@ -918,15 +917,14 @@ class Material(Facet): return ifc_file.by_type("IfcObjectDefinition") def __call__(self, inst: ifcopenshell.entity_instance, logger: Optional[Logger] = None) -> MaterialResult: - if self.cardinality == "optional": - return MaterialResult(True) - material = ifcopenshell.util.element.get_material(inst, should_skip_usage=True) is_pass = material is not None reason = None if not is_pass: + if self.cardinality == "optional": + return MaterialResult(True) reason = {"type": "NOVALUE"} if is_pass and self.value: diff --git a/src/ifctester/test/test_facet.py b/src/ifctester/test/test_facet.py index 108c2733fd..e23300ee03 100644 --- a/src/ifctester/test/test_facet.py +++ b/src/ifctester/test/test_facet.py @@ -259,9 +259,19 @@ class TestAttribute: facet = Attribute(name="Name", cardinality="prohibited") run("A prohibited facet returns the opposite of a required facet", facet=facet, inst=element, expected=False) facet = Attribute(name="Name", cardinality="optional") - run("An optional facet always passes regardless of outcome 1/2", facet=facet, inst=element, expected=True) + run( + "An optional facet only checks requirements if there is a value to check 1/2", + facet=facet, + inst=element, + expected=True, + ) facet = Attribute(name="Rabbit", cardinality="optional") - run("An optional facet always passes regardless of outcome 2/2", facet=facet, inst=element, expected=True) + run( + "An optional facet only checks requirements if there is a value to check 2/2", + facet=facet, + inst=element, + expected=True, + ) ifc = ifcopenshell.file() facet = Attribute(name="Name") @@ -750,9 +760,19 @@ class TestClassification: facet = Classification(system="Foobar", cardinality="prohibited") run("A prohibited facet returns the opposite of a required facet", facet=facet, inst=element1, expected=False) facet = Classification(system="Foobar", cardinality="optional") - run("An optional facet always passes regardless of outcome 1/2", facet=facet, inst=element0, expected=True) + run( + "An optional facet only checks requirements if there is a value to check 1/2", + facet=facet, + inst=element0, + expected=True, + ) facet = Classification(system="Foobar", cardinality="optional") - run("An optional facet always passes regardless of outcome 2/2", facet=facet, inst=element1, expected=True) + run( + "An optional facet only checks requirements if there is a value to check 2/2", + facet=facet, + inst=element1, + expected=True, + ) facet = Classification(system="Foobar", value="1") run( @@ -887,9 +907,19 @@ class TestProperty: facet = Property(propertySet="Foo_Bar", baseName="Foo", dataType="IFCLABEL", cardinality="prohibited") run("A prohibited facet returns the opposite of a required facet", facet=facet, inst=element, expected=False) facet = Property(propertySet="Foo_Bar", baseName="Foo", dataType="IFCLABEL", cardinality="optional") - run("An optional facet always passes regardless of outcome 1/2", facet=facet, inst=element, expected=True) + run( + "An optional facet only checks requirements if there is a value to check 1/2", + facet=facet, + inst=element, + expected=True, + ) facet = Property(propertySet="Foo_Bar", baseName="Bar", dataType="IFCLABEL", cardinality="optional") - run("An optional facet always passes regardless of outcome 2/2", facet=facet, inst=element, expected=True) + run( + "An optional facet only checks requirements if there is a value to check 2/2", + facet=facet, + inst=element, + expected=True, + ) ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": ""}) facet = Property(propertySet="Foo_Bar", baseName="Foo", dataType="IFCLOGICAL") @@ -1278,9 +1308,19 @@ class TestMaterial: facet = Material(cardinality="prohibited") run("A prohibited facet returns the opposite of a required facet", facet=facet, inst=element, expected=False) facet = Material(cardinality="optional") - run("An optional facet always passes regardless of outcome 1/2", facet=facet, inst=element, expected=True) + run( + "An optional facet only checks requirements if there is a value to check 1/2", + facet=facet, + inst=element, + expected=True, + ) facet = Material(value="Foo", cardinality="optional") - run("An optional facet always passes regardless of outcome 1/2", facet=facet, inst=element, expected=True) + run( + "An optional facet only checks requirements if there is a value to check 1/2", + facet=facet, + inst=element, + expected=False, + ) ifc = ifcopenshell.file() facet = Material(value="Foo") diff --git a/src/ifctester/test/test_ids.py b/src/ifctester/test/test_ids.py index 0278ded943..6099e1bcea 100644 --- a/src/ifctester/test/test_ids.py +++ b/src/ifctester/test/test_ids.py @@ -51,7 +51,7 @@ def run( class TestIds: def test_failing_on_opening_invalid_ids_data(self): - with pytest.raises(xmlschema.validators.exceptions.XMLSchemaValidationError): + with pytest.raises(ids.IdsXmlValidationError): ids.open("""""") def test_create_an_ids_with_minimal_information(self): From ba9693519b8a3931c24894b0c9ae0b474cbef319 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sat, 11 Jan 2025 13:49:21 +0100 Subject: [PATCH 25/61] Remove mathutils import from shape_builder.py --- src/ifcopenshell-python/ifcopenshell/util/shape_builder.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py b/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py index a2595c783b..c7dd729dd3 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py +++ b/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py @@ -30,7 +30,6 @@ import ifcopenshell.util.unit from math import cos, sin, pi, tan, radians, degrees, atan, sqrt from typing import Union, Optional, Literal, Any, Sequence, TYPE_CHECKING from itertools import chain -from mathutils import Vector PRECISION = 1.0e-5 From d1ad082979e013898b1dea6eb2b224a77cc65e4b Mon Sep 17 00:00:00 2001 From: c4rlosdias Date: Thu, 2 Jan 2025 08:37:06 -0300 Subject: [PATCH 26/61] Add derived unit --- .../ifcopenshell/api/unit/__init__.py | 2 + .../ifcopenshell/api/unit/add_derived_unit.py | 80 +++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 src/ifcopenshell-python/ifcopenshell/api/unit/add_derived_unit.py diff --git a/src/ifcopenshell-python/ifcopenshell/api/unit/__init__.py b/src/ifcopenshell-python/ifcopenshell/api/unit/__init__.py index 890af4fbde..8b17d0ecab 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/unit/__init__.py +++ b/src/ifcopenshell-python/ifcopenshell/api/unit/__init__.py @@ -28,6 +28,7 @@ from .add_context_dependent_unit import add_context_dependent_unit from .add_conversion_based_unit import add_conversion_based_unit from .add_monetary_unit import add_monetary_unit from .add_si_unit import add_si_unit +from .add_derived_unit import add_derived_unit from .assign_unit import assign_unit from .edit_derived_unit import edit_derived_unit from .edit_monetary_unit import edit_monetary_unit @@ -42,6 +43,7 @@ __all__ = [ "add_conversion_based_unit", "add_monetary_unit", "add_si_unit", + "add_derived_unit", "assign_unit", "edit_derived_unit", "edit_monetary_unit", diff --git a/src/ifcopenshell-python/ifcopenshell/api/unit/add_derived_unit.py b/src/ifcopenshell-python/ifcopenshell/api/unit/add_derived_unit.py new file mode 100644 index 0000000000..90271acb4f --- /dev/null +++ b/src/ifcopenshell-python/ifcopenshell/api/unit/add_derived_unit.py @@ -0,0 +1,80 @@ +# IfcOpenShell - IFC toolkit and geometry engine +# Copyright (C) 2021 Dion Moult +# +# This file is part of IfcOpenShell. +# +# IfcOpenShell is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# IfcOpenShell is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with IfcOpenShell. If not, see . + +import ifcopenshell.util.unit +from typing import Any, Optional + + +def add_derived_unit(file: ifcopenshell.file, unit_type: str, userdefinedtype : str, attributes: dict[ifcopenshell.entity_instance, int]) -> ifcopenshell.entity_instance: + """Add a new Derive unit + + The supported types are ANGULARVELOCITYUNIT, AREADENSITYUNIT, COMPOUNDPLANEANGLEUNIT, + DYNAMICVISCOSITYUNIT, HEATFLUXDENSITYUNIT, INTEGERCOUNTRATEUNIT, ISOTHERMALMOISTURECAPACITYUNIT, + KINEMATICVISCOSITYUNIT, LINEARVELOCITYUNIT, MASSDENSITYUNIT, MASSFLOWRATEUNIT, MOISTUREDIFFUSIVITYUNIT, + MOLECULARWEIGHTUNIT, SPECIFICHEATCAPACITYUNIT, THERMALADMITTANCEUNIT, THERMALCONDUCTANCEUNIT, + THERMALRESISTANCEUNIT, THERMALTRANSMITTANCEUNIT, VAPORPERMEABILITYUNIT, VOLUMETRICFLOWRATEUNIT, + ROTATIONALFREQUENCYUNIT, TORQUEUNIT, MOMENTOFINERTIAUNIT, LINEARMOMENTUNIT, LINEARFORCEUNIT, + PLANARFORCEUNIT, MODULUSOFELASTICITYUNIT, SHEARMODULUSUNIT, LINEARSTIFFNESSUNIT, ROTATIONALSTIFFNESSUNIT, + MODULUSOFSUBGRADEREACTIONUNIT, ACCELERATIONUNIT, CURVATUREUNIT, HEATINGVALUEUNIT, IONCONCENTRATIONUNIT, + LUMINOUSINTENSITYDISTRIBUTIONUNIT, MASSPERLENGTHUNIT, MODULUSOFLINEARSUBGRADEREACTIONUNIT, + MODULUSOFROTATIONALSUBGRADEREACTIONUNIT, PHUNIT, ROTATIONALMASSUNIT, SECTIONAREAINTEGRALUNIT, + SECTIONMODULUSUNIT, SOUNDPOWERLEVELUNIT, SOUNDPOWERUNIT, SOUNDPRESSURELEVELUNIT, SOUNDPRESSUREUNIT, + TEMPERATUREGRADIENTUNIT, TEMPERATURERATEOFCHANGEUNIT, THERMALEXPANSIONCOEFFICIENTUNIT, WARPINGCONSTANTUNIT, + WARPINGMOMENTUNIT, USERDEFINED. + + In case of choosing USERDEFINED, the UserDefinedType parameter needs to be provided + + :param unit_type: A type of unit chosen from the list above. For + example, choosing THERMALCONDUCTANCEUNIT will give you a Thermal conductance. + :type unit_type: str + :param userdefinedtype: The user defined type in case of choosing USERDEFINED, or None for no + user defined type. + :type userdefinedtype: str or None + :param attributes: a dictionary of attribute names and values. + :type attributes: dict + :return: The newly created IfcDerivedUnit + :rtype: ifcopenshell.entity_instance + + Example: + + .. code:: python + + # Linear velocity in m/s + length = ifcopenshell.api.unit.add_si_unit(model, unit_type="LENGTHUNIT") + #2=IfcSIUnit(*,.LENGTHUNIT.,$,.METRE.) + + time = ifcopenshell.api.unit.add_si_unit(model, unit_type="TIMEUNIT") + #4=IfcSIUnit(*,.TIMEUNIT.,$,.SECOND.) + + linear_velocity = ifcopenshell.api.unit.add_derived_unit(model, 'LINEARVELOCITY', None, {length : 1, time : -1}) + #10=IfcDerivedUnitElement(#2, 1) + #11=IfcDerivedUnitElement(#4, -1) + #12=IfcDerivedUnit((#10,#11),.LINEARVELOCITY.,$) + + """ + settings = {"unit_type": unit_type, "attributes": attributes} + + derive_unit_elements = [] + + for named_unit in settings['attributes']: + derive_unit_elements.append(file.create_entity("IfcDerivedUnitElement", Unit=named_unit, Exponent = settings['attributes'][named_unit])) + + return file.create_entity("IfcDerivedUnit", + Elements = derive_unit_elements, + UnitType=settings["unit_type"], + UserDefinedType=userdefinedtype) From 07817ec6fcd75aef82f14c177307710d9d8bd7c9 Mon Sep 17 00:00:00 2001 From: ti Date: Fri, 20 Dec 2024 15:37:26 +0100 Subject: [PATCH 27/61] updated restriction types --- src/ifctester/ifctester/facet.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ifctester/ifctester/facet.py b/src/ifctester/ifctester/facet.py index 92104af211..fd23006b43 100644 --- a/src/ifctester/ifctester/facet.py +++ b/src/ifctester/ifctester/facet.py @@ -998,7 +998,8 @@ class Restriction: for constraint, value in self.options.items(): value = [value] if not isinstance(value, list) else value for v in value: - if constraint in ["length", "minLength", "maxLength"]: + if constraint in ["length", "minLength", "maxLength", "maxExclusive", "maxInclusive", + "minExclusive", "minInclusive", "totalDigits", "fractionDigits"]: value_dict = {"@value": v} else: value_dict = {"@value": str(v)} From 293cd83a9c701ba3876c972dcd097bc871cbb927 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radek=20Hlav=C3=A1=C4=8Dek?= Date: Mon, 21 Oct 2024 18:22:15 +0200 Subject: [PATCH 28/61] Update report.html Adding "Skipped" grey colored container for specification and requirement if no applicable element is found --- src/ifctester/ifctester/templates/report.html | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/ifctester/ifctester/templates/report.html b/src/ifctester/ifctester/templates/report.html index 7a3c582a02..71f89a3d08 100644 --- a/src/ifctester/ifctester/templates/report.html +++ b/src/ifctester/ifctester/templates/report.html @@ -107,10 +107,10 @@ {{/instructions}}
-
{{percent_checks_pass}}%
+
{{^total_checks}}Skipped{{/total_checks}}{{#total_checks}}{{percent_checks_pass}}%{{/total_checks}}

- {{#status}}Pass{{/status}}{{^status}}Fail{{/status}} + {{^total_checks}}Skipped{{/total_checks}}{{#total_checks}}{{#status}}Pass{{/status}}{{^status}}Fail{{/status}}{{/total_checks}} Checks passed: {{total_checks_pass}} / {{total_checks}} @@ -140,11 +140,17 @@

    {{#requirements}} -
  1. +
  2. {{description}} + {{#total_ckecks}} + + + +
    + {{/total_ckecks}} {{#total_pass}} From d10b327c5f0cb539b791a46aac1d75e82c78ae80 Mon Sep 17 00:00:00 2001 From: Lucas Nascimento Date: Sun, 22 Sep 2024 11:28:26 -0300 Subject: [PATCH 29/61] Initial commit, able to show structural curve action on the sample file of IFC documentation --- .gitignore | 1 + .../bonsai/bim/module/structural/__init__.py | 2 + .../bonsai/bim/module/structural/decorator.py | 108 ++++ .../bonsai/bim/module/structural/operator.py | 30 ++ .../bonsai/bim/module/structural/shader.py | 478 ++++++++++++++++++ src/bonsai/bonsai/bim/module/structural/ui.py | 24 + 6 files changed, 643 insertions(+) create mode 100644 src/bonsai/bonsai/bim/module/structural/decorator.py create mode 100644 src/bonsai/bonsai/bim/module/structural/shader.py diff --git a/.gitignore b/.gitignore index c219a65be7..240190a857 100644 --- a/.gitignore +++ b/.gitignore @@ -98,3 +98,4 @@ src/ifcopenshell-python/ifcopenshell/ifcopenshell_wrapper.py # Brickschema src/bonsai/bonsai/bim/schema/Brick.ttl +bonsaiDecoratorForLoads.code-workspace diff --git a/src/bonsai/bonsai/bim/module/structural/__init__.py b/src/bonsai/bonsai/bim/module/structural/__init__.py index 22bd3c1f1f..db72ad497c 100644 --- a/src/bonsai/bonsai/bim/module/structural/__init__.py +++ b/src/bonsai/bonsai/bim/module/structural/__init__.py @@ -20,6 +20,7 @@ import bpy from . import ui, prop, operator, workspace classes = ( + operator.ShowLoads, operator.LoadStructuralAnalysisModels, operator.DisableStructuralAnalysisModelEditingUI, operator.AddStructuralAnalysisModel, @@ -83,6 +84,7 @@ classes = ( ui.BIM_PT_connected_structural_members, ui.BIM_UL_structural_analysis_models, ui.BIM_UL_structural_activities, + ui.BIM_PT_show_structural_activities, ui.BIM_PT_structural_load_cases, ui.BIM_UL_structural_loads, ui.BIM_PT_structural_loads, diff --git a/src/bonsai/bonsai/bim/module/structural/decorator.py b/src/bonsai/bonsai/bim/module/structural/decorator.py new file mode 100644 index 0000000000..eb15b819ac --- /dev/null +++ b/src/bonsai/bonsai/bim/module/structural/decorator.py @@ -0,0 +1,108 @@ +from math import pi +from mathutils import Vector +import bpy +import gpu +import blf +from bpy.types import SpaceView3D +from gpu_extras.batch import batch_for_shader +from bonsai.bim.module.structural.shader import ShaderInfo + +class LoadsDecorator: + is_installed = False + handlers = [] + linear_load_shader = None + text_info = [] + + @classmethod + def install(cls, context): + if cls.is_installed: + cls.uninstall() + handler = cls() + cls.handlers.append( + SpaceView3D.draw_handler_add(handler.draw_load_values, ((context,)), "WINDOW", "POST_PIXEL") + ) + #self.handlers.append(SpaceView3D.draw_handler_add(handler.draw_extra_info, (context,), "WINDOW", "POST_PIXEL")) + #self.handlers.append( + # SpaceView3D.draw_handler_add(handler.draw_curve_loads, (context,), "WINDOW", "POST_VIEW") + #) + cls.handlers.append(SpaceView3D.draw_handler_add(handler, (), "WINDOW", "POST_VIEW")) + cls.linear_load_shader = ShaderInfo("DistributedLoad") + cls.is_installed = True + + @classmethod + def uninstall(cls): + for handler in cls.handlers: + try: + SpaceView3D.draw_handler_remove(handler, "WINDOW") + except ValueError: + pass + cls.is_installed = False + + @classmethod + def update(cls, context): + cls.linear_load_shader.update() + cls.text_info += cls.linear_load_shader.text_info + + def __call__(self): + # set open gl configurations + original_blend = gpu.state.blend_get() + gpu.state.blend_set('ALPHA') + original_depth_mask = gpu.state.depth_mask_get() + #gpu.state.depth_mask_set(True) + original_depth_test = gpu.state.depth_test_get() + gpu.state.depth_test_set('ALWAYS') + + self.draw_batch("DistributedLoad") + + # restore opengl configurations + gpu.state.blend_set(original_blend) + gpu.state.depth_mask_set(original_depth_mask) + gpu.state.depth_test_set(original_depth_test) + + def draw_batch(self,shader_type: str): + """ param: shader_type: type of shader in ["DistributedLoad", "PointLoad"]""" + + if shader_type == "DistributedLoad" and not self.linear_load_shader.is_empty: + shader_info = self.linear_load_shader + shader = shader_info.shader + args = shader_info.args + indices = shader_info.indices + batch = batch_for_shader(shader, 'TRIS', args, indices=indices) + matrix = bpy.context.region_data.perspective_matrix + shader.uniform_float("viewProjectionMatrix", matrix) + shader.uniform_float("spacing", 0.2) # make it customizable + shader.uniform_float("maxload", 200) # make it customizable + batch.draw(shader) + + def draw_load_values(self, context): + for info in self.text_info: + text_position = location_3d_to_region_2d(info["position"],info["normal"],context) + if text_position is not None: + font_id = 0 # , need to find out how best to get this. + # draw some text + blf.position(font_id, text_position[0], text_position[1], 0) + blf.size(font_id, 20.0) + blf.color(font_id, 0.9, 0.9, 0.9, 1.0) + blf.draw(font_id, info["text"]) + +def location_3d_to_region_2d(coord, normal, context): + """Convert from 3D space to 2D screen space""" + rv3d = context.region_data + perspective = rv3d.view_perspective + view_matrix = rv3d.view_matrix + point_view_space = view_matrix @ coord + x,y,z = view_matrix.to_3x3() + angle = abs(0.5*pi-normal.angle(z)) + #if small view angle betwen the load and viewport + if angle<0.05: + return None + + if perspective == 'ORTHO' or -20 < point_view_space.z < 0: + prj = rv3d.perspective_matrix @ Vector((coord[0], coord[1], coord[2], 1.0)) + width_half = context.region.width / 2.0 + height_half = context.region.height / 2.0 + co = Vector((width_half + width_half * (prj.x / prj.w), + height_half + height_half * (prj.y / prj.w), + )) + return co + return None diff --git a/src/bonsai/bonsai/bim/module/structural/operator.py b/src/bonsai/bonsai/bim/module/structural/operator.py index cf7a271797..bc69b31a4e 100644 --- a/src/bonsai/bonsai/bim/module/structural/operator.py +++ b/src/bonsai/bonsai/bim/module/structural/operator.py @@ -27,6 +27,36 @@ import bonsai.tool as tool from math import degrees from mathutils import Vector, Matrix from bonsai.bim.ifc import IfcStore +from bonsai.bim.module.structural.decorator import LoadsDecorator + +class ShowLoads(bpy.types.Operator): + """Draw decorations to show strucutural actions in 3d view""" + bl_idname = "bim.show_loads" + bl_label = "Show loads in 3D View" + + def modal(self, context, event): + if event.type == 'F5': + LoadsDecorator.update(context) + for area in context.screen.areas: + if area.type == 'VIEW_3D': + area.tag_redraw() + if event.type == 'ESC': + LoadsDecorator.uninstall() + for area in context.screen.areas: + if area.type == 'VIEW_3D': + area.tag_redraw() + return {'FINISHED'} + return {'PASS_THROUGH'} + + def invoke(self, context, event): + LoadsDecorator.install(context) + LoadsDecorator.update(context) + context.window_manager.modal_handler_add(self) + for area in context.screen.areas: + if area.type == 'VIEW_3D': + area.tag_redraw() + + return {'RUNNING_MODAL'} class AddStructuralMemberConnection(bpy.types.Operator, tool.Ifc.Operator): diff --git a/src/bonsai/bonsai/bim/module/structural/shader.py b/src/bonsai/bonsai/bim/module/structural/shader.py new file mode 100644 index 0000000000..ab465c8b89 --- /dev/null +++ b/src/bonsai/bonsai/bim/module/structural/shader.py @@ -0,0 +1,478 @@ +import bpy +import gpu +import numpy as np +from math import sin +from mathutils import Vector, Matrix +import ifcopenshell +import ifcopenshell.api +import ifcopenshell.util.attribute +import bonsai.tool as tool +from bonsai.bim.ifc import IfcStore + + +class ShaderInfo: + def __init__(self,shader_type: str): + self.is_empty = True + self.shader = None + self.shader_type = shader_type + self.args = {} + self.indices = [] + self.text_info = [] + + def update(self): + self.get_shader() + self.get_args_and_indices() + if len(self.args["position"]): + self.is_empty = False + + def get_shader(self): + """ param: shader_type: type of shader in ["DistributedLoad", "PointLoad"] + return: shader""" + if self.shader_type == "DistributedLoad": + vert_out = gpu.types.GPUStageInterfaceInfo("my_interface") + vert_out.smooth('VEC3', "colour") + vert_out.smooth('VEC3', "forces") + vert_out.smooth('VEC2', "co") + + shader_info = gpu.types.GPUShaderCreateInfo() + shader_info.push_constant('MAT4', "viewProjectionMatrix") + shader_info.push_constant('FLOAT', "spacing") + shader_info.push_constant('FLOAT', "maxload") + + shader_info.vertex_in(0, 'VEC3', "position") + shader_info.vertex_in(1, 'VEC3', "color") + shader_info.vertex_in(2, 'VEC3', "sin_quad_lin_forces") + shader_info.vertex_in(3, 'VEC2', "uv_coord") + + shader_info.vertex_out(vert_out) + shader_info.fragment_out(0, 'VEC4', "FragColor") + + shader_info.vertex_source( + "void main()" + "{" + " colour = color;" + " gl_Position = viewProjectionMatrix * vec4(position, 1.0f);" + " co = uv_coord;" + " forces = sin_quad_lin_forces;" + " gl_Position = viewProjectionMatrix * vec4(position, 1.0f);" + "}" + ) + + + shader_info.fragment_source( + "void main()" + "{" + "float x = co.x;" + "float y = co.y;" + "float abs_y = abs(y);" + + "float a = abs(mod(x,spacing)-0.5*spacing)*5.0;" + "float b = step(a,abs_y)*(step(abs_y,1.2*spacing));" + "float c = step(0.8*spacing,mod(x+0.4*spacing,spacing))*(step(1.2*spacing,abs_y));" + + "float sinvalue = forces.x;" + "float quadraticvalue = forces.y;" + "float linearvalue = forces.z;" + "float f = (sin(x*3.1416)*sinvalue" + "+(-4.*x*x+4.*x)*quadraticvalue" + "+linearvalue)/maxload;" + "float mask = step(0.,y)*step(y,f)+step(y,0.)*step(f,y);" + + "float top = step(abs(y-f),0.2*1.2*spacing);" + "float d = clamp(0.2*(1-3*(abs_y*y))+top+b+c,0.0,0.5)*mask;" + + "gl_FragColor = vec4(colour,d);" + "}" + ) + + self.shader = gpu.shader.create_from_info(shader_info) + del vert_out + del shader_info + + def get_args_and_indices(self): #for now it only works for distributed loads + coords = [] + indices = [] + load_info = [] + coords_2d = [] + color = [] + text_info = [] + + list_of_curve_members = tool.Ifc.get().by_type("IfcStructuralCurveMember") + for member in list_of_curve_members: + activity_list = [getattr(a, 'RelatedStructuralActivity', None) for a in getattr(member, 'AssignedStructuralActivity', None) + if getattr(a, 'RelatedStructuralActivity', None).is_a() == 'IfcStructuralCurveAction'] + if len(activity_list) == 0: + continue + # member is a structural curve member + # get Axis attribute from member -> (IFCDIRECTION) + # get Representation attribute from member -> (IFCPRODUCTDEFINITIONSHAPE) + # get Representations attribute from Representation -> (IFCTOPOLOGYREPRESENTATION) + # get Items attribute from Representations -> (IFCEDGE) + # get EdgeStart attribute from Items -> (IFCVERTEX) + # get EdgeEnd attribure from Items -> (IFCVERTEX) + # using blender just get the global coordinates of the first and second vertex in the mesh + + blender_object = IfcStore.get_element(getattr(member, 'GlobalId', None)) + if blender_object.type == 'MESH': + start_co = blender_object.matrix_world @ blender_object.data.vertices[0].co + end_co = blender_object.matrix_world @ blender_object.data.vertices[1].co + x_axis = Vector(end_co-start_co).normalized() + direction = getattr(member, 'Axis', None) + #local coordinates + z_axis = Vector(getattr(direction, 'DirectionRatios', None)).normalized() + y_axis = z_axis.cross(x_axis).normalized() + z_axis = x_axis.cross(y_axis).normalized() + global_to_local = Matrix(((x_axis.x,y_axis.x,z_axis.x,0), + (x_axis.y,y_axis.y,z_axis.y,0), + (x_axis.z,y_axis.z,z_axis.z,0), + (0,0,0,1))) + + #get shader args for each direction + reference_frame = 'LOCAL_COORDS' #make it a scene property so it can be changed in a panel + is_global = reference_frame == 'GLOBAL_COORDS' + x_match = x_axis == Vector((1,0,0)) + y_match = y_axis == Vector((0,1,0)) + z_match = z_axis == Vector((0,0,1)) + direction_dict = { + "fx": Vector((1,0,0)) if is_global and not x_match else Vector((0,1,1)) if is_global else y_axis+z_axis, + "fy": Vector((0,1,0)) if is_global and not y_match else Vector((1,0,1)) if is_global else y_axis, + "fz": Vector((0,0,1)) if is_global and not z_match else Vector((1,1,0)) if is_global else z_axis, + "mx": Vector((1,0,0)) if is_global and not x_match else Vector((0,1,1)) if is_global else y_axis+z_axis, + "my": Vector((0,1,0)) if is_global and not y_match else Vector((1,0,1)) if is_global else y_axis, + "mz": Vector((0,0,1)) if is_global and not z_match else Vector((1,1,0)) if is_global else z_axis, + } + xyzdict = get_loads_per_direction(activity_list,global_to_local) + keys = ["fx","fy","fz","mx","my","mz"] + maxforce = 200 #should be the maximum value expected for the loads + memberlength = Vector(end_co-start_co).length + for key in keys: + polyline = xyzdict[key]["polyline"] + sinus = xyzdict[key]["sinus"] + quadratic = xyzdict[key]["quadratic"] + constant = xyzdict[key]["constant"] + direction = direction_dict[key] #depends on the key and on the frame of reference + color_axis = (0,0,1) + if 'x' in key: + color_axis = (1,0,0) + if 'y' in key: + color_axis = (0,1,0) + addindex = len(coords) + counter = 0 + for i in range(len(polyline)-1): + current = Vector(polyline[i]+[0]) + nextitem = Vector(polyline[i+1]+[0]) + + if current[1] != 0 or nextitem[1] != 0: #if there is load in the z direction + negative = -direction + start_co + x_axis*current.x + positive = direction + start_co + x_axis*current.x + coords.append(negative) + coords_2d.append((current.x, 1.0)) + load_info.append((sinus, quadratic, current.y + constant)) + color.append(color_axis) + #info to render load value + x = current.length/memberlength + func = sin(x*3.1416)*sinus + (-4.*x*x+4.*x)*quadratic+constant+current.y + if func: + text_info.append( + {"position": -direction*func/maxforce + start_co + x_axis*current.x, + "normal": direction.cross(x_axis).normalized(), "text": f'{func:.2f} '} + ) + coords.append(positive) + coords_2d.append((current[0],-1.0)) + load_info.append((sinus, quadratic, current.y + constant)) + color.append(color_axis) + + indices.append((0 + counter + addindex, + 1 + counter + addindex, + 2 + counter + addindex)) + indices.append((3 + counter + addindex, + 1 + counter + addindex, + 2 + counter + addindex)) + if i == len(polyline)-2: + negative = -direction + start_co + x_axis*nextitem.x + positive = direction + start_co + x_axis*nextitem.x + coords.append(negative) + coords_2d.append((nextitem.x, 1.0)) + load_info.append((sinus, quadratic, nextitem.y + constant)) + color.append(color_axis) + #info to render load value + x = nextitem.length/memberlength + func = sin(x*3.1416)*sinus + (-4.*x*x+4.*x)*quadratic+constant+nextitem.y + if func: + text_info.append( + {"position": -direction*func/maxforce + start_co + x_axis*nextitem.x, + "normal": direction.cross(x_axis).normalized(), "text": f'{func:.2f} '} + ) + + coords.append(positive) + coords_2d.append((nextitem.x,-1.0)) + load_info.append((sinus, quadratic, nextitem.y + constant)) + color.append(color_axis) + + counter += 2 + self.args = {"position": coords,"color": color, + "sin_quad_lin_forces": load_info,"uv_coord": coords_2d} + self.indices = indices + self.text_info = text_info + + +def get_loads_per_direction(activity_list,global_to_local): + """ returns a dict with values for applied loads in each direction + return = { + "fx": values_in_this_direction + "fy": values_in_this_direction + "fz": values_in_this_direction + "mx": values_in_this_direction + "my": values_in_this_direction + "mz": values_in_this_direction + } + values_in_this_direction = { + "constant": float, + "quadratic": float, + "sinus": float, + "polyline": list[(position: float, load: float),...] + } + """ + loads_dict = get_loads_dict(activity_list,global_to_local) + const = loads_dict["constant force"] + quad = loads_dict["quadratic force"] + sinus = loads_dict["sinus force"] + loads = loads_dict["load configuration"] + unique_list = getuniquepositionlist(loads) + final_list = [] + for pos in unique_list: + value = get_before_and_after(pos,loads) + if value["before"] == value["after"]: + final_list.append([pos]+value["before"]) + else: + final_list.append([pos]+value["before"]) + final_list.append([pos]+value["after"]) + if len(final_list)>2: + del final_list[0] + del final_list[-1] + array = np.array(final_list) #7xn -> ["pos","fx","fy","fz","mx","my","mz"] + keys = ["fx","fy","fz","mx","my","mz"] + polyline = { + "fx": [], + "fy": [], + "fz": [], + "mx": [], + "my": [], + "mz": [], + } + return_value = { + "fx": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, + "fy": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, + "fz": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, + "mx": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, + "my": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, + "mz": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, + } + for component, key in enumerate(keys): + if( sinus[component] or quad[component] or const[component] or + any(item != 0 for item in array[:,component+1])): + for currentitem in final_list: + polyline[key].append([currentitem[0],currentitem[component+1]]) + inner_dict = return_value[key] + inner_dict["constant"] = const[component] + inner_dict["quadratic"] = quad[component] + inner_dict["sinus"] = sinus[component] + inner_dict["polyline"] = polyline[key] + return_value[key] = inner_dict + + return return_value + + +def getuniquepositionlist(load_config_list): + """return an ordereded list of unique locations based on the load configuration list + ex: load_config_list = [[{"pos":1.0,...},{"pos":3.0,...}], + [{"pos":2.0,...},{"pos":3.0,...}], + [{"pos":1.5,...},{"pos":2.5,...}]] + return = [1.0, 1.5, 2.0, 2.5, 3.0] + """ + unique = [] + for config in load_config_list: + for info in config: + if info["pos"] in unique: + continue + unique.append(info["pos"]) + unique.sort() + return unique + +def interp1d(l1,l2, pos): + """ 1d linear interpolation for the vector components""" + fac = (l2[1]-l1[1])/(l2[0]-l1[0]) + v = l1[1] + fac*(pos-l1[0]) + return v + +def interpolate(pos,loadinfo,start,end,key): + """ interpolate the result vectors between load poits""" + result = Vector((0,0,0)) + for i in range(3): + value1 = [loadinfo[start]["pos"], loadinfo[start][key][i]] #[position, force_component] + value2= [loadinfo[end]["pos"], loadinfo[end][key][i]] # [position, force_component] + result[i] = interp1d(value1,value2, pos) # interpolated [position, force_component] + return result + +def get_before_and_after(pos,load_config_list): + """ get total values for forces and moments with polilyne distribution + before and after the position + ex: load_config_list = [[{"pos":1.0,...,"forces":(1,0,0),...},{"pos":3.0,...,"forces":(3,0,0),...}], + [{"pos":2.0,...,"forces":(1,0,0),...},{"pos":3.0,...,"forces":(1,0,0),...}], + [{"pos":1.5,...,"forces":(1,0,0),...},{"pos":2.5,...,"forces":(1,0,0),...}]] + pos = 2.0 + return = { + "before": (3,0,0,0,0,0), ->(fx, fy, fz, mx, my, mz) + " after": (4,0,0,0,0,0) ->(fx, fy, fz, mx, my, mz) + } + """ + force_before = Vector((0,0,0)) + force_after = Vector((0,0,0)) + moment_before = Vector((0,0,0)) + moment_after = Vector((0,0,0)) + + for config in load_config_list: + if pos < config[0]["pos"] or pos > config[-1]["pos"]: + continue + start = 0 + end = len(config)-1 + while end-start > 0: + if pos < config[start]["pos"] or pos > config[end]["pos"]: + break + if config[start]["pos"] == pos: + if config[start]["descr"] in ['start','middle']: + force_after += config[start]["forces"] + moment_after += config[start]["moments"] + elif config[start]["descr"] in ['end','middle']: + force_before += config[start]["forces"] + moment_before += config[start]["moments"] + + elif config[end]["pos"] == pos: + if config[end]["descr"] in ['start','middle']: + force_after += config[end]["forces"] + moment_after += config[end]["moments"] + elif config[end]["descr"] in ['end','middle']: + force_before += config[end]["forces"] + moment_before += config[end]["moments"] + + elif end-start == 1: + force_before += interpolate(pos,config,start,end,"forces") + force_after += interpolate(pos,config,start,end,"forces") + moment_before += interpolate(pos,config,start,end,"moments") + moment_after += interpolate(pos,config,start,end,"moments") + start += 1 + end -=1 + return_value = { + "before": [force_before.x,force_before.y,force_before.z, + moment_before.x,moment_before.y,moment_before.z], + "after": [force_after.x, force_after.y, force_after.z, + moment_after.x, moment_after.y, moment_after.z] + } + return return_value + +def get_loads_dict(activity_list,global_to_local): + """ + get load list + activity_list: list of IfcStructuralCurveAction or IfcStructuralCurveReaction + applied in the structural curve member + global_to_local: transformation matrix from global coordinates to local coordinetes + return: dict{ + "constant force": (fx,fy,fz,mx,my,mz), -> sum of linear loads applied with + constant distribution + "quadratic force": (fx,fy,fz,mx,my,mz), -> sum of linear loads applied with + quadratic distribution + "sinus force": (fx,fy,fz,mx,my,mz), -> sum of linear loads applied with + sinus distribution + "load configuration": list -> list of load configurations for linear + and polyline distributions of linear loads + } + description of "load configuration": + list[ -> one item (list)for each IfcStructuralCurveAction applied in the member + with IfcStructuralLoadConfiguration as the applied load + list[ -> one item (dict) for each item found in the + Locations attribute of IfcLoadConfiguration + dict{ + "pos": float, -> local position along curve length + "descr": string, -> describe if the item is at the star, middle or end of the list + "forces": Vector, -> linear force applied at that point + "moments": Vector -> linear moment applied at that point + } + ] + ] + """ + constant_force = Vector((0,0,0)) + constant_moment = Vector((0,0,0)) + quadratic_force = Vector((0,0,0)) + quadratic_moment = Vector((0,0,0)) + sinus_force = Vector((0,0,0)) + sinus_moment = Vector((0,0,0)) + load_configurations = [] + + unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get(),"LENGTHUNIT") + + def get_force_vector(load,transform_matrix): + x = 0 if getattr(load, 'LinearForceX', 0) is None else getattr(load, 'LinearForceX', 0) + y = 0 if getattr(load, 'LinearForceY', 0) is None else getattr(load, 'LinearForceY', 0) + z = 0 if getattr(load, 'LinearForceZ', 0) is None else getattr(load, 'LinearForceZ', 0) + return transform_matrix @ Vector((x,y,z)) + + def get_moment_vector(load,transform_matrix): + x = 0 if getattr(load, 'LinearMomentX', 0) is None else getattr(load, 'LinearMomentX', 0) + y = 0 if getattr(load, 'LinearMomentY', 0) is None else getattr(load, 'LinearMomentY', 0) + z = 0 if getattr(load, 'LinearMomentZ', 0) is None else getattr(load, 'LinearMomentZ', 0) + return transform_matrix @ Vector((x,y,z)) + + for activity in activity_list: + load = activity.AppliedLoad + global_or_local = activity.GlobalOrLocal + reference_frame = 'LOCAL_COORDS' #make it a scene property so it can be changed in a panel + transform_matrix = Matrix() + if reference_frame == 'LOCAL_COORDS' and global_or_local != reference_frame: + transform_matrix = global_to_local + elif reference_frame == 'GLOBAL_COORDS' and global_or_local != reference_frame: + transform_matrix = global_to_local.invert() + #values for linear loads + if load.is_a('IfcStructuralLoadConfiguration'): + locations = getattr(load, 'Locations', []) + values = [l for l in getattr(load, 'Values', None) + if l.is_a() == "IfcStructuralLoadLinearForce" + ] + config_list = [] + for i,l in enumerate(values): + forcevalues = get_force_vector(l,transform_matrix) + momentvalues = get_moment_vector(l,transform_matrix) + if i == 0: + descr = 'start' + elif i == len(values)-1: + descr = 'end' + else: + descr = 'middle' + config_list.append( + {"pos": locations[i][0]*unit_scale, + "descr": descr, + "forces":forcevalues, + "moments":momentvalues} + ) + load_configurations.append(config_list) + else: + forcevalues = get_force_vector(load,transform_matrix) + momentvalues = get_moment_vector(load,transform_matrix) + if 'CONST' == getattr(activity, 'PredefinedType', None): + constant_force += forcevalues + constant_moment += momentvalues + elif 'PARABOLA' == getattr(activity, 'PredefinedType', None): + quadratic_force += forcevalues + quadratic_moment += momentvalues + elif 'SINUS' == getattr(activity, 'PredefinedType', None): + sinus_force += forcevalues + sinus_moment += momentvalues + return_value = { + "constant force": [constant_force.x,constant_force.y,constant_force.z, + constant_moment.x,constant_moment.y,constant_moment.z], + "quadratic force": [quadratic_force.x,quadratic_force.y,quadratic_force.z, + quadratic_moment.x,quadratic_moment.y,quadratic_moment.z], + "sinus force": [sinus_force.x,sinus_force.y,sinus_force.z, + sinus_moment.x,sinus_moment.y,sinus_moment.z], + "load configuration": load_configurations + } + return return_value diff --git a/src/bonsai/bonsai/bim/module/structural/ui.py b/src/bonsai/bonsai/bim/module/structural/ui.py index 0dbcf84d62..5374f898b9 100644 --- a/src/bonsai/bonsai/bim/module/structural/ui.py +++ b/src/bonsai/bonsai/bim/module/structural/ui.py @@ -444,6 +444,30 @@ class BIM_UL_structural_activities(UIList): row.label(text=item.name) row.label(text=item.applied_load_class) +class BIM_PT_show_structural_activities(Panel): + bl_label = "Show Loads" + bl_idname = "BIM_PT_show_structural_activities" + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "scene" + bl_parent_id = "BIM_PT_tab_structural" + + @classmethod + def poll(cls, context): + file = IfcStore.get_file() + return file and hasattr(file, "schema") and file.schema != "IFC2X3" + + def draw(self, context): + + self.props = context.scene.BIMStructuralProperties + + row = self.layout.row(align=True) + row.operator( + "bim.show_loads", + text="Show loads" , + icon="FILTER", + ) + class BIM_PT_structural_loads(Panel): bl_label = "Structural Loads" From 53a2b87c9764a7cc7a9c9b251194d9ab6b554c03 Mon Sep 17 00:00:00 2001 From: Lucas Nascimento Date: Tue, 24 Sep 2024 20:47:32 -0300 Subject: [PATCH 30/61] updates to shader class --- .../bonsai/bim/module/structural/shader.py | 159 +++++++++++------- 1 file changed, 98 insertions(+), 61 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/structural/shader.py b/src/bonsai/bonsai/bim/module/structural/shader.py index ab465c8b89..56897b2934 100644 --- a/src/bonsai/bonsai/bim/module/structural/shader.py +++ b/src/bonsai/bonsai/bim/module/structural/shader.py @@ -18,11 +18,12 @@ class ShaderInfo: self.args = {} self.indices = [] self.text_info = [] + self.info = [] def update(self): - self.get_shader() - self.get_args_and_indices() - if len(self.args["position"]): + self.info = [] + self.get_linear_loads() + if len(self.info): self.is_empty = False def get_shader(self): @@ -30,19 +31,18 @@ class ShaderInfo: return: shader""" if self.shader_type == "DistributedLoad": vert_out = gpu.types.GPUStageInterfaceInfo("my_interface") - vert_out.smooth('VEC3', "colour") vert_out.smooth('VEC3', "forces") - vert_out.smooth('VEC2', "co") + vert_out.smooth('VEC3', "co") shader_info = gpu.types.GPUShaderCreateInfo() shader_info.push_constant('MAT4', "viewProjectionMatrix") + shader_info.push_constant('VEC4', "color") shader_info.push_constant('FLOAT', "spacing") shader_info.push_constant('FLOAT', "maxload") shader_info.vertex_in(0, 'VEC3', "position") - shader_info.vertex_in(1, 'VEC3', "color") - shader_info.vertex_in(2, 'VEC3', "sin_quad_lin_forces") - shader_info.vertex_in(3, 'VEC2', "uv_coord") + shader_info.vertex_in(1, 'VEC3', "sin_quad_lin_forces") + shader_info.vertex_in(2, 'VEC3', "coord") shader_info.vertex_out(vert_out) shader_info.fragment_out(0, 'VEC4', "FragColor") @@ -50,9 +50,8 @@ class ShaderInfo: shader_info.vertex_source( "void main()" "{" - " colour = color;" " gl_Position = viewProjectionMatrix * vec4(position, 1.0f);" - " co = uv_coord;" + " co = coord;" " forces = sin_quad_lin_forces;" " gl_Position = viewProjectionMatrix * vec4(position, 1.0f);" "}" @@ -73,34 +72,39 @@ class ShaderInfo: "float sinvalue = forces.x;" "float quadraticvalue = forces.y;" "float linearvalue = forces.z;" + "x = co.x/co.z;" "float f = (sin(x*3.1416)*sinvalue" "+(-4.*x*x+4.*x)*quadraticvalue" "+linearvalue)/maxload;" "float mask = step(0.,y)*step(y,f)+step(y,0.)*step(f,y);" "float top = step(abs(y-f),0.2*1.2*spacing);" - "float d = clamp(0.2*(1-3*(abs_y*y))+top+b+c,0.0,0.5)*mask;" + "float d = clamp(0.1+top+b+c,0.0,0.5)*mask;" - "gl_FragColor = vec4(colour,d);" + "FragColor = vec4(color.xyz,d*color.w);" "}" ) - self.shader = gpu.shader.create_from_info(shader_info) + shader = gpu.shader.create_from_info(shader_info) del vert_out del shader_info + return shader - def get_args_and_indices(self): #for now it only works for distributed loads + + def get_linear_loads(self): #for now it only works for distributed loads coords = [] indices = [] load_info = [] - coords_2d = [] + coords_for_shader = [] color = [] text_info = [] + uniforms = [] + info = [] list_of_curve_members = tool.Ifc.get().by_type("IfcStructuralCurveMember") for member in list_of_curve_members: activity_list = [getattr(a, 'RelatedStructuralActivity', None) for a in getattr(member, 'AssignedStructuralActivity', None) - if getattr(a, 'RelatedStructuralActivity', None).is_a() == 'IfcStructuralCurveAction'] + if getattr(a, 'RelatedStructuralActivity', None).is_a() in ['IfcStructuralCurveAction','IfcStructuralLinearAction']] if len(activity_list) == 0: continue # member is a structural curve member @@ -117,9 +121,9 @@ class ShaderInfo: start_co = blender_object.matrix_world @ blender_object.data.vertices[0].co end_co = blender_object.matrix_world @ blender_object.data.vertices[1].co x_axis = Vector(end_co-start_co).normalized() - direction = getattr(member, 'Axis', None) + z_direction = getattr(member, 'Axis') #local coordinates - z_axis = Vector(getattr(direction, 'DirectionRatios', None)).normalized() + z_axis = Vector(getattr(z_direction, 'DirectionRatios', None)).normalized() y_axis = z_axis.cross(x_axis).normalized() z_axis = x_axis.cross(y_axis).normalized() global_to_local = Matrix(((x_axis.x,y_axis.x,z_axis.x,0), @@ -128,57 +132,60 @@ class ShaderInfo: (0,0,0,1))) #get shader args for each direction - reference_frame = 'LOCAL_COORDS' #make it a scene property so it can be changed in a panel - is_global = reference_frame == 'GLOBAL_COORDS' - x_match = x_axis == Vector((1,0,0)) - y_match = y_axis == Vector((0,1,0)) - z_match = z_axis == Vector((0,0,1)) + reference_frame = 'GLOBAL_COORDS' #make it a scene property so it can be changed in a panel + is_local = reference_frame == 'LOCAL_COORDS' + x_match = abs(Vector((1,0,0)).dot(x_axis)) > 0.99 + y_match = abs(Vector((0,1,0)).dot(x_axis)) > 0.99 + z_match = abs(Vector((0,0,1)).dot(x_axis)) > 0.99 direction_dict = { - "fx": Vector((1,0,0)) if is_global and not x_match else Vector((0,1,1)) if is_global else y_axis+z_axis, - "fy": Vector((0,1,0)) if is_global and not y_match else Vector((1,0,1)) if is_global else y_axis, - "fz": Vector((0,0,1)) if is_global and not z_match else Vector((1,1,0)) if is_global else z_axis, - "mx": Vector((1,0,0)) if is_global and not x_match else Vector((0,1,1)) if is_global else y_axis+z_axis, - "my": Vector((0,1,0)) if is_global and not y_match else Vector((1,0,1)) if is_global else y_axis, - "mz": Vector((0,0,1)) if is_global and not z_match else Vector((1,1,0)) if is_global else z_axis, + "fx": y_axis+z_axis if is_local else Vector((1,0,0)) if not x_match else Vector((0,1,1)), + "fy": y_axis if is_local else Vector((0,1,0)) if not y_match else Vector((1,0,1)), + "fz": z_axis if is_local else Vector((0,0,1)) if not z_match else Vector((1,1,0)), + "mx": z_axis-y_axis if is_local or x_match else Vector((1,0,0)).cross(x_axis), + "my": z_axis if is_local else Vector((-1,0,1)) if y_match else Vector((0,1,0)).cross(x_axis).normalized(), + "mz": y_axis if is_local else Vector((-1,1,0)) if z_match else Vector((0,0,1)).cross(x_axis).normalized() } - xyzdict = get_loads_per_direction(activity_list,global_to_local) + shader = self.get_shader() + member_length = Vector(end_co-start_co).length + loads_dict, maxforce = get_loads_per_direction(activity_list,global_to_local,member_length) keys = ["fx","fy","fz","mx","my","mz"] - maxforce = 200 #should be the maximum value expected for the loads - memberlength = Vector(end_co-start_co).length + for key in keys: - polyline = xyzdict[key]["polyline"] - sinus = xyzdict[key]["sinus"] - quadratic = xyzdict[key]["quadratic"] - constant = xyzdict[key]["constant"] + polyline = loads_dict[key]["polyline"] + sinus = loads_dict[key]["sinus"] + quadratic = loads_dict[key]["quadratic"] + constant = loads_dict[key]["constant"] direction = direction_dict[key] #depends on the key and on the frame of reference - color_axis = (0,0,1) + color_axis = (0,0,1,1) if 'x' in key: - color_axis = (1,0,0) + color_axis = (1,0,0,1) if 'y' in key: - color_axis = (0,1,0) + color_axis = (0,1,0,1) + addindex = len(coords) counter = 0 for i in range(len(polyline)-1): current = Vector(polyline[i]+[0]) nextitem = Vector(polyline[i+1]+[0]) - if current[1] != 0 or nextitem[1] != 0: #if there is load in the z direction + if any([current.y, nextitem.y,constant,quadratic,sinus]): #if there is load in the z direction negative = -direction + start_co + x_axis*current.x positive = direction + start_co + x_axis*current.x coords.append(negative) - coords_2d.append((current.x, 1.0)) + coords_for_shader.append((current.x, 1.0,member_length)) load_info.append((sinus, quadratic, current.y + constant)) color.append(color_axis) #info to render load value - x = current.length/memberlength + x = current.x/member_length func = sin(x*3.1416)*sinus + (-4.*x*x+4.*x)*quadratic+constant+current.y if func: text_info.append( {"position": -direction*func/maxforce + start_co + x_axis*current.x, "normal": direction.cross(x_axis).normalized(), "text": f'{func:.2f} '} ) + maxforce = max(maxforce,abs(func)) coords.append(positive) - coords_2d.append((current[0],-1.0)) + coords_for_shader.append((current[0],-1.0,member_length)) load_info.append((sinus, quadratic, current.y + constant)) color.append(color_axis) @@ -186,37 +193,50 @@ class ShaderInfo: 1 + counter + addindex, 2 + counter + addindex)) indices.append((3 + counter + addindex, - 1 + counter + addindex, - 2 + counter + addindex)) + 2 + counter + addindex, + 1 + counter + addindex)) if i == len(polyline)-2: negative = -direction + start_co + x_axis*nextitem.x positive = direction + start_co + x_axis*nextitem.x coords.append(negative) - coords_2d.append((nextitem.x, 1.0)) + coords_for_shader.append((nextitem.x, 1.0,member_length)) load_info.append((sinus, quadratic, nextitem.y + constant)) color.append(color_axis) #info to render load value - x = nextitem.length/memberlength + x = nextitem.x/member_length func = sin(x*3.1416)*sinus + (-4.*x*x+4.*x)*quadratic+constant+nextitem.y if func: text_info.append( {"position": -direction*func/maxforce + start_co + x_axis*nextitem.x, "normal": direction.cross(x_axis).normalized(), "text": f'{func:.2f} '} ) - + maxforce = max(maxforce,abs(func)) coords.append(positive) - coords_2d.append((nextitem.x,-1.0)) + coords_for_shader.append((nextitem.x,-1.0,member_length)) load_info.append((sinus, quadratic, nextitem.y + constant)) color.append(color_axis) counter += 2 - self.args = {"position": coords,"color": color, - "sin_quad_lin_forces": load_info,"uv_coord": coords_2d} - self.indices = indices + if len(coords): + self.info.append( + { + "shader": shader, + "args": {"position": coords, "sin_quad_lin_forces": load_info,"coord": coords_for_shader}, + "indices": indices, + "uniforms": [["color", color_axis],["spacing", 0.2],["maxload",maxforce]] + } + ) + coords = [] + load_info = [] + coords_for_shader = [] + indices = [] + for info in self.info: + info["uniforms"][2][1] = maxforce + self.text_info = text_info -def get_loads_per_direction(activity_list,global_to_local): +def get_loads_per_direction(activity_list,global_to_local,member_length): """ returns a dict with values for applied loads in each direction return = { "fx": values_in_this_direction @@ -247,9 +267,21 @@ def get_loads_per_direction(activity_list,global_to_local): else: final_list.append([pos]+value["before"]) final_list.append([pos]+value["after"]) - if len(final_list)>2: - del final_list[0] - del final_list[-1] + + if not len(final_list) and any(const+quad+sinus): + final_list.append([0.0,0.0,0.0,0.0,0.0,0.0,0.0]) + final_list.append([member_length,0.0,0.0,0.0,0.0,0.0,0.0]) + + elif len(final_list) and any(const+quad+sinus): + if final_list[0][0]: #if first item location is not 0 append an item at the zero + final_list = [[0.0,0.0,0.0,0.0,0.0,0.0,0.0]]+final_list + else: + del final_list[0] + if abs(final_list[-1][0] - member_length) > 0.01: + final_list.append([member_length,0.0,0.0,0.0,0.0,0.0,0.0]) + else: + del final_list[-1] + array = np.array(final_list) #7xn -> ["pos","fx","fy","fz","mx","my","mz"] keys = ["fx","fy","fz","mx","my","mz"] polyline = { @@ -268,11 +300,16 @@ def get_loads_per_direction(activity_list,global_to_local): "my": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, "mz": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, } + max_load = 0 for component, key in enumerate(keys): - if( sinus[component] or quad[component] or const[component] or - any(item != 0 for item in array[:,component+1])): + if(any([sinus[component], quad[component], const[component]]) or + any(item for item in array[:,component+1])): + for currentitem in final_list: polyline[key].append([currentitem[0],currentitem[component+1]]) + x = currentitem[0]/member_length + func = sin(x*3.1416)*sinus[component] + (-4.*x*x+4.*x)*quad[component]+const[component]+currentitem[component+1] + max_load = max(max_load,abs(func)) inner_dict = return_value[key] inner_dict["constant"] = const[component] inner_dict["quadratic"] = quad[component] @@ -280,7 +317,7 @@ def get_loads_per_direction(activity_list,global_to_local): inner_dict["polyline"] = polyline[key] return_value[key] = inner_dict - return return_value + return return_value, max_load+abs(sinus[component]+quad[component]) def getuniquepositionlist(load_config_list): @@ -425,7 +462,7 @@ def get_loads_dict(activity_list,global_to_local): for activity in activity_list: load = activity.AppliedLoad global_or_local = activity.GlobalOrLocal - reference_frame = 'LOCAL_COORDS' #make it a scene property so it can be changed in a panel + reference_frame = 'GLOBAL_COORDS' #make it a scene property so it can be changed in a panel transform_matrix = Matrix() if reference_frame == 'LOCAL_COORDS' and global_or_local != reference_frame: transform_matrix = global_to_local @@ -457,7 +494,7 @@ def get_loads_dict(activity_list,global_to_local): else: forcevalues = get_force_vector(load,transform_matrix) momentvalues = get_moment_vector(load,transform_matrix) - if 'CONST' == getattr(activity, 'PredefinedType', None): + if 'CONST' == getattr(activity, 'PredefinedType', None) or activity.is_a('IfcStructuralLinearAction'): constant_force += forcevalues constant_moment += momentvalues elif 'PARABOLA' == getattr(activity, 'PredefinedType', None): From d915dc9df0911f4c553a5ee6b74bfc4d82d5bb58 Mon Sep 17 00:00:00 2001 From: Lucas Nascimento Date: Tue, 24 Sep 2024 20:53:13 -0300 Subject: [PATCH 31/61] update decorator to match shader + changes to text rendering --- .../bonsai/bim/module/structural/decorator.py | 43 +++++++++++-------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/structural/decorator.py b/src/bonsai/bonsai/bim/module/structural/decorator.py index eb15b819ac..aedbade6c3 100644 --- a/src/bonsai/bonsai/bim/module/structural/decorator.py +++ b/src/bonsai/bonsai/bim/module/structural/decorator.py @@ -3,6 +3,7 @@ from mathutils import Vector import bpy import gpu import blf +from bpy_extras import view3d_utils from bpy.types import SpaceView3D from gpu_extras.batch import batch_for_shader from bonsai.bim.module.structural.shader import ShaderInfo @@ -12,6 +13,7 @@ class LoadsDecorator: handlers = [] linear_load_shader = None text_info = [] + shader_info = [] @classmethod def install(cls, context): @@ -27,6 +29,7 @@ class LoadsDecorator: #) cls.handlers.append(SpaceView3D.draw_handler_add(handler, (), "WINDOW", "POST_VIEW")) cls.linear_load_shader = ShaderInfo("DistributedLoad") + cls.update(context) cls.is_installed = True @classmethod @@ -41,12 +44,13 @@ class LoadsDecorator: @classmethod def update(cls, context): cls.linear_load_shader.update() - cls.text_info += cls.linear_load_shader.text_info + cls.text_info = cls.linear_load_shader.text_info + cls.shader_info = cls.linear_load_shader.info def __call__(self): # set open gl configurations original_blend = gpu.state.blend_get() - gpu.state.blend_set('ALPHA') + gpu.state.blend_set('ADDITIVE') original_depth_mask = gpu.state.depth_mask_get() #gpu.state.depth_mask_set(True) original_depth_test = gpu.state.depth_test_get() @@ -62,17 +66,20 @@ class LoadsDecorator: def draw_batch(self,shader_type: str): """ param: shader_type: type of shader in ["DistributedLoad", "PointLoad"]""" - if shader_type == "DistributedLoad" and not self.linear_load_shader.is_empty: - shader_info = self.linear_load_shader - shader = shader_info.shader - args = shader_info.args - indices = shader_info.indices - batch = batch_for_shader(shader, 'TRIS', args, indices=indices) - matrix = bpy.context.region_data.perspective_matrix - shader.uniform_float("viewProjectionMatrix", matrix) - shader.uniform_float("spacing", 0.2) # make it customizable - shader.uniform_float("maxload", 200) # make it customizable - batch.draw(shader) + if not self.linear_load_shader.is_empty: + for info in self.shader_info: + shader = info["shader"] + args = info["args"] + indices = info["indices"] + batch = batch_for_shader(shader, 'TRIS', args, indices=indices) + matrix = bpy.context.region_data.perspective_matrix + shader.bind() + shader.uniform_float("viewProjectionMatrix", matrix) + + for key, value in info["uniforms"]: + shader.uniform_float(key, value) + + batch.draw(shader) def draw_load_values(self, context): for info in self.text_info: @@ -91,11 +98,6 @@ def location_3d_to_region_2d(coord, normal, context): perspective = rv3d.view_perspective view_matrix = rv3d.view_matrix point_view_space = view_matrix @ coord - x,y,z = view_matrix.to_3x3() - angle = abs(0.5*pi-normal.angle(z)) - #if small view angle betwen the load and viewport - if angle<0.05: - return None if perspective == 'ORTHO' or -20 < point_view_space.z < 0: prj = rv3d.perspective_matrix @ Vector((coord[0], coord[1], coord[2], 1.0)) @@ -104,5 +106,10 @@ def location_3d_to_region_2d(coord, normal, context): co = Vector((width_half + width_half * (prj.x / prj.w), height_half + height_half * (prj.y / prj.w), )) + view_vector = view3d_utils.region_2d_to_vector_3d(context.region, rv3d, co) + angle = abs(0.5*pi-normal.angle(view_vector)) + #if small view angle betwen the load and viewport + if angle<0.05: + return None return co return None From 477725529bfa77e634efbf9068f3d334260d0d52 Mon Sep 17 00:00:00 2001 From: Lucas Nascimento Date: Thu, 3 Oct 2024 22:23:12 -0300 Subject: [PATCH 32/61] now with shader for point loads --- .../bonsai/bim/module/structural/decorator.py | 9 +- .../bonsai/bim/module/structural/operator.py | 2 + .../bonsai/bim/module/structural/shader.py | 278 ++++++++++++++++-- 3 files changed, 257 insertions(+), 32 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/structural/decorator.py b/src/bonsai/bonsai/bim/module/structural/decorator.py index aedbade6c3..4d6b42790e 100644 --- a/src/bonsai/bonsai/bim/module/structural/decorator.py +++ b/src/bonsai/bonsai/bim/module/structural/decorator.py @@ -50,11 +50,11 @@ class LoadsDecorator: def __call__(self): # set open gl configurations original_blend = gpu.state.blend_get() - gpu.state.blend_set('ADDITIVE') + gpu.state.blend_set('ALPHA') original_depth_mask = gpu.state.depth_mask_get() - #gpu.state.depth_mask_set(True) + gpu.state.depth_mask_set(True) original_depth_test = gpu.state.depth_test_get() - gpu.state.depth_test_set('ALWAYS') + gpu.state.depth_test_set('LESS_EQUAL') self.draw_batch("DistributedLoad") @@ -98,8 +98,9 @@ def location_3d_to_region_2d(coord, normal, context): perspective = rv3d.view_perspective view_matrix = rv3d.view_matrix point_view_space = view_matrix @ coord + - if perspective == 'ORTHO' or -20 < point_view_space.z < 0: + if perspective == 'ORTHO' or -10 < point_view_space.z < 0: prj = rv3d.perspective_matrix @ Vector((coord[0], coord[1], coord[2], 1.0)) width_half = context.region.width / 2.0 height_half = context.region.height / 2.0 diff --git a/src/bonsai/bonsai/bim/module/structural/operator.py b/src/bonsai/bonsai/bim/module/structural/operator.py index bc69b31a4e..e750d62321 100644 --- a/src/bonsai/bonsai/bim/module/structural/operator.py +++ b/src/bonsai/bonsai/bim/module/structural/operator.py @@ -49,6 +49,8 @@ class ShowLoads(bpy.types.Operator): return {'PASS_THROUGH'} def invoke(self, context, event): + collection = bpy.data.collections["IfcStructuralItem"] + collection.hide_viewport = False LoadsDecorator.install(context) LoadsDecorator.update(context) context.window_manager.modal_handler_add(self) diff --git a/src/bonsai/bonsai/bim/module/structural/shader.py b/src/bonsai/bonsai/bim/module/structural/shader.py index 56897b2934..8b1409c8a8 100644 --- a/src/bonsai/bonsai/bim/module/structural/shader.py +++ b/src/bonsai/bonsai/bim/module/structural/shader.py @@ -23,11 +23,12 @@ class ShaderInfo: def update(self): self.info = [] self.get_linear_loads() + self.get_point_loads() if len(self.info): self.is_empty = False - def get_shader(self): - """ param: shader_type: type of shader in ["DistributedLoad", "PointLoad"] + def get_shader(self, pattern): + """ param: pattern: type of pattern in ["force", "force match", "moment"] return: shader""" if self.shader_type == "DistributedLoad": vert_out = gpu.types.GPUStageInterfaceInfo("my_interface") @@ -57,8 +58,8 @@ class ShaderInfo: "}" ) - - shader_info.fragment_source( + if pattern == "force": + shader_info.fragment_source( "void main()" "{" "float x = co.x;" @@ -80,7 +81,74 @@ class ShaderInfo: "float top = step(abs(y-f),0.2*1.2*spacing);" "float d = clamp(0.1+top+b+c,0.0,0.5)*mask;" + "if (d == 0.0) discard;" + "FragColor = vec4(color.xyz,d*color.w);" + "}" + ) + + if pattern == "force match": + shader_info.fragment_source( + "void main()" + "{" + "float y = co.y;" + "float x = step(0.,y)*(co.z-co.x)+step(y,0.)*(co.x);" + "float abs_y = abs(y);" + "float a = abs(mod(abs_y,spacing)-0.5*spacing)*5.0;" + "float a2 = mod(x,3.0*spacing);" + "float b = step(a,a2)*step(a2,1.2*spacing);" + "float c = step(0.8*spacing,mod(abs_y+0.4*spacing,spacing))" + "*(step(1.2*spacing,a2))*step(a2,2.5*spacing);" + "float sinvalue = forces.x;" + "float quadraticvalue = forces.y;" + "float linearvalue = forces.z;" + "x = co.x/co.z;" + "float f = (sin(x*3.1416)*sinvalue" + "+(-4.*x*x+4.*x)*quadraticvalue" + "+linearvalue)/maxload;" + "float mask = step(0.,y)*step(y,f)+step(y,0.)*step(f,y);" + + "float top = step(abs(y-f),0.2*1.2*spacing);" + "float d = clamp(0.1+top+b+c,0.0,0.5)*mask;" + "if (d == 0.0) discard;" + "FragColor = vec4(color.xyz,d*color.w);" + "}" + ) + + if pattern == "moment": + shader_info.fragment_source( + "void main()" + "{" + "float x = step(co.y,0.)*(co.x)+step(0.,co.y)*(co.z-co.x);" + "float y = step(co.y,-0.00001)*(co.y)+step(0.,co.y)*(0.-co.y);" + "x = mod((0.5/spacing)*x,1.4)-0.7;" + "y = mod((0.5/spacing)*y,1.4)-0.7;" + "float abs_y = abs(y);" + "vec2 st = vec2(1.9*x,y);" + "vec2 orig = vec2(0.,0.);" + + "float circ = step(distance(st,orig),0.33)*step(0.27,distance(st,orig));" + "float tri_mask = step(st.y,st.x)+step(-st.x,st.y);" + "float circ_arrow = step(st.x,4.0*st.y-0.75)*step(0.25*st.y-0.34,st.x)*(1.-tri_mask);" + + "float circmask = step(distance(st,orig),0.1)+step(0.5,distance(st,orig))+step(st.x,0.);" + "float body = step(-0.03,st.y)*step(st.y,0.03)*step(-0.3,x)*step(x,0.576);" + "float body_arrow = step(-0.5+3.*st.y,x)*step(-0.5-3.*st.y,x)*step(x,-0.3);" + "float d = clamp(circmask*(body+body_arrow)+circ_arrow+circ*tri_mask,0.,1.);" + + "float sinvalue = forces.x;" + "float quadraticvalue = forces.y;" + "float linearvalue = forces.z;" + "x = co.x/co.z;" + "float f = (sin(x*3.1416)*sinvalue" + "+(-4.*x*x+4.*x)*quadraticvalue" + "+linearvalue)/maxload;" + "float mask = step(0.,co.y)*step(co.y,f)+step(co.y,0.)*step(f,co.y);" + + "float top = step(abs(co.y-f),0.2*1.2*spacing);" + + "d = clamp(0.1+top+d,0.0,0.5)*mask;" + "if (d == 0.0) discard;" "FragColor = vec4(color.xyz,d*color.w);" "}" ) @@ -89,12 +157,158 @@ class ShaderInfo: del vert_out del shader_info return shader + + def get_point_shader(self, pattern): + """ param: pattern: type of pattern in ["arrow", "circ arrow"] + return: shader""" + vert_out = gpu.types.GPUStageInterfaceInfo("my_interface") + vert_out.smooth('VEC3', "co") + + shader_info = gpu.types.GPUShaderCreateInfo() + shader_info.push_constant('MAT4', "viewProjectionMatrix") + shader_info.push_constant('VEC4', "color") + shader_info.push_constant('FLOAT', "spacing") + + shader_info.vertex_in(0, 'VEC3', "position") + shader_info.vertex_in(1, 'VEC3', "coord") + + shader_info.vertex_out(vert_out) + shader_info.fragment_out(0, 'VEC4', "FragColor") + + shader_info.vertex_source( + "void main()" + "{" + " gl_Position = viewProjectionMatrix * vec4(position, 1.0f);" + " co = coord;" + "}" + ) + + if pattern == "arrow": + shader_info.fragment_source( + "void main()" + "{" + "float body = step(abs(co.x),0.2*spacing)*step(2.*spacing,co.y);" + "float arrow = step(3.5*abs(co.x)+0.02,abs(co.y))*step(co.y,2.*spacing)*step(0.,co.y);" + "float d = clamp(body+arrow,0.0,0.5);" + "if (d == 0.0) discard;" + "FragColor = vec4(color.xyz,d*color.w);" + "}" + ) + + if pattern == "circ arrow": + shader_info.fragment_source( + "void main()" + "{" + "float circ = step(distance(co.xy,vec2(0.,0.)),0.33)*step(0.27,distance(co.xy,vec2(0.,0.)));" + "float mask = step(co.y,co.x)+step(-co.x,co.y);" + "float circ_arrow = step(co.x,4.0*co.y-0.75)*step(0.25*co.y-0.34,co.x)*(1.-mask);" + "float d = clamp(circ_arrow+circ*mask,0.0,0.5);" + "if (d == 0.0) discard;" + "FragColor = vec4(color.xyz,d*color.w);" + "}" + ) + + shader = gpu.shader.create_from_info(shader_info) + del vert_out + del shader_info + return shader + + def get_point_loads(self): + list_of_point_connections = tool.Ifc.get().by_type("IfcStructuralPointConnection") + for conn in list_of_point_connections: + activity_list = [getattr(a, 'RelatedStructuralActivity', None) for a in getattr(conn, 'AssignedStructuralActivity', None) + if getattr(a, 'RelatedStructuralActivity', None).is_a() in ['IfcStructuralPointAction']] + if len(activity_list) == 0: + continue + blender_object = IfcStore.get_element(getattr(conn, 'GlobalId', None)) + if blender_object.type == 'MESH': + conn_location = blender_object.matrix_world @ blender_object.data.vertices[0].co + #get local coordinates of the connection + loads = self.get_point_loads_list(activity_list) + self.get_point_shader_args(loads, conn_location) + + def get_point_shader_args(self,loads, location): + indices = [] + text_info = [] + direction_dict = { + "fx": (Vector((1,0,0)),Vector((0,1,0)),Vector((0,0,1))), + "fy": (Vector((0,1,0)),Vector((1,0,0)),Vector((0,0,1))), + "fz": (Vector((0,0,1)),Vector((0,1,0)),Vector((1,0,0))), + "mx": (Vector((0,1,0)),Vector((0,0,1))), + "my": (Vector((1,0,0)),Vector((0,0,1))), + "mz": (Vector((1,0,0)),Vector((0,1,0))), + } + keys = ["fx","fy","fz","mx","my","mz"] + for i, key in enumerate(keys): + if loads[i] == 0: + continue + color = (1,0,0,1) + if i in [1,4]: + color = (0,1,0,1) + elif i in [2,5]: + color = (0,0,1,1) + d1 = -(direction_dict[key][0]*loads[i]).normalized() + if i < 3: + d2 = direction_dict[key][1] + d3 = direction_dict[key][2] + p1 = location + p2 = location + d1 + d2 + p3 = location + d1 - d2 + p4 = location + d1 + d3 + p5 = location + d1 - d3 + position = [p1,p2,p3,p4,p5] + indices = [(0,1,2),(0,3,4)] + c1 = (0,0,0) + c2 = (1,1,0) + c3 = (-1,1,0) + coords_for_shader = [c1,c2,c3,c2,c3] + shader = self.get_point_shader("arrow") + self.info.append( + { + "shader": shader, + "args": {"position": position,"coord": coords_for_shader}, + "indices": indices, + "uniforms": [["color", color],["spacing", 0.2]] + } + ) + else: + d2 = d2 = direction_dict[key][1] + p1 = location - d2 + p2 = location + d1 + d2 + p3 = location - d1 + d2 + position = [p1,p2,p3] + indices = [(0,1,2)] + c1 = (-1,0,0) + c2 = (1,1,0) + c3 = (1,-1,0) + coords_for_shader = [c1,c2,c3] + shader = self.get_point_shader("circ arrow") + self.info.append( + { + "shader": shader, + "args": {"position": position,"coord": coords_for_shader}, + "indices": indices, + "uniforms": [["color", color]]#,["spacing", 0.2]] + } + ) + + + + def get_point_loads_list(self,activity_list): + result_list = [0,0,0,0,0,0] + attr_list = ['ForceX','ForceY','ForceZ','MomentX','MomentY','MomentZ'] + for activity in activity_list: + load = activity.AppliedLoad + for i, attr in enumerate(attr_list): + value = 0 if getattr(load, attr, 0) is None else getattr(load, attr, 0) + result_list[i] += value + return result_list def get_linear_loads(self): #for now it only works for distributed loads - coords = [] + position = [] indices = [] - load_info = [] + sin_quad_lin = [] coords_for_shader = [] color = [] text_info = [] @@ -145,7 +359,7 @@ class ShaderInfo: "my": z_axis if is_local else Vector((-1,0,1)) if y_match else Vector((0,1,0)).cross(x_axis).normalized(), "mz": y_axis if is_local else Vector((-1,1,0)) if z_match else Vector((0,0,1)).cross(x_axis).normalized() } - shader = self.get_shader() + match_dict = {'fx': x_match, 'fy': y_match, 'fz': z_match} member_length = Vector(end_co-start_co).length loads_dict, maxforce = get_loads_per_direction(activity_list,global_to_local,member_length) keys = ["fx","fy","fz","mx","my","mz"] @@ -161,32 +375,40 @@ class ShaderInfo: color_axis = (1,0,0,1) if 'y' in key: color_axis = (0,1,0,1) + + if 'f' in key: + if match_dict[key]: + shader = self.get_shader("force match") + else: + shader = self.get_shader("force") + else: + shader = self.get_shader("moment") - addindex = len(coords) + addindex = len(position) counter = 0 for i in range(len(polyline)-1): current = Vector(polyline[i]+[0]) nextitem = Vector(polyline[i+1]+[0]) if any([current.y, nextitem.y,constant,quadratic,sinus]): #if there is load in the z direction - negative = -direction + start_co + x_axis*current.x + negative = -1*direction + start_co + x_axis*current.x positive = direction + start_co + x_axis*current.x - coords.append(negative) + position.append(negative) coords_for_shader.append((current.x, 1.0,member_length)) - load_info.append((sinus, quadratic, current.y + constant)) + sin_quad_lin.append((sinus, quadratic, current.y + constant)) color.append(color_axis) #info to render load value x = current.x/member_length func = sin(x*3.1416)*sinus + (-4.*x*x+4.*x)*quadratic+constant+current.y if func: text_info.append( - {"position": -direction*func/maxforce + start_co + x_axis*current.x, + {"position": -1*direction*func/maxforce + start_co + x_axis*current.x, "normal": direction.cross(x_axis).normalized(), "text": f'{func:.2f} '} ) maxforce = max(maxforce,abs(func)) - coords.append(positive) + position.append(positive) coords_for_shader.append((current[0],-1.0,member_length)) - load_info.append((sinus, quadratic, current.y + constant)) + sin_quad_lin.append((sinus, quadratic, current.y + constant)) color.append(color_axis) indices.append((0 + counter + addindex, @@ -196,38 +418,38 @@ class ShaderInfo: 2 + counter + addindex, 1 + counter + addindex)) if i == len(polyline)-2: - negative = -direction + start_co + x_axis*nextitem.x + negative = -1*direction + start_co + x_axis*nextitem.x positive = direction + start_co + x_axis*nextitem.x - coords.append(negative) + position.append(negative) coords_for_shader.append((nextitem.x, 1.0,member_length)) - load_info.append((sinus, quadratic, nextitem.y + constant)) + sin_quad_lin.append((sinus, quadratic, nextitem.y + constant)) color.append(color_axis) #info to render load value x = nextitem.x/member_length func = sin(x*3.1416)*sinus + (-4.*x*x+4.*x)*quadratic+constant+nextitem.y if func: text_info.append( - {"position": -direction*func/maxforce + start_co + x_axis*nextitem.x, + {"position": -1*direction*func/maxforce + start_co + x_axis*nextitem.x, "normal": direction.cross(x_axis).normalized(), "text": f'{func:.2f} '} ) maxforce = max(maxforce,abs(func)) - coords.append(positive) + position.append(positive) coords_for_shader.append((nextitem.x,-1.0,member_length)) - load_info.append((sinus, quadratic, nextitem.y + constant)) + sin_quad_lin.append((sinus, quadratic, nextitem.y + constant)) color.append(color_axis) counter += 2 - if len(coords): + if len(position): self.info.append( { "shader": shader, - "args": {"position": coords, "sin_quad_lin_forces": load_info,"coord": coords_for_shader}, + "args": {"position": position, "sin_quad_lin_forces": sin_quad_lin,"coord": coords_for_shader}, "indices": indices, "uniforms": [["color", color_axis],["spacing", 0.2],["maxload",maxforce]] } ) - coords = [] - load_info = [] + position = [] + sin_quad_lin = [] coords_for_shader = [] indices = [] for info in self.info: @@ -272,12 +494,12 @@ def get_loads_per_direction(activity_list,global_to_local,member_length): final_list.append([0.0,0.0,0.0,0.0,0.0,0.0,0.0]) final_list.append([member_length,0.0,0.0,0.0,0.0,0.0,0.0]) - elif len(final_list) and any(const+quad+sinus): - if final_list[0][0]: #if first item location is not 0 append an item at the zero + elif len(final_list): + if final_list[0][0] and any(const+quad+sinus): #if first item location is not 0 append an item at the zero final_list = [[0.0,0.0,0.0,0.0,0.0,0.0,0.0]]+final_list else: del final_list[0] - if abs(final_list[-1][0] - member_length) > 0.01: + if abs(final_list[-1][0] - member_length) > 0.01 and any(const+quad+sinus): final_list.append([member_length,0.0,0.0,0.0,0.0,0.0,0.0]) else: del final_list[-1] @@ -430,7 +652,7 @@ def get_loads_dict(activity_list,global_to_local): Locations attribute of IfcLoadConfiguration dict{ "pos": float, -> local position along curve length - "descr": string, -> describe if the item is at the star, middle or end of the list + "descr": string, -> describe if the item is at the start, middle or end of the list "forces": Vector, -> linear force applied at that point "moments": Vector -> linear moment applied at that point } From 2912580087631cb7e511bf9d0b4df070ce35bb0a Mon Sep 17 00:00:00 2001 From: Lucas Nascimento Date: Wed, 4 Dec 2024 20:31:07 -0300 Subject: [PATCH 33/61] shit ton of changes --- .gitignore | 1 + .../bonsai/bim/module/structural/data.py | 32 + .../bonsai/bim/module/structural/decorator.py | 69 +- .../bonsai/bim/module/structural/operator.py | 3 +- .../bonsai/bim/module/structural/prop.py | 17 +- .../bonsai/bim/module/structural/shader.py | 639 ++++++++++++++---- src/bonsai/bonsai/bim/module/structural/ui.py | 8 +- 7 files changed, 614 insertions(+), 155 deletions(-) diff --git a/.gitignore b/.gitignore index 240190a857..69fbc5d66b 100644 --- a/.gitignore +++ b/.gitignore @@ -99,3 +99,4 @@ src/ifcopenshell-python/ifcopenshell/ifcopenshell_wrapper.py # Brickschema src/bonsai/bonsai/bim/schema/Brick.ttl bonsaiDecoratorForLoads.code-workspace +dev_environment.bat diff --git a/src/bonsai/bonsai/bim/module/structural/data.py b/src/bonsai/bonsai/bim/module/structural/data.py index c088889f94..118b8b1eb7 100644 --- a/src/bonsai/bonsai/bim/module/structural/data.py +++ b/src/bonsai/bonsai/bim/module/structural/data.py @@ -30,6 +30,38 @@ def refresh(): StructuralLoadCasesData.is_loaded = False StructuralLoadsData.is_loaded = False BoundaryConditionsData.is_loaded = False + LoadGroupDecorationData.is_loaded = False + +class LoadGroupDecorationData: + data = {} + is_loaded = False + + @classmethod + def load(cls): + cls.data = {"load groups to show": cls.load_groups_to_show()} + cls.is_loaded = True + + @classmethod + def load_groups_to_show(cls): + ret = [] + abrv = {"LOAD_CASE": "L.Case: ", + "LOAD_COMBINATION": "L.Comb: ", + "LOAD_GROUP": "L.Gr: ", + "USERDEFINED": "U.Def: ", + "NOTDEFINED": "N.Def: " + } + models = tool.Ifc.get().by_type("IfcStructuralAnalysisModel") + m = models[0] + groups = m.LoadedBy or [] + for g in groups: + ret.append((str(g.id()),". "+abrv[g.PredefinedType]+" "+g.Name,"")) + related_objects = [rel.RelatedObjects for rel in g.IsGroupedBy] + for item in related_objects: + for subgoup in [sg for sg in item if sg.is_a("IfcStructuralLoadGroup")]: + ret.append((str(subgoup.id()),". "+abrv[subgoup.PredefinedType]+subgoup.Name,"")) + if len(ret) == 0: + ret.append(("","","")) + return ret class StructuralBoundaryConditionsData: diff --git a/src/bonsai/bonsai/bim/module/structural/decorator.py b/src/bonsai/bonsai/bim/module/structural/decorator.py index 4d6b42790e..e8fab591d0 100644 --- a/src/bonsai/bonsai/bim/module/structural/decorator.py +++ b/src/bonsai/bonsai/bim/module/structural/decorator.py @@ -1,5 +1,6 @@ from math import pi from mathutils import Vector +import numpy as np import bpy import gpu import blf @@ -14,6 +15,7 @@ class LoadsDecorator: linear_load_shader = None text_info = [] shader_info = [] + depth_array = None @classmethod def install(cls, context): @@ -28,7 +30,7 @@ class LoadsDecorator: # SpaceView3D.draw_handler_add(handler.draw_curve_loads, (context,), "WINDOW", "POST_VIEW") #) cls.handlers.append(SpaceView3D.draw_handler_add(handler, (), "WINDOW", "POST_VIEW")) - cls.linear_load_shader = ShaderInfo("DistributedLoad") + cls.linear_load_shader = ShaderInfo() cls.update(context) cls.is_installed = True @@ -52,7 +54,7 @@ class LoadsDecorator: original_blend = gpu.state.blend_get() gpu.state.blend_set('ALPHA') original_depth_mask = gpu.state.depth_mask_get() - gpu.state.depth_mask_set(True) + #gpu.state.depth_mask_set(True) original_depth_test = gpu.state.depth_test_get() gpu.state.depth_test_set('LESS_EQUAL') @@ -82,35 +84,52 @@ class LoadsDecorator: batch.draw(shader) def draw_load_values(self, context): + framebuffer = gpu.state.active_framebuffer_get() + viewport_info = gpu.state.viewport_get() + width = viewport_info[2] + height = viewport_info[3] + depth_buffer = framebuffer.read_depth(0, 0, width, height) + depth_array = np.array(depth_buffer.to_list()) + + f = context.area.spaces.active.clip_end + n = context.area.spaces.active.clip_start + + self.depth_array = n / (f - (f - n) * depth_array) * (f - n) + for info in self.text_info: - text_position = location_3d_to_region_2d(info["position"],info["normal"],context) + text_position = self.location_3d_to_region_2d(info["position"],info["normal"],context) if text_position is not None: font_id = 0 # , need to find out how best to get this. # draw some text - blf.position(font_id, text_position[0], text_position[1], 0) + blf.position(font_id, text_position[0], text_position[1], text_position[2]) blf.size(font_id, 20.0) blf.color(font_id, 0.9, 0.9, 0.9, 1.0) blf.draw(font_id, info["text"]) -def location_3d_to_region_2d(coord, normal, context): - """Convert from 3D space to 2D screen space""" - rv3d = context.region_data - perspective = rv3d.view_perspective - view_matrix = rv3d.view_matrix - point_view_space = view_matrix @ coord - + def location_3d_to_region_2d(self, coord, normal, context): + """Convert from 3D space to 2D screen space""" + rv3d = context.region_data + perspective = rv3d.view_perspective + view_matrix = rv3d.view_matrix + point_view_space = view_matrix @ coord - if perspective == 'ORTHO' or -10 < point_view_space.z < 0: - prj = rv3d.perspective_matrix @ Vector((coord[0], coord[1], coord[2], 1.0)) - width_half = context.region.width / 2.0 - height_half = context.region.height / 2.0 - co = Vector((width_half + width_half * (prj.x / prj.w), - height_half + height_half * (prj.y / prj.w), - )) - view_vector = view3d_utils.region_2d_to_vector_3d(context.region, rv3d, co) - angle = abs(0.5*pi-normal.angle(view_vector)) - #if small view angle betwen the load and viewport - if angle<0.05: - return None - return co - return None + + if perspective == 'ORTHO' or -10 < point_view_space.z < 0: + prj = rv3d.perspective_matrix @ Vector((coord[0], coord[1], coord[2], 1.0)) + width_half = context.region.width / 2.0 + height_half = context.region.height / 2.0 + co = Vector((width_half + width_half * (prj.x / prj.w), + height_half + height_half * (prj.y / prj.w), + point_view_space.z)) + if co[0]> context.region.width or co[1] > context.region.height or co[0] < 0 or co[1] < 0: + return None + depth = self.depth_array[int(co[1])][int(co[0])] + if -0.98*point_view_space.z > depth: + return None + view_vector = view3d_utils.region_2d_to_vector_3d(context.region, rv3d, co) + angle = abs(0.5*pi-normal.angle(view_vector)) + #if small view angle betwen the load and viewport + if angle<0.05: + return None + return co + return None diff --git a/src/bonsai/bonsai/bim/module/structural/operator.py b/src/bonsai/bonsai/bim/module/structural/operator.py index e750d62321..ef2a221819 100644 --- a/src/bonsai/bonsai/bim/module/structural/operator.py +++ b/src/bonsai/bonsai/bim/module/structural/operator.py @@ -51,8 +51,9 @@ class ShowLoads(bpy.types.Operator): def invoke(self, context, event): collection = bpy.data.collections["IfcStructuralItem"] collection.hide_viewport = False + context.window.cursor_modal_set("WAIT") LoadsDecorator.install(context) - LoadsDecorator.update(context) + context.window.cursor_modal_restore() context.window_manager.modal_handler_add(self) for area in context.screen.areas: if area.type == 'VIEW_3D': diff --git a/src/bonsai/bonsai/bim/module/structural/prop.py b/src/bonsai/bonsai/bim/module/structural/prop.py index 484bb2bb67..3c5fad7d2f 100644 --- a/src/bonsai/bonsai/bim/module/structural/prop.py +++ b/src/bonsai/bonsai/bim/module/structural/prop.py @@ -21,7 +21,7 @@ import bpy import bonsai.tool as tool from bonsai.bim.ifc import IfcStore from bonsai.bim.prop import StrProperty, Attribute -from bonsai.bim.module.structural.data import StructuralLoadCasesData, StructuralLoadsData, BoundaryConditionsData +from bonsai.bim.module.structural.data import StructuralLoadCasesData, StructuralLoadsData, BoundaryConditionsData, LoadGroupDecorationData from bpy.types import PropertyGroup from bpy.props import ( PointerProperty, @@ -34,6 +34,10 @@ from bpy.props import ( CollectionProperty, ) +def get_load_groups_to_show(self, context): + if not LoadGroupDecorationData.is_loaded: + LoadGroupDecorationData.load() + return LoadGroupDecorationData.data["load groups to show"] def get_applicable_structural_load_types(self, context): if not StructuralLoadCasesData.is_loaded: @@ -152,6 +156,17 @@ class BIMStructuralProperties(PropertyGroup): boundary_condition_attributes: CollectionProperty(name="Boundary Condition Attributes", type=Attribute) filtered_boundary_conditions: BoolProperty(name="Filtered Boundary Conditions", default=False) + show_loads: BoolProperty(name="Show Loads", default=False) + update_load_repr: BoolProperty(name="Update Load Representation", default=False) + enable_repr_auto_update: BoolProperty(name="Auto Update", default=False) + reference_frame: EnumProperty(items=[("GLOBAL_COORDS","Global","Show loads in global reference frame"), + ("LOCAL_COORDS","Local","Show loads in local reference frame")], name= "Reference Frame") + activity_type: EnumProperty(items=[("Action","Actions","Show actions loads"), + ("External Reaction","External Reactions","Show reactions on boundary conditions"), + ("Internal Reactions","Internal Reactions","Show internal reactions on members")], + name="Activity Type") + load_group_to_show: EnumProperty(items=get_load_groups_to_show, name="Load Groups") + class BIMObjectStructuralProperties(PropertyGroup): boundary_condition_attributes: CollectionProperty(name="Boundary Condition Attributes", type=Attribute) diff --git a/src/bonsai/bonsai/bim/module/structural/shader.py b/src/bonsai/bonsai/bim/module/structural/shader.py index 8b1409c8a8..0f50e89216 100644 --- a/src/bonsai/bonsai/bim/module/structural/shader.py +++ b/src/bonsai/bonsai/bim/module/structural/shader.py @@ -1,5 +1,6 @@ import bpy import gpu +import bmesh import numpy as np from math import sin from mathutils import Vector, Matrix @@ -11,152 +12,319 @@ from bonsai.bim.ifc import IfcStore class ShaderInfo: - def __init__(self,shader_type: str): + def __init__(self): self.is_empty = True - self.shader = None - self.shader_type = shader_type - self.args = {} - self.indices = [] + #self.shader = None + #self.shader_type = shader_type + #self.args = {} + #self.indices = [] + self.curve_members = [] + self.point_members = [] + self.surface_members = {} self.text_info = [] self.info = [] + self.force_unit = "" + self.linear_force_unit = "" + self.planar_force_unit = "" def update(self): self.info = [] + self.get_force_units() + self.get_strucutural_elements_and_activities() self.get_linear_loads() self.get_point_loads() + self.get_planar_loads_2() if len(self.info): self.is_empty = False + + def get_force_units(self): + def get_unit_symbol(unit: ifcopenshell.entity_instance) -> str: + prefix_symbols = { + "EXA": "E", + "PETA": "P", + "TERA": "T", + "GIGA": "G", + "MEGA": "M", + "KILO": "k", + "HECTO": "h", + "DECA": "da", + "DECI": "d", + "CENTI": "c", + "MILLI": "m", + "MICRO": "μ", + "NANO": "n", + "PICO": "p", + "FEMTO": "f", + "ATTO": "a", + } + + unit_symbols = { + # si units + "CUBIC_METRE": "m3", + "GRAM": "g", + "SECOND": "s", + "SQUARE_METRE": "m2", + "METRE": "m", + "NEWTON": "N", + "PASCAL": "Pa", + # conversion based units + "pound-force": "lbf", + 'pound-force per square inch': "psi", + "thou": "th", + "inch": "in", + "foot": "ft", + "yard": "yd", + "mile": "mi", + "square thou": "th2", + "square inch": "in2", + "square foot": "ft2", + "square yard": "yd2", + "acre": "ac", + "square mile": "mi2", + "cubic thou": "th3", + "cubic inch": "in3", + "cubic foot": "ft3", + "cubic yard": "yd3", + "cubic mile": "mi3", + "litre": "L", + "fluid ounce UK": "fl oz", + "fluid ounce US": "fl oz", + "pint UK": "pt", + "pint US": "pt", + "gallon UK": "gal", + "gallon US": "gal", + "degree": "°", + "ounce": "oz", + "pound": "lb", + "ton UK": "ton", + "ton US": "ton", + "lbf": "lbf", + "kip": "kip", + "psi": "psi", + "ksi": "ksi", + "minute": "min", + "hour": "hr", + "day": "day", + "btu": "btu", + "fahrenheit": "°F", + } + symbol = "" + if unit.is_a("IfcSIUnit"): + symbol += prefix_symbols.get(unit.Prefix, "") + symbol += unit_symbols.get(unit.Name.replace("METER", "METRE"), "?") + return symbol + + force_units = [u for u in tool.Ifc.get().by_type("IfcNamedUnit") + if u.UnitType == "FORCEUNIT"] + linear_force_units = [u for u in tool.Ifc.get().by_type("IfcDerivedUnit") + if u.UnitType == "LINEARFORCEUNIT"] + planar_force_units = [u for u in tool.Ifc.get().by_type("IfcDerivedUnit") + if u.UnitType == "PLANARFORCEUNIT"] + + conversion_force_unit = [u for u in force_units if u.is_a("IfcConversionBasedUnit")] + if len(conversion_force_unit) == 0: + conversion_force_unit.append(force_units[0]) + self.force_unit = get_unit_symbol(conversion_force_unit[0]) + first = "" + second = "" + for e in linear_force_units[0].Elements: + if e.Unit.UnitType == "FORCEUNIT": + first = get_unit_symbol(e.Unit) + if e.Unit.UnitType == "LENGTHUNIT": + second = get_unit_symbol(e.Unit) + self.linear_force_unit = first + "/" + second + first = "" + second = "" + for e in planar_force_units[0].Elements: + if e.Unit.UnitType == "FORCEUNIT": + first = get_unit_symbol(e.Unit) + if e.Unit.UnitType == "LENGTHUNIT": + second = get_unit_symbol(e.Unit)+"2" + if e.Unit.UnitType == "AREAUNIT": + second = get_unit_symbol(e.Unit) + self.planar_force_unit = first + "/" + second + + def get_strucutural_elements_and_activities(self): + + def populate_members_dict(dict_name,element, activity, factor): + dic = getattr(self,dict_name,None) + if dic is None: + return + member = dic.get(element.GlobalId) + if member is None: + dic.update({ + element.GlobalId: { + "member": element, + "activities": [(activity,factor)]} + }) + else: + member["activities"].append((activity,factor)) + + def recursive_subgroups(groups, rec_limit, factor = 1): + if len(groups) == 0 or rec_limit == 0: + return None + for group in groups: + subgorups = [] + activities = [] + relationship = [rel for rel in group.IsGroupedBy] + group_coef = group.Coefficient if group.Coefficient is not None else 1.0 + rel_factor = 1.0 + + for rel in relationship: + if rel.is_a("IfcRelAssignsToGroupByFactor"): + rel_factor = rel.Factor if rel.Factor is not None else 1.0 + objects = rel.RelatedObjects + subgorups = [sg for sg in objects if sg.is_a("IfcStructuralLoadGroup")] + activities = [a for a in objects if a.is_a("IfcStructuralActivity")] + factor = factor*group_coef*rel_factor + for activity in activities: + if len(activity.AssignedToStructuralItem): + element = activity.AssignedToStructuralItem[0].RelatingElement + if element is not None: + if element.is_a("IfcStructuralCurveMember"): + self.curve_members.append(element) + elif element.is_a("IfcStructuralPoinConnection"): + self.point_members.append(element) + elif element.is_a("IfcStructuralSurfaceMember"): + populate_members_dict("surface_members",element,activity,factor) + recursive_subgroups(subgorups,rec_limit-1,factor=factor) + + props = bpy.context.scene.BIMStructuralProperties + group_definition_id = int(props.load_group_to_show) + file = IfcStore.get_file() + groups = [file.by_id(group_definition_id)] + recursive_subgroups(groups,10) + def get_shader(self, pattern): """ param: pattern: type of pattern in ["force", "force match", "moment"] return: shader""" - if self.shader_type == "DistributedLoad": - vert_out = gpu.types.GPUStageInterfaceInfo("my_interface") - vert_out.smooth('VEC3', "forces") - vert_out.smooth('VEC3', "co") + #if self.shader_type == "DistributedLoad": + vert_out = gpu.types.GPUStageInterfaceInfo("my_interface") + vert_out.smooth('VEC3', "forces") + vert_out.smooth('VEC3', "co") + + shader_info = gpu.types.GPUShaderCreateInfo() + shader_info.push_constant('MAT4', "viewProjectionMatrix") + shader_info.push_constant('VEC4', "color") + shader_info.push_constant('FLOAT', "spacing") + shader_info.push_constant('FLOAT', "maxload") + + shader_info.vertex_in(0, 'VEC3', "position") + shader_info.vertex_in(1, 'VEC3', "sin_quad_lin_forces") + shader_info.vertex_in(2, 'VEC3', "coord") - shader_info = gpu.types.GPUShaderCreateInfo() - shader_info.push_constant('MAT4', "viewProjectionMatrix") - shader_info.push_constant('VEC4', "color") - shader_info.push_constant('FLOAT', "spacing") - shader_info.push_constant('FLOAT', "maxload") - - shader_info.vertex_in(0, 'VEC3', "position") - shader_info.vertex_in(1, 'VEC3', "sin_quad_lin_forces") - shader_info.vertex_in(2, 'VEC3', "coord") - - shader_info.vertex_out(vert_out) - shader_info.fragment_out(0, 'VEC4', "FragColor") - - shader_info.vertex_source( - "void main()" - "{" - " gl_Position = viewProjectionMatrix * vec4(position, 1.0f);" - " co = coord;" - " forces = sin_quad_lin_forces;" - " gl_Position = viewProjectionMatrix * vec4(position, 1.0f);" - "}" - ) - - if pattern == "force": - shader_info.fragment_source( + shader_info.vertex_out(vert_out) + shader_info.fragment_out(0, 'VEC4', "FragColor") + + shader_info.vertex_source( "void main()" "{" - "float x = co.x;" - "float y = co.y;" - "float abs_y = abs(y);" - - "float a = abs(mod(x,spacing)-0.5*spacing)*5.0;" - "float b = step(a,abs_y)*(step(abs_y,1.2*spacing));" - "float c = step(0.8*spacing,mod(x+0.4*spacing,spacing))*(step(1.2*spacing,abs_y));" - - "float sinvalue = forces.x;" - "float quadraticvalue = forces.y;" - "float linearvalue = forces.z;" - "x = co.x/co.z;" - "float f = (sin(x*3.1416)*sinvalue" - "+(-4.*x*x+4.*x)*quadraticvalue" - "+linearvalue)/maxload;" - "float mask = step(0.,y)*step(y,f)+step(y,0.)*step(f,y);" - - "float top = step(abs(y-f),0.2*1.2*spacing);" - "float d = clamp(0.1+top+b+c,0.0,0.5)*mask;" - "if (d == 0.0) discard;" - "FragColor = vec4(color.xyz,d*color.w);" + " gl_Position = viewProjectionMatrix * vec4(position, 1.0f);" + " co = coord;" + " forces = sin_quad_lin_forces;" "}" - ) - - if pattern == "force match": - shader_info.fragment_source( - "void main()" - "{" - "float y = co.y;" - "float x = step(0.,y)*(co.z-co.x)+step(y,0.)*(co.x);" - "float abs_y = abs(y);" + ) + + if pattern == "force": + shader_info.fragment_source( + "void main()" + "{" + "float x = co.x;" + "float y = co.y;" + "float abs_y = abs(y);" + + "float a = abs(mod(x,spacing)-0.5*spacing)*5.0;" + "float b = step(a,abs_y)*(step(abs_y,1.2*spacing));" + "float c = step(0.8*spacing,mod(x+0.4*spacing,spacing))*(step(1.2*spacing,abs_y));" + + "float sinvalue = forces.x;" + "float quadraticvalue = forces.y;" + "float linearvalue = forces.z;" + "x = co.x/co.z;" + "float f = (sin(x*3.1416)*sinvalue" + "+(-4.*x*x+4.*x)*quadraticvalue" + "+linearvalue)/maxload;" + "float mask = step(0.,y)*step(y,f)+step(y,0.)*step(f,y);" - "float a = abs(mod(abs_y,spacing)-0.5*spacing)*5.0;" - "float a2 = mod(x,3.0*spacing);" - "float b = step(a,a2)*step(a2,1.2*spacing);" - "float c = step(0.8*spacing,mod(abs_y+0.4*spacing,spacing))" - "*(step(1.2*spacing,a2))*step(a2,2.5*spacing);" - "float sinvalue = forces.x;" - "float quadraticvalue = forces.y;" - "float linearvalue = forces.z;" - "x = co.x/co.z;" - "float f = (sin(x*3.1416)*sinvalue" - "+(-4.*x*x+4.*x)*quadraticvalue" - "+linearvalue)/maxload;" - "float mask = step(0.,y)*step(y,f)+step(y,0.)*step(f,y);" - - "float top = step(abs(y-f),0.2*1.2*spacing);" - "float d = clamp(0.1+top+b+c,0.0,0.5)*mask;" - "if (d == 0.0) discard;" - "FragColor = vec4(color.xyz,d*color.w);" - "}" - ) + "float top = step(abs(y-f),0.2*1.2*spacing);" + "float d = clamp(top+b+c,0.0,0.9)*mask;" + "if (d == 0.0) discard;" + "FragColor = vec4(color.xyz,d*color.w);" + "}" + ) - if pattern == "moment": - shader_info.fragment_source( - "void main()" - "{" - "float x = step(co.y,0.)*(co.x)+step(0.,co.y)*(co.z-co.x);" - "float y = step(co.y,-0.00001)*(co.y)+step(0.,co.y)*(0.-co.y);" - "x = mod((0.5/spacing)*x,1.4)-0.7;" - "y = mod((0.5/spacing)*y,1.4)-0.7;" - "float abs_y = abs(y);" - "vec2 st = vec2(1.9*x,y);" - "vec2 orig = vec2(0.,0.);" + if pattern == "force match": + shader_info.fragment_source( + "void main()" + "{" + "float y = co.y;" + "float x = step(0.,y)*(co.z-co.x)+step(y,0.)*(co.x);" + "float abs_y = abs(y);" + + "float a = abs(mod(abs_y,spacing)-0.5*spacing)*5.0;" + "float a2 = mod(x,3.0*spacing);" + "float b = step(a,a2)*step(a2,1.2*spacing);" + "float c = step(0.8*spacing,mod(abs_y+0.4*spacing,spacing))" + "*(step(1.2*spacing,a2))*step(a2,2.5*spacing);" + "float sinvalue = forces.x;" + "float quadraticvalue = forces.y;" + "float linearvalue = forces.z;" + "x = co.x/co.z;" + "float f = (sin(x*3.1416)*sinvalue" + "+(-4.*x*x+4.*x)*quadraticvalue" + "+linearvalue)/maxload;" + "float mask = step(0.,y)*step(y,f)+step(y,0.)*step(f,y);" - "float circ = step(distance(st,orig),0.33)*step(0.27,distance(st,orig));" - "float tri_mask = step(st.y,st.x)+step(-st.x,st.y);" - "float circ_arrow = step(st.x,4.0*st.y-0.75)*step(0.25*st.y-0.34,st.x)*(1.-tri_mask);" + "float top = step(abs(y-f),0.2*1.2*spacing);" + "float d = clamp(top+b+c,0.0,0.9)*mask;" + "if (d == 0.0) discard;" + "FragColor = vec4(color.xyz,d*color.w);" + "}" + ) - "float circmask = step(distance(st,orig),0.1)+step(0.5,distance(st,orig))+step(st.x,0.);" - "float body = step(-0.03,st.y)*step(st.y,0.03)*step(-0.3,x)*step(x,0.576);" - "float body_arrow = step(-0.5+3.*st.y,x)*step(-0.5-3.*st.y,x)*step(x,-0.3);" - "float d = clamp(circmask*(body+body_arrow)+circ_arrow+circ*tri_mask,0.,1.);" + if pattern == "moment": + shader_info.fragment_source( + "void main()" + "{" + "float x = step(co.y,0.)*(co.x)+step(0.,co.y)*(co.z-co.x);" + "float y = step(co.y,-0.00001)*(co.y)+step(0.,co.y)*(0.-co.y);" + "x = mod((0.5/spacing)*x,1.4)-0.7;" + "y = mod((0.5/spacing)*y,1.4)-0.7;" + "float abs_y = abs(y);" + "vec2 st = vec2(1.9*x,y);" + "vec2 orig = vec2(0.,0.);" + + "float circ = step(distance(st,orig),0.33)*step(0.27,distance(st,orig));" + "float tri_mask = step(st.y,st.x)+step(-st.x,st.y);" + "float circ_arrow = step(st.x,4.0*st.y-0.75)*step(0.25*st.y-0.34,st.x)*(1.-tri_mask);" - "float sinvalue = forces.x;" - "float quadraticvalue = forces.y;" - "float linearvalue = forces.z;" - "x = co.x/co.z;" - "float f = (sin(x*3.1416)*sinvalue" - "+(-4.*x*x+4.*x)*quadraticvalue" - "+linearvalue)/maxload;" - "float mask = step(0.,co.y)*step(co.y,f)+step(co.y,0.)*step(f,co.y);" - - "float top = step(abs(co.y-f),0.2*1.2*spacing);" + "float circmask = step(distance(st,orig),0.1)+step(0.5,distance(st,orig))+step(st.x,0.);" + "float body = step(-0.03,st.y)*step(st.y,0.03)*step(-0.3,x)*step(x,0.576);" + "float body_arrow = step(-0.5+3.*st.y,x)*step(-0.5-3.*st.y,x)*step(x,-0.3);" + "float d = clamp(circmask*(body+body_arrow)+circ_arrow+circ*tri_mask,0.,1.);" - "d = clamp(0.1+top+d,0.0,0.5)*mask;" - "if (d == 0.0) discard;" - "FragColor = vec4(color.xyz,d*color.w);" - "}" - ) + "float sinvalue = forces.x;" + "float quadraticvalue = forces.y;" + "float linearvalue = forces.z;" + "x = co.x/co.z;" + "float f = (sin(x*3.1416)*sinvalue" + "+(-4.*x*x+4.*x)*quadraticvalue" + "+linearvalue)/maxload;" + "float mask = step(0.,co.y)*step(co.y,f)+step(co.y,0.)*step(f,co.y);" - shader = gpu.shader.create_from_info(shader_info) - del vert_out - del shader_info - return shader + "float top = step(abs(co.y-f),0.2*1.2*spacing);" + + "d = clamp(top+d,0.0,0.9)*mask;" + "if (d == 0.0) discard;" + "FragColor = vec4(color.xyz,d*color.w);" + "}" + ) + + shader = gpu.shader.create_from_info(shader_info) + del vert_out + del shader_info + return shader def get_point_shader(self, pattern): """ param: pattern: type of pattern in ["arrow", "circ arrow"] @@ -212,6 +380,220 @@ class ShaderInfo: del vert_out del shader_info return shader + + def get_planar_shader(self): + """ param: pattern: type of pattern in ["force", "force match", "moment"] + return: shader""" + #if self.shader_type == "DistributedLoad": + vert_out = gpu.types.GPUStageInterfaceInfo("my_interface") + vert_out.smooth('VEC3', "co") + + shader_info = gpu.types.GPUShaderCreateInfo() + shader_info.push_constant('MAT4', "viewProjectionMatrix") + shader_info.push_constant('VEC4', "color") + shader_info.push_constant('FLOAT', "spacing") + + shader_info.vertex_in(0, 'VEC3', "position") + shader_info.vertex_in(1, 'VEC3', "coord") + + shader_info.vertex_out(vert_out) + shader_info.fragment_out(0, 'VEC4', "FragColor") + + shader_info.vertex_source( + "void main()" + "{" + " gl_Position = viewProjectionMatrix * vec4(position, 1.0f);" + " co = coord;" + "}" + ) + + shader_info.fragment_source( + "void main()" + "{" + "float x = co.x;" + "float y = co.y;" + "float abs_y = abs(y);" + + "float a = abs(mod(x,spacing)-0.5*spacing)*5.0;" + "float b = step(a,abs_y)*(step(abs_y,1.2*spacing));" + "float c = step(0.8*spacing,mod(x+0.4*spacing,spacing))*(step(1.2*spacing,abs_y));" + + + "float mask = step(0.,y)*step(y,0.98)+step(y,0.)*step(0.98,y);" + + "float top = step(abs(y-0.98),0.2*1.2*spacing);" + "float d = clamp(0.2*y+(top+b+c)*mask,0.0,0.4);" + "FragColor = vec4(color.xyz,d*color.w);" + "}" + )#"float d = clamp(0.1+top+b+c,0.0,0.4);" + + shader = gpu.shader.create_from_info(shader_info) + del vert_out + del shader_info + return shader + + def get_planar_loads(self): + list_of_surfaces = self.surface_members + shader = self.get_planar_shader() + for value in list_of_surfaces.values(): + surf = value["element"] + activity_list = [getattr(a, 'RelatedStructuralActivity', None) for a in getattr(surf, 'AssignedStructuralActivity', None) + if getattr(a, 'RelatedStructuralActivity', None).is_a() in ['IfcStructuralPlanarAction','IfcStructuralSurfaceAction']] + if len(activity_list) == 0: + continue + blender_object: bpy.types.Object = IfcStore.get_element(getattr(surf, 'GlobalId', None)) + mat = blender_object.matrix_world + mesh: bpy.types.Mesh = blender_object.data + z = Vector((0,0,1)) + positions = [] + indices = [] + coord = [] + for p in mesh.polygons: + add_index = len(positions) + for i, v in enumerate(p.vertices): + p1 = mesh.vertices[v].co + positions.append(p1) + p2 = p1 + z + positions.append(p2) + if i == 0: + coord.append((0,0,1)) + coord.append((0,1,1)) + else: + vec = positions[-1] - positions [-3] + l = vec.length + coord.append((l,0,1)) + coord.append((l,1,1)) + add = add_index+2*i + indices.append((0+add,2+add,1+add)) + indices.append((1+add,2+add,3+add)) + length = len(p.vertices)-1 + indices.append((length+add_index-1,length+add_index,0+add_index)) + indices.append((length+add_index,0+add_index,1+add_index)) + indices.append((1+add_index,3+add_index,5+add_index)) + if len(p.vertices) > 3: + indices.append((1+add_index,5+add_index,7+add_index)) + + self.info.append( + { + "shader": shader, + "args": {"position": positions, "coord": coord}, + "indices": indices, + "uniforms": [["color", (0.2,0,1,1)],["spacing", 0.2]] + } + ) + + def get_planar_loads_2(self): + list_of_surfaces = self.surface_members + shader = self.get_planar_shader() + maximum = 0 + for value in list_of_surfaces.values(): + surf = value["member"] + activity_list = [getattr(a, 'RelatedStructuralActivity', None) for a in getattr(surf, 'AssignedStructuralActivity', None) + if getattr(a, 'RelatedStructuralActivity', None).is_a() in ['IfcStructuralPlanarAction','IfcStructuralSurfaceAction']] + activity_list = value["activities"] + if len(activity_list) == 0: + continue + values = self.get_planar_loads_values(activity_list) + if maximum == 0: + maximum = max([abs(float(i)) for i in values]) + if maximum == 0: + continue + blender_object: bpy.types.Object = IfcStore.get_element(getattr(surf, 'GlobalId', None)) + mat = blender_object.matrix_world + mesh: bpy.types.Mesh = blender_object.data + rotation = self.get_surface_member_rotation(surf) + x = rotation @ (np.array((1,0,0))*0.2) + y = rotation @ (np.array((0,1,0))*0.2) + z = rotation @ (np.array((0,0,1))*0.2) + + positions = [] + indices = [] + coord = [] + bm = bmesh.new() + bm.from_mesh(mesh) + bmesh.ops.triangulate(bm, faces = bm.faces) + bm.edges.ensure_lookup_table() + bm.verts.ensure_lookup_table() + bm.faces.ensure_lookup_table() + + add_index = len(positions) + for v in bm.verts: + p1 = np.array(mat @ v.co) + positions.append(p1) + p2 = p1 - (rotation@values)*0.2/maximum + positions.append(p2) + coord.append((float(p1[0]+p1[1]),0,1)) + coord.append((float(p1[0]+p1[1]),1,1)) + for e in bm.edges: + if len(e.link_faces) > 1: + continue + indices.append((2*e.verts[0].index, + 2*e.verts[0].index+1, + 2*e.verts[1].index)) + indices.append((2*e.verts[0].index+1, + 2*e.verts[1].index, + 2*e.verts[1].index+1)) + for p in bm.faces: + indices.append((2*p.verts[0].index+1, + 2*p.verts[1].index+1, + 2*p.verts[2].index+1)) + bmesh.ops.dissolve_limit(bm, angle_limit = 0.01, verts = bm.verts, edges = bm.edges) + bm.faces.ensure_lookup_table() + center = bm.faces[0].calc_center_bounds() + + self.text_info.append( + {"position": mat @ center - Vector((rotation@values)*0.2/maximum), + "normal": Vector(mesh.polygons[0].normal), + "text": f'{values[2]:.5f} {self.planar_force_unit}'} + ) + + self.info.append( + { + "shader": shader, + "args": {"position": positions, "coord": coord}, + "indices": indices, + "uniforms": [["color", (0.2,0,1,1)],["spacing", 0.2]] + } + ) + def get_planar_loads_values(self, activity_list): + values = np.zeros((3)) + for item in activity_list: + activity = item[0] + factor = item[1] + load = activity.AppliedLoad + temp = np.zeros((3)) + if load is not None and load.is_a("IfcStructuralLoadPlanarForce"): + temp[0] = load.PlanarForceX if load.PlanarForceX is not None else 0 + temp[1] = load.PlanarForceY if load.PlanarForceY is not None else 0 + temp[2] = load.PlanarForceZ if load.PlanarForceZ is not None else 0 + temp = temp*factor + values = values + temp + return values + + def get_surface_member_rotation(self,surface_member): + representation = ifcopenshell.util.representation.get_representation(surface_member, "Model") + repr_item = representation.Items[0] + placement = ifcopenshell.util.placement.get_axis2placement(repr_item.FaceSurface.Position) + rotation = placement[0:3,0:3] + return rotation + + def get_point_connection_rotation(self, point_connection): + if point_connection.ConditionCoordinateSystem is not None: + placement = ifcopenshell.util.placement.get_axis2placement(point_connection.ConditionCoordinateSystem) + else: + placement = np.eye(4) + rotation = placement[0:3,0:3] + return rotation + + def get_curve_member_rotation(self, curve_member): + z = curve_member.Axis.DirectionRatios + edge = curve_member.Representation.Representations[0].Items[0] + origin = edge.EdgeStart.VertexGeometry.Coordinates + end = edge.EdgeEnd.VertexGeometry.Coordinates + x = [c2 - c1 for c1, c2 in zip(origin, end)] + placement = ifcopenshell.util.placement.a2p(origin,z,x) + rotation = placement[0:3,0:3] + return rotation def get_point_loads(self): list_of_point_connections = tool.Ifc.get().by_type("IfcStructuralPointConnection") @@ -223,9 +605,9 @@ class ShaderInfo: blender_object = IfcStore.get_element(getattr(conn, 'GlobalId', None)) if blender_object.type == 'MESH': conn_location = blender_object.matrix_world @ blender_object.data.vertices[0].co - #get local coordinates of the connection - loads = self.get_point_loads_list(activity_list) - self.get_point_shader_args(loads, conn_location) + #get local coordinates of the connection + loads = self.get_point_loads_list(activity_list) + self.get_point_shader_args(loads, conn_location) def get_point_shader_args(self,loads, location): indices = [] @@ -288,7 +670,7 @@ class ShaderInfo: "shader": shader, "args": {"position": position,"coord": coords_for_shader}, "indices": indices, - "uniforms": [["color", color]]#,["spacing", 0.2]] + "uniforms": [["color", color]] } ) @@ -316,6 +698,7 @@ class ShaderInfo: info = [] list_of_curve_members = tool.Ifc.get().by_type("IfcStructuralCurveMember") + list_of_curve_members = self.curve_members for member in list_of_curve_members: activity_list = [getattr(a, 'RelatedStructuralActivity', None) for a in getattr(member, 'AssignedStructuralActivity', None) if getattr(a, 'RelatedStructuralActivity', None).is_a() in ['IfcStructuralCurveAction','IfcStructuralLinearAction']] @@ -403,7 +786,8 @@ class ShaderInfo: if func: text_info.append( {"position": -1*direction*func/maxforce + start_co + x_axis*current.x, - "normal": direction.cross(x_axis).normalized(), "text": f'{func:.2f} '} + "normal": direction.cross(x_axis).normalized(), + "text": f'{func:.2f} {self.linear_force_unit}'} ) maxforce = max(maxforce,abs(func)) position.append(positive) @@ -430,7 +814,8 @@ class ShaderInfo: if func: text_info.append( {"position": -1*direction*func/maxforce + start_co + x_axis*nextitem.x, - "normal": direction.cross(x_axis).normalized(), "text": f'{func:.2f} '} + "normal": direction.cross(x_axis).normalized(), + "text": f'{func:.2f} {self.linear_force_unit}'} ) maxforce = max(maxforce,abs(func)) position.append(positive) diff --git a/src/bonsai/bonsai/bim/module/structural/ui.py b/src/bonsai/bonsai/bim/module/structural/ui.py index 5374f898b9..23e075613c 100644 --- a/src/bonsai/bonsai/bim/module/structural/ui.py +++ b/src/bonsai/bonsai/bim/module/structural/ui.py @@ -465,8 +465,14 @@ class BIM_PT_show_structural_activities(Panel): row.operator( "bim.show_loads", text="Show loads" , - icon="FILTER", + icon="HIDE_OFF", ) + row = self.layout.row(align=True) + row.prop(self.props,"reference_frame") + row = self.layout.row(align=True) + row.prop(self.props,"activity_type") + row = self.layout.row(align=True) + row.prop(self.props,"load_group_to_show") class BIM_PT_structural_loads(Panel): From 3eb29af49654841da6bca51a3e4b04544effd853 Mon Sep 17 00:00:00 2001 From: Lucas Nascimento Date: Fri, 13 Dec 2024 10:56:45 -0300 Subject: [PATCH 34/61] seems to be working --- .../bonsai/bim/module/structural/data.py | 24 +- .../bonsai/bim/module/structural/decorator.py | 2 + .../bonsai/bim/module/structural/operator.py | 6 +- .../bonsai/bim/module/structural/prop.py | 6 +- .../bonsai/bim/module/structural/shader.py | 785 ++++++++++-------- 5 files changed, 447 insertions(+), 376 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/structural/data.py b/src/bonsai/bonsai/bim/module/structural/data.py index 118b8b1eb7..bef238f92e 100644 --- a/src/bonsai/bonsai/bim/module/structural/data.py +++ b/src/bonsai/bonsai/bim/module/structural/data.py @@ -52,13 +52,23 @@ class LoadGroupDecorationData: } models = tool.Ifc.get().by_type("IfcStructuralAnalysisModel") m = models[0] - groups = m.LoadedBy or [] - for g in groups: - ret.append((str(g.id()),". "+abrv[g.PredefinedType]+" "+g.Name,"")) - related_objects = [rel.RelatedObjects for rel in g.IsGroupedBy] - for item in related_objects: - for subgoup in [sg for sg in item if sg.is_a("IfcStructuralLoadGroup")]: - ret.append((str(subgoup.id()),". "+abrv[subgoup.PredefinedType]+subgoup.Name,"")) + props = bpy.context.scene.BIMStructuralProperties + if props.activity_type == "Action": + groups = m.LoadedBy or [] + for g in groups: + ret.append((str(g.id()),". "+abrv[g.PredefinedType]+" "+g.Name,"")) + related_objects = [rel.RelatedObjects for rel in g.IsGroupedBy] + for item in related_objects: + for subgoup in [sg for sg in item if sg.is_a("IfcStructuralLoadGroup")]: + ret.append((str(subgoup.id()),". "+abrv[subgoup.PredefinedType]+subgoup.Name,"")) + + if props.activity_type == "External Reaction": + groups = m.HasResults or [] + for g in groups: + result_name = g.ResultForLoadGroup.Name or "" + group_name = g.Name or "" + ret.append((str(g.id()), group_name + " " + result_name,"")) + if len(ret) == 0: ret.append(("","","")) return ret diff --git a/src/bonsai/bonsai/bim/module/structural/decorator.py b/src/bonsai/bonsai/bim/module/structural/decorator.py index e8fab591d0..ccd6b848c6 100644 --- a/src/bonsai/bonsai/bim/module/structural/decorator.py +++ b/src/bonsai/bonsai/bim/module/structural/decorator.py @@ -108,6 +108,8 @@ class LoadsDecorator: def location_3d_to_region_2d(self, coord, normal, context): """Convert from 3D space to 2D screen space""" + coord = Vector(coord) + normal = Vector(normal) rv3d = context.region_data perspective = rv3d.view_perspective view_matrix = rv3d.view_matrix diff --git a/src/bonsai/bonsai/bim/module/structural/operator.py b/src/bonsai/bonsai/bim/module/structural/operator.py index ef2a221819..4070c6ae35 100644 --- a/src/bonsai/bonsai/bim/module/structural/operator.py +++ b/src/bonsai/bonsai/bim/module/structural/operator.py @@ -52,7 +52,11 @@ class ShowLoads(bpy.types.Operator): collection = bpy.data.collections["IfcStructuralItem"] collection.hide_viewport = False context.window.cursor_modal_set("WAIT") - LoadsDecorator.install(context) + try: + LoadsDecorator.install(context) + except Exception as exc: + context.window.cursor_modal_restore() + raise exc context.window.cursor_modal_restore() context.window_manager.modal_handler_add(self) for area in context.screen.areas: diff --git a/src/bonsai/bonsai/bim/module/structural/prop.py b/src/bonsai/bonsai/bim/module/structural/prop.py index 3c5fad7d2f..11d2da1a2f 100644 --- a/src/bonsai/bonsai/bim/module/structural/prop.py +++ b/src/bonsai/bonsai/bim/module/structural/prop.py @@ -39,6 +39,9 @@ def get_load_groups_to_show(self, context): LoadGroupDecorationData.load() return LoadGroupDecorationData.data["load groups to show"] +def update_activity_type(self, context): + LoadGroupDecorationData.is_loaded = False + def get_applicable_structural_load_types(self, context): if not StructuralLoadCasesData.is_loaded: StructuralLoadCasesData.load() @@ -164,7 +167,8 @@ class BIMStructuralProperties(PropertyGroup): activity_type: EnumProperty(items=[("Action","Actions","Show actions loads"), ("External Reaction","External Reactions","Show reactions on boundary conditions"), ("Internal Reactions","Internal Reactions","Show internal reactions on members")], - name="Activity Type") + name="Activity Type", + update=update_activity_type) load_group_to_show: EnumProperty(items=get_load_groups_to_show, name="Load Groups") diff --git a/src/bonsai/bonsai/bim/module/structural/shader.py b/src/bonsai/bonsai/bim/module/structural/shader.py index 0f50e89216..626cc9f3a9 100644 --- a/src/bonsai/bonsai/bim/module/structural/shader.py +++ b/src/bonsai/bonsai/bim/module/structural/shader.py @@ -18,8 +18,8 @@ class ShaderInfo: #self.shader_type = shader_type #self.args = {} #self.indices = [] - self.curve_members = [] - self.point_members = [] + self.curve_members = {} + self.point_members = {} self.surface_members = {} self.text_info = [] self.info = [] @@ -29,6 +29,10 @@ class ShaderInfo: def update(self): self.info = [] + self.text_info = [] + self.curve_members = {} + self.point_members = {} + self.surface_members = {} self.get_force_units() self.get_strucutural_elements_and_activities() self.get_linear_loads() @@ -160,14 +164,15 @@ class ShaderInfo: else: member["activities"].append((activity,factor)) - def recursive_subgroups(groups, rec_limit, factor = 1): + def recursive_subgroups(groups, rec_limit, activity_type, factor = 1): if len(groups) == 0 or rec_limit == 0: return None for group in groups: subgorups = [] activities = [] relationship = [rel for rel in group.IsGroupedBy] - group_coef = group.Coefficient if group.Coefficient is not None else 1.0 + coef = getattr(group, 'Coefficient', 1.0) + group_coef = coef if coef is not None else 1.0 rel_factor = 1.0 for rel in relationship: @@ -181,19 +186,28 @@ class ShaderInfo: if len(activity.AssignedToStructuralItem): element = activity.AssignedToStructuralItem[0].RelatingElement if element is not None: - if element.is_a("IfcStructuralCurveMember"): - self.curve_members.append(element) - elif element.is_a("IfcStructuralPoinConnection"): - self.point_members.append(element) - elif element.is_a("IfcStructuralSurfaceMember"): - populate_members_dict("surface_members",element,activity,factor) - recursive_subgroups(subgorups,rec_limit-1,factor=factor) + if activity_type == "Action": + if element.is_a("IfcStructuralCurveMember"): + populate_members_dict("curve_members",element,activity,factor) + elif element.is_a("IfcStructuralPointConnection"): + populate_members_dict("point_members",element,activity,factor) + elif element.is_a("IfcStructuralSurfaceMember"): + populate_members_dict("surface_members",element,activity,factor) + + elif activity_type == "External Reaction" and getattr(element,"AppliedCondition",None) is not None: + if element.is_a("IfcStructuralCurveMember"): + populate_members_dict("curve_members",element,activity,factor) + elif element.is_a("IfcStructuralPointConnection"): + populate_members_dict("point_members",element,activity,factor) + elif element.is_a("IfcStructuralSurfaceMember"): + populate_members_dict("surface_members",element,activity,factor) + recursive_subgroups(subgorups,rec_limit-1,activity_type,factor=factor) props = bpy.context.scene.BIMStructuralProperties group_definition_id = int(props.load_group_to_show) file = IfcStore.get_file() groups = [file.by_id(group_definition_id)] - recursive_subgroups(groups,10) + recursive_subgroups(groups,10,props.activity_type) def get_shader(self, pattern): @@ -431,56 +445,6 @@ class ShaderInfo: del vert_out del shader_info return shader - - def get_planar_loads(self): - list_of_surfaces = self.surface_members - shader = self.get_planar_shader() - for value in list_of_surfaces.values(): - surf = value["element"] - activity_list = [getattr(a, 'RelatedStructuralActivity', None) for a in getattr(surf, 'AssignedStructuralActivity', None) - if getattr(a, 'RelatedStructuralActivity', None).is_a() in ['IfcStructuralPlanarAction','IfcStructuralSurfaceAction']] - if len(activity_list) == 0: - continue - blender_object: bpy.types.Object = IfcStore.get_element(getattr(surf, 'GlobalId', None)) - mat = blender_object.matrix_world - mesh: bpy.types.Mesh = blender_object.data - z = Vector((0,0,1)) - positions = [] - indices = [] - coord = [] - for p in mesh.polygons: - add_index = len(positions) - for i, v in enumerate(p.vertices): - p1 = mesh.vertices[v].co - positions.append(p1) - p2 = p1 + z - positions.append(p2) - if i == 0: - coord.append((0,0,1)) - coord.append((0,1,1)) - else: - vec = positions[-1] - positions [-3] - l = vec.length - coord.append((l,0,1)) - coord.append((l,1,1)) - add = add_index+2*i - indices.append((0+add,2+add,1+add)) - indices.append((1+add,2+add,3+add)) - length = len(p.vertices)-1 - indices.append((length+add_index-1,length+add_index,0+add_index)) - indices.append((length+add_index,0+add_index,1+add_index)) - indices.append((1+add_index,3+add_index,5+add_index)) - if len(p.vertices) > 3: - indices.append((1+add_index,5+add_index,7+add_index)) - - self.info.append( - { - "shader": shader, - "args": {"position": positions, "coord": coord}, - "indices": indices, - "uniforms": [["color", (0.2,0,1,1)],["spacing", 0.2]] - } - ) def get_planar_loads_2(self): list_of_surfaces = self.surface_members @@ -493,19 +457,21 @@ class ShaderInfo: activity_list = value["activities"] if len(activity_list) == 0: continue - values = self.get_planar_loads_values(activity_list) + rotation = self.get_surface_member_rotation(surf) + values = self.get_planar_loads_values(activity_list,rotation) if maximum == 0: maximum = max([abs(float(i)) for i in values]) if maximum == 0: continue + props = bpy.context.scene.BIMStructuralProperties + reference_frame = props.reference_frame + orientation = np.eye(3) + if reference_frame == "LOCAL_COORDS": + orientation = rotation blender_object: bpy.types.Object = IfcStore.get_element(getattr(surf, 'GlobalId', None)) mat = blender_object.matrix_world mesh: bpy.types.Mesh = blender_object.data - rotation = self.get_surface_member_rotation(surf) - x = rotation @ (np.array((1,0,0))*0.2) - y = rotation @ (np.array((0,1,0))*0.2) - z = rotation @ (np.array((0,0,1))*0.2) - + positions = [] indices = [] coord = [] @@ -520,7 +486,7 @@ class ShaderInfo: for v in bm.verts: p1 = np.array(mat @ v.co) positions.append(p1) - p2 = p1 - (rotation@values)*0.2/maximum + p2 = p1 - (orientation@values)*0.2/maximum positions.append(p2) coord.append((float(p1[0]+p1[1]),0,1)) coord.append((float(p1[0]+p1[1]),1,1)) @@ -542,7 +508,7 @@ class ShaderInfo: center = bm.faces[0].calc_center_bounds() self.text_info.append( - {"position": mat @ center - Vector((rotation@values)*0.2/maximum), + {"position": mat @ center - Vector((orientation@values)*0.2/maximum), "normal": Vector(mesh.polygons[0].normal), "text": f'{values[2]:.5f} {self.planar_force_unit}'} ) @@ -555,7 +521,7 @@ class ShaderInfo: "uniforms": [["color", (0.2,0,1,1)],["spacing", 0.2]] } ) - def get_planar_loads_values(self, activity_list): + def get_planar_loads_values(self, activity_list,element_rotation_matrix): values = np.zeros((3)) for item in activity_list: activity = item[0] @@ -567,7 +533,8 @@ class ShaderInfo: temp[1] = load.PlanarForceY if load.PlanarForceY is not None else 0 temp[2] = load.PlanarForceZ if load.PlanarForceZ is not None else 0 temp = temp*factor - values = values + temp + transform = self.get_activity_transform_matrix(activity,element_rotation_matrix) + values += transform@temp return values def get_surface_member_rotation(self,surface_member): @@ -594,33 +561,60 @@ class ShaderInfo: placement = ifcopenshell.util.placement.a2p(origin,z,x) rotation = placement[0:3,0:3] return rotation + + def get_activity_transform_matrix(self, activity, element_rotation_matrix): + "provides the transformation matrix to convert between reference frames" + global_or_local = activity.GlobalOrLocal + props = bpy.context.scene.BIMStructuralProperties + reference_frame = props.reference_frame + transform_matrix = np.eye(3) + if reference_frame == 'LOCAL_COORDS' and global_or_local != reference_frame: + transform_matrix = np.linalg.inv(element_rotation_matrix) + elif reference_frame == 'GLOBAL_COORDS' and global_or_local != reference_frame: + transform_matrix = element_rotation_matrix + return transform_matrix def get_point_loads(self): list_of_point_connections = tool.Ifc.get().by_type("IfcStructuralPointConnection") - for conn in list_of_point_connections: + list_of_point_connections = self.point_members + for value in list_of_point_connections.values(): + conn = value["member"] activity_list = [getattr(a, 'RelatedStructuralActivity', None) for a in getattr(conn, 'AssignedStructuralActivity', None) if getattr(a, 'RelatedStructuralActivity', None).is_a() in ['IfcStructuralPointAction']] + activity_list = value["activities"] if len(activity_list) == 0: continue blender_object = IfcStore.get_element(getattr(conn, 'GlobalId', None)) if blender_object.type == 'MESH': conn_location = blender_object.matrix_world @ blender_object.data.vertices[0].co #get local coordinates of the connection - loads = self.get_point_loads_list(activity_list) - self.get_point_shader_args(loads, conn_location) + rotation = self.get_point_connection_rotation(conn) + loads = self.get_point_loads_values(activity_list, rotation) + self.get_point_shader_args(loads, conn_location, rotation) - def get_point_shader_args(self,loads, location): + def get_point_shader_args(self,loads, location, rotation): + location = np.array(location) indices = [] text_info = [] direction_dict = { - "fx": (Vector((1,0,0)),Vector((0,1,0)),Vector((0,0,1))), - "fy": (Vector((0,1,0)),Vector((1,0,0)),Vector((0,0,1))), - "fz": (Vector((0,0,1)),Vector((0,1,0)),Vector((1,0,0))), - "mx": (Vector((0,1,0)),Vector((0,0,1))), - "my": (Vector((1,0,0)),Vector((0,0,1))), - "mz": (Vector((1,0,0)),Vector((0,1,0))), + "fx": (np.array((1,0,0)),np.array((0,1,0)),np.array((0,0,1))), + "fy": (np.array((0,1,0)),np.array((1,0,0)),np.array((0,0,1))), + "fz": (np.array((0,0,1)),np.array((0,1,0)),np.array((1,0,0))), + "mx": (np.array((0,1,0)),np.array((0,0,1))), + "my": (np.array((1,0,0)),np.array((0,0,1))), + "mz": (np.array((1,0,0)),np.array((0,1,0))), } keys = ["fx","fy","fz","mx","my","mz"] + props = bpy.context.scene.BIMStructuralProperties + reference_frame = props.reference_frame + if reference_frame == "LOCAL_COORDS": + for key in keys: + tup = direction_dict[key] + li = [] + for item in tup: + li.append(rotation@item) + direction_dict[key] = li + for i, key in enumerate(keys): if loads[i] == 0: continue @@ -629,7 +623,8 @@ class ShaderInfo: color = (0,1,0,1) elif i in [2,5]: color = (0,0,1,1) - d1 = -(direction_dict[key][0]*loads[i]).normalized() + d1 = -(direction_dict[key][0]*loads[i]) + d1 = d1/np.linalg.norm(d1) if i < 3: d2 = direction_dict[key][1] d3 = direction_dict[key][2] @@ -653,6 +648,11 @@ class ShaderInfo: "uniforms": [["color", color],["spacing", 0.2]] } ) + self.text_info.append( + {"position": location + d1, + "normal": d2/np.linalg.norm(d2), + "text": f'{loads[i]:.2f} {self.force_unit}'} + ) else: d2 = d2 = direction_dict[key][1] p1 = location - d2 @@ -673,17 +673,29 @@ class ShaderInfo: "uniforms": [["color", color]] } ) + self.text_info.append( + {"position": location +0.25*(d1 + d2), + "normal": d2/np.linalg.norm(d2), + "text": f'{loads[i]:.2f} {self.force_unit}'}#change to moment unit + ) - - - def get_point_loads_list(self,activity_list): - result_list = [0,0,0,0,0,0] + def get_point_loads_values(self,activity_list,element_rotation_matrix): + result_list = np.zeros(6) attr_list = ['ForceX','ForceY','ForceZ','MomentX','MomentY','MomentZ'] - for activity in activity_list: + for item in activity_list: + activity = item[0] + factor = item[1] load = activity.AppliedLoad + temp = np.zeros(6) for i, attr in enumerate(attr_list): value = 0 if getattr(load, attr, 0) is None else getattr(load, attr, 0) - result_list[i] += value + temp[i] += value*factor + transform_3 = self.get_activity_transform_matrix(activity,element_rotation_matrix) + transform_6 = np.zeros((6,6)) + transform_6[0:3,0:3] = transform_3 + transform_6[3:6,3:6] = transform_3 + result_list += transform_6@temp + return result_list @@ -699,9 +711,11 @@ class ShaderInfo: list_of_curve_members = tool.Ifc.get().by_type("IfcStructuralCurveMember") list_of_curve_members = self.curve_members - for member in list_of_curve_members: + for value in list_of_curve_members.values(): + member = value["member"] activity_list = [getattr(a, 'RelatedStructuralActivity', None) for a in getattr(member, 'AssignedStructuralActivity', None) if getattr(a, 'RelatedStructuralActivity', None).is_a() in ['IfcStructuralCurveAction','IfcStructuralLinearAction']] + activity_list = value["activities"] if len(activity_list) == 0: continue # member is a structural curve member @@ -714,22 +728,25 @@ class ShaderInfo: # using blender just get the global coordinates of the first and second vertex in the mesh blender_object = IfcStore.get_element(getattr(member, 'GlobalId', None)) - if blender_object.type == 'MESH': - start_co = blender_object.matrix_world @ blender_object.data.vertices[0].co - end_co = blender_object.matrix_world @ blender_object.data.vertices[1].co + + start_co = blender_object.matrix_world @ blender_object.data.vertices[0].co + end_co = blender_object.matrix_world @ blender_object.data.vertices[1].co x_axis = Vector(end_co-start_co).normalized() z_direction = getattr(member, 'Axis') #local coordinates z_axis = Vector(getattr(z_direction, 'DirectionRatios', None)).normalized() y_axis = z_axis.cross(x_axis).normalized() z_axis = x_axis.cross(y_axis).normalized() - global_to_local = Matrix(((x_axis.x,y_axis.x,z_axis.x,0), - (x_axis.y,y_axis.y,z_axis.y,0), - (x_axis.z,y_axis.z,z_axis.z,0), - (0,0,0,1))) + rot = self.get_curve_member_rotation(member) + global_to_local = Matrix(((x_axis.x,y_axis.x,z_axis.x), + (x_axis.y,y_axis.y,z_axis.y), + (x_axis.z,y_axis.z,z_axis.z), + )) + global_to_local = Matrix(rot) #get shader args for each direction - reference_frame = 'GLOBAL_COORDS' #make it a scene property so it can be changed in a panel + props = bpy.context.scene.BIMStructuralProperties + reference_frame = props.reference_frame #make it a scene property so it can be changed in a panel is_local = reference_frame == 'LOCAL_COORDS' x_match = abs(Vector((1,0,0)).dot(x_axis)) > 0.99 y_match = abs(Vector((0,1,0)).dot(x_axis)) > 0.99 @@ -742,9 +759,18 @@ class ShaderInfo: "my": z_axis if is_local else Vector((-1,0,1)) if y_match else Vector((0,1,0)).cross(x_axis).normalized(), "mz": y_axis if is_local else Vector((-1,1,0)) if z_match else Vector((0,0,1)).cross(x_axis).normalized() } - match_dict = {'fx': x_match, 'fy': y_match, 'fz': z_match} + match_dict = {'fx': x_match or is_local, 'fy': y_match, 'fz': z_match} member_length = Vector(end_co-start_co).length - loads_dict, maxforce = get_loads_per_direction(activity_list,global_to_local,member_length) + loads_dict, maxforce, point_loads = self.get_loads_per_direction(activity_list,global_to_local,member_length) + if len(point_loads): + for item in point_loads: + for sub_item in item: + pos = sub_item["pos"] + values = sub_item["values"] + pos_vector = start_co + x_axis*pos + self.get_point_shader_args(values,pos_vector) + if loads_dict is None: + continue keys = ["fx","fy","fz","mx","my","mz"] for key in keys: @@ -843,280 +869,305 @@ class ShaderInfo: self.text_info = text_info -def get_loads_per_direction(activity_list,global_to_local,member_length): - """ returns a dict with values for applied loads in each direction - return = { - "fx": values_in_this_direction - "fy": values_in_this_direction - "fz": values_in_this_direction - "mx": values_in_this_direction - "my": values_in_this_direction - "mz": values_in_this_direction - } - values_in_this_direction = { - "constant": float, - "quadratic": float, - "sinus": float, - "polyline": list[(position: float, load: float),...] - } - """ - loads_dict = get_loads_dict(activity_list,global_to_local) - const = loads_dict["constant force"] - quad = loads_dict["quadratic force"] - sinus = loads_dict["sinus force"] - loads = loads_dict["load configuration"] - unique_list = getuniquepositionlist(loads) - final_list = [] - for pos in unique_list: - value = get_before_and_after(pos,loads) - if value["before"] == value["after"]: - final_list.append([pos]+value["before"]) - else: - final_list.append([pos]+value["before"]) - final_list.append([pos]+value["after"]) - - if not len(final_list) and any(const+quad+sinus): - final_list.append([0.0,0.0,0.0,0.0,0.0,0.0,0.0]) - final_list.append([member_length,0.0,0.0,0.0,0.0,0.0,0.0]) - - elif len(final_list): - if final_list[0][0] and any(const+quad+sinus): #if first item location is not 0 append an item at the zero - final_list = [[0.0,0.0,0.0,0.0,0.0,0.0,0.0]]+final_list - else: - del final_list[0] - if abs(final_list[-1][0] - member_length) > 0.01 and any(const+quad+sinus): - final_list.append([member_length,0.0,0.0,0.0,0.0,0.0,0.0]) - else: - del final_list[-1] - - array = np.array(final_list) #7xn -> ["pos","fx","fy","fz","mx","my","mz"] - keys = ["fx","fy","fz","mx","my","mz"] - polyline = { - "fx": [], - "fy": [], - "fz": [], - "mx": [], - "my": [], - "mz": [], - } - return_value = { - "fx": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, - "fy": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, - "fz": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, - "mx": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, - "my": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, - "mz": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, - } - max_load = 0 - for component, key in enumerate(keys): - if(any([sinus[component], quad[component], const[component]]) or - any(item for item in array[:,component+1])): - - for currentitem in final_list: - polyline[key].append([currentitem[0],currentitem[component+1]]) - x = currentitem[0]/member_length - func = sin(x*3.1416)*sinus[component] + (-4.*x*x+4.*x)*quad[component]+const[component]+currentitem[component+1] - max_load = max(max_load,abs(func)) - inner_dict = return_value[key] - inner_dict["constant"] = const[component] - inner_dict["quadratic"] = quad[component] - inner_dict["sinus"] = sinus[component] - inner_dict["polyline"] = polyline[key] - return_value[key] = inner_dict - - return return_value, max_load+abs(sinus[component]+quad[component]) - - -def getuniquepositionlist(load_config_list): - """return an ordereded list of unique locations based on the load configuration list - ex: load_config_list = [[{"pos":1.0,...},{"pos":3.0,...}], - [{"pos":2.0,...},{"pos":3.0,...}], - [{"pos":1.5,...},{"pos":2.5,...}]] - return = [1.0, 1.5, 2.0, 2.5, 3.0] - """ - unique = [] - for config in load_config_list: - for info in config: - if info["pos"] in unique: - continue - unique.append(info["pos"]) - unique.sort() - return unique - -def interp1d(l1,l2, pos): - """ 1d linear interpolation for the vector components""" - fac = (l2[1]-l1[1])/(l2[0]-l1[0]) - v = l1[1] + fac*(pos-l1[0]) - return v - -def interpolate(pos,loadinfo,start,end,key): - """ interpolate the result vectors between load poits""" - result = Vector((0,0,0)) - for i in range(3): - value1 = [loadinfo[start]["pos"], loadinfo[start][key][i]] #[position, force_component] - value2= [loadinfo[end]["pos"], loadinfo[end][key][i]] # [position, force_component] - result[i] = interp1d(value1,value2, pos) # interpolated [position, force_component] - return result - -def get_before_and_after(pos,load_config_list): - """ get total values for forces and moments with polilyne distribution - before and after the position - ex: load_config_list = [[{"pos":1.0,...,"forces":(1,0,0),...},{"pos":3.0,...,"forces":(3,0,0),...}], - [{"pos":2.0,...,"forces":(1,0,0),...},{"pos":3.0,...,"forces":(1,0,0),...}], - [{"pos":1.5,...,"forces":(1,0,0),...},{"pos":2.5,...,"forces":(1,0,0),...}]] - pos = 2.0 + def get_loads_per_direction(self,activity_list,global_to_local,member_length): + """ returns a dict with values for applied loads in each direction return = { - "before": (3,0,0,0,0,0), ->(fx, fy, fz, mx, my, mz) - " after": (4,0,0,0,0,0) ->(fx, fy, fz, mx, my, mz) - } - """ - force_before = Vector((0,0,0)) - force_after = Vector((0,0,0)) - moment_before = Vector((0,0,0)) - moment_after = Vector((0,0,0)) + "fx": values_in_this_direction + "fy": values_in_this_direction + "fz": values_in_this_direction + "mx": values_in_this_direction + "my": values_in_this_direction + "mz": values_in_this_direction + } + values_in_this_direction = { + "constant": float, + "quadratic": float, + "sinus": float, + "polyline": list[(position: float, load: float),...] + } + """ + loads_dict = self.get_loads_dict(activity_list,global_to_local) + const = loads_dict["constant force"] + quad = loads_dict["quadratic force"] + sinus = loads_dict["sinus force"] + loads = loads_dict["linear load configuration"] + unique_list = self.getuniquepositionlist(loads) + final_list = [] + return_value = None + max_load = 0 + for pos in unique_list: + value = self.get_before_and_after(pos,loads) + if value["before"] == value["after"]: + final_list.append([pos]+value["before"]) + else: + final_list.append([pos]+value["before"]) + final_list.append([pos]+value["after"]) + + if not len(final_list) and any(const+quad+sinus): + final_list.append([0.0,0.0,0.0,0.0,0.0,0.0,0.0]) + final_list.append([member_length,0.0,0.0,0.0,0.0,0.0,0.0]) + + elif len(final_list): + if final_list[0][0] and any(const+quad+sinus): #if first item location is not 0 append an item at the zero + final_list = [[0.0,0.0,0.0,0.0,0.0,0.0,0.0]]+final_list + else: + del final_list[0] + if abs(final_list[-1][0] - member_length) > 0.01 and any(const+quad+sinus): + final_list.append([member_length,0.0,0.0,0.0,0.0,0.0,0.0]) + else: + del final_list[-1] + if len(final_list): + array = np.array(final_list) #7xn -> ["pos","fx","fy","fz","mx","my","mz"] + keys = ["fx","fy","fz","mx","my","mz"] + polyline = { + "fx": [], + "fy": [], + "fz": [], + "mx": [], + "my": [], + "mz": [], + } + return_value = { + "fx": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, + "fy": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, + "fz": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, + "mx": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, + "my": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, + "mz": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, + } + max_load = 0 + for component, key in enumerate(keys): + if(any([sinus[component], quad[component], const[component]]) or + any(item for item in array[:,component+1])): - for config in load_config_list: - if pos < config[0]["pos"] or pos > config[-1]["pos"]: - continue - start = 0 - end = len(config)-1 - while end-start > 0: - if pos < config[start]["pos"] or pos > config[end]["pos"]: - break - if config[start]["pos"] == pos: - if config[start]["descr"] in ['start','middle']: - force_after += config[start]["forces"] - moment_after += config[start]["moments"] - elif config[start]["descr"] in ['end','middle']: - force_before += config[start]["forces"] - moment_before += config[start]["moments"] + for currentitem in final_list: + polyline[key].append([currentitem[0],currentitem[component+1]]) + x = currentitem[0]/member_length + func = sin(x*3.1416)*sinus[component] + (-4.*x*x+4.*x)*quad[component]+const[component]+currentitem[component+1] + max_load = max(max_load,abs(sinus[component]+quad[component]+const[component]+currentitem[component+1])) + inner_dict = return_value[key] + inner_dict["constant"] = const[component] + inner_dict["quadratic"] = quad[component] + inner_dict["sinus"] = sinus[component] + inner_dict["polyline"] = polyline[key] + return_value[key] = inner_dict - elif config[end]["pos"] == pos: - if config[end]["descr"] in ['start','middle']: - force_after += config[end]["forces"] - moment_after += config[end]["moments"] - elif config[end]["descr"] in ['end','middle']: - force_before += config[end]["forces"] - moment_before += config[end]["moments"] + return return_value, max_load, loads_dict["point load configuration"] - elif end-start == 1: - force_before += interpolate(pos,config,start,end,"forces") - force_after += interpolate(pos,config,start,end,"forces") - moment_before += interpolate(pos,config,start,end,"moments") - moment_after += interpolate(pos,config,start,end,"moments") - start += 1 - end -=1 - return_value = { - "before": [force_before.x,force_before.y,force_before.z, - moment_before.x,moment_before.y,moment_before.z], - "after": [force_after.x, force_after.y, force_after.z, - moment_after.x, moment_after.y, moment_after.z] - } - return return_value -def get_loads_dict(activity_list,global_to_local): + def getuniquepositionlist(self, load_config_list): + """return an ordereded list of unique locations based on the load configuration list + ex: load_config_list = [[{"pos":1.0,...},{"pos":3.0,...}], + [{"pos":2.0,...},{"pos":3.0,...}], + [{"pos":1.5,...},{"pos":2.5,...}]] + return = [1.0, 1.5, 2.0, 2.5, 3.0] """ - get load list - activity_list: list of IfcStructuralCurveAction or IfcStructuralCurveReaction - applied in the structural curve member - global_to_local: transformation matrix from global coordinates to local coordinetes - return: dict{ - "constant force": (fx,fy,fz,mx,my,mz), -> sum of linear loads applied with - constant distribution - "quadratic force": (fx,fy,fz,mx,my,mz), -> sum of linear loads applied with - quadratic distribution - "sinus force": (fx,fy,fz,mx,my,mz), -> sum of linear loads applied with - sinus distribution - "load configuration": list -> list of load configurations for linear - and polyline distributions of linear loads - } - description of "load configuration": - list[ -> one item (list)for each IfcStructuralCurveAction applied in the member - with IfcStructuralLoadConfiguration as the applied load - list[ -> one item (dict) for each item found in the - Locations attribute of IfcLoadConfiguration - dict{ - "pos": float, -> local position along curve length - "descr": string, -> describe if the item is at the start, middle or end of the list - "forces": Vector, -> linear force applied at that point - "moments": Vector -> linear moment applied at that point - } - ] - ] - """ - constant_force = Vector((0,0,0)) - constant_moment = Vector((0,0,0)) - quadratic_force = Vector((0,0,0)) - quadratic_moment = Vector((0,0,0)) - sinus_force = Vector((0,0,0)) - sinus_moment = Vector((0,0,0)) - load_configurations = [] + unique = [] + for config in load_config_list: + for info in config: + if info["pos"] in unique: + continue + unique.append(info["pos"]) + unique.sort() + return unique - unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get(),"LENGTHUNIT") + def interp1d(self,l1,l2, pos): + """ 1d linear interpolation for the vector components""" + fac = (l2[1]-l1[1])/(l2[0]-l1[0]) + v = l1[1] + fac*(pos-l1[0]) + return v - def get_force_vector(load,transform_matrix): - x = 0 if getattr(load, 'LinearForceX', 0) is None else getattr(load, 'LinearForceX', 0) - y = 0 if getattr(load, 'LinearForceY', 0) is None else getattr(load, 'LinearForceY', 0) - z = 0 if getattr(load, 'LinearForceZ', 0) is None else getattr(load, 'LinearForceZ', 0) - return transform_matrix @ Vector((x,y,z)) + def interpolate(self,pos,loadinfo,start,end,key): + """ interpolate the result vectors between load poits""" + result = Vector((0,0,0)) + for i in range(3): + value1 = [loadinfo[start]["pos"], loadinfo[start][key][i]] #[position, force_component] + value2= [loadinfo[end]["pos"], loadinfo[end][key][i]] # [position, force_component] + result[i] = self.interp1d(value1,value2, pos) # interpolated [position, force_component] + return result - def get_moment_vector(load,transform_matrix): - x = 0 if getattr(load, 'LinearMomentX', 0) is None else getattr(load, 'LinearMomentX', 0) - y = 0 if getattr(load, 'LinearMomentY', 0) is None else getattr(load, 'LinearMomentY', 0) - z = 0 if getattr(load, 'LinearMomentZ', 0) is None else getattr(load, 'LinearMomentZ', 0) - return transform_matrix @ Vector((x,y,z)) + def get_before_and_after(self,pos,load_config_list): + """ get total values for forces and moments with polilyne distribution + before and after the position + ex: load_config_list = [[{"pos":1.0,...,"forces":(1,0,0),...},{"pos":3.0,...,"forces":(3,0,0),...}], + [{"pos":2.0,...,"forces":(1,0,0),...},{"pos":3.0,...,"forces":(1,0,0),...}], + [{"pos":1.5,...,"forces":(1,0,0),...},{"pos":2.5,...,"forces":(1,0,0),...}]] + pos = 2.0 + return = { + "before": (3,0,0,0,0,0), ->(fx, fy, fz, mx, my, mz) + " after": (4,0,0,0,0,0) ->(fx, fy, fz, mx, my, mz) + } + """ + force_before = Vector((0,0,0)) + force_after = Vector((0,0,0)) + moment_before = Vector((0,0,0)) + moment_after = Vector((0,0,0)) - for activity in activity_list: - load = activity.AppliedLoad - global_or_local = activity.GlobalOrLocal - reference_frame = 'GLOBAL_COORDS' #make it a scene property so it can be changed in a panel - transform_matrix = Matrix() - if reference_frame == 'LOCAL_COORDS' and global_or_local != reference_frame: - transform_matrix = global_to_local - elif reference_frame == 'GLOBAL_COORDS' and global_or_local != reference_frame: - transform_matrix = global_to_local.invert() - #values for linear loads - if load.is_a('IfcStructuralLoadConfiguration'): - locations = getattr(load, 'Locations', []) - values = [l for l in getattr(load, 'Values', None) - if l.is_a() == "IfcStructuralLoadLinearForce" - ] - config_list = [] - for i,l in enumerate(values): - forcevalues = get_force_vector(l,transform_matrix) - momentvalues = get_moment_vector(l,transform_matrix) - if i == 0: - descr = 'start' - elif i == len(values)-1: - descr = 'end' - else: - descr = 'middle' - config_list.append( - {"pos": locations[i][0]*unit_scale, - "descr": descr, - "forces":forcevalues, - "moments":momentvalues} - ) - load_configurations.append(config_list) - else: - forcevalues = get_force_vector(load,transform_matrix) - momentvalues = get_moment_vector(load,transform_matrix) - if 'CONST' == getattr(activity, 'PredefinedType', None) or activity.is_a('IfcStructuralLinearAction'): - constant_force += forcevalues - constant_moment += momentvalues - elif 'PARABOLA' == getattr(activity, 'PredefinedType', None): - quadratic_force += forcevalues - quadratic_moment += momentvalues - elif 'SINUS' == getattr(activity, 'PredefinedType', None): - sinus_force += forcevalues - sinus_moment += momentvalues - return_value = { - "constant force": [constant_force.x,constant_force.y,constant_force.z, - constant_moment.x,constant_moment.y,constant_moment.z], - "quadratic force": [quadratic_force.x,quadratic_force.y,quadratic_force.z, - quadratic_moment.x,quadratic_moment.y,quadratic_moment.z], - "sinus force": [sinus_force.x,sinus_force.y,sinus_force.z, - sinus_moment.x,sinus_moment.y,sinus_moment.z], - "load configuration": load_configurations - } - return return_value + for config in load_config_list: + if pos < config[0]["pos"] or pos > config[-1]["pos"]: + continue + start = 0 + end = len(config)-1 + while end-start > 0: + if pos < config[start]["pos"] or pos > config[end]["pos"]: + break + if config[start]["pos"] == pos: + if config[start]["descr"] in ['start','middle']: + force_after += config[start]["forces"] + moment_after += config[start]["moments"] + elif config[start]["descr"] in ['end','middle']: + force_before += config[start]["forces"] + moment_before += config[start]["moments"] + + elif config[end]["pos"] == pos: + if config[end]["descr"] in ['start','middle']: + force_after += config[end]["forces"] + moment_after += config[end]["moments"] + elif config[end]["descr"] in ['end','middle']: + force_before += config[end]["forces"] + moment_before += config[end]["moments"] + + elif end-start == 1: + force_before += self.interpolate(pos,config,start,end,"forces") + force_after += self.interpolate(pos,config,start,end,"forces") + moment_before += self.interpolate(pos,config,start,end,"moments") + moment_after += self.interpolate(pos,config,start,end,"moments") + start += 1 + end -=1 + return_value = { + "before": [force_before.x,force_before.y,force_before.z, + moment_before.x,moment_before.y,moment_before.z], + "after": [force_after.x, force_after.y, force_after.z, + moment_after.x, moment_after.y, moment_after.z] + } + return return_value + + def get_loads_dict(self,activity_list,element_rotation_matrix): + """ + get load list + activity_list: list of IfcStructuralCurveAction or IfcStructuralCurveReaction + applied in the structural curve member + global_to_local: transformation matrix from global coordinates to local coordinetes + return: dict{ + "constant force": (fx,fy,fz,mx,my,mz), -> sum of linear loads applied with + constant distribution + "quadratic force": (fx,fy,fz,mx,my,mz), -> sum of linear loads applied with + quadratic distribution + "sinus force": (fx,fy,fz,mx,my,mz), -> sum of linear loads applied with + sinus distribution + "lienar load configuration": list -> list of load configurations for linear + and polyline distributions of linear loads + } + description of "linear load configuration": + list[ -> one item (list)for each IfcStructuralCurveAction applied in the member + with IfcStructuralLoadConfiguration as the applied load + list[ -> one item (dict) for each item found in the + Locations attribute of IfcLoadConfiguration + dict{ + "pos": float, -> local position along curve length + "descr": string, -> describe if the item is at the start, middle or end of the list + "forces": Vector, -> linear force applied at that point + "moments": Vector -> linear moment applied at that point + } + ] + ] + """ + constant_force = Vector((0,0,0)) + constant_moment = Vector((0,0,0)) + quadratic_force = Vector((0,0,0)) + quadratic_moment = Vector((0,0,0)) + sinus_force = Vector((0,0,0)) + sinus_moment = Vector((0,0,0)) + linear_load_configurations = [] + point_load_configurations = [] + + unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get(),"LENGTHUNIT") + + def get_force_vector(load,transform_matrix,factor = 1.0): + x = 0 if getattr(load, 'LinearForceX', 0) is None else getattr(load, 'LinearForceX', 0) + y = 0 if getattr(load, 'LinearForceY', 0) is None else getattr(load, 'LinearForceY', 0) + z = 0 if getattr(load, 'LinearForceZ', 0) is None else getattr(load, 'LinearForceZ', 0) + return transform_matrix @ (Vector((x,y,z))*factor) + + def get_moment_vector(load,transform_matrix,factor = 1.0): + x = 0 if getattr(load, 'LinearMomentX', 0) is None else getattr(load, 'LinearMomentX', 0) + y = 0 if getattr(load, 'LinearMomentY', 0) is None else getattr(load, 'LinearMomentY', 0) + z = 0 if getattr(load, 'LinearMomentZ', 0) is None else getattr(load, 'LinearMomentZ', 0) + return transform_matrix @ (Vector((x,y,z))*factor) + + for item in activity_list: + activity = item[0] + factor = item[1] + load = activity.AppliedLoad + global_or_local = activity.GlobalOrLocal + props = bpy.context.scene.BIMStructuralProperties + reference_frame = props.reference_frame #make it a scene property so it can be changed in a panel + transform_matrix = Matrix() + if reference_frame == 'LOCAL_COORDS' and global_or_local != reference_frame: + transform_matrix = element_rotation_matrix + transform_matrix.invert() + elif reference_frame == 'GLOBAL_COORDS' and global_or_local != reference_frame: + transform_matrix = element_rotation_matrix + #values for linear loads + if load.is_a('IfcStructuralLoadConfiguration'): + locations = getattr(load, 'Locations', []) + values = [l for l in getattr(load, 'Values', None) + if l.is_a() == "IfcStructuralLoadLinearForce" + ] + config_list = [] + for i,l in enumerate(values): + forcevalues = get_force_vector(l,transform_matrix,factor) + momentvalues = get_moment_vector(l,transform_matrix,factor) + if i == 0: + descr = 'start' + elif i == len(values)-1: + descr = 'end' + else: + descr = 'middle' + config_list.append( + {"pos": locations[i][0]*unit_scale, + "descr": descr, + "forces":forcevalues, + "moments":momentvalues} + ) + linear_load_configurations.append(config_list) + #load configurations with point loads + values = [l for l in getattr(load, 'Values', None) + if l.is_a() == "IfcStructuralLoadSingleForce" + ] + attr_list = ['ForceX','ForceY','ForceZ','MomentX','MomentY','MomentZ'] + config_list = [] + for i,load in enumerate(values): + result_list = [0,0,0,0,0,0] + for j, attr in enumerate(attr_list): + value = 0 if getattr(load, attr, 0) is None else getattr(load, attr, 0) + result_list[j] += value*factor + config_list.append( + {"pos": locations[i][0]*unit_scale, + "values": result_list} + ) + point_load_configurations.append(config_list) + + else: + forcevalues = get_force_vector(load,transform_matrix,factor) + momentvalues = get_moment_vector(load,transform_matrix,factor) + if 'CONST' == getattr(activity, 'PredefinedType', None) or activity.is_a('IfcStructuralLinearAction'): + constant_force += forcevalues + constant_moment += momentvalues + elif 'PARABOLA' == getattr(activity, 'PredefinedType', None): + quadratic_force += forcevalues + quadratic_moment += momentvalues + elif 'SINUS' == getattr(activity, 'PredefinedType', None): + sinus_force += forcevalues + sinus_moment += momentvalues + return_value = { + "constant force": [constant_force.x,constant_force.y,constant_force.z, + constant_moment.x,constant_moment.y,constant_moment.z], + "quadratic force": [quadratic_force.x,quadratic_force.y,quadratic_force.z, + quadratic_moment.x,quadratic_moment.y,quadratic_moment.z], + "sinus force": [sinus_force.x,sinus_force.y,sinus_force.z, + sinus_moment.x,sinus_moment.y,sinus_moment.z], + "linear load configuration": linear_load_configurations, + "point load configuration": point_load_configurations + } + return return_value From 6eee445502c8a6d9bae5c19af4a1415d668b2d2c Mon Sep 17 00:00:00 2001 From: Lucas Nascimento Date: Fri, 13 Dec 2024 12:10:19 -0300 Subject: [PATCH 35/61] Cleaning up and type hints --- .../bonsai/bim/module/structural/decorator.py | 67 +++++++++---------- 1 file changed, 31 insertions(+), 36 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/structural/decorator.py b/src/bonsai/bonsai/bim/module/structural/decorator.py index ccd6b848c6..f65a0e5999 100644 --- a/src/bonsai/bonsai/bim/module/structural/decorator.py +++ b/src/bonsai/bonsai/bim/module/structural/decorator.py @@ -7,35 +7,33 @@ import blf from bpy_extras import view3d_utils from bpy.types import SpaceView3D from gpu_extras.batch import batch_for_shader +from typing import Iterable, Union from bonsai.bim.module.structural.shader import ShaderInfo class LoadsDecorator: + """Decorator to show strucutural loads in 3D""" is_installed = False handlers = [] - linear_load_shader = None + decoration_data = None text_info = [] shader_info = [] depth_array = None @classmethod - def install(cls, context): + def install(cls, context: bpy.types.Context)-> None: if cls.is_installed: cls.uninstall() handler = cls() cls.handlers.append( SpaceView3D.draw_handler_add(handler.draw_load_values, ((context,)), "WINDOW", "POST_PIXEL") ) - #self.handlers.append(SpaceView3D.draw_handler_add(handler.draw_extra_info, (context,), "WINDOW", "POST_PIXEL")) - #self.handlers.append( - # SpaceView3D.draw_handler_add(handler.draw_curve_loads, (context,), "WINDOW", "POST_VIEW") - #) cls.handlers.append(SpaceView3D.draw_handler_add(handler, (), "WINDOW", "POST_VIEW")) - cls.linear_load_shader = ShaderInfo() + cls.decoration_data = ShaderInfo() cls.update(context) cls.is_installed = True @classmethod - def uninstall(cls): + def uninstall(cls)-> None: for handler in cls.handlers: try: SpaceView3D.draw_handler_remove(handler, "WINDOW") @@ -44,31 +42,28 @@ class LoadsDecorator: cls.is_installed = False @classmethod - def update(cls, context): - cls.linear_load_shader.update() - cls.text_info = cls.linear_load_shader.text_info - cls.shader_info = cls.linear_load_shader.info + def update(cls, context:bpy.types.Context) -> None: + cls.decoration_data.update() + cls.text_info = cls.decoration_data.text_info + cls.shader_info = cls.decoration_data.info - def __call__(self): + def __call__(self) -> None: + """set gpu configurations to draw 3D representations""" # set open gl configurations original_blend = gpu.state.blend_get() - gpu.state.blend_set('ALPHA') - original_depth_mask = gpu.state.depth_mask_get() - #gpu.state.depth_mask_set(True) original_depth_test = gpu.state.depth_test_get() + gpu.state.blend_set('ALPHA') gpu.state.depth_test_set('LESS_EQUAL') - self.draw_batch("DistributedLoad") + self.draw_batch() # restore opengl configurations gpu.state.blend_set(original_blend) - gpu.state.depth_mask_set(original_depth_mask) gpu.state.depth_test_set(original_depth_test) - def draw_batch(self,shader_type: str): - """ param: shader_type: type of shader in ["DistributedLoad", "PointLoad"]""" - - if not self.linear_load_shader.is_empty: + def draw_batch(self) -> None: + """draw the 3D representation of loads""" + if not self.decoration_data.is_empty: for info in self.shader_info: shader = info["shader"] args = info["args"] @@ -83,7 +78,10 @@ class LoadsDecorator: batch.draw(shader) - def draw_load_values(self, context): + def draw_load_values(self, context: bpy.types.Context) -> None: + """draw text representing the load values""" + #getting depth buffer info, code adapted from: + #https://blender.stackexchange.com/questions/177185/is-there-a-way-to-render-depth-buffer-into-a-texture-with-gpu-bgl-python-modules framebuffer = gpu.state.active_framebuffer_get() viewport_info = gpu.state.viewport_get() width = viewport_info[2] @@ -99,15 +97,17 @@ class LoadsDecorator: for info in self.text_info: text_position = self.location_3d_to_region_2d(info["position"],info["normal"],context) if text_position is not None: - font_id = 0 # , need to find out how best to get this. - # draw some text + font_id = 0 blf.position(font_id, text_position[0], text_position[1], text_position[2]) blf.size(font_id, 20.0) blf.color(font_id, 0.9, 0.9, 0.9, 1.0) blf.draw(font_id, info["text"]) - def location_3d_to_region_2d(self, coord, normal, context): - """Convert from 3D space to 2D screen space""" + def location_3d_to_region_2d(self, coord: Iterable, normal: Iterable, context: bpy.types.Context) -> Union[Vector,None]: + """Convert from 3D space to 2D screen space. + Filter out the text supposed to be hidden by 3D elements, using the depth array. + It also hides text that are distant from the camera view to avoid clutter""" + coord = Vector(coord) normal = Vector(normal) rv3d = context.region_data @@ -120,18 +120,13 @@ class LoadsDecorator: prj = rv3d.perspective_matrix @ Vector((coord[0], coord[1], coord[2], 1.0)) width_half = context.region.width / 2.0 height_half = context.region.height / 2.0 - co = Vector((width_half + width_half * (prj.x / prj.w), + coord_2d = Vector((width_half + width_half * (prj.x / prj.w), height_half + height_half * (prj.y / prj.w), point_view_space.z)) - if co[0]> context.region.width or co[1] > context.region.height or co[0] < 0 or co[1] < 0: + if coord_2d[0] < 0 or coord_2d[0]> context.region.width or coord_2d[1] > context.region.height or coord_2d[1] < 0: return None - depth = self.depth_array[int(co[1])][int(co[0])] + depth = self.depth_array[int(coord_2d[1])][int(coord_2d[0])] if -0.98*point_view_space.z > depth: return None - view_vector = view3d_utils.region_2d_to_vector_3d(context.region, rv3d, co) - angle = abs(0.5*pi-normal.angle(view_vector)) - #if small view angle betwen the load and viewport - if angle<0.05: - return None - return co + return coord_2d return None From aa21fe906093502d722943b5b3b1df0ca2f608ef Mon Sep 17 00:00:00 2001 From: Lucas Nascimento Date: Fri, 13 Dec 2024 17:07:53 -0300 Subject: [PATCH 36/61] separate shader file from decoration data --- .../bonsai/bim/module/structural/decorator.py | 2 +- .../module/structural/load_decoration_data.py | 937 +++++++++++++++ .../bonsai/bim/module/structural/shader.py | 1013 +---------------- .../bonsai/bim/module/structural/workspace.py | 4 +- 4 files changed, 1000 insertions(+), 956 deletions(-) create mode 100644 src/bonsai/bonsai/bim/module/structural/load_decoration_data.py diff --git a/src/bonsai/bonsai/bim/module/structural/decorator.py b/src/bonsai/bonsai/bim/module/structural/decorator.py index f65a0e5999..fcf9056a5f 100644 --- a/src/bonsai/bonsai/bim/module/structural/decorator.py +++ b/src/bonsai/bonsai/bim/module/structural/decorator.py @@ -8,7 +8,7 @@ from bpy_extras import view3d_utils from bpy.types import SpaceView3D from gpu_extras.batch import batch_for_shader from typing import Iterable, Union -from bonsai.bim.module.structural.shader import ShaderInfo +from bonsai.bim.module.structural.load_decoration_data import ShaderInfo class LoadsDecorator: """Decorator to show strucutural loads in 3D""" diff --git a/src/bonsai/bonsai/bim/module/structural/load_decoration_data.py b/src/bonsai/bonsai/bim/module/structural/load_decoration_data.py new file mode 100644 index 0000000000..bed81cf736 --- /dev/null +++ b/src/bonsai/bonsai/bim/module/structural/load_decoration_data.py @@ -0,0 +1,937 @@ +import bpy +import gpu +import bmesh +import numpy as np +from math import sin +from mathutils import Vector, Matrix +import ifcopenshell +import ifcopenshell.api +import ifcopenshell.util.attribute +import bonsai.tool as tool +from bonsai.bim.ifc import IfcStore +from bonsai.bim.module.structural.shader import DecorationShader + + +class ShaderInfo: + def __init__(self): + self.is_empty = True + self.shader = DecorationShader() + #self.shader_type = shader_type + #self.args = {} + #self.indices = [] + self.curve_members = {} + self.point_members = {} + self.surface_members = {} + self.text_info = [] + self.info = [] + self.force_unit = "" + self.linear_force_unit = "" + self.planar_force_unit = "" + + def update(self): + self.info = [] + self.text_info = [] + self.curve_members = {} + self.point_members = {} + self.surface_members = {} + self.get_force_units() + self.get_strucutural_elements_and_activities() + self.get_linear_loads() + self.get_point_loads() + self.get_planar_loads() + if len(self.info): + self.is_empty = False + + def get_force_units(self): + def get_unit_symbol(unit: ifcopenshell.entity_instance) -> str: + prefix_symbols = { + "EXA": "E", + "PETA": "P", + "TERA": "T", + "GIGA": "G", + "MEGA": "M", + "KILO": "k", + "HECTO": "h", + "DECA": "da", + "DECI": "d", + "CENTI": "c", + "MILLI": "m", + "MICRO": "μ", + "NANO": "n", + "PICO": "p", + "FEMTO": "f", + "ATTO": "a", + } + + unit_symbols = { + # si units + "CUBIC_METRE": "m3", + "GRAM": "g", + "SECOND": "s", + "SQUARE_METRE": "m2", + "METRE": "m", + "NEWTON": "N", + "PASCAL": "Pa", + # conversion based units + "pound-force": "lbf", + 'pound-force per square inch': "psi", + "thou": "th", + "inch": "in", + "foot": "ft", + "yard": "yd", + "mile": "mi", + "square thou": "th2", + "square inch": "in2", + "square foot": "ft2", + "square yard": "yd2", + "acre": "ac", + "square mile": "mi2", + "cubic thou": "th3", + "cubic inch": "in3", + "cubic foot": "ft3", + "cubic yard": "yd3", + "cubic mile": "mi3", + "litre": "L", + "fluid ounce UK": "fl oz", + "fluid ounce US": "fl oz", + "pint UK": "pt", + "pint US": "pt", + "gallon UK": "gal", + "gallon US": "gal", + "degree": "°", + "ounce": "oz", + "pound": "lb", + "ton UK": "ton", + "ton US": "ton", + "lbf": "lbf", + "kip": "kip", + "psi": "psi", + "ksi": "ksi", + "minute": "min", + "hour": "hr", + "day": "day", + "btu": "btu", + "fahrenheit": "°F", + } + symbol = "" + if unit.is_a("IfcSIUnit"): + symbol += prefix_symbols.get(unit.Prefix, "") + symbol += unit_symbols.get(unit.Name.replace("METER", "METRE"), "?") + return symbol + + force_units = [u for u in tool.Ifc.get().by_type("IfcNamedUnit") + if u.UnitType == "FORCEUNIT"] + linear_force_units = [u for u in tool.Ifc.get().by_type("IfcDerivedUnit") + if u.UnitType == "LINEARFORCEUNIT"] + planar_force_units = [u for u in tool.Ifc.get().by_type("IfcDerivedUnit") + if u.UnitType == "PLANARFORCEUNIT"] + + conversion_force_unit = [u for u in force_units if u.is_a("IfcConversionBasedUnit")] + if len(conversion_force_unit) == 0: + conversion_force_unit.append(force_units[0]) + self.force_unit = get_unit_symbol(conversion_force_unit[0]) + first = "" + second = "" + for e in linear_force_units[0].Elements: + if e.Unit.UnitType == "FORCEUNIT": + first = get_unit_symbol(e.Unit) + if e.Unit.UnitType == "LENGTHUNIT": + second = get_unit_symbol(e.Unit) + self.linear_force_unit = first + "/" + second + first = "" + second = "" + for e in planar_force_units[0].Elements: + if e.Unit.UnitType == "FORCEUNIT": + first = get_unit_symbol(e.Unit) + if e.Unit.UnitType == "LENGTHUNIT": + second = get_unit_symbol(e.Unit)+"2" + if e.Unit.UnitType == "AREAUNIT": + second = get_unit_symbol(e.Unit) + self.planar_force_unit = first + "/" + second + + def get_strucutural_elements_and_activities(self): + + def populate_members_dict(dict_name,element, activity, factor): + dic = getattr(self,dict_name,None) + if dic is None: + return + member = dic.get(element.GlobalId) + if member is None: + dic.update({ + element.GlobalId: { + "member": element, + "activities": [(activity,factor)]} + }) + else: + member["activities"].append((activity,factor)) + + def recursive_subgroups(groups, rec_limit, activity_type, factor = 1): + if len(groups) == 0 or rec_limit == 0: + return None + for group in groups: + subgorups = [] + activities = [] + relationship = [rel for rel in group.IsGroupedBy] + coef = getattr(group, 'Coefficient', 1.0) + group_coef = coef if coef is not None else 1.0 + rel_factor = 1.0 + + for rel in relationship: + if rel.is_a("IfcRelAssignsToGroupByFactor"): + rel_factor = rel.Factor if rel.Factor is not None else 1.0 + objects = rel.RelatedObjects + subgorups = [sg for sg in objects if sg.is_a("IfcStructuralLoadGroup")] + activities = [a for a in objects if a.is_a("IfcStructuralActivity")] + factor = factor*group_coef*rel_factor + for activity in activities: + if len(activity.AssignedToStructuralItem): + element = activity.AssignedToStructuralItem[0].RelatingElement + if element is not None: + if activity_type == "Action": + if element.is_a("IfcStructuralCurveMember"): + populate_members_dict("curve_members",element,activity,factor) + elif element.is_a("IfcStructuralPointConnection"): + populate_members_dict("point_members",element,activity,factor) + elif element.is_a("IfcStructuralSurfaceMember"): + populate_members_dict("surface_members",element,activity,factor) + + elif activity_type == "External Reaction" and getattr(element,"AppliedCondition",None) is not None: + if element.is_a("IfcStructuralCurveMember"): + populate_members_dict("curve_members",element,activity,factor) + elif element.is_a("IfcStructuralPointConnection"): + populate_members_dict("point_members",element,activity,factor) + elif element.is_a("IfcStructuralSurfaceMember"): + populate_members_dict("surface_members",element,activity,factor) + recursive_subgroups(subgorups,rec_limit-1,activity_type,factor=factor) + + props = bpy.context.scene.BIMStructuralProperties + group_definition_id = int(props.load_group_to_show) + file = IfcStore.get_file() + groups = [file.by_id(group_definition_id)] + recursive_subgroups(groups,10,props.activity_type) + + def get_planar_loads(self): + list_of_surfaces = self.surface_members + shader = self.shader.get("PLANAR LOAD") + maximum = 0 + for value in list_of_surfaces.values(): + surf = value["member"] + activity_list = [getattr(a, 'RelatedStructuralActivity', None) for a in getattr(surf, 'AssignedStructuralActivity', None) + if getattr(a, 'RelatedStructuralActivity', None).is_a() in ['IfcStructuralPlanarAction','IfcStructuralSurfaceAction']] + activity_list = value["activities"] + if len(activity_list) == 0: + continue + rotation = self.get_surface_member_rotation(surf) + values = self.get_planar_loads_values(activity_list,rotation) + if maximum == 0: + maximum = max([abs(float(i)) for i in values]) + if maximum == 0: + continue + props = bpy.context.scene.BIMStructuralProperties + reference_frame = props.reference_frame + orientation = np.eye(3) + if reference_frame == "LOCAL_COORDS": + orientation = rotation + blender_object: bpy.types.Object = IfcStore.get_element(getattr(surf, 'GlobalId', None)) + mat = blender_object.matrix_world + mesh: bpy.types.Mesh = blender_object.data + + positions = [] + indices = [] + coord = [] + bm = bmesh.new() + bm.from_mesh(mesh) + bmesh.ops.triangulate(bm, faces = bm.faces) + bm.edges.ensure_lookup_table() + bm.verts.ensure_lookup_table() + bm.faces.ensure_lookup_table() + + add_index = len(positions) + for v in bm.verts: + p1 = np.array(mat @ v.co) + positions.append(p1) + p2 = p1 - (orientation@values)*0.2/maximum + positions.append(p2) + coord.append((float(p1[0]+p1[1]),0,1)) + coord.append((float(p1[0]+p1[1]),1,1)) + for e in bm.edges: + if len(e.link_faces) > 1: + continue + indices.append((2*e.verts[0].index, + 2*e.verts[0].index+1, + 2*e.verts[1].index)) + indices.append((2*e.verts[0].index+1, + 2*e.verts[1].index, + 2*e.verts[1].index+1)) + for p in bm.faces: + indices.append((2*p.verts[0].index+1, + 2*p.verts[1].index+1, + 2*p.verts[2].index+1)) + bmesh.ops.dissolve_limit(bm, angle_limit = 0.01, verts = bm.verts, edges = bm.edges) + bm.faces.ensure_lookup_table() + center = bm.faces[0].calc_center_bounds() + + self.text_info.append( + {"position": mat @ center - Vector((orientation@values)*0.2/maximum), + "normal": Vector(mesh.polygons[0].normal), + "text": f'{values[2]:.5f} {self.planar_force_unit}'} + ) + + self.info.append( + { + "shader": shader, + "args": {"position": positions, "coord": coord}, + "indices": indices, + "uniforms": [["color", (0.2,0,1,1)],["spacing", 0.2]] + } + ) + def get_planar_loads_values(self, activity_list,element_rotation_matrix): + values = np.zeros((3)) + for item in activity_list: + activity = item[0] + factor = item[1] + load = activity.AppliedLoad + temp = np.zeros((3)) + if load is not None and load.is_a("IfcStructuralLoadPlanarForce"): + temp[0] = load.PlanarForceX if load.PlanarForceX is not None else 0 + temp[1] = load.PlanarForceY if load.PlanarForceY is not None else 0 + temp[2] = load.PlanarForceZ if load.PlanarForceZ is not None else 0 + temp = temp*factor + transform = self.get_activity_transform_matrix(activity,element_rotation_matrix) + values += transform@temp + return values + + def get_surface_member_rotation(self,surface_member): + representation = ifcopenshell.util.representation.get_representation(surface_member, "Model") + repr_item = representation.Items[0] + placement = ifcopenshell.util.placement.get_axis2placement(repr_item.FaceSurface.Position) + rotation = placement[0:3,0:3] + return rotation + + def get_point_connection_rotation(self, point_connection): + if point_connection.ConditionCoordinateSystem is not None: + placement = ifcopenshell.util.placement.get_axis2placement(point_connection.ConditionCoordinateSystem) + else: + placement = np.eye(4) + rotation = placement[0:3,0:3] + return rotation + + def get_curve_member_rotation(self, curve_member): + z = curve_member.Axis.DirectionRatios + edge = curve_member.Representation.Representations[0].Items[0] + origin = edge.EdgeStart.VertexGeometry.Coordinates + end = edge.EdgeEnd.VertexGeometry.Coordinates + x = [c2 - c1 for c1, c2 in zip(origin, end)] + placement = ifcopenshell.util.placement.a2p(origin,z,x) + rotation = placement[0:3,0:3] + return rotation + + def get_activity_transform_matrix(self, activity, element_rotation_matrix): + "provides the transformation matrix to convert between reference frames" + global_or_local = activity.GlobalOrLocal + props = bpy.context.scene.BIMStructuralProperties + reference_frame = props.reference_frame + transform_matrix = np.eye(3) + if reference_frame == 'LOCAL_COORDS' and global_or_local != reference_frame: + transform_matrix = np.linalg.inv(element_rotation_matrix) + elif reference_frame == 'GLOBAL_COORDS' and global_or_local != reference_frame: + transform_matrix = element_rotation_matrix + return transform_matrix + + def get_point_loads(self): + list_of_point_connections = tool.Ifc.get().by_type("IfcStructuralPointConnection") + list_of_point_connections = self.point_members + for value in list_of_point_connections.values(): + conn = value["member"] + activity_list = [getattr(a, 'RelatedStructuralActivity', None) for a in getattr(conn, 'AssignedStructuralActivity', None) + if getattr(a, 'RelatedStructuralActivity', None).is_a() in ['IfcStructuralPointAction']] + activity_list = value["activities"] + if len(activity_list) == 0: + continue + blender_object = IfcStore.get_element(getattr(conn, 'GlobalId', None)) + if blender_object.type == 'MESH': + conn_location = blender_object.matrix_world @ blender_object.data.vertices[0].co + #get local coordinates of the connection + rotation = self.get_point_connection_rotation(conn) + loads = self.get_point_loads_values(activity_list, rotation) + self.get_point_shader_args(loads, conn_location, rotation) + + def get_point_shader_args(self,loads, location, rotation): + location = np.array(location) + indices = [] + text_info = [] + direction_dict = { + "fx": (np.array((1,0,0)),np.array((0,1,0)),np.array((0,0,1))), + "fy": (np.array((0,1,0)),np.array((1,0,0)),np.array((0,0,1))), + "fz": (np.array((0,0,1)),np.array((0,1,0)),np.array((1,0,0))), + "mx": (np.array((0,1,0)),np.array((0,0,1))), + "my": (np.array((1,0,0)),np.array((0,0,1))), + "mz": (np.array((1,0,0)),np.array((0,1,0))), + } + keys = ["fx","fy","fz","mx","my","mz"] + props = bpy.context.scene.BIMStructuralProperties + reference_frame = props.reference_frame + if reference_frame == "LOCAL_COORDS": + for key in keys: + tup = direction_dict[key] + li = [] + for item in tup: + li.append(rotation@item) + direction_dict[key] = li + + for i, key in enumerate(keys): + if loads[i] == 0: + continue + color = (1,0,0,1) + if i in [1,4]: + color = (0,1,0,1) + elif i in [2,5]: + color = (0,0,1,1) + d1 = -(direction_dict[key][0]*loads[i]) + d1 = d1/np.linalg.norm(d1) + if i < 3: + d2 = direction_dict[key][1] + d3 = direction_dict[key][2] + p1 = location + p2 = location + d1 + d2 + p3 = location + d1 - d2 + p4 = location + d1 + d3 + p5 = location + d1 - d3 + position = [p1,p2,p3,p4,p5] + indices = [(0,1,2),(0,3,4)] + c1 = (0,0,0) + c2 = (1,1,0) + c3 = (-1,1,0) + coords_for_shader = [c1,c2,c3,c2,c3] + shader = self.shader.get("SINGLE FORCE") + self.info.append( + { + "shader": shader, + "args": {"position": position,"coord": coords_for_shader}, + "indices": indices, + "uniforms": [["color", color],["spacing", 0.2]] + } + ) + self.text_info.append( + {"position": location + d1, + "normal": d2/np.linalg.norm(d2), + "text": f'{loads[i]:.2f} {self.force_unit}'} + ) + else: + d2 = d2 = direction_dict[key][1] + p1 = location - d2 + p2 = location + d1 + d2 + p3 = location - d1 + d2 + position = [p1,p2,p3] + indices = [(0,1,2)] + c1 = (-1,0,0) + c2 = (1,1,0) + c3 = (1,-1,0) + coords_for_shader = [c1,c2,c3] + shader = self.shader.get("SINGLE MOMENT") + self.info.append( + { + "shader": shader, + "args": {"position": position,"coord": coords_for_shader}, + "indices": indices, + "uniforms": [["color", color]] + } + ) + self.text_info.append( + {"position": location +0.25*(d1 + d2), + "normal": d2/np.linalg.norm(d2), + "text": f'{loads[i]:.2f} {self.force_unit}'}#change to moment unit + ) + + def get_point_loads_values(self,activity_list,element_rotation_matrix): + result_list = np.zeros(6) + attr_list = ['ForceX','ForceY','ForceZ','MomentX','MomentY','MomentZ'] + for item in activity_list: + activity = item[0] + factor = item[1] + load = activity.AppliedLoad + temp = np.zeros(6) + for i, attr in enumerate(attr_list): + value = 0 if getattr(load, attr, 0) is None else getattr(load, attr, 0) + temp[i] += value*factor + transform_3 = self.get_activity_transform_matrix(activity,element_rotation_matrix) + transform_6 = np.zeros((6,6)) + transform_6[0:3,0:3] = transform_3 + transform_6[3:6,3:6] = transform_3 + result_list += transform_6@temp + + return result_list + + + def get_linear_loads(self): #for now it only works for distributed loads + position = [] + indices = [] + sin_quad_lin = [] + coords_for_shader = [] + color = [] + text_info = [] + uniforms = [] + info = [] + + list_of_curve_members = tool.Ifc.get().by_type("IfcStructuralCurveMember") + list_of_curve_members = self.curve_members + for value in list_of_curve_members.values(): + member = value["member"] + activity_list = [getattr(a, 'RelatedStructuralActivity', None) for a in getattr(member, 'AssignedStructuralActivity', None) + if getattr(a, 'RelatedStructuralActivity', None).is_a() in ['IfcStructuralCurveAction','IfcStructuralLinearAction']] + activity_list = value["activities"] + if len(activity_list) == 0: + continue + # member is a structural curve member + # get Axis attribute from member -> (IFCDIRECTION) + # get Representation attribute from member -> (IFCPRODUCTDEFINITIONSHAPE) + # get Representations attribute from Representation -> (IFCTOPOLOGYREPRESENTATION) + # get Items attribute from Representations -> (IFCEDGE) + # get EdgeStart attribute from Items -> (IFCVERTEX) + # get EdgeEnd attribure from Items -> (IFCVERTEX) + # using blender just get the global coordinates of the first and second vertex in the mesh + + blender_object = IfcStore.get_element(getattr(member, 'GlobalId', None)) + + start_co = blender_object.matrix_world @ blender_object.data.vertices[0].co + end_co = blender_object.matrix_world @ blender_object.data.vertices[1].co + x_axis = Vector(end_co-start_co).normalized() + z_direction = getattr(member, 'Axis') + #local coordinates + z_axis = Vector(getattr(z_direction, 'DirectionRatios', None)).normalized() + y_axis = z_axis.cross(x_axis).normalized() + z_axis = x_axis.cross(y_axis).normalized() + rot = self.get_curve_member_rotation(member) + global_to_local = Matrix(((x_axis.x,y_axis.x,z_axis.x), + (x_axis.y,y_axis.y,z_axis.y), + (x_axis.z,y_axis.z,z_axis.z), + )) + global_to_local = Matrix(rot) + + #get shader args for each direction + props = bpy.context.scene.BIMStructuralProperties + reference_frame = props.reference_frame #make it a scene property so it can be changed in a panel + is_local = reference_frame == 'LOCAL_COORDS' + x_match = abs(Vector((1,0,0)).dot(x_axis)) > 0.99 + y_match = abs(Vector((0,1,0)).dot(x_axis)) > 0.99 + z_match = abs(Vector((0,0,1)).dot(x_axis)) > 0.99 + direction_dict = { + "fx": y_axis+z_axis if is_local else Vector((1,0,0)) if not x_match else Vector((0,1,1)), + "fy": y_axis if is_local else Vector((0,1,0)) if not y_match else Vector((1,0,1)), + "fz": z_axis if is_local else Vector((0,0,1)) if not z_match else Vector((1,1,0)), + "mx": z_axis-y_axis if is_local or x_match else Vector((1,0,0)).cross(x_axis), + "my": z_axis if is_local else Vector((-1,0,1)) if y_match else Vector((0,1,0)).cross(x_axis).normalized(), + "mz": y_axis if is_local else Vector((-1,1,0)) if z_match else Vector((0,0,1)).cross(x_axis).normalized() + } + match_dict = {'fx': x_match or is_local, 'fy': y_match, 'fz': z_match} + member_length = Vector(end_co-start_co).length + loads_dict, maxforce, point_loads = self.get_loads_per_direction(activity_list,global_to_local,member_length) + if len(point_loads): + for item in point_loads: + for sub_item in item: + pos = sub_item["pos"] + values = sub_item["values"] + pos_vector = start_co + x_axis*pos + self.get_point_shader_args(values,pos_vector) + if loads_dict is None: + continue + keys = ["fx","fy","fz","mx","my","mz"] + + for key in keys: + polyline = loads_dict[key]["polyline"] + sinus = loads_dict[key]["sinus"] + quadratic = loads_dict[key]["quadratic"] + constant = loads_dict[key]["constant"] + direction = direction_dict[key] #depends on the key and on the frame of reference + color_axis = (0,0,1,1) + if 'x' in key: + color_axis = (1,0,0,1) + if 'y' in key: + color_axis = (0,1,0,1) + + if 'f' in key: + if match_dict[key]: + shader = self.shader.get("PARALLEL DISTRIBUTED FORCE") + else: + shader = self.shader.get("PERPENDICULAR DISTRIBUTED FORCE") + else: + shader = self.shader.get("DISTRIBUTED MOMENT") + + addindex = len(position) + counter = 0 + for i in range(len(polyline)-1): + current = Vector(polyline[i]+[0]) + nextitem = Vector(polyline[i+1]+[0]) + + if any([current.y, nextitem.y,constant,quadratic,sinus]): #if there is load in the z direction + negative = -1*direction + start_co + x_axis*current.x + positive = direction + start_co + x_axis*current.x + position.append(negative) + coords_for_shader.append((current.x, 1.0,member_length)) + sin_quad_lin.append((sinus, quadratic, current.y + constant)) + color.append(color_axis) + #info to render load value + x = current.x/member_length + func = sin(x*3.1416)*sinus + (-4.*x*x+4.*x)*quadratic+constant+current.y + if func: + text_info.append( + {"position": -1*direction*func/maxforce + start_co + x_axis*current.x, + "normal": direction.cross(x_axis).normalized(), + "text": f'{func:.2f} {self.linear_force_unit}'} + ) + maxforce = max(maxforce,abs(func)) + position.append(positive) + coords_for_shader.append((current[0],-1.0,member_length)) + sin_quad_lin.append((sinus, quadratic, current.y + constant)) + color.append(color_axis) + + indices.append((0 + counter + addindex, + 1 + counter + addindex, + 2 + counter + addindex)) + indices.append((3 + counter + addindex, + 2 + counter + addindex, + 1 + counter + addindex)) + if i == len(polyline)-2: + negative = -1*direction + start_co + x_axis*nextitem.x + positive = direction + start_co + x_axis*nextitem.x + position.append(negative) + coords_for_shader.append((nextitem.x, 1.0,member_length)) + sin_quad_lin.append((sinus, quadratic, nextitem.y + constant)) + color.append(color_axis) + #info to render load value + x = nextitem.x/member_length + func = sin(x*3.1416)*sinus + (-4.*x*x+4.*x)*quadratic+constant+nextitem.y + if func: + text_info.append( + {"position": -1*direction*func/maxforce + start_co + x_axis*nextitem.x, + "normal": direction.cross(x_axis).normalized(), + "text": f'{func:.2f} {self.linear_force_unit}'} + ) + maxforce = max(maxforce,abs(func)) + position.append(positive) + coords_for_shader.append((nextitem.x,-1.0,member_length)) + sin_quad_lin.append((sinus, quadratic, nextitem.y + constant)) + color.append(color_axis) + + counter += 2 + if len(position): + self.info.append( + { + "shader": shader, + "args": {"position": position, "sin_quad_lin_forces": sin_quad_lin,"coord": coords_for_shader}, + "indices": indices, + "uniforms": [["color", color_axis],["spacing", 0.2],["maxload",maxforce]] + } + ) + position = [] + sin_quad_lin = [] + coords_for_shader = [] + indices = [] + for info in self.info: + info["uniforms"][2][1] = maxforce + + self.text_info = text_info + + + def get_loads_per_direction(self,activity_list,global_to_local,member_length): + """ returns a dict with values for applied loads in each direction + return = { + "fx": values_in_this_direction + "fy": values_in_this_direction + "fz": values_in_this_direction + "mx": values_in_this_direction + "my": values_in_this_direction + "mz": values_in_this_direction + } + values_in_this_direction = { + "constant": float, + "quadratic": float, + "sinus": float, + "polyline": list[(position: float, load: float),...] + } + """ + loads_dict = self.get_loads_dict(activity_list,global_to_local) + const = loads_dict["constant force"] + quad = loads_dict["quadratic force"] + sinus = loads_dict["sinus force"] + loads = loads_dict["linear load configuration"] + unique_list = self.getuniquepositionlist(loads) + final_list = [] + return_value = None + max_load = 0 + for pos in unique_list: + value = self.get_before_and_after(pos,loads) + if value["before"] == value["after"]: + final_list.append([pos]+value["before"]) + else: + final_list.append([pos]+value["before"]) + final_list.append([pos]+value["after"]) + + if not len(final_list) and any(const+quad+sinus): + final_list.append([0.0,0.0,0.0,0.0,0.0,0.0,0.0]) + final_list.append([member_length,0.0,0.0,0.0,0.0,0.0,0.0]) + + elif len(final_list): + if final_list[0][0] and any(const+quad+sinus): #if first item location is not 0 append an item at the zero + final_list = [[0.0,0.0,0.0,0.0,0.0,0.0,0.0]]+final_list + else: + del final_list[0] + if abs(final_list[-1][0] - member_length) > 0.01 and any(const+quad+sinus): + final_list.append([member_length,0.0,0.0,0.0,0.0,0.0,0.0]) + else: + del final_list[-1] + if len(final_list): + array = np.array(final_list) #7xn -> ["pos","fx","fy","fz","mx","my","mz"] + keys = ["fx","fy","fz","mx","my","mz"] + polyline = { + "fx": [], + "fy": [], + "fz": [], + "mx": [], + "my": [], + "mz": [], + } + return_value = { + "fx": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, + "fy": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, + "fz": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, + "mx": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, + "my": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, + "mz": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, + } + max_load = 0 + for component, key in enumerate(keys): + if(any([sinus[component], quad[component], const[component]]) or + any(item for item in array[:,component+1])): + + for currentitem in final_list: + polyline[key].append([currentitem[0],currentitem[component+1]]) + x = currentitem[0]/member_length + func = sin(x*3.1416)*sinus[component] + (-4.*x*x+4.*x)*quad[component]+const[component]+currentitem[component+1] + max_load = max(max_load,abs(sinus[component]+quad[component]+const[component]+currentitem[component+1])) + inner_dict = return_value[key] + inner_dict["constant"] = const[component] + inner_dict["quadratic"] = quad[component] + inner_dict["sinus"] = sinus[component] + inner_dict["polyline"] = polyline[key] + return_value[key] = inner_dict + + return return_value, max_load, loads_dict["point load configuration"] + + + def getuniquepositionlist(self, load_config_list): + """return an ordereded list of unique locations based on the load configuration list + ex: load_config_list = [[{"pos":1.0,...},{"pos":3.0,...}], + [{"pos":2.0,...},{"pos":3.0,...}], + [{"pos":1.5,...},{"pos":2.5,...}]] + return = [1.0, 1.5, 2.0, 2.5, 3.0] + """ + unique = [] + for config in load_config_list: + for info in config: + if info["pos"] in unique: + continue + unique.append(info["pos"]) + unique.sort() + return unique + + def interp1d(self,l1,l2, pos): + """ 1d linear interpolation for the vector components""" + fac = (l2[1]-l1[1])/(l2[0]-l1[0]) + v = l1[1] + fac*(pos-l1[0]) + return v + + def interpolate(self,pos,loadinfo,start,end,key): + """ interpolate the result vectors between load poits""" + result = Vector((0,0,0)) + for i in range(3): + value1 = [loadinfo[start]["pos"], loadinfo[start][key][i]] #[position, force_component] + value2= [loadinfo[end]["pos"], loadinfo[end][key][i]] # [position, force_component] + result[i] = self.interp1d(value1,value2, pos) # interpolated [position, force_component] + return result + + def get_before_and_after(self,pos,load_config_list): + """ get total values for forces and moments with polilyne distribution + before and after the position + ex: load_config_list = [[{"pos":1.0,...,"forces":(1,0,0),...},{"pos":3.0,...,"forces":(3,0,0),...}], + [{"pos":2.0,...,"forces":(1,0,0),...},{"pos":3.0,...,"forces":(1,0,0),...}], + [{"pos":1.5,...,"forces":(1,0,0),...},{"pos":2.5,...,"forces":(1,0,0),...}]] + pos = 2.0 + return = { + "before": (3,0,0,0,0,0), ->(fx, fy, fz, mx, my, mz) + " after": (4,0,0,0,0,0) ->(fx, fy, fz, mx, my, mz) + } + """ + force_before = Vector((0,0,0)) + force_after = Vector((0,0,0)) + moment_before = Vector((0,0,0)) + moment_after = Vector((0,0,0)) + + for config in load_config_list: + if pos < config[0]["pos"] or pos > config[-1]["pos"]: + continue + start = 0 + end = len(config)-1 + while end-start > 0: + if pos < config[start]["pos"] or pos > config[end]["pos"]: + break + if config[start]["pos"] == pos: + if config[start]["descr"] in ['start','middle']: + force_after += config[start]["forces"] + moment_after += config[start]["moments"] + elif config[start]["descr"] in ['end','middle']: + force_before += config[start]["forces"] + moment_before += config[start]["moments"] + + elif config[end]["pos"] == pos: + if config[end]["descr"] in ['start','middle']: + force_after += config[end]["forces"] + moment_after += config[end]["moments"] + elif config[end]["descr"] in ['end','middle']: + force_before += config[end]["forces"] + moment_before += config[end]["moments"] + + elif end-start == 1: + force_before += self.interpolate(pos,config,start,end,"forces") + force_after += self.interpolate(pos,config,start,end,"forces") + moment_before += self.interpolate(pos,config,start,end,"moments") + moment_after += self.interpolate(pos,config,start,end,"moments") + start += 1 + end -=1 + return_value = { + "before": [force_before.x,force_before.y,force_before.z, + moment_before.x,moment_before.y,moment_before.z], + "after": [force_after.x, force_after.y, force_after.z, + moment_after.x, moment_after.y, moment_after.z] + } + return return_value + + def get_loads_dict(self,activity_list,element_rotation_matrix): + """ + get load list + activity_list: list of IfcStructuralCurveAction or IfcStructuralCurveReaction + applied in the structural curve member + global_to_local: transformation matrix from global coordinates to local coordinetes + return: dict{ + "constant force": (fx,fy,fz,mx,my,mz), -> sum of linear loads applied with + constant distribution + "quadratic force": (fx,fy,fz,mx,my,mz), -> sum of linear loads applied with + quadratic distribution + "sinus force": (fx,fy,fz,mx,my,mz), -> sum of linear loads applied with + sinus distribution + "lienar load configuration": list -> list of load configurations for linear + and polyline distributions of linear loads + } + description of "linear load configuration": + list[ -> one item (list)for each IfcStructuralCurveAction applied in the member + with IfcStructuralLoadConfiguration as the applied load + list[ -> one item (dict) for each item found in the + Locations attribute of IfcLoadConfiguration + dict{ + "pos": float, -> local position along curve length + "descr": string, -> describe if the item is at the start, middle or end of the list + "forces": Vector, -> linear force applied at that point + "moments": Vector -> linear moment applied at that point + } + ] + ] + """ + constant_force = Vector((0,0,0)) + constant_moment = Vector((0,0,0)) + quadratic_force = Vector((0,0,0)) + quadratic_moment = Vector((0,0,0)) + sinus_force = Vector((0,0,0)) + sinus_moment = Vector((0,0,0)) + linear_load_configurations = [] + point_load_configurations = [] + + unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get(),"LENGTHUNIT") + + def get_force_vector(load,transform_matrix,factor = 1.0): + x = 0 if getattr(load, 'LinearForceX', 0) is None else getattr(load, 'LinearForceX', 0) + y = 0 if getattr(load, 'LinearForceY', 0) is None else getattr(load, 'LinearForceY', 0) + z = 0 if getattr(load, 'LinearForceZ', 0) is None else getattr(load, 'LinearForceZ', 0) + return transform_matrix @ (Vector((x,y,z))*factor) + + def get_moment_vector(load,transform_matrix,factor = 1.0): + x = 0 if getattr(load, 'LinearMomentX', 0) is None else getattr(load, 'LinearMomentX', 0) + y = 0 if getattr(load, 'LinearMomentY', 0) is None else getattr(load, 'LinearMomentY', 0) + z = 0 if getattr(load, 'LinearMomentZ', 0) is None else getattr(load, 'LinearMomentZ', 0) + return transform_matrix @ (Vector((x,y,z))*factor) + + for item in activity_list: + activity = item[0] + factor = item[1] + load = activity.AppliedLoad + global_or_local = activity.GlobalOrLocal + props = bpy.context.scene.BIMStructuralProperties + reference_frame = props.reference_frame #make it a scene property so it can be changed in a panel + transform_matrix = Matrix() + if reference_frame == 'LOCAL_COORDS' and global_or_local != reference_frame: + transform_matrix = element_rotation_matrix + transform_matrix.invert() + elif reference_frame == 'GLOBAL_COORDS' and global_or_local != reference_frame: + transform_matrix = element_rotation_matrix + #values for linear loads + if load.is_a('IfcStructuralLoadConfiguration'): + locations = getattr(load, 'Locations', []) + values = [l for l in getattr(load, 'Values', None) + if l.is_a() == "IfcStructuralLoadLinearForce" + ] + config_list = [] + for i,l in enumerate(values): + forcevalues = get_force_vector(l,transform_matrix,factor) + momentvalues = get_moment_vector(l,transform_matrix,factor) + if i == 0: + descr = 'start' + elif i == len(values)-1: + descr = 'end' + else: + descr = 'middle' + config_list.append( + {"pos": locations[i][0]*unit_scale, + "descr": descr, + "forces":forcevalues, + "moments":momentvalues} + ) + linear_load_configurations.append(config_list) + #load configurations with point loads + values = [l for l in getattr(load, 'Values', None) + if l.is_a() == "IfcStructuralLoadSingleForce" + ] + attr_list = ['ForceX','ForceY','ForceZ','MomentX','MomentY','MomentZ'] + config_list = [] + for i,load in enumerate(values): + result_list = [0,0,0,0,0,0] + for j, attr in enumerate(attr_list): + value = 0 if getattr(load, attr, 0) is None else getattr(load, attr, 0) + result_list[j] += value*factor + config_list.append( + {"pos": locations[i][0]*unit_scale, + "values": result_list} + ) + point_load_configurations.append(config_list) + + else: + forcevalues = get_force_vector(load,transform_matrix,factor) + momentvalues = get_moment_vector(load,transform_matrix,factor) + if 'CONST' == getattr(activity, 'PredefinedType', None) or activity.is_a('IfcStructuralLinearAction'): + constant_force += forcevalues + constant_moment += momentvalues + elif 'PARABOLA' == getattr(activity, 'PredefinedType', None): + quadratic_force += forcevalues + quadratic_moment += momentvalues + elif 'SINUS' == getattr(activity, 'PredefinedType', None): + sinus_force += forcevalues + sinus_moment += momentvalues + return_value = { + "constant force": [constant_force.x,constant_force.y,constant_force.z, + constant_moment.x,constant_moment.y,constant_moment.z], + "quadratic force": [quadratic_force.x,quadratic_force.y,quadratic_force.z, + quadratic_moment.x,quadratic_moment.y,quadratic_moment.z], + "sinus force": [sinus_force.x,sinus_force.y,sinus_force.z, + sinus_moment.x,sinus_moment.y,sinus_moment.z], + "linear load configuration": linear_load_configurations, + "point load configuration": point_load_configurations + } + return return_value diff --git a/src/bonsai/bonsai/bim/module/structural/shader.py b/src/bonsai/bonsai/bim/module/structural/shader.py index 626cc9f3a9..881b97cc49 100644 --- a/src/bonsai/bonsai/bim/module/structural/shader.py +++ b/src/bonsai/bonsai/bim/module/structural/shader.py @@ -1,223 +1,57 @@ -import bpy + import gpu -import bmesh -import numpy as np -from math import sin -from mathutils import Vector, Matrix -import ifcopenshell -import ifcopenshell.api -import ifcopenshell.util.attribute -import bonsai.tool as tool -from bonsai.bim.ifc import IfcStore - -class ShaderInfo: +class DecorationShader: + "shader for the load decorations" def __init__(self): - self.is_empty = True - #self.shader = None - #self.shader_type = shader_type - #self.args = {} - #self.indices = [] - self.curve_members = {} - self.point_members = {} - self.surface_members = {} - self.text_info = [] - self.info = [] - self.force_unit = "" - self.linear_force_unit = "" - self.planar_force_unit = "" - - def update(self): - self.info = [] - self.text_info = [] - self.curve_members = {} - self.point_members = {} - self.surface_members = {} - self.get_force_units() - self.get_strucutural_elements_and_activities() - self.get_linear_loads() - self.get_point_loads() - self.get_planar_loads_2() - if len(self.info): - self.is_empty = False - - def get_force_units(self): - def get_unit_symbol(unit: ifcopenshell.entity_instance) -> str: - prefix_symbols = { - "EXA": "E", - "PETA": "P", - "TERA": "T", - "GIGA": "G", - "MEGA": "M", - "KILO": "k", - "HECTO": "h", - "DECA": "da", - "DECI": "d", - "CENTI": "c", - "MILLI": "m", - "MICRO": "μ", - "NANO": "n", - "PICO": "p", - "FEMTO": "f", - "ATTO": "a", - } + pass + def get(self, pattern: str) -> gpu.types.GPUShader: + """pattern: string description of the desired shader + Possible values + PERPENDICULAR DISTRIBUTED FORCE: pattern for distributed force + perpendicular to the curve member axis + PARALLEL DISTRIBUTED FORCE: pattern for distributed force + along the curve member axis + DISTRIBUTED MOMENT: pattern for distributed moment in curve members + SINGLE FORCE: pattern for single forces + SINGLE MOMENT: pattern for single moments + PLANAR LOAD: pattern for planar loads + """ + valid_patterns = {"PERPENDICULAR DISTRIBUTED FORCE", + "PARALLEL DISTRIBUTED FORCE", + "DISTRIBUTED MOMENT", + "SINGLE FORCE", + "SINGLE MOMENT", + "PLANAR LOAD" + } + if pattern not in valid_patterns: + raise ValueError("""pattern must be one of: + PERPENDICULAR DISTRIBUTED FORCE + PARALLEL DISTRIBUTED FORCE, + DISTRIBUTED MOMENT, + SINGLE FORCE, + SINGLE MOMENT, + PLANAR LOAD""") + if "DISTRIBUTED" in pattern.upper(): + shader = self.get_linear_shader(pattern) + return shader + elif "SINGLE" in pattern.upper(): + shader = self.get_point_shader(pattern) + return shader + elif "PLANAR" in pattern.upper(): + shader = self.get_planar_shader() + return shader - unit_symbols = { - # si units - "CUBIC_METRE": "m3", - "GRAM": "g", - "SECOND": "s", - "SQUARE_METRE": "m2", - "METRE": "m", - "NEWTON": "N", - "PASCAL": "Pa", - # conversion based units - "pound-force": "lbf", - 'pound-force per square inch': "psi", - "thou": "th", - "inch": "in", - "foot": "ft", - "yard": "yd", - "mile": "mi", - "square thou": "th2", - "square inch": "in2", - "square foot": "ft2", - "square yard": "yd2", - "acre": "ac", - "square mile": "mi2", - "cubic thou": "th3", - "cubic inch": "in3", - "cubic foot": "ft3", - "cubic yard": "yd3", - "cubic mile": "mi3", - "litre": "L", - "fluid ounce UK": "fl oz", - "fluid ounce US": "fl oz", - "pint UK": "pt", - "pint US": "pt", - "gallon UK": "gal", - "gallon US": "gal", - "degree": "°", - "ounce": "oz", - "pound": "lb", - "ton UK": "ton", - "ton US": "ton", - "lbf": "lbf", - "kip": "kip", - "psi": "psi", - "ksi": "ksi", - "minute": "min", - "hour": "hr", - "day": "day", - "btu": "btu", - "fahrenheit": "°F", - } - symbol = "" - if unit.is_a("IfcSIUnit"): - symbol += prefix_symbols.get(unit.Prefix, "") - symbol += unit_symbols.get(unit.Name.replace("METER", "METRE"), "?") - return symbol - - force_units = [u for u in tool.Ifc.get().by_type("IfcNamedUnit") - if u.UnitType == "FORCEUNIT"] - linear_force_units = [u for u in tool.Ifc.get().by_type("IfcDerivedUnit") - if u.UnitType == "LINEARFORCEUNIT"] - planar_force_units = [u for u in tool.Ifc.get().by_type("IfcDerivedUnit") - if u.UnitType == "PLANARFORCEUNIT"] - - conversion_force_unit = [u for u in force_units if u.is_a("IfcConversionBasedUnit")] - if len(conversion_force_unit) == 0: - conversion_force_unit.append(force_units[0]) - self.force_unit = get_unit_symbol(conversion_force_unit[0]) - first = "" - second = "" - for e in linear_force_units[0].Elements: - if e.Unit.UnitType == "FORCEUNIT": - first = get_unit_symbol(e.Unit) - if e.Unit.UnitType == "LENGTHUNIT": - second = get_unit_symbol(e.Unit) - self.linear_force_unit = first + "/" + second - first = "" - second = "" - for e in planar_force_units[0].Elements: - if e.Unit.UnitType == "FORCEUNIT": - first = get_unit_symbol(e.Unit) - if e.Unit.UnitType == "LENGTHUNIT": - second = get_unit_symbol(e.Unit)+"2" - if e.Unit.UnitType == "AREAUNIT": - second = get_unit_symbol(e.Unit) - self.planar_force_unit = first + "/" + second - - def get_strucutural_elements_and_activities(self): - - def populate_members_dict(dict_name,element, activity, factor): - dic = getattr(self,dict_name,None) - if dic is None: - return - member = dic.get(element.GlobalId) - if member is None: - dic.update({ - element.GlobalId: { - "member": element, - "activities": [(activity,factor)]} - }) - else: - member["activities"].append((activity,factor)) - - def recursive_subgroups(groups, rec_limit, activity_type, factor = 1): - if len(groups) == 0 or rec_limit == 0: - return None - for group in groups: - subgorups = [] - activities = [] - relationship = [rel for rel in group.IsGroupedBy] - coef = getattr(group, 'Coefficient', 1.0) - group_coef = coef if coef is not None else 1.0 - rel_factor = 1.0 - - for rel in relationship: - if rel.is_a("IfcRelAssignsToGroupByFactor"): - rel_factor = rel.Factor if rel.Factor is not None else 1.0 - objects = rel.RelatedObjects - subgorups = [sg for sg in objects if sg.is_a("IfcStructuralLoadGroup")] - activities = [a for a in objects if a.is_a("IfcStructuralActivity")] - factor = factor*group_coef*rel_factor - for activity in activities: - if len(activity.AssignedToStructuralItem): - element = activity.AssignedToStructuralItem[0].RelatingElement - if element is not None: - if activity_type == "Action": - if element.is_a("IfcStructuralCurveMember"): - populate_members_dict("curve_members",element,activity,factor) - elif element.is_a("IfcStructuralPointConnection"): - populate_members_dict("point_members",element,activity,factor) - elif element.is_a("IfcStructuralSurfaceMember"): - populate_members_dict("surface_members",element,activity,factor) - - elif activity_type == "External Reaction" and getattr(element,"AppliedCondition",None) is not None: - if element.is_a("IfcStructuralCurveMember"): - populate_members_dict("curve_members",element,activity,factor) - elif element.is_a("IfcStructuralPointConnection"): - populate_members_dict("point_members",element,activity,factor) - elif element.is_a("IfcStructuralSurfaceMember"): - populate_members_dict("surface_members",element,activity,factor) - recursive_subgroups(subgorups,rec_limit-1,activity_type,factor=factor) - - props = bpy.context.scene.BIMStructuralProperties - group_definition_id = int(props.load_group_to_show) - file = IfcStore.get_file() - groups = [file.by_id(group_definition_id)] - recursive_subgroups(groups,10,props.activity_type) - - - def get_shader(self, pattern): - """ param: pattern: type of pattern in ["force", "force match", "moment"] - return: shader""" - #if self.shader_type == "DistributedLoad": + def get_linear_shader(self, pattern: str) -> gpu.types.GPUShader: + """pattern: type of pattern + PERPENDICULAR DISTRIBUTED FORCE + PARALLEL DISTRIBUTED FORCE, + DISTRIBUTED MOMENT, + """ vert_out = gpu.types.GPUStageInterfaceInfo("my_interface") vert_out.smooth('VEC3', "forces") vert_out.smooth('VEC3', "co") - + shader_info = gpu.types.GPUShaderCreateInfo() shader_info.push_constant('MAT4', "viewProjectionMatrix") shader_info.push_constant('VEC4', "color") @@ -239,8 +73,8 @@ class ShaderInfo: " forces = sin_quad_lin_forces;" "}" ) - - if pattern == "force": + + if pattern == "PERPENDICULAR DISTRIBUTED FORCE": shader_info.fragment_source( "void main()" "{" @@ -268,7 +102,7 @@ class ShaderInfo: "}" ) - if pattern == "force match": + elif pattern == "PARALLEL DISTRIBUTED FORCE": shader_info.fragment_source( "void main()" "{" @@ -297,7 +131,7 @@ class ShaderInfo: "}" ) - if pattern == "moment": + elif pattern == "DISTRIBUTED MOMENT": shader_info.fragment_source( "void main()" "{" @@ -340,9 +174,10 @@ class ShaderInfo: del shader_info return shader - def get_point_shader(self, pattern): - """ param: pattern: type of pattern in ["arrow", "circ arrow"] - return: shader""" + def get_point_shader(self, pattern: str) -> gpu.types.GPUShader: + """ param: pattern: type of pattern + SINGLE FORCE, + SINGLE MOMENT""" vert_out = gpu.types.GPUStageInterfaceInfo("my_interface") vert_out.smooth('VEC3', "co") @@ -365,7 +200,7 @@ class ShaderInfo: "}" ) - if pattern == "arrow": + if pattern == "SINGLE FORCE": shader_info.fragment_source( "void main()" "{" @@ -377,7 +212,7 @@ class ShaderInfo: "}" ) - if pattern == "circ arrow": + elif pattern == "SINGLE MOMENT": shader_info.fragment_source( "void main()" "{" @@ -395,10 +230,8 @@ class ShaderInfo: del shader_info return shader - def get_planar_shader(self): - """ param: pattern: type of pattern in ["force", "force match", "moment"] - return: shader""" - #if self.shader_type == "DistributedLoad": + def get_planar_shader(self) -> gpu.types.GPUShader: + """shader for planar loads""" vert_out = gpu.types.GPUStageInterfaceInfo("my_interface") vert_out.smooth('VEC3', "co") @@ -439,735 +272,9 @@ class ShaderInfo: "float d = clamp(0.2*y+(top+b+c)*mask,0.0,0.4);" "FragColor = vec4(color.xyz,d*color.w);" "}" - )#"float d = clamp(0.1+top+b+c,0.0,0.4);" + ) shader = gpu.shader.create_from_info(shader_info) del vert_out del shader_info return shader - - def get_planar_loads_2(self): - list_of_surfaces = self.surface_members - shader = self.get_planar_shader() - maximum = 0 - for value in list_of_surfaces.values(): - surf = value["member"] - activity_list = [getattr(a, 'RelatedStructuralActivity', None) for a in getattr(surf, 'AssignedStructuralActivity', None) - if getattr(a, 'RelatedStructuralActivity', None).is_a() in ['IfcStructuralPlanarAction','IfcStructuralSurfaceAction']] - activity_list = value["activities"] - if len(activity_list) == 0: - continue - rotation = self.get_surface_member_rotation(surf) - values = self.get_planar_loads_values(activity_list,rotation) - if maximum == 0: - maximum = max([abs(float(i)) for i in values]) - if maximum == 0: - continue - props = bpy.context.scene.BIMStructuralProperties - reference_frame = props.reference_frame - orientation = np.eye(3) - if reference_frame == "LOCAL_COORDS": - orientation = rotation - blender_object: bpy.types.Object = IfcStore.get_element(getattr(surf, 'GlobalId', None)) - mat = blender_object.matrix_world - mesh: bpy.types.Mesh = blender_object.data - - positions = [] - indices = [] - coord = [] - bm = bmesh.new() - bm.from_mesh(mesh) - bmesh.ops.triangulate(bm, faces = bm.faces) - bm.edges.ensure_lookup_table() - bm.verts.ensure_lookup_table() - bm.faces.ensure_lookup_table() - - add_index = len(positions) - for v in bm.verts: - p1 = np.array(mat @ v.co) - positions.append(p1) - p2 = p1 - (orientation@values)*0.2/maximum - positions.append(p2) - coord.append((float(p1[0]+p1[1]),0,1)) - coord.append((float(p1[0]+p1[1]),1,1)) - for e in bm.edges: - if len(e.link_faces) > 1: - continue - indices.append((2*e.verts[0].index, - 2*e.verts[0].index+1, - 2*e.verts[1].index)) - indices.append((2*e.verts[0].index+1, - 2*e.verts[1].index, - 2*e.verts[1].index+1)) - for p in bm.faces: - indices.append((2*p.verts[0].index+1, - 2*p.verts[1].index+1, - 2*p.verts[2].index+1)) - bmesh.ops.dissolve_limit(bm, angle_limit = 0.01, verts = bm.verts, edges = bm.edges) - bm.faces.ensure_lookup_table() - center = bm.faces[0].calc_center_bounds() - - self.text_info.append( - {"position": mat @ center - Vector((orientation@values)*0.2/maximum), - "normal": Vector(mesh.polygons[0].normal), - "text": f'{values[2]:.5f} {self.planar_force_unit}'} - ) - - self.info.append( - { - "shader": shader, - "args": {"position": positions, "coord": coord}, - "indices": indices, - "uniforms": [["color", (0.2,0,1,1)],["spacing", 0.2]] - } - ) - def get_planar_loads_values(self, activity_list,element_rotation_matrix): - values = np.zeros((3)) - for item in activity_list: - activity = item[0] - factor = item[1] - load = activity.AppliedLoad - temp = np.zeros((3)) - if load is not None and load.is_a("IfcStructuralLoadPlanarForce"): - temp[0] = load.PlanarForceX if load.PlanarForceX is not None else 0 - temp[1] = load.PlanarForceY if load.PlanarForceY is not None else 0 - temp[2] = load.PlanarForceZ if load.PlanarForceZ is not None else 0 - temp = temp*factor - transform = self.get_activity_transform_matrix(activity,element_rotation_matrix) - values += transform@temp - return values - - def get_surface_member_rotation(self,surface_member): - representation = ifcopenshell.util.representation.get_representation(surface_member, "Model") - repr_item = representation.Items[0] - placement = ifcopenshell.util.placement.get_axis2placement(repr_item.FaceSurface.Position) - rotation = placement[0:3,0:3] - return rotation - - def get_point_connection_rotation(self, point_connection): - if point_connection.ConditionCoordinateSystem is not None: - placement = ifcopenshell.util.placement.get_axis2placement(point_connection.ConditionCoordinateSystem) - else: - placement = np.eye(4) - rotation = placement[0:3,0:3] - return rotation - - def get_curve_member_rotation(self, curve_member): - z = curve_member.Axis.DirectionRatios - edge = curve_member.Representation.Representations[0].Items[0] - origin = edge.EdgeStart.VertexGeometry.Coordinates - end = edge.EdgeEnd.VertexGeometry.Coordinates - x = [c2 - c1 for c1, c2 in zip(origin, end)] - placement = ifcopenshell.util.placement.a2p(origin,z,x) - rotation = placement[0:3,0:3] - return rotation - - def get_activity_transform_matrix(self, activity, element_rotation_matrix): - "provides the transformation matrix to convert between reference frames" - global_or_local = activity.GlobalOrLocal - props = bpy.context.scene.BIMStructuralProperties - reference_frame = props.reference_frame - transform_matrix = np.eye(3) - if reference_frame == 'LOCAL_COORDS' and global_or_local != reference_frame: - transform_matrix = np.linalg.inv(element_rotation_matrix) - elif reference_frame == 'GLOBAL_COORDS' and global_or_local != reference_frame: - transform_matrix = element_rotation_matrix - return transform_matrix - - def get_point_loads(self): - list_of_point_connections = tool.Ifc.get().by_type("IfcStructuralPointConnection") - list_of_point_connections = self.point_members - for value in list_of_point_connections.values(): - conn = value["member"] - activity_list = [getattr(a, 'RelatedStructuralActivity', None) for a in getattr(conn, 'AssignedStructuralActivity', None) - if getattr(a, 'RelatedStructuralActivity', None).is_a() in ['IfcStructuralPointAction']] - activity_list = value["activities"] - if len(activity_list) == 0: - continue - blender_object = IfcStore.get_element(getattr(conn, 'GlobalId', None)) - if blender_object.type == 'MESH': - conn_location = blender_object.matrix_world @ blender_object.data.vertices[0].co - #get local coordinates of the connection - rotation = self.get_point_connection_rotation(conn) - loads = self.get_point_loads_values(activity_list, rotation) - self.get_point_shader_args(loads, conn_location, rotation) - - def get_point_shader_args(self,loads, location, rotation): - location = np.array(location) - indices = [] - text_info = [] - direction_dict = { - "fx": (np.array((1,0,0)),np.array((0,1,0)),np.array((0,0,1))), - "fy": (np.array((0,1,0)),np.array((1,0,0)),np.array((0,0,1))), - "fz": (np.array((0,0,1)),np.array((0,1,0)),np.array((1,0,0))), - "mx": (np.array((0,1,0)),np.array((0,0,1))), - "my": (np.array((1,0,0)),np.array((0,0,1))), - "mz": (np.array((1,0,0)),np.array((0,1,0))), - } - keys = ["fx","fy","fz","mx","my","mz"] - props = bpy.context.scene.BIMStructuralProperties - reference_frame = props.reference_frame - if reference_frame == "LOCAL_COORDS": - for key in keys: - tup = direction_dict[key] - li = [] - for item in tup: - li.append(rotation@item) - direction_dict[key] = li - - for i, key in enumerate(keys): - if loads[i] == 0: - continue - color = (1,0,0,1) - if i in [1,4]: - color = (0,1,0,1) - elif i in [2,5]: - color = (0,0,1,1) - d1 = -(direction_dict[key][0]*loads[i]) - d1 = d1/np.linalg.norm(d1) - if i < 3: - d2 = direction_dict[key][1] - d3 = direction_dict[key][2] - p1 = location - p2 = location + d1 + d2 - p3 = location + d1 - d2 - p4 = location + d1 + d3 - p5 = location + d1 - d3 - position = [p1,p2,p3,p4,p5] - indices = [(0,1,2),(0,3,4)] - c1 = (0,0,0) - c2 = (1,1,0) - c3 = (-1,1,0) - coords_for_shader = [c1,c2,c3,c2,c3] - shader = self.get_point_shader("arrow") - self.info.append( - { - "shader": shader, - "args": {"position": position,"coord": coords_for_shader}, - "indices": indices, - "uniforms": [["color", color],["spacing", 0.2]] - } - ) - self.text_info.append( - {"position": location + d1, - "normal": d2/np.linalg.norm(d2), - "text": f'{loads[i]:.2f} {self.force_unit}'} - ) - else: - d2 = d2 = direction_dict[key][1] - p1 = location - d2 - p2 = location + d1 + d2 - p3 = location - d1 + d2 - position = [p1,p2,p3] - indices = [(0,1,2)] - c1 = (-1,0,0) - c2 = (1,1,0) - c3 = (1,-1,0) - coords_for_shader = [c1,c2,c3] - shader = self.get_point_shader("circ arrow") - self.info.append( - { - "shader": shader, - "args": {"position": position,"coord": coords_for_shader}, - "indices": indices, - "uniforms": [["color", color]] - } - ) - self.text_info.append( - {"position": location +0.25*(d1 + d2), - "normal": d2/np.linalg.norm(d2), - "text": f'{loads[i]:.2f} {self.force_unit}'}#change to moment unit - ) - - def get_point_loads_values(self,activity_list,element_rotation_matrix): - result_list = np.zeros(6) - attr_list = ['ForceX','ForceY','ForceZ','MomentX','MomentY','MomentZ'] - for item in activity_list: - activity = item[0] - factor = item[1] - load = activity.AppliedLoad - temp = np.zeros(6) - for i, attr in enumerate(attr_list): - value = 0 if getattr(load, attr, 0) is None else getattr(load, attr, 0) - temp[i] += value*factor - transform_3 = self.get_activity_transform_matrix(activity,element_rotation_matrix) - transform_6 = np.zeros((6,6)) - transform_6[0:3,0:3] = transform_3 - transform_6[3:6,3:6] = transform_3 - result_list += transform_6@temp - - return result_list - - - def get_linear_loads(self): #for now it only works for distributed loads - position = [] - indices = [] - sin_quad_lin = [] - coords_for_shader = [] - color = [] - text_info = [] - uniforms = [] - info = [] - - list_of_curve_members = tool.Ifc.get().by_type("IfcStructuralCurveMember") - list_of_curve_members = self.curve_members - for value in list_of_curve_members.values(): - member = value["member"] - activity_list = [getattr(a, 'RelatedStructuralActivity', None) for a in getattr(member, 'AssignedStructuralActivity', None) - if getattr(a, 'RelatedStructuralActivity', None).is_a() in ['IfcStructuralCurveAction','IfcStructuralLinearAction']] - activity_list = value["activities"] - if len(activity_list) == 0: - continue - # member is a structural curve member - # get Axis attribute from member -> (IFCDIRECTION) - # get Representation attribute from member -> (IFCPRODUCTDEFINITIONSHAPE) - # get Representations attribute from Representation -> (IFCTOPOLOGYREPRESENTATION) - # get Items attribute from Representations -> (IFCEDGE) - # get EdgeStart attribute from Items -> (IFCVERTEX) - # get EdgeEnd attribure from Items -> (IFCVERTEX) - # using blender just get the global coordinates of the first and second vertex in the mesh - - blender_object = IfcStore.get_element(getattr(member, 'GlobalId', None)) - - start_co = blender_object.matrix_world @ blender_object.data.vertices[0].co - end_co = blender_object.matrix_world @ blender_object.data.vertices[1].co - x_axis = Vector(end_co-start_co).normalized() - z_direction = getattr(member, 'Axis') - #local coordinates - z_axis = Vector(getattr(z_direction, 'DirectionRatios', None)).normalized() - y_axis = z_axis.cross(x_axis).normalized() - z_axis = x_axis.cross(y_axis).normalized() - rot = self.get_curve_member_rotation(member) - global_to_local = Matrix(((x_axis.x,y_axis.x,z_axis.x), - (x_axis.y,y_axis.y,z_axis.y), - (x_axis.z,y_axis.z,z_axis.z), - )) - global_to_local = Matrix(rot) - - #get shader args for each direction - props = bpy.context.scene.BIMStructuralProperties - reference_frame = props.reference_frame #make it a scene property so it can be changed in a panel - is_local = reference_frame == 'LOCAL_COORDS' - x_match = abs(Vector((1,0,0)).dot(x_axis)) > 0.99 - y_match = abs(Vector((0,1,0)).dot(x_axis)) > 0.99 - z_match = abs(Vector((0,0,1)).dot(x_axis)) > 0.99 - direction_dict = { - "fx": y_axis+z_axis if is_local else Vector((1,0,0)) if not x_match else Vector((0,1,1)), - "fy": y_axis if is_local else Vector((0,1,0)) if not y_match else Vector((1,0,1)), - "fz": z_axis if is_local else Vector((0,0,1)) if not z_match else Vector((1,1,0)), - "mx": z_axis-y_axis if is_local or x_match else Vector((1,0,0)).cross(x_axis), - "my": z_axis if is_local else Vector((-1,0,1)) if y_match else Vector((0,1,0)).cross(x_axis).normalized(), - "mz": y_axis if is_local else Vector((-1,1,0)) if z_match else Vector((0,0,1)).cross(x_axis).normalized() - } - match_dict = {'fx': x_match or is_local, 'fy': y_match, 'fz': z_match} - member_length = Vector(end_co-start_co).length - loads_dict, maxforce, point_loads = self.get_loads_per_direction(activity_list,global_to_local,member_length) - if len(point_loads): - for item in point_loads: - for sub_item in item: - pos = sub_item["pos"] - values = sub_item["values"] - pos_vector = start_co + x_axis*pos - self.get_point_shader_args(values,pos_vector) - if loads_dict is None: - continue - keys = ["fx","fy","fz","mx","my","mz"] - - for key in keys: - polyline = loads_dict[key]["polyline"] - sinus = loads_dict[key]["sinus"] - quadratic = loads_dict[key]["quadratic"] - constant = loads_dict[key]["constant"] - direction = direction_dict[key] #depends on the key and on the frame of reference - color_axis = (0,0,1,1) - if 'x' in key: - color_axis = (1,0,0,1) - if 'y' in key: - color_axis = (0,1,0,1) - - if 'f' in key: - if match_dict[key]: - shader = self.get_shader("force match") - else: - shader = self.get_shader("force") - else: - shader = self.get_shader("moment") - - addindex = len(position) - counter = 0 - for i in range(len(polyline)-1): - current = Vector(polyline[i]+[0]) - nextitem = Vector(polyline[i+1]+[0]) - - if any([current.y, nextitem.y,constant,quadratic,sinus]): #if there is load in the z direction - negative = -1*direction + start_co + x_axis*current.x - positive = direction + start_co + x_axis*current.x - position.append(negative) - coords_for_shader.append((current.x, 1.0,member_length)) - sin_quad_lin.append((sinus, quadratic, current.y + constant)) - color.append(color_axis) - #info to render load value - x = current.x/member_length - func = sin(x*3.1416)*sinus + (-4.*x*x+4.*x)*quadratic+constant+current.y - if func: - text_info.append( - {"position": -1*direction*func/maxforce + start_co + x_axis*current.x, - "normal": direction.cross(x_axis).normalized(), - "text": f'{func:.2f} {self.linear_force_unit}'} - ) - maxforce = max(maxforce,abs(func)) - position.append(positive) - coords_for_shader.append((current[0],-1.0,member_length)) - sin_quad_lin.append((sinus, quadratic, current.y + constant)) - color.append(color_axis) - - indices.append((0 + counter + addindex, - 1 + counter + addindex, - 2 + counter + addindex)) - indices.append((3 + counter + addindex, - 2 + counter + addindex, - 1 + counter + addindex)) - if i == len(polyline)-2: - negative = -1*direction + start_co + x_axis*nextitem.x - positive = direction + start_co + x_axis*nextitem.x - position.append(negative) - coords_for_shader.append((nextitem.x, 1.0,member_length)) - sin_quad_lin.append((sinus, quadratic, nextitem.y + constant)) - color.append(color_axis) - #info to render load value - x = nextitem.x/member_length - func = sin(x*3.1416)*sinus + (-4.*x*x+4.*x)*quadratic+constant+nextitem.y - if func: - text_info.append( - {"position": -1*direction*func/maxforce + start_co + x_axis*nextitem.x, - "normal": direction.cross(x_axis).normalized(), - "text": f'{func:.2f} {self.linear_force_unit}'} - ) - maxforce = max(maxforce,abs(func)) - position.append(positive) - coords_for_shader.append((nextitem.x,-1.0,member_length)) - sin_quad_lin.append((sinus, quadratic, nextitem.y + constant)) - color.append(color_axis) - - counter += 2 - if len(position): - self.info.append( - { - "shader": shader, - "args": {"position": position, "sin_quad_lin_forces": sin_quad_lin,"coord": coords_for_shader}, - "indices": indices, - "uniforms": [["color", color_axis],["spacing", 0.2],["maxload",maxforce]] - } - ) - position = [] - sin_quad_lin = [] - coords_for_shader = [] - indices = [] - for info in self.info: - info["uniforms"][2][1] = maxforce - - self.text_info = text_info - - - def get_loads_per_direction(self,activity_list,global_to_local,member_length): - """ returns a dict with values for applied loads in each direction - return = { - "fx": values_in_this_direction - "fy": values_in_this_direction - "fz": values_in_this_direction - "mx": values_in_this_direction - "my": values_in_this_direction - "mz": values_in_this_direction - } - values_in_this_direction = { - "constant": float, - "quadratic": float, - "sinus": float, - "polyline": list[(position: float, load: float),...] - } - """ - loads_dict = self.get_loads_dict(activity_list,global_to_local) - const = loads_dict["constant force"] - quad = loads_dict["quadratic force"] - sinus = loads_dict["sinus force"] - loads = loads_dict["linear load configuration"] - unique_list = self.getuniquepositionlist(loads) - final_list = [] - return_value = None - max_load = 0 - for pos in unique_list: - value = self.get_before_and_after(pos,loads) - if value["before"] == value["after"]: - final_list.append([pos]+value["before"]) - else: - final_list.append([pos]+value["before"]) - final_list.append([pos]+value["after"]) - - if not len(final_list) and any(const+quad+sinus): - final_list.append([0.0,0.0,0.0,0.0,0.0,0.0,0.0]) - final_list.append([member_length,0.0,0.0,0.0,0.0,0.0,0.0]) - - elif len(final_list): - if final_list[0][0] and any(const+quad+sinus): #if first item location is not 0 append an item at the zero - final_list = [[0.0,0.0,0.0,0.0,0.0,0.0,0.0]]+final_list - else: - del final_list[0] - if abs(final_list[-1][0] - member_length) > 0.01 and any(const+quad+sinus): - final_list.append([member_length,0.0,0.0,0.0,0.0,0.0,0.0]) - else: - del final_list[-1] - if len(final_list): - array = np.array(final_list) #7xn -> ["pos","fx","fy","fz","mx","my","mz"] - keys = ["fx","fy","fz","mx","my","mz"] - polyline = { - "fx": [], - "fy": [], - "fz": [], - "mx": [], - "my": [], - "mz": [], - } - return_value = { - "fx": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, - "fy": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, - "fz": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, - "mx": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, - "my": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, - "mz": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, - } - max_load = 0 - for component, key in enumerate(keys): - if(any([sinus[component], quad[component], const[component]]) or - any(item for item in array[:,component+1])): - - for currentitem in final_list: - polyline[key].append([currentitem[0],currentitem[component+1]]) - x = currentitem[0]/member_length - func = sin(x*3.1416)*sinus[component] + (-4.*x*x+4.*x)*quad[component]+const[component]+currentitem[component+1] - max_load = max(max_load,abs(sinus[component]+quad[component]+const[component]+currentitem[component+1])) - inner_dict = return_value[key] - inner_dict["constant"] = const[component] - inner_dict["quadratic"] = quad[component] - inner_dict["sinus"] = sinus[component] - inner_dict["polyline"] = polyline[key] - return_value[key] = inner_dict - - return return_value, max_load, loads_dict["point load configuration"] - - - def getuniquepositionlist(self, load_config_list): - """return an ordereded list of unique locations based on the load configuration list - ex: load_config_list = [[{"pos":1.0,...},{"pos":3.0,...}], - [{"pos":2.0,...},{"pos":3.0,...}], - [{"pos":1.5,...},{"pos":2.5,...}]] - return = [1.0, 1.5, 2.0, 2.5, 3.0] - """ - unique = [] - for config in load_config_list: - for info in config: - if info["pos"] in unique: - continue - unique.append(info["pos"]) - unique.sort() - return unique - - def interp1d(self,l1,l2, pos): - """ 1d linear interpolation for the vector components""" - fac = (l2[1]-l1[1])/(l2[0]-l1[0]) - v = l1[1] + fac*(pos-l1[0]) - return v - - def interpolate(self,pos,loadinfo,start,end,key): - """ interpolate the result vectors between load poits""" - result = Vector((0,0,0)) - for i in range(3): - value1 = [loadinfo[start]["pos"], loadinfo[start][key][i]] #[position, force_component] - value2= [loadinfo[end]["pos"], loadinfo[end][key][i]] # [position, force_component] - result[i] = self.interp1d(value1,value2, pos) # interpolated [position, force_component] - return result - - def get_before_and_after(self,pos,load_config_list): - """ get total values for forces and moments with polilyne distribution - before and after the position - ex: load_config_list = [[{"pos":1.0,...,"forces":(1,0,0),...},{"pos":3.0,...,"forces":(3,0,0),...}], - [{"pos":2.0,...,"forces":(1,0,0),...},{"pos":3.0,...,"forces":(1,0,0),...}], - [{"pos":1.5,...,"forces":(1,0,0),...},{"pos":2.5,...,"forces":(1,0,0),...}]] - pos = 2.0 - return = { - "before": (3,0,0,0,0,0), ->(fx, fy, fz, mx, my, mz) - " after": (4,0,0,0,0,0) ->(fx, fy, fz, mx, my, mz) - } - """ - force_before = Vector((0,0,0)) - force_after = Vector((0,0,0)) - moment_before = Vector((0,0,0)) - moment_after = Vector((0,0,0)) - - for config in load_config_list: - if pos < config[0]["pos"] or pos > config[-1]["pos"]: - continue - start = 0 - end = len(config)-1 - while end-start > 0: - if pos < config[start]["pos"] or pos > config[end]["pos"]: - break - if config[start]["pos"] == pos: - if config[start]["descr"] in ['start','middle']: - force_after += config[start]["forces"] - moment_after += config[start]["moments"] - elif config[start]["descr"] in ['end','middle']: - force_before += config[start]["forces"] - moment_before += config[start]["moments"] - - elif config[end]["pos"] == pos: - if config[end]["descr"] in ['start','middle']: - force_after += config[end]["forces"] - moment_after += config[end]["moments"] - elif config[end]["descr"] in ['end','middle']: - force_before += config[end]["forces"] - moment_before += config[end]["moments"] - - elif end-start == 1: - force_before += self.interpolate(pos,config,start,end,"forces") - force_after += self.interpolate(pos,config,start,end,"forces") - moment_before += self.interpolate(pos,config,start,end,"moments") - moment_after += self.interpolate(pos,config,start,end,"moments") - start += 1 - end -=1 - return_value = { - "before": [force_before.x,force_before.y,force_before.z, - moment_before.x,moment_before.y,moment_before.z], - "after": [force_after.x, force_after.y, force_after.z, - moment_after.x, moment_after.y, moment_after.z] - } - return return_value - - def get_loads_dict(self,activity_list,element_rotation_matrix): - """ - get load list - activity_list: list of IfcStructuralCurveAction or IfcStructuralCurveReaction - applied in the structural curve member - global_to_local: transformation matrix from global coordinates to local coordinetes - return: dict{ - "constant force": (fx,fy,fz,mx,my,mz), -> sum of linear loads applied with - constant distribution - "quadratic force": (fx,fy,fz,mx,my,mz), -> sum of linear loads applied with - quadratic distribution - "sinus force": (fx,fy,fz,mx,my,mz), -> sum of linear loads applied with - sinus distribution - "lienar load configuration": list -> list of load configurations for linear - and polyline distributions of linear loads - } - description of "linear load configuration": - list[ -> one item (list)for each IfcStructuralCurveAction applied in the member - with IfcStructuralLoadConfiguration as the applied load - list[ -> one item (dict) for each item found in the - Locations attribute of IfcLoadConfiguration - dict{ - "pos": float, -> local position along curve length - "descr": string, -> describe if the item is at the start, middle or end of the list - "forces": Vector, -> linear force applied at that point - "moments": Vector -> linear moment applied at that point - } - ] - ] - """ - constant_force = Vector((0,0,0)) - constant_moment = Vector((0,0,0)) - quadratic_force = Vector((0,0,0)) - quadratic_moment = Vector((0,0,0)) - sinus_force = Vector((0,0,0)) - sinus_moment = Vector((0,0,0)) - linear_load_configurations = [] - point_load_configurations = [] - - unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get(),"LENGTHUNIT") - - def get_force_vector(load,transform_matrix,factor = 1.0): - x = 0 if getattr(load, 'LinearForceX', 0) is None else getattr(load, 'LinearForceX', 0) - y = 0 if getattr(load, 'LinearForceY', 0) is None else getattr(load, 'LinearForceY', 0) - z = 0 if getattr(load, 'LinearForceZ', 0) is None else getattr(load, 'LinearForceZ', 0) - return transform_matrix @ (Vector((x,y,z))*factor) - - def get_moment_vector(load,transform_matrix,factor = 1.0): - x = 0 if getattr(load, 'LinearMomentX', 0) is None else getattr(load, 'LinearMomentX', 0) - y = 0 if getattr(load, 'LinearMomentY', 0) is None else getattr(load, 'LinearMomentY', 0) - z = 0 if getattr(load, 'LinearMomentZ', 0) is None else getattr(load, 'LinearMomentZ', 0) - return transform_matrix @ (Vector((x,y,z))*factor) - - for item in activity_list: - activity = item[0] - factor = item[1] - load = activity.AppliedLoad - global_or_local = activity.GlobalOrLocal - props = bpy.context.scene.BIMStructuralProperties - reference_frame = props.reference_frame #make it a scene property so it can be changed in a panel - transform_matrix = Matrix() - if reference_frame == 'LOCAL_COORDS' and global_or_local != reference_frame: - transform_matrix = element_rotation_matrix - transform_matrix.invert() - elif reference_frame == 'GLOBAL_COORDS' and global_or_local != reference_frame: - transform_matrix = element_rotation_matrix - #values for linear loads - if load.is_a('IfcStructuralLoadConfiguration'): - locations = getattr(load, 'Locations', []) - values = [l for l in getattr(load, 'Values', None) - if l.is_a() == "IfcStructuralLoadLinearForce" - ] - config_list = [] - for i,l in enumerate(values): - forcevalues = get_force_vector(l,transform_matrix,factor) - momentvalues = get_moment_vector(l,transform_matrix,factor) - if i == 0: - descr = 'start' - elif i == len(values)-1: - descr = 'end' - else: - descr = 'middle' - config_list.append( - {"pos": locations[i][0]*unit_scale, - "descr": descr, - "forces":forcevalues, - "moments":momentvalues} - ) - linear_load_configurations.append(config_list) - #load configurations with point loads - values = [l for l in getattr(load, 'Values', None) - if l.is_a() == "IfcStructuralLoadSingleForce" - ] - attr_list = ['ForceX','ForceY','ForceZ','MomentX','MomentY','MomentZ'] - config_list = [] - for i,load in enumerate(values): - result_list = [0,0,0,0,0,0] - for j, attr in enumerate(attr_list): - value = 0 if getattr(load, attr, 0) is None else getattr(load, attr, 0) - result_list[j] += value*factor - config_list.append( - {"pos": locations[i][0]*unit_scale, - "values": result_list} - ) - point_load_configurations.append(config_list) - - else: - forcevalues = get_force_vector(load,transform_matrix,factor) - momentvalues = get_moment_vector(load,transform_matrix,factor) - if 'CONST' == getattr(activity, 'PredefinedType', None) or activity.is_a('IfcStructuralLinearAction'): - constant_force += forcevalues - constant_moment += momentvalues - elif 'PARABOLA' == getattr(activity, 'PredefinedType', None): - quadratic_force += forcevalues - quadratic_moment += momentvalues - elif 'SINUS' == getattr(activity, 'PredefinedType', None): - sinus_force += forcevalues - sinus_moment += momentvalues - return_value = { - "constant force": [constant_force.x,constant_force.y,constant_force.z, - constant_moment.x,constant_moment.y,constant_moment.z], - "quadratic force": [quadratic_force.x,quadratic_force.y,quadratic_force.z, - quadratic_moment.x,quadratic_moment.y,quadratic_moment.z], - "sinus force": [sinus_force.x,sinus_force.y,sinus_force.z, - sinus_moment.x,sinus_moment.y,sinus_moment.z], - "linear load configuration": linear_load_configurations, - "point load configuration": point_load_configurations - } - return return_value diff --git a/src/bonsai/bonsai/bim/module/structural/workspace.py b/src/bonsai/bonsai/bim/module/structural/workspace.py index cec8115a2d..1f4717b9d4 100644 --- a/src/bonsai/bonsai/bim/module/structural/workspace.py +++ b/src/bonsai/bonsai/bim/module/structural/workspace.py @@ -41,8 +41,8 @@ class StructuralTool(WorkSpaceTool): StructuralToolUI.draw(context, layout) -def add_layout_hotkey(layout: bpy.types.UILayout, text: str, hotkey: str, description: str) -> None: - args = ("structural", layout, text, hotkey, description) +def add_layout_hotkey(layout, text, hotkey, description): + args = ["structural", layout, text, hotkey, description] tool.Blender.add_layout_hotkey_operator(*args) From 1918138f68c077da80f460da5fa609928b2b29a5 Mon Sep 17 00:00:00 2001 From: Lucas Nascimento Date: Tue, 17 Dec 2024 17:35:44 -0300 Subject: [PATCH 37/61] cleanup --- .../bonsai/bim/module/structural/decorator.py | 16 +- .../module/structural/load_decoration_data.py | 507 ++++++++++-------- .../bonsai/bim/module/structural/shader.py | 2 +- .../bonsai/bim/module/structural/workspace.py | 4 +- 4 files changed, 291 insertions(+), 238 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/structural/decorator.py b/src/bonsai/bonsai/bim/module/structural/decorator.py index fcf9056a5f..008ac2ea16 100644 --- a/src/bonsai/bonsai/bim/module/structural/decorator.py +++ b/src/bonsai/bonsai/bim/module/structural/decorator.py @@ -1,10 +1,8 @@ -from math import pi from mathutils import Vector import numpy as np import bpy import gpu import blf -from bpy_extras import view3d_utils from bpy.types import SpaceView3D from gpu_extras.batch import batch_for_shader from typing import Iterable, Union @@ -29,7 +27,7 @@ class LoadsDecorator: ) cls.handlers.append(SpaceView3D.draw_handler_add(handler, (), "WINDOW", "POST_VIEW")) cls.decoration_data = ShaderInfo() - cls.update(context) + cls.update() cls.is_installed = True @classmethod @@ -42,7 +40,7 @@ class LoadsDecorator: cls.is_installed = False @classmethod - def update(cls, context:bpy.types.Context) -> None: + def update(cls) -> None: cls.decoration_data.update() cls.text_info = cls.decoration_data.text_info cls.shader_info = cls.decoration_data.info @@ -83,9 +81,8 @@ class LoadsDecorator: #getting depth buffer info, code adapted from: #https://blender.stackexchange.com/questions/177185/is-there-a-way-to-render-depth-buffer-into-a-texture-with-gpu-bgl-python-modules framebuffer = gpu.state.active_framebuffer_get() - viewport_info = gpu.state.viewport_get() - width = viewport_info[2] - height = viewport_info[3] + width = context.region.width + height = context.region.height depth_buffer = framebuffer.read_depth(0, 0, width, height) depth_array = np.array(depth_buffer.to_list()) @@ -95,7 +92,7 @@ class LoadsDecorator: self.depth_array = n / (f - (f - n) * depth_array) * (f - n) for info in self.text_info: - text_position = self.location_3d_to_region_2d(info["position"],info["normal"],context) + text_position = self.location_3d_to_region_2d(info["position"],context) if text_position is not None: font_id = 0 blf.position(font_id, text_position[0], text_position[1], text_position[2]) @@ -103,13 +100,12 @@ class LoadsDecorator: blf.color(font_id, 0.9, 0.9, 0.9, 1.0) blf.draw(font_id, info["text"]) - def location_3d_to_region_2d(self, coord: Iterable, normal: Iterable, context: bpy.types.Context) -> Union[Vector,None]: + def location_3d_to_region_2d(self, coord: Iterable, context: bpy.types.Context) -> Union[Vector,None]: """Convert from 3D space to 2D screen space. Filter out the text supposed to be hidden by 3D elements, using the depth array. It also hides text that are distant from the camera view to avoid clutter""" coord = Vector(coord) - normal = Vector(normal) rv3d = context.region_data perspective = rv3d.view_perspective view_matrix = rv3d.view_matrix diff --git a/src/bonsai/bonsai/bim/module/structural/load_decoration_data.py b/src/bonsai/bonsai/bim/module/structural/load_decoration_data.py index bed81cf736..95d4d7a0a8 100644 --- a/src/bonsai/bonsai/bim/module/structural/load_decoration_data.py +++ b/src/bonsai/bonsai/bim/module/structural/load_decoration_data.py @@ -1,34 +1,67 @@ import bpy -import gpu import bmesh import numpy as np from math import sin -from mathutils import Vector, Matrix +from mathutils import Vector import ifcopenshell import ifcopenshell.api import ifcopenshell.util.attribute +import ifcopenshell.util.unit as ifcunit import bonsai.tool as tool from bonsai.bim.ifc import IfcStore from bonsai.bim.module.structural.shader import DecorationShader +from typing import Literal, TypedDict, Iterable + +MemberInfo = TypedDict("MemberInfo", + {"member": ifcopenshell.entity_instance, + "activities": list[tuple[ifcopenshell.entity_instance,float]]}) + +LoadConfigItem = TypedDict("LoadConfigItem", + {"pos": float, + "descr": Literal["start","end", "middle"], + "load values":np.ndarray}) + +DiscreteConfigItem = TypedDict("DiscreteConfigItem", + {"pos": float, + "values": list[float]}) + +ParsedLoad = TypedDict("ParsedLoad", + {"constant force": list[float], + "quadratic force": list[float], + "sinus force": list[float], + "linear load configuration": list[list[LoadConfigItem]], + "point load configuration": list[list[DiscreteConfigItem]] + }) +LoadByDirection = TypedDict("LoadByDirection", + {"constant": float, + "quadratic": float, + "sinus": float, + "polyline":list[list[float]]}) + +ProcessedLoad = TypedDict("ProcessedLoad", + {"linear loads":LoadByDirection, + "max linear load": float, + "discrete loads": list[list[DiscreteConfigItem]]}) + + class ShaderInfo: - def __init__(self): + def __init__(self) -> None: self.is_empty = True self.shader = DecorationShader() - #self.shader_type = shader_type - #self.args = {} - #self.indices = [] - self.curve_members = {} - self.point_members = {} - self.surface_members = {} + self.curve_members: dict[str,MemberInfo] = {} + self.point_members:dict[str,MemberInfo] = {} + self.surface_members:dict[str,MemberInfo] = {} self.text_info = [] self.info = [] self.force_unit = "" + self.moment_unit = "" self.linear_force_unit = "" + self.linear_moment_unit = "" self.planar_force_unit = "" - def update(self): + def update(self) -> None: self.info = [] self.text_info = [] self.curve_members = {} @@ -42,7 +75,7 @@ class ShaderInfo: if len(self.info): self.is_empty = False - def get_force_units(self): + def get_force_units(self) -> None: def get_unit_symbol(unit: ifcopenshell.entity_instance) -> str: prefix_symbols = { "EXA": "E", @@ -119,39 +152,77 @@ class ShaderInfo: symbol += unit_symbols.get(unit.Name.replace("METER", "METRE"), "?") return symbol + length_units = [u for u in tool.Ifc.get().by_type("IfcNamedUnit") + if u.UnitType == "LENGTHUNIT"] force_units = [u for u in tool.Ifc.get().by_type("IfcNamedUnit") if u.UnitType == "FORCEUNIT"] linear_force_units = [u for u in tool.Ifc.get().by_type("IfcDerivedUnit") if u.UnitType == "LINEARFORCEUNIT"] + linear_moment_units = [u for u in tool.Ifc.get().by_type("IfcDerivedUnit") + if u.UnitType == "LINEARMOMENTUNIT"] planar_force_units = [u for u in tool.Ifc.get().by_type("IfcDerivedUnit") if u.UnitType == "PLANARFORCEUNIT"] conversion_force_unit = [u for u in force_units if u.is_a("IfcConversionBasedUnit")] if len(conversion_force_unit) == 0: conversion_force_unit.append(force_units[0]) - self.force_unit = get_unit_symbol(conversion_force_unit[0]) + self.force_unit = ifcunit.get_unit_symbol(conversion_force_unit[0]) + + conversion_length_unit = [u for u in length_units if u.is_a("IfcConversionBasedUnit")] + if len(conversion_length_unit) == 0: + conversion_length_unit.append(length_units[0]) + length_unit = ifcunit.get_unit_symbol(conversion_length_unit[0]) + self.moment_unit = self.force_unit + "." + length_unit + first = "" second = "" for e in linear_force_units[0].Elements: if e.Unit.UnitType == "FORCEUNIT": - first = get_unit_symbol(e.Unit) + first = ifcunit.get_unit_symbol(e.Unit) if e.Unit.UnitType == "LENGTHUNIT": - second = get_unit_symbol(e.Unit) + second = ifcunit.get_unit_symbol(e.Unit) self.linear_force_unit = first + "/" + second + + first = "" + second = "" + for e in linear_moment_units[0].Elements: + if e.Unit.UnitType == "FORCEUNIT": + first = ifcunit.get_unit_symbol(e.Unit) + if e.Unit.UnitType == "LENGTHUNIT": + second = ifcunit.get_unit_symbol(e.Unit) + self.linear_moment_unit = first + "." + second + "/" + second + first = "" second = "" for e in planar_force_units[0].Elements: if e.Unit.UnitType == "FORCEUNIT": - first = get_unit_symbol(e.Unit) + first = ifcunit.get_unit_symbol(e.Unit) if e.Unit.UnitType == "LENGTHUNIT": - second = get_unit_symbol(e.Unit)+"2" + second = ifcunit.get_unit_symbol(e.Unit)+"2" if e.Unit.UnitType == "AREAUNIT": - second = get_unit_symbol(e.Unit) + second = ifcunit.get_unit_symbol(e.Unit) self.planar_force_unit = first + "/" + second - def get_strucutural_elements_and_activities(self): + def get_strucutural_elements_and_activities(self) -> None: + """fills self.point_members, self.curve_members and self.surface_members dictionaries""" - def populate_members_dict(dict_name,element, activity, factor): + def populate_members_dict(dict_name: Literal["point_members", "curve_members", "surface_members"], + element: ifcopenshell.entity_instance, + activity: ifcopenshell.entity_instance, + factor: float) -> None: + """ + fills self.point_members, self.curve_members and self.surface_members dictionaries + thoses dicts will contain the strucutural member global id as key and a second dict as value + the second dict contais two keys, as follow: + { + "member": the strucutral member itself + "activities: list[(activity, factor)] for each activity applied to the member + } + dict_name: "point_members", "curve_members" or "surface_members" + element: IfcStructuralMember + activity: IfcStructuralActivity + factor: float to multiply the loads values in the structural activity + """ dic = getattr(self,dict_name,None) if dic is None: return @@ -165,8 +236,25 @@ class ShaderInfo: else: member["activities"].append((activity,factor)) - def recursive_subgroups(groups, rec_limit, activity_type, factor = 1): - if len(groups) == 0 or rec_limit == 0: + def recursive_subgroups(groups: list[ifcopenshell.entity_instance], + rec_limit: int, + activity_type: Literal["Action", "External Reaction"], + factor: float = 1) -> None: + """ + Recursively fills self.point_members, self.curve_members and self.surface_members dictionaries + with the structural members to wich the activities in the load group and its subgroups are applied + it also creates a list with all the activities applied to that member that are in the same + load group or subgroup (see populate_members_dict description) + + groups: list of Ifc load case, load group or load combination + rec_limit: maximum number of recursions + activity_type: "Action" or "External Reaction" + factor: the factor applied to the group, default = 1 + this factor will be multiplied by the group coefficient and the factor of a + IfcRelAssignsToGroupByFactor relationship of subgroups in load combinations + + """ + if rec_limit == 0 or len(groups) == 0: return None for group in groups: subgorups = [] @@ -203,21 +291,21 @@ class ShaderInfo: elif element.is_a("IfcStructuralSurfaceMember"): populate_members_dict("surface_members",element,activity,factor) recursive_subgroups(subgorups,rec_limit-1,activity_type,factor=factor) - + props = bpy.context.scene.BIMStructuralProperties group_definition_id = int(props.load_group_to_show) file = IfcStore.get_file() groups = [file.by_id(group_definition_id)] recursive_subgroups(groups,10,props.activity_type) - def get_planar_loads(self): + def get_planar_loads(self) -> None: + """get the necessary information to render the planar load representation in 3D and its text information""" + list_of_surfaces = self.surface_members - shader = self.shader.get("PLANAR LOAD") + shader = self.shader.new("PLANAR LOAD") maximum = 0 for value in list_of_surfaces.values(): surf = value["member"] - activity_list = [getattr(a, 'RelatedStructuralActivity', None) for a in getattr(surf, 'AssignedStructuralActivity', None) - if getattr(a, 'RelatedStructuralActivity', None).is_a() in ['IfcStructuralPlanarAction','IfcStructuralSurfaceAction']] activity_list = value["activities"] if len(activity_list) == 0: continue @@ -246,7 +334,6 @@ class ShaderInfo: bm.verts.ensure_lookup_table() bm.faces.ensure_lookup_table() - add_index = len(positions) for v in bm.verts: p1 = np.array(mat @ v.co) positions.append(p1) @@ -273,7 +360,6 @@ class ShaderInfo: self.text_info.append( {"position": mat @ center - Vector((orientation@values)*0.2/maximum), - "normal": Vector(mesh.polygons[0].normal), "text": f'{values[2]:.5f} {self.planar_force_unit}'} ) @@ -285,7 +371,13 @@ class ShaderInfo: "uniforms": [["color", (0.2,0,1,1)],["spacing", 0.2]] } ) - def get_planar_loads_values(self, activity_list,element_rotation_matrix): + def get_planar_loads_values(self, + activity_list: list[tuple[ifcopenshell.entity_instance,float]], + element_rotation_matrix: np.ndarray) -> np.ndarray: + """ + returns a numpy array with the sum of the values of structural activities + applied loads in each direction, multiplied by the factors in load combinations + """ values = np.zeros((3)) for item in activity_list: activity = item[0] @@ -301,14 +393,20 @@ class ShaderInfo: values += transform@temp return values - def get_surface_member_rotation(self,surface_member): + def get_surface_member_rotation(self, + surface_member: ifcopenshell.entity_instance + ) -> np.ndarray: + """returns the rotation matrix of a structural surface member""" representation = ifcopenshell.util.representation.get_representation(surface_member, "Model") repr_item = representation.Items[0] placement = ifcopenshell.util.placement.get_axis2placement(repr_item.FaceSurface.Position) rotation = placement[0:3,0:3] return rotation - def get_point_connection_rotation(self, point_connection): + def get_point_connection_rotation(self, + point_connection: ifcopenshell.entity_instance + ) -> np.ndarray: + """returns the rotation matrix of a structural point connection""" if point_connection.ConditionCoordinateSystem is not None: placement = ifcopenshell.util.placement.get_axis2placement(point_connection.ConditionCoordinateSystem) else: @@ -316,7 +414,10 @@ class ShaderInfo: rotation = placement[0:3,0:3] return rotation - def get_curve_member_rotation(self, curve_member): + def get_curve_member_rotation(self, + curve_member: ifcopenshell.entity_instance + ) -> np.ndarray: + """returns the rotation matrix of a structural surface member""" z = curve_member.Axis.DirectionRatios edge = curve_member.Representation.Representations[0].Items[0] origin = edge.EdgeStart.VertexGeometry.Coordinates @@ -326,7 +427,10 @@ class ShaderInfo: rotation = placement[0:3,0:3] return rotation - def get_activity_transform_matrix(self, activity, element_rotation_matrix): + def get_activity_transform_matrix(self, + activity: ifcopenshell.entity_instance, + element_rotation_matrix: np.ndarray + ) -> np.ndarray: "provides the transformation matrix to convert between reference frames" global_or_local = activity.GlobalOrLocal props = bpy.context.scene.BIMStructuralProperties @@ -338,28 +442,30 @@ class ShaderInfo: transform_matrix = element_rotation_matrix return transform_matrix - def get_point_loads(self): - list_of_point_connections = tool.Ifc.get().by_type("IfcStructuralPointConnection") + def get_point_loads(self) -> None: + """get the necessary information to render the point load representation in 3D and its text information""" + list_of_point_connections = self.point_members for value in list_of_point_connections.values(): conn = value["member"] - activity_list = [getattr(a, 'RelatedStructuralActivity', None) for a in getattr(conn, 'AssignedStructuralActivity', None) - if getattr(a, 'RelatedStructuralActivity', None).is_a() in ['IfcStructuralPointAction']] activity_list = value["activities"] if len(activity_list) == 0: continue blender_object = IfcStore.get_element(getattr(conn, 'GlobalId', None)) if blender_object.type == 'MESH': conn_location = blender_object.matrix_world @ blender_object.data.vertices[0].co - #get local coordinates of the connection rotation = self.get_point_connection_rotation(conn) loads = self.get_point_loads_values(activity_list, rotation) self.get_point_shader_args(loads, conn_location, rotation) - def get_point_shader_args(self,loads, location, rotation): + def get_point_shader_args(self, + loads: Iterable, + location: np.ndarray, + rotation: np.ndarray + ) -> None: + """get the args to the point shader""" location = np.array(location) indices = [] - text_info = [] direction_dict = { "fx": (np.array((1,0,0)),np.array((0,1,0)),np.array((0,0,1))), "fy": (np.array((0,1,0)),np.array((1,0,0)),np.array((0,0,1))), @@ -403,7 +509,7 @@ class ShaderInfo: c2 = (1,1,0) c3 = (-1,1,0) coords_for_shader = [c1,c2,c3,c2,c3] - shader = self.shader.get("SINGLE FORCE") + shader = self.shader.new("SINGLE FORCE") self.info.append( { "shader": shader, @@ -414,7 +520,6 @@ class ShaderInfo: ) self.text_info.append( {"position": location + d1, - "normal": d2/np.linalg.norm(d2), "text": f'{loads[i]:.2f} {self.force_unit}'} ) else: @@ -428,7 +533,7 @@ class ShaderInfo: c2 = (1,1,0) c3 = (1,-1,0) coords_for_shader = [c1,c2,c3] - shader = self.shader.get("SINGLE MOMENT") + shader = self.shader.new("SINGLE MOMENT") self.info.append( { "shader": shader, @@ -439,11 +544,13 @@ class ShaderInfo: ) self.text_info.append( {"position": location +0.25*(d1 + d2), - "normal": d2/np.linalg.norm(d2), - "text": f'{loads[i]:.2f} {self.force_unit}'}#change to moment unit + "text": f'{loads[i]:.2f} {self.moment_unit}'} ) - def get_point_loads_values(self,activity_list,element_rotation_matrix): + def get_point_loads_values(self, + activity_list: list[tuple[ifcopenshell.entity_instance,float]], + element_rotation_matrix: np.ndarray) -> np.ndarray: + """returns a numpy array with the sum of the point load values""" result_list = np.zeros(6) attr_list = ['ForceX','ForceY','ForceZ','MomentX','MomentY','MomentZ'] for item in activity_list: @@ -463,33 +570,21 @@ class ShaderInfo: return result_list - def get_linear_loads(self): #for now it only works for distributed loads + def get_linear_loads(self)-> None: position = [] indices = [] sin_quad_lin = [] coords_for_shader = [] color = [] - text_info = [] - uniforms = [] info = [] + maxforce = 0 - list_of_curve_members = tool.Ifc.get().by_type("IfcStructuralCurveMember") list_of_curve_members = self.curve_members for value in list_of_curve_members.values(): member = value["member"] - activity_list = [getattr(a, 'RelatedStructuralActivity', None) for a in getattr(member, 'AssignedStructuralActivity', None) - if getattr(a, 'RelatedStructuralActivity', None).is_a() in ['IfcStructuralCurveAction','IfcStructuralLinearAction']] activity_list = value["activities"] if len(activity_list) == 0: continue - # member is a structural curve member - # get Axis attribute from member -> (IFCDIRECTION) - # get Representation attribute from member -> (IFCPRODUCTDEFINITIONSHAPE) - # get Representations attribute from Representation -> (IFCTOPOLOGYREPRESENTATION) - # get Items attribute from Representations -> (IFCEDGE) - # get EdgeStart attribute from Items -> (IFCVERTEX) - # get EdgeEnd attribure from Items -> (IFCVERTEX) - # using blender just get the global coordinates of the first and second vertex in the mesh blender_object = IfcStore.get_element(getattr(member, 'GlobalId', None)) @@ -501,16 +596,11 @@ class ShaderInfo: z_axis = Vector(getattr(z_direction, 'DirectionRatios', None)).normalized() y_axis = z_axis.cross(x_axis).normalized() z_axis = x_axis.cross(y_axis).normalized() - rot = self.get_curve_member_rotation(member) - global_to_local = Matrix(((x_axis.x,y_axis.x,z_axis.x), - (x_axis.y,y_axis.y,z_axis.y), - (x_axis.z,y_axis.z,z_axis.z), - )) - global_to_local = Matrix(rot) + rotation = self.get_curve_member_rotation(member) - #get shader args for each direction + props = bpy.context.scene.BIMStructuralProperties - reference_frame = props.reference_frame #make it a scene property so it can be changed in a panel + reference_frame = props.reference_frame is_local = reference_frame == 'LOCAL_COORDS' x_match = abs(Vector((1,0,0)).dot(x_axis)) > 0.99 y_match = abs(Vector((0,1,0)).dot(x_axis)) > 0.99 @@ -525,24 +615,28 @@ class ShaderInfo: } match_dict = {'fx': x_match or is_local, 'fy': y_match, 'fz': z_match} member_length = Vector(end_co-start_co).length - loads_dict, maxforce, point_loads = self.get_loads_per_direction(activity_list,global_to_local,member_length) - if len(point_loads): + processed_loads = self.process_total_linear_loads(activity_list,rotation,member_length) + linear_loads = processed_loads["linear loads"] + maxforce = max(maxforce,processed_loads["max linear load"]) + point_loads = processed_loads["discrete loads"] + + if len(point_loads) > 0: for item in point_loads: for sub_item in item: pos = sub_item["pos"] values = sub_item["values"] pos_vector = start_co + x_axis*pos - self.get_point_shader_args(values,pos_vector) - if loads_dict is None: + self.get_point_shader_args(values,pos_vector,rotation) + if linear_loads is None: continue keys = ["fx","fy","fz","mx","my","mz"] for key in keys: - polyline = loads_dict[key]["polyline"] - sinus = loads_dict[key]["sinus"] - quadratic = loads_dict[key]["quadratic"] - constant = loads_dict[key]["constant"] - direction = direction_dict[key] #depends on the key and on the frame of reference + polyline = linear_loads[key]["polyline"] + sinus = linear_loads[key]["sinus"] + quadratic = linear_loads[key]["quadratic"] + constant = linear_loads[key]["constant"] + direction = direction_dict[key] color_axis = (0,0,1,1) if 'x' in key: color_axis = (1,0,0,1) @@ -550,47 +644,47 @@ class ShaderInfo: color_axis = (0,1,0,1) if 'f' in key: + unit = self.linear_force_unit if match_dict[key]: - shader = self.shader.get("PARALLEL DISTRIBUTED FORCE") + shader = self.shader.new("PARALLEL DISTRIBUTED FORCE") else: - shader = self.shader.get("PERPENDICULAR DISTRIBUTED FORCE") + shader = self.shader.new("PERPENDICULAR DISTRIBUTED FORCE") else: - shader = self.shader.get("DISTRIBUTED MOMENT") + unit = self.linear_moment_unit + shader = self.shader.new("DISTRIBUTED MOMENT") - addindex = len(position) counter = 0 for i in range(len(polyline)-1): current = Vector(polyline[i]+[0]) nextitem = Vector(polyline[i+1]+[0]) - if any([current.y, nextitem.y,constant,quadratic,sinus]): #if there is load in the z direction + if any([current.y, nextitem.y,constant,quadratic,sinus]): negative = -1*direction + start_co + x_axis*current.x positive = direction + start_co + x_axis*current.x position.append(negative) coords_for_shader.append((current.x, 1.0,member_length)) sin_quad_lin.append((sinus, quadratic, current.y + constant)) color.append(color_axis) - #info to render load value + x = current.x/member_length func = sin(x*3.1416)*sinus + (-4.*x*x+4.*x)*quadratic+constant+current.y if func: - text_info.append( + self.text_info.append( {"position": -1*direction*func/maxforce + start_co + x_axis*current.x, - "normal": direction.cross(x_axis).normalized(), - "text": f'{func:.2f} {self.linear_force_unit}'} + "text": f'{func:.2f} {unit}'} ) - maxforce = max(maxforce,abs(func)) + position.append(positive) coords_for_shader.append((current[0],-1.0,member_length)) sin_quad_lin.append((sinus, quadratic, current.y + constant)) color.append(color_axis) - indices.append((0 + counter + addindex, - 1 + counter + addindex, - 2 + counter + addindex)) - indices.append((3 + counter + addindex, - 2 + counter + addindex, - 1 + counter + addindex)) + indices.append((0 + counter, + 1 + counter, + 2 + counter)) + indices.append((3 + counter, + 2 + counter, + 1 + counter)) if i == len(polyline)-2: negative = -1*direction + start_co + x_axis*nextitem.x positive = direction + start_co + x_axis*nextitem.x @@ -598,23 +692,22 @@ class ShaderInfo: coords_for_shader.append((nextitem.x, 1.0,member_length)) sin_quad_lin.append((sinus, quadratic, nextitem.y + constant)) color.append(color_axis) - #info to render load value + x = nextitem.x/member_length func = sin(x*3.1416)*sinus + (-4.*x*x+4.*x)*quadratic+constant+nextitem.y if func: - text_info.append( + self.text_info.append( {"position": -1*direction*func/maxforce + start_co + x_axis*nextitem.x, - "normal": direction.cross(x_axis).normalized(), - "text": f'{func:.2f} {self.linear_force_unit}'} + "text": f'{func:.2f} {unit}'} ) - maxforce = max(maxforce,abs(func)) + position.append(positive) coords_for_shader.append((nextitem.x,-1.0,member_length)) sin_quad_lin.append((sinus, quadratic, nextitem.y + constant)) color.append(color_axis) counter += 2 - if len(position): + if position: self.info.append( { "shader": shader, @@ -630,34 +723,23 @@ class ShaderInfo: for info in self.info: info["uniforms"][2][1] = maxforce - self.text_info = text_info - - def get_loads_per_direction(self,activity_list,global_to_local,member_length): - """ returns a dict with values for applied loads in each direction - return = { - "fx": values_in_this_direction - "fy": values_in_this_direction - "fz": values_in_this_direction - "mx": values_in_this_direction - "my": values_in_this_direction - "mz": values_in_this_direction - } - values_in_this_direction = { - "constant": float, - "quadratic": float, - "sinus": float, - "polyline": list[(position: float, load: float),...] - } + def process_total_linear_loads(self, + activity_list: list[tuple[ifcopenshell.entity_instance,float]], + element_rotation_matrix: np.ndarray, + member_length: float) -> ProcessedLoad: + """ returns a dict with total values for applied loads in each direction + along with the maximum value for the loads in the member and the discrete loads applied + """ - loads_dict = self.get_loads_dict(activity_list,global_to_local) + loads_dict = self.parse_linear_loads_to_dict(activity_list,element_rotation_matrix) const = loads_dict["constant force"] quad = loads_dict["quadratic force"] sinus = loads_dict["sinus force"] loads = loads_dict["linear load configuration"] unique_list = self.getuniquepositionlist(loads) final_list = [] - return_value = None + distributed_loads = None max_load = 0 for pos in unique_list: value = self.get_before_and_after(pos,loads) @@ -667,11 +749,11 @@ class ShaderInfo: final_list.append([pos]+value["before"]) final_list.append([pos]+value["after"]) - if not len(final_list) and any(const+quad+sinus): + if len(final_list) == 0 and any(const+quad+sinus): final_list.append([0.0,0.0,0.0,0.0,0.0,0.0,0.0]) final_list.append([member_length,0.0,0.0,0.0,0.0,0.0,0.0]) - elif len(final_list): + elif len(final_list)>0: if final_list[0][0] and any(const+quad+sinus): #if first item location is not 0 append an item at the zero final_list = [[0.0,0.0,0.0,0.0,0.0,0.0,0.0]]+final_list else: @@ -680,18 +762,11 @@ class ShaderInfo: final_list.append([member_length,0.0,0.0,0.0,0.0,0.0,0.0]) else: del final_list[-1] - if len(final_list): + if len(final_list)>0: array = np.array(final_list) #7xn -> ["pos","fx","fy","fz","mx","my","mz"] keys = ["fx","fy","fz","mx","my","mz"] - polyline = { - "fx": [], - "fy": [], - "fz": [], - "mx": [], - "my": [], - "mz": [], - } - return_value = { + polyline = [] + distributed_loads = { "fx": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, "fy": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, "fz": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, @@ -705,21 +780,21 @@ class ShaderInfo: any(item for item in array[:,component+1])): for currentitem in final_list: - polyline[key].append([currentitem[0],currentitem[component+1]]) - x = currentitem[0]/member_length - func = sin(x*3.1416)*sinus[component] + (-4.*x*x+4.*x)*quad[component]+const[component]+currentitem[component+1] + polyline.append([currentitem[0],currentitem[component+1]]) max_load = max(max_load,abs(sinus[component]+quad[component]+const[component]+currentitem[component+1])) - inner_dict = return_value[key] + inner_dict = distributed_loads[key] inner_dict["constant"] = const[component] inner_dict["quadratic"] = quad[component] inner_dict["sinus"] = sinus[component] - inner_dict["polyline"] = polyline[key] - return_value[key] = inner_dict + inner_dict["polyline"] = polyline + distributed_loads[key] = inner_dict - return return_value, max_load, loads_dict["point load configuration"] + return {"linear loads":distributed_loads, + "max linear load": max_load, + "discrete loads": loads_dict["point load configuration"]} - def getuniquepositionlist(self, load_config_list): + def getuniquepositionlist(self, load_config_list:list[list[LoadConfigItem]])-> list[float]: """return an ordereded list of unique locations based on the load configuration list ex: load_config_list = [[{"pos":1.0,...},{"pos":3.0,...}], [{"pos":2.0,...},{"pos":3.0,...}], @@ -735,37 +810,41 @@ class ShaderInfo: unique.sort() return unique - def interp1d(self,l1,l2, pos): + def interp1d(self,l1:list[float],l2: list[float], pos:float) -> float: """ 1d linear interpolation for the vector components""" fac = (l2[1]-l1[1])/(l2[0]-l1[0]) v = l1[1] + fac*(pos-l1[0]) return v - def interpolate(self,pos,loadinfo,start,end,key): + def interpolate(self,pos: float,loadinfo:list[LoadConfigItem],start:int,end:int,key: str)-> np.ndarray: """ interpolate the result vectors between load poits""" - result = Vector((0,0,0)) - for i in range(3): + result = np.zeros(6) + for i in range(6): value1 = [loadinfo[start]["pos"], loadinfo[start][key][i]] #[position, force_component] value2= [loadinfo[end]["pos"], loadinfo[end][key][i]] # [position, force_component] result[i] = self.interp1d(value1,value2, pos) # interpolated [position, force_component] return result - def get_before_and_after(self,pos,load_config_list): - """ get total values for forces and moments with polilyne distribution - before and after the position - ex: load_config_list = [[{"pos":1.0,...,"forces":(1,0,0),...},{"pos":3.0,...,"forces":(3,0,0),...}], - [{"pos":2.0,...,"forces":(1,0,0),...},{"pos":3.0,...,"forces":(1,0,0),...}], - [{"pos":1.5,...,"forces":(1,0,0),...},{"pos":2.5,...,"forces":(1,0,0),...}]] - pos = 2.0 - return = { - "before": (3,0,0,0,0,0), ->(fx, fy, fz, mx, my, mz) - " after": (4,0,0,0,0,0) ->(fx, fy, fz, mx, my, mz) - } + def get_before_and_after(self, + pos: float, + load_config_list:list[list[LoadConfigItem]] + ) -> dict[str,list[float]]: + """ get total values for forces and moments before and after the position + example: + pos = 2.0 + load_config_list = [[{"pos":1.0, "descr":"start, "load values":[1,0,0,0,0,0]}, + {"pos":3.0, "descr":"end, "load values":[3,0,0,0,0,0]}], + [{"pos":2.0, "descr":"start, "load values":[1,0,0,0,0,0]}, + {"pos":3.0, "descr":"end, "load values":[1,0,0,0,0,0]}], + [{"pos":1.5, "descr":"start, "load values":[1,0,0,0,0,0]}, + {"pos":2.5, "descr":"end, "load values":[1,0,0,0,0,0]}], + return = { + "before": [3,0,0,0,0,0], ->(fx, fy, fz, mx, my, mz) + " after": [4,0,0,0,0,0] ->(fx, fy, fz, mx, my, mz) + } """ - force_before = Vector((0,0,0)) - force_after = Vector((0,0,0)) - moment_before = Vector((0,0,0)) - moment_after = Vector((0,0,0)) + load_before = np.zeros(6) + load_after = np.zeros(6) for config in load_config_list: if pos < config[0]["pos"] or pos > config[-1]["pos"]: @@ -777,36 +856,32 @@ class ShaderInfo: break if config[start]["pos"] == pos: if config[start]["descr"] in ['start','middle']: - force_after += config[start]["forces"] - moment_after += config[start]["moments"] + load_after += config[start]["load values"] + elif config[start]["descr"] in ['end','middle']: - force_before += config[start]["forces"] - moment_before += config[start]["moments"] + load_before += config[start]["load values"] elif config[end]["pos"] == pos: if config[end]["descr"] in ['start','middle']: - force_after += config[end]["forces"] - moment_after += config[end]["moments"] + load_after += config[end]["load values"] + elif config[end]["descr"] in ['end','middle']: - force_before += config[end]["forces"] - moment_before += config[end]["moments"] + load_before += config[end]["load values"] elif end-start == 1: - force_before += self.interpolate(pos,config,start,end,"forces") - force_after += self.interpolate(pos,config,start,end,"forces") - moment_before += self.interpolate(pos,config,start,end,"moments") - moment_after += self.interpolate(pos,config,start,end,"moments") + load_before += self.interpolate(pos,config,start,end,"load values") + load_after += self.interpolate(pos,config,start,end,"load values") start += 1 end -=1 return_value = { - "before": [force_before.x,force_before.y,force_before.z, - moment_before.x,moment_before.y,moment_before.z], - "after": [force_after.x, force_after.y, force_after.z, - moment_after.x, moment_after.y, moment_after.z] - } + "before": load_before.tolist(), + "after": load_after.tolist() + } return return_value - def get_loads_dict(self,activity_list,element_rotation_matrix): + def parse_linear_loads_to_dict(self, + activity_list: list[tuple[ifcopenshell.entity_instance,float]], + element_rotation_matrix: np.ndarray) -> ParsedLoad: """ get load list activity_list: list of IfcStructuralCurveAction or IfcStructuralCurveReaction @@ -819,7 +894,7 @@ class ShaderInfo: quadratic distribution "sinus force": (fx,fy,fz,mx,my,mz), -> sum of linear loads applied with sinus distribution - "lienar load configuration": list -> list of load configurations for linear + "linear load configuration": list -> list of load configurations for linear and polyline distributions of linear loads } description of "linear load configuration": @@ -830,48 +905,37 @@ class ShaderInfo: dict{ "pos": float, -> local position along curve length "descr": string, -> describe if the item is at the start, middle or end of the list - "forces": Vector, -> linear force applied at that point - "moments": Vector -> linear moment applied at that point + "load values": Array, -> linear force applied at that point } ] ] """ - constant_force = Vector((0,0,0)) - constant_moment = Vector((0,0,0)) - quadratic_force = Vector((0,0,0)) - quadratic_moment = Vector((0,0,0)) - sinus_force = Vector((0,0,0)) - sinus_moment = Vector((0,0,0)) + constant = np.zeros(6) + quadratic = np.zeros(6) + sinus = np.zeros(6) linear_load_configurations = [] point_load_configurations = [] unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get(),"LENGTHUNIT") - def get_force_vector(load,transform_matrix,factor = 1.0): - x = 0 if getattr(load, 'LinearForceX', 0) is None else getattr(load, 'LinearForceX', 0) - y = 0 if getattr(load, 'LinearForceY', 0) is None else getattr(load, 'LinearForceY', 0) - z = 0 if getattr(load, 'LinearForceZ', 0) is None else getattr(load, 'LinearForceZ', 0) - return transform_matrix @ (Vector((x,y,z))*factor) - - def get_moment_vector(load,transform_matrix,factor = 1.0): - x = 0 if getattr(load, 'LinearMomentX', 0) is None else getattr(load, 'LinearMomentX', 0) - y = 0 if getattr(load, 'LinearMomentY', 0) is None else getattr(load, 'LinearMomentY', 0) - z = 0 if getattr(load, 'LinearMomentZ', 0) is None else getattr(load, 'LinearMomentZ', 0) - return transform_matrix @ (Vector((x,y,z))*factor) + def get_load_values(load,transform_matrix,factor = 1.0): + result = np.zeros(6) + keys = ['LinearForceX','LinearForceY','LinearForceZ','LinearMomentX','LinearMomentY','LinearMomentZ'] + for i, key in enumerate(keys): + value = 0 if getattr(load, key, 0) is None else getattr(load, key, 0) + result[i] += value*factor + return transform_matrix @ result for item in activity_list: activity = item[0] factor = item[1] load = activity.AppliedLoad - global_or_local = activity.GlobalOrLocal - props = bpy.context.scene.BIMStructuralProperties - reference_frame = props.reference_frame #make it a scene property so it can be changed in a panel - transform_matrix = Matrix() - if reference_frame == 'LOCAL_COORDS' and global_or_local != reference_frame: - transform_matrix = element_rotation_matrix - transform_matrix.invert() - elif reference_frame == 'GLOBAL_COORDS' and global_or_local != reference_frame: - transform_matrix = element_rotation_matrix + + transform_3by3 = self.get_activity_transform_matrix(activity,element_rotation_matrix) + transform_6by6 = np.zeros((6,6)) + transform_6by6[0:3,0:3] = transform_3by3 + transform_6by6[3:6,3:6] = transform_3by3 + #values for linear loads if load.is_a('IfcStructuralLoadConfiguration'): locations = getattr(load, 'Locations', []) @@ -880,8 +944,7 @@ class ShaderInfo: ] config_list = [] for i,l in enumerate(values): - forcevalues = get_force_vector(l,transform_matrix,factor) - momentvalues = get_moment_vector(l,transform_matrix,factor) + load_values = get_load_values(l,transform_6by6,factor) if i == 0: descr = 'start' elif i == len(values)-1: @@ -891,20 +954,20 @@ class ShaderInfo: config_list.append( {"pos": locations[i][0]*unit_scale, "descr": descr, - "forces":forcevalues, - "moments":momentvalues} + "load values":load_values} ) linear_load_configurations.append(config_list) + #load configurations with point loads values = [l for l in getattr(load, 'Values', None) if l.is_a() == "IfcStructuralLoadSingleForce" ] attr_list = ['ForceX','ForceY','ForceZ','MomentX','MomentY','MomentZ'] config_list = [] - for i,load in enumerate(values): + for i,val in enumerate(values): result_list = [0,0,0,0,0,0] for j, attr in enumerate(attr_list): - value = 0 if getattr(load, attr, 0) is None else getattr(load, attr, 0) + value = 0 if getattr(val, attr, 0) is None else getattr(val, attr, 0) result_list[j] += value*factor config_list.append( {"pos": locations[i][0]*unit_scale, @@ -913,25 +976,19 @@ class ShaderInfo: point_load_configurations.append(config_list) else: - forcevalues = get_force_vector(load,transform_matrix,factor) - momentvalues = get_moment_vector(load,transform_matrix,factor) + load_values = get_load_values(load,transform_6by6,factor) if 'CONST' == getattr(activity, 'PredefinedType', None) or activity.is_a('IfcStructuralLinearAction'): - constant_force += forcevalues - constant_moment += momentvalues + constant += load_values elif 'PARABOLA' == getattr(activity, 'PredefinedType', None): - quadratic_force += forcevalues - quadratic_moment += momentvalues + quadratic += load_values elif 'SINUS' == getattr(activity, 'PredefinedType', None): - sinus_force += forcevalues - sinus_moment += momentvalues + sinus += load_values return_value = { - "constant force": [constant_force.x,constant_force.y,constant_force.z, - constant_moment.x,constant_moment.y,constant_moment.z], - "quadratic force": [quadratic_force.x,quadratic_force.y,quadratic_force.z, - quadratic_moment.x,quadratic_moment.y,quadratic_moment.z], - "sinus force": [sinus_force.x,sinus_force.y,sinus_force.z, - sinus_moment.x,sinus_moment.y,sinus_moment.z], + "constant force": constant.tolist(), + "quadratic force": quadratic.tolist(), + "sinus force": sinus.tolist(), "linear load configuration": linear_load_configurations, "point load configuration": point_load_configurations } return return_value + diff --git a/src/bonsai/bonsai/bim/module/structural/shader.py b/src/bonsai/bonsai/bim/module/structural/shader.py index 881b97cc49..cd7f14a53d 100644 --- a/src/bonsai/bonsai/bim/module/structural/shader.py +++ b/src/bonsai/bonsai/bim/module/structural/shader.py @@ -5,7 +5,7 @@ class DecorationShader: "shader for the load decorations" def __init__(self): pass - def get(self, pattern: str) -> gpu.types.GPUShader: + def new(self, pattern: str) -> gpu.types.GPUShader: """pattern: string description of the desired shader Possible values PERPENDICULAR DISTRIBUTED FORCE: pattern for distributed force diff --git a/src/bonsai/bonsai/bim/module/structural/workspace.py b/src/bonsai/bonsai/bim/module/structural/workspace.py index 1f4717b9d4..cec8115a2d 100644 --- a/src/bonsai/bonsai/bim/module/structural/workspace.py +++ b/src/bonsai/bonsai/bim/module/structural/workspace.py @@ -41,8 +41,8 @@ class StructuralTool(WorkSpaceTool): StructuralToolUI.draw(context, layout) -def add_layout_hotkey(layout, text, hotkey, description): - args = ["structural", layout, text, hotkey, description] +def add_layout_hotkey(layout: bpy.types.UILayout, text: str, hotkey: str, description: str) -> None: + args = ("structural", layout, text, hotkey, description) tool.Blender.add_layout_hotkey_operator(*args) From a329de9f7152a57ceded719f856454f4c003b097 Mon Sep 17 00:00:00 2001 From: Lucas Nascimento Date: Wed, 18 Dec 2024 14:09:11 -0300 Subject: [PATCH 38/61] licence comment --- .../bonsai/bim/module/structural/decorator.py | 18 ++++++++++++++++++ .../module/structural/load_decoration_data.py | 18 ++++++++++++++++++ .../bonsai/bim/module/structural/operator.py | 2 +- .../bonsai/bim/module/structural/shader.py | 17 +++++++++++++++++ 4 files changed, 54 insertions(+), 1 deletion(-) diff --git a/src/bonsai/bonsai/bim/module/structural/decorator.py b/src/bonsai/bonsai/bim/module/structural/decorator.py index 008ac2ea16..840c6bea31 100644 --- a/src/bonsai/bonsai/bim/module/structural/decorator.py +++ b/src/bonsai/bonsai/bim/module/structural/decorator.py @@ -1,3 +1,21 @@ +# Bonsai - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of Bonsai. +# +# Bonsai is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Bonsai is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Bonsai. If not, see . + from mathutils import Vector import numpy as np import bpy diff --git a/src/bonsai/bonsai/bim/module/structural/load_decoration_data.py b/src/bonsai/bonsai/bim/module/structural/load_decoration_data.py index 95d4d7a0a8..119d0227a9 100644 --- a/src/bonsai/bonsai/bim/module/structural/load_decoration_data.py +++ b/src/bonsai/bonsai/bim/module/structural/load_decoration_data.py @@ -1,3 +1,21 @@ +# Bonsai - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of Bonsai. +# +# Bonsai is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Bonsai is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Bonsai. If not, see . + import bpy import bmesh import numpy as np diff --git a/src/bonsai/bonsai/bim/module/structural/operator.py b/src/bonsai/bonsai/bim/module/structural/operator.py index 4070c6ae35..62e2dffe1f 100644 --- a/src/bonsai/bonsai/bim/module/structural/operator.py +++ b/src/bonsai/bonsai/bim/module/structural/operator.py @@ -36,7 +36,7 @@ class ShowLoads(bpy.types.Operator): def modal(self, context, event): if event.type == 'F5': - LoadsDecorator.update(context) + LoadsDecorator.update() for area in context.screen.areas: if area.type == 'VIEW_3D': area.tag_redraw() diff --git a/src/bonsai/bonsai/bim/module/structural/shader.py b/src/bonsai/bonsai/bim/module/structural/shader.py index cd7f14a53d..29e710fafe 100644 --- a/src/bonsai/bonsai/bim/module/structural/shader.py +++ b/src/bonsai/bonsai/bim/module/structural/shader.py @@ -1,3 +1,20 @@ +# Bonsai - OpenBIM Blender Add-on +# Copyright (C) 2020, 2021 Dion Moult +# +# This file is part of Bonsai. +# +# Bonsai is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Bonsai is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Bonsai. If not, see . import gpu From 80996dee1f3a97807cf1b8a93f3a3ab7d1714db6 Mon Sep 17 00:00:00 2001 From: LM-Nascimento Date: Wed, 18 Dec 2024 14:42:23 -0300 Subject: [PATCH 39/61] Update unit.py --- src/ifcopenshell-python/ifcopenshell/util/unit.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/ifcopenshell-python/ifcopenshell/util/unit.py b/src/ifcopenshell-python/ifcopenshell/util/unit.py index 329ccff281..a19594f1b5 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/unit.py +++ b/src/ifcopenshell-python/ifcopenshell/util/unit.py @@ -289,15 +289,11 @@ unit_symbols = { "SECOND": "s", "SQUARE_METRE": "m2", "METRE": "m", - # non si units - "cubic inch": "in3", - "cubic foot": "ft3", - "cubic yard": "yd3", - "square inch": "in2", - "square foot": "ft2", - "square yard": "yd2", - "square mile": "mi2", + "NEWTON": "N", + "PASCAL": "Pa", # conversion based units + "pound-force": "lbf", + "pound-force per square inch": "psi", "thou": "th", "inch": "in", "foot": "ft", From dff9f56ce3634365f02ecddeaa00b354014eccb8 Mon Sep 17 00:00:00 2001 From: Lucas Nascimento Date: Wed, 18 Dec 2024 14:46:46 -0300 Subject: [PATCH 40/61] black formatting and changes in shader typing --- .../bonsai/bim/module/structural/data.py | 22 +- .../bonsai/bim/module/structural/decorator.py | 48 +- .../module/structural/load_decoration_data.py | 797 +++++++++--------- .../bonsai/bim/module/structural/operator.py | 18 +- .../bonsai/bim/module/structural/prop.py | 33 +- .../bonsai/bim/module/structural/shader.py | 351 ++++---- src/bonsai/bonsai/bim/module/structural/ui.py | 15 +- 7 files changed, 644 insertions(+), 640 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/structural/data.py b/src/bonsai/bonsai/bim/module/structural/data.py index bef238f92e..9a55a826fb 100644 --- a/src/bonsai/bonsai/bim/module/structural/data.py +++ b/src/bonsai/bonsai/bim/module/structural/data.py @@ -32,6 +32,7 @@ def refresh(): BoundaryConditionsData.is_loaded = False LoadGroupDecorationData.is_loaded = False + class LoadGroupDecorationData: data = {} is_loaded = False @@ -40,15 +41,16 @@ class LoadGroupDecorationData: def load(cls): cls.data = {"load groups to show": cls.load_groups_to_show()} cls.is_loaded = True - + @classmethod def load_groups_to_show(cls): ret = [] - abrv = {"LOAD_CASE": "L.Case: ", - "LOAD_COMBINATION": "L.Comb: ", - "LOAD_GROUP": "L.Gr: ", - "USERDEFINED": "U.Def: ", - "NOTDEFINED": "N.Def: " + abrv = { + "LOAD_CASE": "L.Case: ", + "LOAD_COMBINATION": "L.Comb: ", + "LOAD_GROUP": "L.Gr: ", + "USERDEFINED": "U.Def: ", + "NOTDEFINED": "N.Def: ", } models = tool.Ifc.get().by_type("IfcStructuralAnalysisModel") m = models[0] @@ -56,21 +58,21 @@ class LoadGroupDecorationData: if props.activity_type == "Action": groups = m.LoadedBy or [] for g in groups: - ret.append((str(g.id()),". "+abrv[g.PredefinedType]+" "+g.Name,"")) + ret.append((str(g.id()), ". " + abrv[g.PredefinedType] + " " + g.Name, "")) related_objects = [rel.RelatedObjects for rel in g.IsGroupedBy] for item in related_objects: for subgoup in [sg for sg in item if sg.is_a("IfcStructuralLoadGroup")]: - ret.append((str(subgoup.id()),". "+abrv[subgoup.PredefinedType]+subgoup.Name,"")) + ret.append((str(subgoup.id()), ". " + abrv[subgoup.PredefinedType] + subgoup.Name, "")) if props.activity_type == "External Reaction": groups = m.HasResults or [] for g in groups: result_name = g.ResultForLoadGroup.Name or "" group_name = g.Name or "" - ret.append((str(g.id()), group_name + " " + result_name,"")) + ret.append((str(g.id()), group_name + " " + result_name, "")) if len(ret) == 0: - ret.append(("","","")) + ret.append(("", "", "")) return ret diff --git a/src/bonsai/bonsai/bim/module/structural/decorator.py b/src/bonsai/bonsai/bim/module/structural/decorator.py index 840c6bea31..f17c643d34 100644 --- a/src/bonsai/bonsai/bim/module/structural/decorator.py +++ b/src/bonsai/bonsai/bim/module/structural/decorator.py @@ -26,8 +26,10 @@ from gpu_extras.batch import batch_for_shader from typing import Iterable, Union from bonsai.bim.module.structural.load_decoration_data import ShaderInfo + class LoadsDecorator: """Decorator to show strucutural loads in 3D""" + is_installed = False handlers = [] decoration_data = None @@ -36,20 +38,20 @@ class LoadsDecorator: depth_array = None @classmethod - def install(cls, context: bpy.types.Context)-> None: + def install(cls, context: bpy.types.Context) -> None: if cls.is_installed: cls.uninstall() handler = cls() cls.handlers.append( SpaceView3D.draw_handler_add(handler.draw_load_values, ((context,)), "WINDOW", "POST_PIXEL") - ) + ) cls.handlers.append(SpaceView3D.draw_handler_add(handler, (), "WINDOW", "POST_VIEW")) cls.decoration_data = ShaderInfo() cls.update() cls.is_installed = True @classmethod - def uninstall(cls)-> None: + def uninstall(cls) -> None: for handler in cls.handlers: try: SpaceView3D.draw_handler_remove(handler, "WINDOW") @@ -68,8 +70,8 @@ class LoadsDecorator: # set open gl configurations original_blend = gpu.state.blend_get() original_depth_test = gpu.state.depth_test_get() - gpu.state.blend_set('ALPHA') - gpu.state.depth_test_set('LESS_EQUAL') + gpu.state.blend_set("ALPHA") + gpu.state.depth_test_set("LESS_EQUAL") self.draw_batch() @@ -80,11 +82,11 @@ class LoadsDecorator: def draw_batch(self) -> None: """draw the 3D representation of loads""" if not self.decoration_data.is_empty: - for info in self.shader_info: + for info in self.shader_info: shader = info["shader"] args = info["args"] indices = info["indices"] - batch = batch_for_shader(shader, 'TRIS', args, indices=indices) + batch = batch_for_shader(shader, "TRIS", args, indices=indices) matrix = bpy.context.region_data.perspective_matrix shader.bind() shader.uniform_float("viewProjectionMatrix", matrix) @@ -96,10 +98,10 @@ class LoadsDecorator: def draw_load_values(self, context: bpy.types.Context) -> None: """draw text representing the load values""" - #getting depth buffer info, code adapted from: - #https://blender.stackexchange.com/questions/177185/is-there-a-way-to-render-depth-buffer-into-a-texture-with-gpu-bgl-python-modules + # getting depth buffer info, code adapted from: + # https://blender.stackexchange.com/questions/177185/is-there-a-way-to-render-depth-buffer-into-a-texture-with-gpu-bgl-python-modules framebuffer = gpu.state.active_framebuffer_get() - width = context.region.width + width = context.region.width height = context.region.height depth_buffer = framebuffer.read_depth(0, 0, width, height) depth_array = np.array(depth_buffer.to_list()) @@ -110,7 +112,7 @@ class LoadsDecorator: self.depth_array = n / (f - (f - n) * depth_array) * (f - n) for info in self.text_info: - text_position = self.location_3d_to_region_2d(info["position"],context) + text_position = self.location_3d_to_region_2d(info["position"], context) if text_position is not None: font_id = 0 blf.position(font_id, text_position[0], text_position[1], text_position[2]) @@ -118,7 +120,7 @@ class LoadsDecorator: blf.color(font_id, 0.9, 0.9, 0.9, 1.0) blf.draw(font_id, info["text"]) - def location_3d_to_region_2d(self, coord: Iterable, context: bpy.types.Context) -> Union[Vector,None]: + def location_3d_to_region_2d(self, coord: Iterable, context: bpy.types.Context) -> Union[Vector, None]: """Convert from 3D space to 2D screen space. Filter out the text supposed to be hidden by 3D elements, using the depth array. It also hides text that are distant from the camera view to avoid clutter""" @@ -129,18 +131,26 @@ class LoadsDecorator: view_matrix = rv3d.view_matrix point_view_space = view_matrix @ coord - - if perspective == 'ORTHO' or -10 < point_view_space.z < 0: + if perspective == "ORTHO" or -10 < point_view_space.z < 0: prj = rv3d.perspective_matrix @ Vector((coord[0], coord[1], coord[2], 1.0)) width_half = context.region.width / 2.0 height_half = context.region.height / 2.0 - coord_2d = Vector((width_half + width_half * (prj.x / prj.w), - height_half + height_half * (prj.y / prj.w), - point_view_space.z)) - if coord_2d[0] < 0 or coord_2d[0]> context.region.width or coord_2d[1] > context.region.height or coord_2d[1] < 0: + coord_2d = Vector( + ( + width_half + width_half * (prj.x / prj.w), + height_half + height_half * (prj.y / prj.w), + point_view_space.z, + ) + ) + if ( + coord_2d[0] < 0 + or coord_2d[0] > context.region.width + or coord_2d[1] > context.region.height + or coord_2d[1] < 0 + ): return None depth = self.depth_array[int(coord_2d[1])][int(coord_2d[0])] - if -0.98*point_view_space.z > depth: + if -0.98 * point_view_space.z > depth: return None return coord_2d return None diff --git a/src/bonsai/bonsai/bim/module/structural/load_decoration_data.py b/src/bonsai/bonsai/bim/module/structural/load_decoration_data.py index 119d0227a9..5a9817b7f9 100644 --- a/src/bonsai/bonsai/bim/module/structural/load_decoration_data.py +++ b/src/bonsai/bonsai/bim/module/structural/load_decoration_data.py @@ -30,47 +30,44 @@ from bonsai.bim.ifc import IfcStore from bonsai.bim.module.structural.shader import DecorationShader from typing import Literal, TypedDict, Iterable -MemberInfo = TypedDict("MemberInfo", - {"member": ifcopenshell.entity_instance, - "activities": list[tuple[ifcopenshell.entity_instance,float]]}) +MemberInfo = TypedDict( + "MemberInfo", + {"member": ifcopenshell.entity_instance, "activities": list[tuple[ifcopenshell.entity_instance, float]]}, +) -LoadConfigItem = TypedDict("LoadConfigItem", - {"pos": float, - "descr": Literal["start","end", "middle"], - "load values":np.ndarray}) +LoadConfigItem = TypedDict( + "LoadConfigItem", {"pos": float, "descr": Literal["start", "end", "middle"], "load values": np.ndarray} +) -DiscreteConfigItem = TypedDict("DiscreteConfigItem", - {"pos": float, - "values": list[float]}) - -ParsedLoad = TypedDict("ParsedLoad", - {"constant force": list[float], - "quadratic force": list[float], - "sinus force": list[float], - "linear load configuration": list[list[LoadConfigItem]], - "point load configuration": list[list[DiscreteConfigItem]] - }) -LoadByDirection = TypedDict("LoadByDirection", - {"constant": float, - "quadratic": float, - "sinus": float, - "polyline":list[list[float]]}) - -ProcessedLoad = TypedDict("ProcessedLoad", - {"linear loads":LoadByDirection, - "max linear load": float, - "discrete loads": list[list[DiscreteConfigItem]]}) +DiscreteConfigItem = TypedDict("DiscreteConfigItem", {"pos": float, "values": list[float]}) +ParsedLoad = TypedDict( + "ParsedLoad", + { + "constant force": list[float], + "quadratic force": list[float], + "sinus force": list[float], + "linear load configuration": list[list[LoadConfigItem]], + "point load configuration": list[list[DiscreteConfigItem]], + }, +) +LoadByDirection = TypedDict( + "LoadByDirection", {"constant": float, "quadratic": float, "sinus": float, "polyline": list[list[float]]} +) +ProcessedLoad = TypedDict( + "ProcessedLoad", + {"linear loads": LoadByDirection, "max linear load": float, "discrete loads": list[list[DiscreteConfigItem]]}, +) class ShaderInfo: def __init__(self) -> None: self.is_empty = True self.shader = DecorationShader() - self.curve_members: dict[str,MemberInfo] = {} - self.point_members:dict[str,MemberInfo] = {} - self.surface_members:dict[str,MemberInfo] = {} + self.curve_members: dict[str, MemberInfo] = {} + self.point_members: dict[str, MemberInfo] = {} + self.surface_members: dict[str, MemberInfo] = {} self.text_info = [] self.info = [] self.force_unit = "" @@ -78,7 +75,7 @@ class ShaderInfo: self.linear_force_unit = "" self.linear_moment_unit = "" self.planar_force_unit = "" - + def update(self) -> None: self.info = [] self.text_info = [] @@ -92,7 +89,7 @@ class ShaderInfo: self.get_planar_loads() if len(self.info): self.is_empty = False - + def get_force_units(self) -> None: def get_unit_symbol(unit: ifcopenshell.entity_instance) -> str: prefix_symbols = { @@ -125,7 +122,7 @@ class ShaderInfo: "PASCAL": "Pa", # conversion based units "pound-force": "lbf", - 'pound-force per square inch': "psi", + "pound-force per square inch": "psi", "thou": "th", "inch": "in", "foot": "ft", @@ -169,18 +166,13 @@ class ShaderInfo: symbol += prefix_symbols.get(unit.Prefix, "") symbol += unit_symbols.get(unit.Name.replace("METER", "METRE"), "?") return symbol - - length_units = [u for u in tool.Ifc.get().by_type("IfcNamedUnit") - if u.UnitType == "LENGTHUNIT"] - force_units = [u for u in tool.Ifc.get().by_type("IfcNamedUnit") - if u.UnitType == "FORCEUNIT"] - linear_force_units = [u for u in tool.Ifc.get().by_type("IfcDerivedUnit") - if u.UnitType == "LINEARFORCEUNIT"] - linear_moment_units = [u for u in tool.Ifc.get().by_type("IfcDerivedUnit") - if u.UnitType == "LINEARMOMENTUNIT"] - planar_force_units = [u for u in tool.Ifc.get().by_type("IfcDerivedUnit") - if u.UnitType == "PLANARFORCEUNIT"] - + + length_units = [u for u in tool.Ifc.get().by_type("IfcNamedUnit") if u.UnitType == "LENGTHUNIT"] + force_units = [u for u in tool.Ifc.get().by_type("IfcNamedUnit") if u.UnitType == "FORCEUNIT"] + linear_force_units = [u for u in tool.Ifc.get().by_type("IfcDerivedUnit") if u.UnitType == "LINEARFORCEUNIT"] + linear_moment_units = [u for u in tool.Ifc.get().by_type("IfcDerivedUnit") if u.UnitType == "LINEARMOMENTUNIT"] + planar_force_units = [u for u in tool.Ifc.get().by_type("IfcDerivedUnit") if u.UnitType == "PLANARFORCEUNIT"] + conversion_force_unit = [u for u in force_units if u.is_a("IfcConversionBasedUnit")] if len(conversion_force_unit) == 0: conversion_force_unit.append(force_units[0]) @@ -208,7 +200,7 @@ class ShaderInfo: first = ifcunit.get_unit_symbol(e.Unit) if e.Unit.UnitType == "LENGTHUNIT": second = ifcunit.get_unit_symbol(e.Unit) - self.linear_moment_unit = first + "." + second + "/" + second + self.linear_moment_unit = first + "." + second + "/" + second first = "" second = "" @@ -216,18 +208,20 @@ class ShaderInfo: if e.Unit.UnitType == "FORCEUNIT": first = ifcunit.get_unit_symbol(e.Unit) if e.Unit.UnitType == "LENGTHUNIT": - second = ifcunit.get_unit_symbol(e.Unit)+"2" + second = ifcunit.get_unit_symbol(e.Unit) + "2" if e.Unit.UnitType == "AREAUNIT": second = ifcunit.get_unit_symbol(e.Unit) self.planar_force_unit = first + "/" + second - + def get_strucutural_elements_and_activities(self) -> None: """fills self.point_members, self.curve_members and self.surface_members dictionaries""" - def populate_members_dict(dict_name: Literal["point_members", "curve_members", "surface_members"], - element: ifcopenshell.entity_instance, - activity: ifcopenshell.entity_instance, - factor: float) -> None: + def populate_members_dict( + dict_name: Literal["point_members", "curve_members", "surface_members"], + element: ifcopenshell.entity_instance, + activity: ifcopenshell.entity_instance, + factor: float, + ) -> None: """ fills self.point_members, self.curve_members and self.surface_members dictionaries thoses dicts will contain the strucutural member global id as key and a second dict as value @@ -241,23 +235,21 @@ class ShaderInfo: activity: IfcStructuralActivity factor: float to multiply the loads values in the structural activity """ - dic = getattr(self,dict_name,None) + dic = getattr(self, dict_name, None) if dic is None: return member = dic.get(element.GlobalId) if member is None: - dic.update({ - element.GlobalId: { - "member": element, - "activities": [(activity,factor)]} - }) + dic.update({element.GlobalId: {"member": element, "activities": [(activity, factor)]}}) else: - member["activities"].append((activity,factor)) + member["activities"].append((activity, factor)) - def recursive_subgroups(groups: list[ifcopenshell.entity_instance], - rec_limit: int, - activity_type: Literal["Action", "External Reaction"], - factor: float = 1) -> None: + def recursive_subgroups( + groups: list[ifcopenshell.entity_instance], + rec_limit: int, + activity_type: Literal["Action", "External Reaction"], + factor: float = 1, + ) -> None: """ Recursively fills self.point_members, self.curve_members and self.surface_members dictionaries with the structural members to wich the activities in the load group and its subgroups are applied @@ -278,8 +270,8 @@ class ShaderInfo: subgorups = [] activities = [] relationship = [rel for rel in group.IsGroupedBy] - coef = getattr(group, 'Coefficient', 1.0) - group_coef = coef if coef is not None else 1.0 + coef = getattr(group, "Coefficient", 1.0) + group_coef = coef if coef is not None else 1.0 rel_factor = 1.0 for rel in relationship: @@ -288,33 +280,36 @@ class ShaderInfo: objects = rel.RelatedObjects subgorups = [sg for sg in objects if sg.is_a("IfcStructuralLoadGroup")] activities = [a for a in objects if a.is_a("IfcStructuralActivity")] - factor = factor*group_coef*rel_factor + factor = factor * group_coef * rel_factor for activity in activities: if len(activity.AssignedToStructuralItem): element = activity.AssignedToStructuralItem[0].RelatingElement if element is not None: if activity_type == "Action": if element.is_a("IfcStructuralCurveMember"): - populate_members_dict("curve_members",element,activity,factor) + populate_members_dict("curve_members", element, activity, factor) elif element.is_a("IfcStructuralPointConnection"): - populate_members_dict("point_members",element,activity,factor) + populate_members_dict("point_members", element, activity, factor) elif element.is_a("IfcStructuralSurfaceMember"): - populate_members_dict("surface_members",element,activity,factor) + populate_members_dict("surface_members", element, activity, factor) - elif activity_type == "External Reaction" and getattr(element,"AppliedCondition",None) is not None: + elif ( + activity_type == "External Reaction" + and getattr(element, "AppliedCondition", None) is not None + ): if element.is_a("IfcStructuralCurveMember"): - populate_members_dict("curve_members",element,activity,factor) + populate_members_dict("curve_members", element, activity, factor) elif element.is_a("IfcStructuralPointConnection"): - populate_members_dict("point_members",element,activity,factor) + populate_members_dict("point_members", element, activity, factor) elif element.is_a("IfcStructuralSurfaceMember"): - populate_members_dict("surface_members",element,activity,factor) - recursive_subgroups(subgorups,rec_limit-1,activity_type,factor=factor) - + populate_members_dict("surface_members", element, activity, factor) + recursive_subgroups(subgorups, rec_limit - 1, activity_type, factor=factor) + props = bpy.context.scene.BIMStructuralProperties group_definition_id = int(props.load_group_to_show) file = IfcStore.get_file() groups = [file.by_id(group_definition_id)] - recursive_subgroups(groups,10,props.activity_type) + recursive_subgroups(groups, 10, props.activity_type) def get_planar_loads(self) -> None: """get the necessary information to render the planar load representation in 3D and its text information""" @@ -328,7 +323,7 @@ class ShaderInfo: if len(activity_list) == 0: continue rotation = self.get_surface_member_rotation(surf) - values = self.get_planar_loads_values(activity_list,rotation) + values = self.get_planar_loads_values(activity_list, rotation) if maximum == 0: maximum = max([abs(float(i)) for i in values]) if maximum == 0: @@ -338,16 +333,16 @@ class ShaderInfo: orientation = np.eye(3) if reference_frame == "LOCAL_COORDS": orientation = rotation - blender_object: bpy.types.Object = IfcStore.get_element(getattr(surf, 'GlobalId', None)) + blender_object: bpy.types.Object = IfcStore.get_element(getattr(surf, "GlobalId", None)) mat = blender_object.matrix_world mesh: bpy.types.Mesh = blender_object.data - + positions = [] indices = [] coord = [] bm = bmesh.new() bm.from_mesh(mesh) - bmesh.ops.triangulate(bm, faces = bm.faces) + bmesh.ops.triangulate(bm, faces=bm.faces) bm.edges.ensure_lookup_table() bm.verts.ensure_lookup_table() bm.faces.ensure_lookup_table() @@ -355,43 +350,40 @@ class ShaderInfo: for v in bm.verts: p1 = np.array(mat @ v.co) positions.append(p1) - p2 = p1 - (orientation@values)*0.2/maximum + p2 = p1 - (orientation @ values) * 0.2 / maximum positions.append(p2) - coord.append((float(p1[0]+p1[1]),0,1)) - coord.append((float(p1[0]+p1[1]),1,1)) + coord.append((float(p1[0] + p1[1]), 0, 1)) + coord.append((float(p1[0] + p1[1]), 1, 1)) for e in bm.edges: if len(e.link_faces) > 1: continue - indices.append((2*e.verts[0].index, - 2*e.verts[0].index+1, - 2*e.verts[1].index)) - indices.append((2*e.verts[0].index+1, - 2*e.verts[1].index, - 2*e.verts[1].index+1)) + indices.append((2 * e.verts[0].index, 2 * e.verts[0].index + 1, 2 * e.verts[1].index)) + indices.append((2 * e.verts[0].index + 1, 2 * e.verts[1].index, 2 * e.verts[1].index + 1)) for p in bm.faces: - indices.append((2*p.verts[0].index+1, - 2*p.verts[1].index+1, - 2*p.verts[2].index+1)) - bmesh.ops.dissolve_limit(bm, angle_limit = 0.01, verts = bm.verts, edges = bm.edges) + indices.append((2 * p.verts[0].index + 1, 2 * p.verts[1].index + 1, 2 * p.verts[2].index + 1)) + bmesh.ops.dissolve_limit(bm, angle_limit=0.01, verts=bm.verts, edges=bm.edges) bm.faces.ensure_lookup_table() center = bm.faces[0].calc_center_bounds() self.text_info.append( - {"position": mat @ center - Vector((orientation@values)*0.2/maximum), - "text": f'{values[2]:.5f} {self.planar_force_unit}'} - ) - - self.info.append( - { - "shader": shader, - "args": {"position": positions, "coord": coord}, - "indices": indices, - "uniforms": [["color", (0.2,0,1,1)],["spacing", 0.2]] - } + { + "position": mat @ center - Vector((orientation @ values) * 0.2 / maximum), + "text": f"{values[2]:.5f} {self.planar_force_unit}", + } ) - def get_planar_loads_values(self, - activity_list: list[tuple[ifcopenshell.entity_instance,float]], - element_rotation_matrix: np.ndarray) -> np.ndarray: + + self.info.append( + { + "shader": shader, + "args": {"position": positions, "coord": coord}, + "indices": indices, + "uniforms": [["color", (0.2, 0, 1, 1)], ["spacing", 0.2]], + } + ) + + def get_planar_loads_values( + self, activity_list: list[tuple[ifcopenshell.entity_instance, float]], element_rotation_matrix: np.ndarray + ) -> np.ndarray: """ returns a numpy array with the sum of the values of structural activities applied loads in each direction, multiplied by the factors in load combinations @@ -406,57 +398,50 @@ class ShaderInfo: temp[0] = load.PlanarForceX if load.PlanarForceX is not None else 0 temp[1] = load.PlanarForceY if load.PlanarForceY is not None else 0 temp[2] = load.PlanarForceZ if load.PlanarForceZ is not None else 0 - temp = temp*factor - transform = self.get_activity_transform_matrix(activity,element_rotation_matrix) - values += transform@temp + temp = temp * factor + transform = self.get_activity_transform_matrix(activity, element_rotation_matrix) + values += transform @ temp return values - def get_surface_member_rotation(self, - surface_member: ifcopenshell.entity_instance - ) -> np.ndarray: + def get_surface_member_rotation(self, surface_member: ifcopenshell.entity_instance) -> np.ndarray: """returns the rotation matrix of a structural surface member""" representation = ifcopenshell.util.representation.get_representation(surface_member, "Model") repr_item = representation.Items[0] placement = ifcopenshell.util.placement.get_axis2placement(repr_item.FaceSurface.Position) - rotation = placement[0:3,0:3] + rotation = placement[0:3, 0:3] return rotation - def get_point_connection_rotation(self, - point_connection: ifcopenshell.entity_instance - ) -> np.ndarray: + def get_point_connection_rotation(self, point_connection: ifcopenshell.entity_instance) -> np.ndarray: """returns the rotation matrix of a structural point connection""" if point_connection.ConditionCoordinateSystem is not None: placement = ifcopenshell.util.placement.get_axis2placement(point_connection.ConditionCoordinateSystem) else: placement = np.eye(4) - rotation = placement[0:3,0:3] + rotation = placement[0:3, 0:3] return rotation - - def get_curve_member_rotation(self, - curve_member: ifcopenshell.entity_instance - ) -> np.ndarray: + + def get_curve_member_rotation(self, curve_member: ifcopenshell.entity_instance) -> np.ndarray: """returns the rotation matrix of a structural surface member""" z = curve_member.Axis.DirectionRatios edge = curve_member.Representation.Representations[0].Items[0] origin = edge.EdgeStart.VertexGeometry.Coordinates end = edge.EdgeEnd.VertexGeometry.Coordinates x = [c2 - c1 for c1, c2 in zip(origin, end)] - placement = ifcopenshell.util.placement.a2p(origin,z,x) - rotation = placement[0:3,0:3] + placement = ifcopenshell.util.placement.a2p(origin, z, x) + rotation = placement[0:3, 0:3] return rotation - - def get_activity_transform_matrix(self, - activity: ifcopenshell.entity_instance, - element_rotation_matrix: np.ndarray - ) -> np.ndarray: + + def get_activity_transform_matrix( + self, activity: ifcopenshell.entity_instance, element_rotation_matrix: np.ndarray + ) -> np.ndarray: "provides the transformation matrix to convert between reference frames" global_or_local = activity.GlobalOrLocal props = bpy.context.scene.BIMStructuralProperties reference_frame = props.reference_frame transform_matrix = np.eye(3) - if reference_frame == 'LOCAL_COORDS' and global_or_local != reference_frame: + if reference_frame == "LOCAL_COORDS" and global_or_local != reference_frame: transform_matrix = np.linalg.inv(element_rotation_matrix) - elif reference_frame == 'GLOBAL_COORDS' and global_or_local != reference_frame: + elif reference_frame == "GLOBAL_COORDS" and global_or_local != reference_frame: transform_matrix = element_rotation_matrix return transform_matrix @@ -469,30 +454,26 @@ class ShaderInfo: activity_list = value["activities"] if len(activity_list) == 0: continue - blender_object = IfcStore.get_element(getattr(conn, 'GlobalId', None)) - if blender_object.type == 'MESH': + blender_object = IfcStore.get_element(getattr(conn, "GlobalId", None)) + if blender_object.type == "MESH": conn_location = blender_object.matrix_world @ blender_object.data.vertices[0].co rotation = self.get_point_connection_rotation(conn) loads = self.get_point_loads_values(activity_list, rotation) self.get_point_shader_args(loads, conn_location, rotation) - def get_point_shader_args(self, - loads: Iterable, - location: np.ndarray, - rotation: np.ndarray - ) -> None: + def get_point_shader_args(self, loads: Iterable, location: np.ndarray, rotation: np.ndarray) -> None: """get the args to the point shader""" location = np.array(location) indices = [] direction_dict = { - "fx": (np.array((1,0,0)),np.array((0,1,0)),np.array((0,0,1))), - "fy": (np.array((0,1,0)),np.array((1,0,0)),np.array((0,0,1))), - "fz": (np.array((0,0,1)),np.array((0,1,0)),np.array((1,0,0))), - "mx": (np.array((0,1,0)),np.array((0,0,1))), - "my": (np.array((1,0,0)),np.array((0,0,1))), - "mz": (np.array((1,0,0)),np.array((0,1,0))), - } - keys = ["fx","fy","fz","mx","my","mz"] + "fx": (np.array((1, 0, 0)), np.array((0, 1, 0)), np.array((0, 0, 1))), + "fy": (np.array((0, 1, 0)), np.array((1, 0, 0)), np.array((0, 0, 1))), + "fz": (np.array((0, 0, 1)), np.array((0, 1, 0)), np.array((1, 0, 0))), + "mx": (np.array((0, 1, 0)), np.array((0, 0, 1))), + "my": (np.array((1, 0, 0)), np.array((0, 0, 1))), + "mz": (np.array((1, 0, 0)), np.array((0, 1, 0))), + } + keys = ["fx", "fy", "fz", "mx", "my", "mz"] props = bpy.context.scene.BIMStructuralProperties reference_frame = props.reference_frame if reference_frame == "LOCAL_COORDS": @@ -500,19 +481,19 @@ class ShaderInfo: tup = direction_dict[key] li = [] for item in tup: - li.append(rotation@item) + li.append(rotation @ item) direction_dict[key] = li - + for i, key in enumerate(keys): if loads[i] == 0: continue - color = (1,0,0,1) - if i in [1,4]: - color = (0,1,0,1) - elif i in [2,5]: - color = (0,0,1,1) - d1 = -(direction_dict[key][0]*loads[i]) - d1 = d1/np.linalg.norm(d1) + color = (1, 0, 0, 1) + if i in [1, 4]: + color = (0, 1, 0, 1) + elif i in [2, 5]: + color = (0, 0, 1, 1) + d1 = -(direction_dict[key][0] * loads[i]) + d1 = d1 / np.linalg.norm(d1) if i < 3: d2 = direction_dict[key][1] d3 = direction_dict[key][2] @@ -521,56 +502,52 @@ class ShaderInfo: p3 = location + d1 - d2 p4 = location + d1 + d3 p5 = location + d1 - d3 - position = [p1,p2,p3,p4,p5] - indices = [(0,1,2),(0,3,4)] - c1 = (0,0,0) - c2 = (1,1,0) - c3 = (-1,1,0) - coords_for_shader = [c1,c2,c3,c2,c3] + position = [p1, p2, p3, p4, p5] + indices = [(0, 1, 2), (0, 3, 4)] + c1 = (0, 0, 0) + c2 = (1, 1, 0) + c3 = (-1, 1, 0) + coords_for_shader = [c1, c2, c3, c2, c3] shader = self.shader.new("SINGLE FORCE") self.info.append( { "shader": shader, - "args": {"position": position,"coord": coords_for_shader}, + "args": {"position": position, "coord": coords_for_shader}, "indices": indices, - "uniforms": [["color", color],["spacing", 0.2]] + "uniforms": [["color", color], ["spacing", 0.2]], } ) - self.text_info.append( - {"position": location + d1, - "text": f'{loads[i]:.2f} {self.force_unit}'} - ) + self.text_info.append({"position": location + d1, "text": f"{loads[i]:.2f} {self.force_unit}"}) else: d2 = d2 = direction_dict[key][1] p1 = location - d2 p2 = location + d1 + d2 p3 = location - d1 + d2 - position = [p1,p2,p3] - indices = [(0,1,2)] - c1 = (-1,0,0) - c2 = (1,1,0) - c3 = (1,-1,0) - coords_for_shader = [c1,c2,c3] + position = [p1, p2, p3] + indices = [(0, 1, 2)] + c1 = (-1, 0, 0) + c2 = (1, 1, 0) + c3 = (1, -1, 0) + coords_for_shader = [c1, c2, c3] shader = self.shader.new("SINGLE MOMENT") self.info.append( { "shader": shader, - "args": {"position": position,"coord": coords_for_shader}, + "args": {"position": position, "coord": coords_for_shader}, "indices": indices, - "uniforms": [["color", color]] + "uniforms": [["color", color]], } ) self.text_info.append( - {"position": location +0.25*(d1 + d2), - "text": f'{loads[i]:.2f} {self.moment_unit}'} - ) + {"position": location + 0.25 * (d1 + d2), "text": f"{loads[i]:.2f} {self.moment_unit}"} + ) - def get_point_loads_values(self, - activity_list: list[tuple[ifcopenshell.entity_instance,float]], - element_rotation_matrix: np.ndarray) -> np.ndarray: + def get_point_loads_values( + self, activity_list: list[tuple[ifcopenshell.entity_instance, float]], element_rotation_matrix: np.ndarray + ) -> np.ndarray: """returns a numpy array with the sum of the point load values""" result_list = np.zeros(6) - attr_list = ['ForceX','ForceY','ForceZ','MomentX','MomentY','MomentZ'] + attr_list = ["ForceX", "ForceY", "ForceZ", "MomentX", "MomentY", "MomentZ"] for item in activity_list: activity = item[0] factor = item[1] @@ -578,17 +555,16 @@ class ShaderInfo: temp = np.zeros(6) for i, attr in enumerate(attr_list): value = 0 if getattr(load, attr, 0) is None else getattr(load, attr, 0) - temp[i] += value*factor - transform_3 = self.get_activity_transform_matrix(activity,element_rotation_matrix) - transform_6 = np.zeros((6,6)) - transform_6[0:3,0:3] = transform_3 - transform_6[3:6,3:6] = transform_3 - result_list += transform_6@temp + temp[i] += value * factor + transform_3 = self.get_activity_transform_matrix(activity, element_rotation_matrix) + transform_6 = np.zeros((6, 6)) + transform_6[0:3, 0:3] = transform_3 + transform_6[3:6, 3:6] = transform_3 + result_list += transform_6 @ temp return result_list - - def get_linear_loads(self)-> None: + def get_linear_loads(self) -> None: position = [] indices = [] sin_quad_lin = [] @@ -596,46 +572,53 @@ class ShaderInfo: color = [] info = [] maxforce = 0 - + list_of_curve_members = self.curve_members for value in list_of_curve_members.values(): member = value["member"] activity_list = value["activities"] if len(activity_list) == 0: continue - - blender_object = IfcStore.get_element(getattr(member, 'GlobalId', None)) - + + blender_object = IfcStore.get_element(getattr(member, "GlobalId", None)) + start_co = blender_object.matrix_world @ blender_object.data.vertices[0].co end_co = blender_object.matrix_world @ blender_object.data.vertices[1].co - x_axis = Vector(end_co-start_co).normalized() - z_direction = getattr(member, 'Axis') - #local coordinates - z_axis = Vector(getattr(z_direction, 'DirectionRatios', None)).normalized() + x_axis = Vector(end_co - start_co).normalized() + z_direction = getattr(member, "Axis") + # local coordinates + z_axis = Vector(getattr(z_direction, "DirectionRatios", None)).normalized() y_axis = z_axis.cross(x_axis).normalized() z_axis = x_axis.cross(y_axis).normalized() rotation = self.get_curve_member_rotation(member) - - + props = bpy.context.scene.BIMStructuralProperties reference_frame = props.reference_frame - is_local = reference_frame == 'LOCAL_COORDS' - x_match = abs(Vector((1,0,0)).dot(x_axis)) > 0.99 - y_match = abs(Vector((0,1,0)).dot(x_axis)) > 0.99 - z_match = abs(Vector((0,0,1)).dot(x_axis)) > 0.99 + is_local = reference_frame == "LOCAL_COORDS" + x_match = abs(Vector((1, 0, 0)).dot(x_axis)) > 0.99 + y_match = abs(Vector((0, 1, 0)).dot(x_axis)) > 0.99 + z_match = abs(Vector((0, 0, 1)).dot(x_axis)) > 0.99 direction_dict = { - "fx": y_axis+z_axis if is_local else Vector((1,0,0)) if not x_match else Vector((0,1,1)), - "fy": y_axis if is_local else Vector((0,1,0)) if not y_match else Vector((1,0,1)), - "fz": z_axis if is_local else Vector((0,0,1)) if not z_match else Vector((1,1,0)), - "mx": z_axis-y_axis if is_local or x_match else Vector((1,0,0)).cross(x_axis), - "my": z_axis if is_local else Vector((-1,0,1)) if y_match else Vector((0,1,0)).cross(x_axis).normalized(), - "mz": y_axis if is_local else Vector((-1,1,0)) if z_match else Vector((0,0,1)).cross(x_axis).normalized() + "fx": y_axis + z_axis if is_local else Vector((1, 0, 0)) if not x_match else Vector((0, 1, 1)), + "fy": y_axis if is_local else Vector((0, 1, 0)) if not y_match else Vector((1, 0, 1)), + "fz": z_axis if is_local else Vector((0, 0, 1)) if not z_match else Vector((1, 1, 0)), + "mx": z_axis - y_axis if is_local or x_match else Vector((1, 0, 0)).cross(x_axis), + "my": ( + z_axis + if is_local + else Vector((-1, 0, 1)) if y_match else Vector((0, 1, 0)).cross(x_axis).normalized() + ), + "mz": ( + y_axis + if is_local + else Vector((-1, 1, 0)) if z_match else Vector((0, 0, 1)).cross(x_axis).normalized() + ), } - match_dict = {'fx': x_match or is_local, 'fy': y_match, 'fz': z_match} - member_length = Vector(end_co-start_co).length - processed_loads = self.process_total_linear_loads(activity_list,rotation,member_length) + match_dict = {"fx": x_match or is_local, "fy": y_match, "fz": z_match} + member_length = Vector(end_co - start_co).length + processed_loads = self.process_total_linear_loads(activity_list, rotation, member_length) linear_loads = processed_loads["linear loads"] - maxforce = max(maxforce,processed_loads["max linear load"]) + maxforce = max(maxforce, processed_loads["max linear load"]) point_loads = processed_loads["discrete loads"] if len(point_loads) > 0: @@ -643,11 +626,11 @@ class ShaderInfo: for sub_item in item: pos = sub_item["pos"] values = sub_item["values"] - pos_vector = start_co + x_axis*pos - self.get_point_shader_args(values,pos_vector,rotation) + pos_vector = start_co + x_axis * pos + self.get_point_shader_args(values, pos_vector, rotation) if linear_loads is None: continue - keys = ["fx","fy","fz","mx","my","mz"] + keys = ["fx", "fy", "fz", "mx", "my", "mz"] for key in keys: polyline = linear_loads[key]["polyline"] @@ -655,13 +638,13 @@ class ShaderInfo: quadratic = linear_loads[key]["quadratic"] constant = linear_loads[key]["constant"] direction = direction_dict[key] - color_axis = (0,0,1,1) - if 'x' in key: - color_axis = (1,0,0,1) - if 'y' in key: - color_axis = (0,1,0,1) - - if 'f' in key: + color_axis = (0, 0, 1, 1) + if "x" in key: + color_axis = (1, 0, 0, 1) + if "y" in key: + color_axis = (0, 1, 0, 1) + + if "f" in key: unit = self.linear_force_unit if match_dict[key]: shader = self.shader.new("PARALLEL DISTRIBUTED FORCE") @@ -672,68 +655,74 @@ class ShaderInfo: shader = self.shader.new("DISTRIBUTED MOMENT") counter = 0 - for i in range(len(polyline)-1): - current = Vector(polyline[i]+[0]) - nextitem = Vector(polyline[i+1]+[0]) + for i in range(len(polyline) - 1): + current = Vector(polyline[i] + [0]) + nextitem = Vector(polyline[i + 1] + [0]) - if any([current.y, nextitem.y,constant,quadratic,sinus]): - negative = -1*direction + start_co + x_axis*current.x - positive = direction + start_co + x_axis*current.x + if any([current.y, nextitem.y, constant, quadratic, sinus]): + negative = -1 * direction + start_co + x_axis * current.x + positive = direction + start_co + x_axis * current.x position.append(negative) - coords_for_shader.append((current.x, 1.0,member_length)) + coords_for_shader.append((current.x, 1.0, member_length)) sin_quad_lin.append((sinus, quadratic, current.y + constant)) color.append(color_axis) - - x = current.x/member_length - func = sin(x*3.1416)*sinus + (-4.*x*x+4.*x)*quadratic+constant+current.y + + x = current.x / member_length + func = sin(x * 3.1416) * sinus + (-4.0 * x * x + 4.0 * x) * quadratic + constant + current.y if func: self.text_info.append( - {"position": -1*direction*func/maxforce + start_co + x_axis*current.x, - "text": f'{func:.2f} {unit}'} - ) - + { + "position": -1 * direction * func / maxforce + start_co + x_axis * current.x, + "text": f"{func:.2f} {unit}", + } + ) + position.append(positive) - coords_for_shader.append((current[0],-1.0,member_length)) + coords_for_shader.append((current[0], -1.0, member_length)) sin_quad_lin.append((sinus, quadratic, current.y + constant)) color.append(color_axis) - indices.append((0 + counter, - 1 + counter, - 2 + counter)) - indices.append((3 + counter, - 2 + counter, - 1 + counter)) - if i == len(polyline)-2: - negative = -1*direction + start_co + x_axis*nextitem.x - positive = direction + start_co + x_axis*nextitem.x + indices.append((0 + counter, 1 + counter, 2 + counter)) + indices.append((3 + counter, 2 + counter, 1 + counter)) + if i == len(polyline) - 2: + negative = -1 * direction + start_co + x_axis * nextitem.x + positive = direction + start_co + x_axis * nextitem.x position.append(negative) - coords_for_shader.append((nextitem.x, 1.0,member_length)) + coords_for_shader.append((nextitem.x, 1.0, member_length)) sin_quad_lin.append((sinus, quadratic, nextitem.y + constant)) color.append(color_axis) - - x = nextitem.x/member_length - func = sin(x*3.1416)*sinus + (-4.*x*x+4.*x)*quadratic+constant+nextitem.y + + x = nextitem.x / member_length + func = ( + sin(x * 3.1416) * sinus + (-4.0 * x * x + 4.0 * x) * quadratic + constant + nextitem.y + ) if func: self.text_info.append( - {"position": -1*direction*func/maxforce + start_co + x_axis*nextitem.x, - "text": f'{func:.2f} {unit}'} - ) - + { + "position": -1 * direction * func / maxforce + start_co + x_axis * nextitem.x, + "text": f"{func:.2f} {unit}", + } + ) + position.append(positive) - coords_for_shader.append((nextitem.x,-1.0,member_length)) + coords_for_shader.append((nextitem.x, -1.0, member_length)) sin_quad_lin.append((sinus, quadratic, nextitem.y + constant)) color.append(color_axis) counter += 2 if position: self.info.append( - { - "shader": shader, - "args": {"position": position, "sin_quad_lin_forces": sin_quad_lin,"coord": coords_for_shader}, - "indices": indices, - "uniforms": [["color", color_axis],["spacing", 0.2],["maxload",maxforce]] - } - ) + { + "shader": shader, + "args": { + "position": position, + "sin_quad_lin_forces": sin_quad_lin, + "coord": coords_for_shader, + }, + "indices": indices, + "uniforms": [["color", color_axis], ["spacing", 0.2], ["maxload", maxforce]], + } + ) position = [] sin_quad_lin = [] coords_for_shader = [] @@ -741,16 +730,17 @@ class ShaderInfo: for info in self.info: info["uniforms"][2][1] = maxforce - - def process_total_linear_loads(self, - activity_list: list[tuple[ifcopenshell.entity_instance,float]], - element_rotation_matrix: np.ndarray, - member_length: float) -> ProcessedLoad: - """ returns a dict with total values for applied loads in each direction + def process_total_linear_loads( + self, + activity_list: list[tuple[ifcopenshell.entity_instance, float]], + element_rotation_matrix: np.ndarray, + member_length: float, + ) -> ProcessedLoad: + """returns a dict with total values for applied loads in each direction along with the maximum value for the loads in the member and the discrete loads applied - + """ - loads_dict = self.parse_linear_loads_to_dict(activity_list,element_rotation_matrix) + loads_dict = self.parse_linear_loads_to_dict(activity_list, element_rotation_matrix) const = loads_dict["constant force"] quad = loads_dict["quadratic force"] sinus = loads_dict["sinus force"] @@ -760,46 +750,52 @@ class ShaderInfo: distributed_loads = None max_load = 0 for pos in unique_list: - value = self.get_before_and_after(pos,loads) + value = self.get_before_and_after(pos, loads) if value["before"] == value["after"]: - final_list.append([pos]+value["before"]) + final_list.append([pos] + value["before"]) else: - final_list.append([pos]+value["before"]) - final_list.append([pos]+value["after"]) - - if len(final_list) == 0 and any(const+quad+sinus): - final_list.append([0.0,0.0,0.0,0.0,0.0,0.0,0.0]) - final_list.append([member_length,0.0,0.0,0.0,0.0,0.0,0.0]) - - elif len(final_list)>0: - if final_list[0][0] and any(const+quad+sinus): #if first item location is not 0 append an item at the zero - final_list = [[0.0,0.0,0.0,0.0,0.0,0.0,0.0]]+final_list + final_list.append([pos] + value["before"]) + final_list.append([pos] + value["after"]) + + if len(final_list) == 0 and any(const + quad + sinus): + final_list.append([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) + final_list.append([member_length, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) + + elif len(final_list) > 0: + if final_list[0][0] and any( + const + quad + sinus + ): # if first item location is not 0 append an item at the zero + final_list = [[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]] + final_list else: del final_list[0] - if abs(final_list[-1][0] - member_length) > 0.01 and any(const+quad+sinus): - final_list.append([member_length,0.0,0.0,0.0,0.0,0.0,0.0]) + if abs(final_list[-1][0] - member_length) > 0.01 and any(const + quad + sinus): + final_list.append([member_length, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) else: del final_list[-1] - if len(final_list)>0: - array = np.array(final_list) #7xn -> ["pos","fx","fy","fz","mx","my","mz"] - keys = ["fx","fy","fz","mx","my","mz"] + if len(final_list) > 0: + array = np.array(final_list) # 7xn -> ["pos","fx","fy","fz","mx","my","mz"] + keys = ["fx", "fy", "fz", "mx", "my", "mz"] polyline = [] distributed_loads = { - "fx": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, - "fy": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, - "fz": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, - "mx": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, - "my": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, - "mz": {"constant": 0, "quadratic": 0,"sinus": 0,"polyline": []}, - } + "fx": {"constant": 0, "quadratic": 0, "sinus": 0, "polyline": []}, + "fy": {"constant": 0, "quadratic": 0, "sinus": 0, "polyline": []}, + "fz": {"constant": 0, "quadratic": 0, "sinus": 0, "polyline": []}, + "mx": {"constant": 0, "quadratic": 0, "sinus": 0, "polyline": []}, + "my": {"constant": 0, "quadratic": 0, "sinus": 0, "polyline": []}, + "mz": {"constant": 0, "quadratic": 0, "sinus": 0, "polyline": []}, + } max_load = 0 for component, key in enumerate(keys): - if(any([sinus[component], quad[component], const[component]]) or - any(item for item in array[:,component+1])): + if any([sinus[component], quad[component], const[component]]) or any( + item for item in array[:, component + 1] + ): for currentitem in final_list: - polyline.append([currentitem[0],currentitem[component+1]]) - max_load = max(max_load,abs(sinus[component]+quad[component]+const[component]+currentitem[component+1])) + polyline.append([currentitem[0], currentitem[component + 1]]) + max_load = max( + max_load, + abs(sinus[component] + quad[component] + const[component] + currentitem[component + 1]), + ) inner_dict = distributed_loads[key] inner_dict["constant"] = const[component] inner_dict["quadratic"] = quad[component] @@ -807,18 +803,19 @@ class ShaderInfo: inner_dict["polyline"] = polyline distributed_loads[key] = inner_dict - return {"linear loads":distributed_loads, - "max linear load": max_load, - "discrete loads": loads_dict["point load configuration"]} + return { + "linear loads": distributed_loads, + "max linear load": max_load, + "discrete loads": loads_dict["point load configuration"], + } - - def getuniquepositionlist(self, load_config_list:list[list[LoadConfigItem]])-> list[float]: + def getuniquepositionlist(self, load_config_list: list[list[LoadConfigItem]]) -> list[float]: """return an ordereded list of unique locations based on the load configuration list - ex: load_config_list = [[{"pos":1.0,...},{"pos":3.0,...}], - [{"pos":2.0,...},{"pos":3.0,...}], - [{"pos":1.5,...},{"pos":2.5,...}]] - return = [1.0, 1.5, 2.0, 2.5, 3.0] - """ + ex: load_config_list = [[{"pos":1.0,...},{"pos":3.0,...}], + [{"pos":2.0,...},{"pos":3.0,...}], + [{"pos":1.5,...},{"pos":2.5,...}]] + return = [1.0, 1.5, 2.0, 2.5, 3.0] + """ unique = [] for config in load_config_list: for info in config: @@ -828,39 +825,36 @@ class ShaderInfo: unique.sort() return unique - def interp1d(self,l1:list[float],l2: list[float], pos:float) -> float: - """ 1d linear interpolation for the vector components""" - fac = (l2[1]-l1[1])/(l2[0]-l1[0]) - v = l1[1] + fac*(pos-l1[0]) + def interp1d(self, l1: list[float], l2: list[float], pos: float) -> float: + """1d linear interpolation for the vector components""" + fac = (l2[1] - l1[1]) / (l2[0] - l1[0]) + v = l1[1] + fac * (pos - l1[0]) return v - def interpolate(self,pos: float,loadinfo:list[LoadConfigItem],start:int,end:int,key: str)-> np.ndarray: - """ interpolate the result vectors between load poits""" + def interpolate(self, pos: float, loadinfo: list[LoadConfigItem], start: int, end: int, key: str) -> np.ndarray: + """interpolate the result vectors between load poits""" result = np.zeros(6) for i in range(6): - value1 = [loadinfo[start]["pos"], loadinfo[start][key][i]] #[position, force_component] - value2= [loadinfo[end]["pos"], loadinfo[end][key][i]] # [position, force_component] - result[i] = self.interp1d(value1,value2, pos) # interpolated [position, force_component] + value1 = [loadinfo[start]["pos"], loadinfo[start][key][i]] # [position, force_component] + value2 = [loadinfo[end]["pos"], loadinfo[end][key][i]] # [position, force_component] + result[i] = self.interp1d(value1, value2, pos) # interpolated [position, force_component] return result - def get_before_and_after(self, - pos: float, - load_config_list:list[list[LoadConfigItem]] - ) -> dict[str,list[float]]: - """ get total values for forces and moments before and after the position - example: - pos = 2.0 - load_config_list = [[{"pos":1.0, "descr":"start, "load values":[1,0,0,0,0,0]}, - {"pos":3.0, "descr":"end, "load values":[3,0,0,0,0,0]}], - [{"pos":2.0, "descr":"start, "load values":[1,0,0,0,0,0]}, - {"pos":3.0, "descr":"end, "load values":[1,0,0,0,0,0]}], - [{"pos":1.5, "descr":"start, "load values":[1,0,0,0,0,0]}, - {"pos":2.5, "descr":"end, "load values":[1,0,0,0,0,0]}], - return = { - "before": [3,0,0,0,0,0], ->(fx, fy, fz, mx, my, mz) - " after": [4,0,0,0,0,0] ->(fx, fy, fz, mx, my, mz) - } - """ + def get_before_and_after(self, pos: float, load_config_list: list[list[LoadConfigItem]]) -> dict[str, list[float]]: + """get total values for forces and moments before and after the position + example: + pos = 2.0 + load_config_list = [[{"pos":1.0, "descr":"start, "load values":[1,0,0,0,0,0]}, + {"pos":3.0, "descr":"end, "load values":[3,0,0,0,0,0]}], + [{"pos":2.0, "descr":"start, "load values":[1,0,0,0,0,0]}, + {"pos":3.0, "descr":"end, "load values":[1,0,0,0,0,0]}], + [{"pos":1.5, "descr":"start, "load values":[1,0,0,0,0,0]}, + {"pos":2.5, "descr":"end, "load values":[1,0,0,0,0,0]}], + return = { + "before": [3,0,0,0,0,0], ->(fx, fy, fz, mx, my, mz) + " after": [4,0,0,0,0,0] ->(fx, fy, fz, mx, my, mz) + } + """ load_before = np.zeros(6) load_after = np.zeros(6) @@ -868,49 +862,46 @@ class ShaderInfo: if pos < config[0]["pos"] or pos > config[-1]["pos"]: continue start = 0 - end = len(config)-1 - while end-start > 0: + end = len(config) - 1 + while end - start > 0: if pos < config[start]["pos"] or pos > config[end]["pos"]: break if config[start]["pos"] == pos: - if config[start]["descr"] in ['start','middle']: + if config[start]["descr"] in ["start", "middle"]: load_after += config[start]["load values"] - elif config[start]["descr"] in ['end','middle']: + elif config[start]["descr"] in ["end", "middle"]: load_before += config[start]["load values"] elif config[end]["pos"] == pos: - if config[end]["descr"] in ['start','middle']: + if config[end]["descr"] in ["start", "middle"]: load_after += config[end]["load values"] - elif config[end]["descr"] in ['end','middle']: + elif config[end]["descr"] in ["end", "middle"]: load_before += config[end]["load values"] - elif end-start == 1: - load_before += self.interpolate(pos,config,start,end,"load values") - load_after += self.interpolate(pos,config,start,end,"load values") + elif end - start == 1: + load_before += self.interpolate(pos, config, start, end, "load values") + load_after += self.interpolate(pos, config, start, end, "load values") start += 1 - end -=1 - return_value = { - "before": load_before.tolist(), - "after": load_after.tolist() - } + end -= 1 + return_value = {"before": load_before.tolist(), "after": load_after.tolist()} return return_value - def parse_linear_loads_to_dict(self, - activity_list: list[tuple[ifcopenshell.entity_instance,float]], - element_rotation_matrix: np.ndarray) -> ParsedLoad: + def parse_linear_loads_to_dict( + self, activity_list: list[tuple[ifcopenshell.entity_instance, float]], element_rotation_matrix: np.ndarray + ) -> ParsedLoad: """ get load list - activity_list: list of IfcStructuralCurveAction or IfcStructuralCurveReaction + activity_list: list of IfcStructuralCurveAction or IfcStructuralCurveReaction applied in the structural curve member global_to_local: transformation matrix from global coordinates to local coordinetes return: dict{ - "constant force": (fx,fy,fz,mx,my,mz), -> sum of linear loads applied with + "constant force": (fx,fy,fz,mx,my,mz), -> sum of linear loads applied with constant distribution "quadratic force": (fx,fy,fz,mx,my,mz), -> sum of linear loads applied with quadratic distribution - "sinus force": (fx,fy,fz,mx,my,mz), -> sum of linear loads applied with + "sinus force": (fx,fy,fz,mx,my,mz), -> sum of linear loads applied with sinus distribution "linear load configuration": list -> list of load configurations for linear and polyline distributions of linear loads @@ -918,7 +909,7 @@ class ShaderInfo: description of "linear load configuration": list[ -> one item (list)for each IfcStructuralCurveAction applied in the member with IfcStructuralLoadConfiguration as the applied load - list[ -> one item (dict) for each item found in the + list[ -> one item (dict) for each item found in the Locations attribute of IfcLoadConfiguration dict{ "pos": float, -> local position along curve length @@ -927,86 +918,76 @@ class ShaderInfo: } ] ] - """ + """ constant = np.zeros(6) quadratic = np.zeros(6) sinus = np.zeros(6) linear_load_configurations = [] point_load_configurations = [] - unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get(),"LENGTHUNIT") + unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get(), "LENGTHUNIT") - def get_load_values(load,transform_matrix,factor = 1.0): + def get_load_values(load, transform_matrix, factor=1.0): result = np.zeros(6) - keys = ['LinearForceX','LinearForceY','LinearForceZ','LinearMomentX','LinearMomentY','LinearMomentZ'] + keys = ["LinearForceX", "LinearForceY", "LinearForceZ", "LinearMomentX", "LinearMomentY", "LinearMomentZ"] for i, key in enumerate(keys): value = 0 if getattr(load, key, 0) is None else getattr(load, key, 0) - result[i] += value*factor + result[i] += value * factor return transform_matrix @ result for item in activity_list: activity = item[0] factor = item[1] load = activity.AppliedLoad - - transform_3by3 = self.get_activity_transform_matrix(activity,element_rotation_matrix) - transform_6by6 = np.zeros((6,6)) - transform_6by6[0:3,0:3] = transform_3by3 - transform_6by6[3:6,3:6] = transform_3by3 - - #values for linear loads - if load.is_a('IfcStructuralLoadConfiguration'): - locations = getattr(load, 'Locations', []) - values = [l for l in getattr(load, 'Values', None) - if l.is_a() == "IfcStructuralLoadLinearForce" - ] + + transform_3by3 = self.get_activity_transform_matrix(activity, element_rotation_matrix) + transform_6by6 = np.zeros((6, 6)) + transform_6by6[0:3, 0:3] = transform_3by3 + transform_6by6[3:6, 3:6] = transform_3by3 + + # values for linear loads + if load.is_a("IfcStructuralLoadConfiguration"): + locations = getattr(load, "Locations", []) + values = [l for l in getattr(load, "Values", None) if l.is_a() == "IfcStructuralLoadLinearForce"] config_list = [] - for i,l in enumerate(values): - load_values = get_load_values(l,transform_6by6,factor) + for i, l in enumerate(values): + load_values = get_load_values(l, transform_6by6, factor) if i == 0: - descr = 'start' - elif i == len(values)-1: - descr = 'end' + descr = "start" + elif i == len(values) - 1: + descr = "end" else: - descr = 'middle' + descr = "middle" config_list.append( - {"pos": locations[i][0]*unit_scale, - "descr": descr, - "load values":load_values} + {"pos": locations[i][0] * unit_scale, "descr": descr, "load values": load_values} ) linear_load_configurations.append(config_list) - #load configurations with point loads - values = [l for l in getattr(load, 'Values', None) - if l.is_a() == "IfcStructuralLoadSingleForce" - ] - attr_list = ['ForceX','ForceY','ForceZ','MomentX','MomentY','MomentZ'] + # load configurations with point loads + values = [l for l in getattr(load, "Values", None) if l.is_a() == "IfcStructuralLoadSingleForce"] + attr_list = ["ForceX", "ForceY", "ForceZ", "MomentX", "MomentY", "MomentZ"] config_list = [] - for i,val in enumerate(values): - result_list = [0,0,0,0,0,0] + for i, val in enumerate(values): + result_list = [0, 0, 0, 0, 0, 0] for j, attr in enumerate(attr_list): value = 0 if getattr(val, attr, 0) is None else getattr(val, attr, 0) - result_list[j] += value*factor - config_list.append( - {"pos": locations[i][0]*unit_scale, - "values": result_list} - ) + result_list[j] += value * factor + config_list.append({"pos": locations[i][0] * unit_scale, "values": result_list}) point_load_configurations.append(config_list) else: - load_values = get_load_values(load,transform_6by6,factor) - if 'CONST' == getattr(activity, 'PredefinedType', None) or activity.is_a('IfcStructuralLinearAction'): + load_values = get_load_values(load, transform_6by6, factor) + if "CONST" == getattr(activity, "PredefinedType", None) or activity.is_a("IfcStructuralLinearAction"): constant += load_values - elif 'PARABOLA' == getattr(activity, 'PredefinedType', None): + elif "PARABOLA" == getattr(activity, "PredefinedType", None): quadratic += load_values - elif 'SINUS' == getattr(activity, 'PredefinedType', None): + elif "SINUS" == getattr(activity, "PredefinedType", None): sinus += load_values return_value = { - "constant force": constant.tolist(), - "quadratic force": quadratic.tolist(), - "sinus force": sinus.tolist(), - "linear load configuration": linear_load_configurations, - "point load configuration": point_load_configurations - } + "constant force": constant.tolist(), + "quadratic force": quadratic.tolist(), + "sinus force": sinus.tolist(), + "linear load configuration": linear_load_configurations, + "point load configuration": point_load_configurations, + } return return_value - diff --git a/src/bonsai/bonsai/bim/module/structural/operator.py b/src/bonsai/bonsai/bim/module/structural/operator.py index 62e2dffe1f..69ce579a2b 100644 --- a/src/bonsai/bonsai/bim/module/structural/operator.py +++ b/src/bonsai/bonsai/bim/module/structural/operator.py @@ -29,24 +29,26 @@ from mathutils import Vector, Matrix from bonsai.bim.ifc import IfcStore from bonsai.bim.module.structural.decorator import LoadsDecorator + class ShowLoads(bpy.types.Operator): """Draw decorations to show strucutural actions in 3d view""" + bl_idname = "bim.show_loads" bl_label = "Show loads in 3D View" def modal(self, context, event): - if event.type == 'F5': + if event.type == "F5": LoadsDecorator.update() for area in context.screen.areas: - if area.type == 'VIEW_3D': + if area.type == "VIEW_3D": area.tag_redraw() - if event.type == 'ESC': + if event.type == "ESC": LoadsDecorator.uninstall() for area in context.screen.areas: - if area.type == 'VIEW_3D': + if area.type == "VIEW_3D": area.tag_redraw() - return {'FINISHED'} - return {'PASS_THROUGH'} + return {"FINISHED"} + return {"PASS_THROUGH"} def invoke(self, context, event): collection = bpy.data.collections["IfcStructuralItem"] @@ -60,10 +62,10 @@ class ShowLoads(bpy.types.Operator): context.window.cursor_modal_restore() context.window_manager.modal_handler_add(self) for area in context.screen.areas: - if area.type == 'VIEW_3D': + if area.type == "VIEW_3D": area.tag_redraw() - return {'RUNNING_MODAL'} + return {"RUNNING_MODAL"} class AddStructuralMemberConnection(bpy.types.Operator, tool.Ifc.Operator): diff --git a/src/bonsai/bonsai/bim/module/structural/prop.py b/src/bonsai/bonsai/bim/module/structural/prop.py index 11d2da1a2f..64d8c1bed0 100644 --- a/src/bonsai/bonsai/bim/module/structural/prop.py +++ b/src/bonsai/bonsai/bim/module/structural/prop.py @@ -21,7 +21,12 @@ import bpy import bonsai.tool as tool from bonsai.bim.ifc import IfcStore from bonsai.bim.prop import StrProperty, Attribute -from bonsai.bim.module.structural.data import StructuralLoadCasesData, StructuralLoadsData, BoundaryConditionsData, LoadGroupDecorationData +from bonsai.bim.module.structural.data import ( + StructuralLoadCasesData, + StructuralLoadsData, + BoundaryConditionsData, + LoadGroupDecorationData, +) from bpy.types import PropertyGroup from bpy.props import ( PointerProperty, @@ -34,14 +39,17 @@ from bpy.props import ( CollectionProperty, ) + def get_load_groups_to_show(self, context): if not LoadGroupDecorationData.is_loaded: LoadGroupDecorationData.load() return LoadGroupDecorationData.data["load groups to show"] + def update_activity_type(self, context): LoadGroupDecorationData.is_loaded = False + def get_applicable_structural_load_types(self, context): if not StructuralLoadCasesData.is_loaded: StructuralLoadCasesData.load() @@ -162,13 +170,22 @@ class BIMStructuralProperties(PropertyGroup): show_loads: BoolProperty(name="Show Loads", default=False) update_load_repr: BoolProperty(name="Update Load Representation", default=False) enable_repr_auto_update: BoolProperty(name="Auto Update", default=False) - reference_frame: EnumProperty(items=[("GLOBAL_COORDS","Global","Show loads in global reference frame"), - ("LOCAL_COORDS","Local","Show loads in local reference frame")], name= "Reference Frame") - activity_type: EnumProperty(items=[("Action","Actions","Show actions loads"), - ("External Reaction","External Reactions","Show reactions on boundary conditions"), - ("Internal Reactions","Internal Reactions","Show internal reactions on members")], - name="Activity Type", - update=update_activity_type) + reference_frame: EnumProperty( + items=[ + ("GLOBAL_COORDS", "Global", "Show loads in global reference frame"), + ("LOCAL_COORDS", "Local", "Show loads in local reference frame"), + ], + name="Reference Frame", + ) + activity_type: EnumProperty( + items=[ + ("Action", "Actions", "Show actions loads"), + ("External Reaction", "External Reactions", "Show reactions on boundary conditions"), + ("Internal Reactions", "Internal Reactions", "Show internal reactions on members"), + ], + name="Activity Type", + update=update_activity_type, + ) load_group_to_show: EnumProperty(items=get_load_groups_to_show, name="Load Groups") diff --git a/src/bonsai/bonsai/bim/module/structural/shader.py b/src/bonsai/bonsai/bim/module/structural/shader.py index 29e710fafe..c866819bc0 100644 --- a/src/bonsai/bonsai/bim/module/structural/shader.py +++ b/src/bonsai/bonsai/bim/module/structural/shader.py @@ -17,38 +17,49 @@ # along with Bonsai. If not, see . import gpu +from typing import Literal class DecorationShader: "shader for the load decorations" + def __init__(self): pass - def new(self, pattern: str) -> gpu.types.GPUShader: + + def new(self, pattern: Literal["PERPENDICULAR DISTRIBUTED FORCE", + "PARALLEL DISTRIBUTED FORCE", + "DISTRIBUTED MOMENT", + "SINGLE FORCE", + "SINGLE MOMENT", + "PLANAR LOAD",]) -> gpu.types.GPUShader: """pattern: string description of the desired shader Possible values - PERPENDICULAR DISTRIBUTED FORCE: pattern for distributed force + PERPENDICULAR DISTRIBUTED FORCE: pattern for distributed force perpendicular to the curve member axis - PARALLEL DISTRIBUTED FORCE: pattern for distributed force + PARALLEL DISTRIBUTED FORCE: pattern for distributed force along the curve member axis DISTRIBUTED MOMENT: pattern for distributed moment in curve members SINGLE FORCE: pattern for single forces SINGLE MOMENT: pattern for single moments PLANAR LOAD: pattern for planar loads """ - valid_patterns = {"PERPENDICULAR DISTRIBUTED FORCE", - "PARALLEL DISTRIBUTED FORCE", - "DISTRIBUTED MOMENT", - "SINGLE FORCE", - "SINGLE MOMENT", - "PLANAR LOAD" - } + valid_patterns = { + "PERPENDICULAR DISTRIBUTED FORCE", + "PARALLEL DISTRIBUTED FORCE", + "DISTRIBUTED MOMENT", + "SINGLE FORCE", + "SINGLE MOMENT", + "PLANAR LOAD", + } if pattern not in valid_patterns: - raise ValueError("""pattern must be one of: + raise ValueError( + """pattern must be one of: PERPENDICULAR DISTRIBUTED FORCE PARALLEL DISTRIBUTED FORCE, DISTRIBUTED MOMENT, SINGLE FORCE, SINGLE MOMENT, - PLANAR LOAD""") + PLANAR LOAD""" + ) if "DISTRIBUTED" in pattern.upper(): shader = self.get_linear_shader(pattern) return shader @@ -59,29 +70,31 @@ class DecorationShader: shader = self.get_planar_shader() return shader - def get_linear_shader(self, pattern: str) -> gpu.types.GPUShader: + def get_linear_shader(self, pattern: Literal["PERPENDICULAR DISTRIBUTED FORCE", + "PARALLEL DISTRIBUTED FORCE", + "DISTRIBUTED MOMENT"]) -> gpu.types.GPUShader: """pattern: type of pattern PERPENDICULAR DISTRIBUTED FORCE PARALLEL DISTRIBUTED FORCE, DISTRIBUTED MOMENT, """ vert_out = gpu.types.GPUStageInterfaceInfo("my_interface") - vert_out.smooth('VEC3', "forces") - vert_out.smooth('VEC3', "co") + vert_out.smooth("VEC3", "forces") + vert_out.smooth("VEC3", "co") shader_info = gpu.types.GPUShaderCreateInfo() - shader_info.push_constant('MAT4', "viewProjectionMatrix") - shader_info.push_constant('VEC4', "color") - shader_info.push_constant('FLOAT', "spacing") - shader_info.push_constant('FLOAT', "maxload") - - shader_info.vertex_in(0, 'VEC3', "position") - shader_info.vertex_in(1, 'VEC3', "sin_quad_lin_forces") - shader_info.vertex_in(2, 'VEC3', "coord") - + shader_info.push_constant("MAT4", "viewProjectionMatrix") + shader_info.push_constant("VEC4", "color") + shader_info.push_constant("FLOAT", "spacing") + shader_info.push_constant("FLOAT", "maxload") + + shader_info.vertex_in(0, "VEC3", "position") + shader_info.vertex_in(1, "VEC3", "sin_quad_lin_forces") + shader_info.vertex_in(2, "VEC3", "coord") + shader_info.vertex_out(vert_out) - shader_info.fragment_out(0, 'VEC4', "FragColor") - + shader_info.fragment_out(0, "VEC4", "FragColor") + shader_info.vertex_source( "void main()" "{" @@ -90,207 +103,185 @@ class DecorationShader: " forces = sin_quad_lin_forces;" "}" ) - + if pattern == "PERPENDICULAR DISTRIBUTED FORCE": shader_info.fragment_source( - "void main()" - "{" - "float x = co.x;" - "float y = co.y;" - "float abs_y = abs(y);" - - "float a = abs(mod(x,spacing)-0.5*spacing)*5.0;" - "float b = step(a,abs_y)*(step(abs_y,1.2*spacing));" - "float c = step(0.8*spacing,mod(x+0.4*spacing,spacing))*(step(1.2*spacing,abs_y));" - - "float sinvalue = forces.x;" - "float quadraticvalue = forces.y;" - "float linearvalue = forces.z;" - "x = co.x/co.z;" - "float f = (sin(x*3.1416)*sinvalue" - "+(-4.*x*x+4.*x)*quadraticvalue" - "+linearvalue)/maxload;" - "float mask = step(0.,y)*step(y,f)+step(y,0.)*step(f,y);" - - "float top = step(abs(y-f),0.2*1.2*spacing);" - "float d = clamp(top+b+c,0.0,0.9)*mask;" - "if (d == 0.0) discard;" - "FragColor = vec4(color.xyz,d*color.w);" - "}" - ) + "void main()" + "{" + "float x = co.x;" + "float y = co.y;" + "float abs_y = abs(y);" + "float a = abs(mod(x,spacing)-0.5*spacing)*5.0;" + "float b = step(a,abs_y)*(step(abs_y,1.2*spacing));" + "float c = step(0.8*spacing,mod(x+0.4*spacing,spacing))*(step(1.2*spacing,abs_y));" + "float sinvalue = forces.x;" + "float quadraticvalue = forces.y;" + "float linearvalue = forces.z;" + "x = co.x/co.z;" + "float f = (sin(x*3.1416)*sinvalue" + "+(-4.*x*x+4.*x)*quadraticvalue" + "+linearvalue)/maxload;" + "float mask = step(0.,y)*step(y,f)+step(y,0.)*step(f,y);" + "float top = step(abs(y-f),0.2*1.2*spacing);" + "float d = clamp(top+b+c,0.0,0.9)*mask;" + "if (d == 0.0) discard;" + "FragColor = vec4(color.xyz,d*color.w);" + "}" + ) elif pattern == "PARALLEL DISTRIBUTED FORCE": shader_info.fragment_source( - "void main()" - "{" - "float y = co.y;" - "float x = step(0.,y)*(co.z-co.x)+step(y,0.)*(co.x);" - "float abs_y = abs(y);" - - "float a = abs(mod(abs_y,spacing)-0.5*spacing)*5.0;" - "float a2 = mod(x,3.0*spacing);" - "float b = step(a,a2)*step(a2,1.2*spacing);" - "float c = step(0.8*spacing,mod(abs_y+0.4*spacing,spacing))" - "*(step(1.2*spacing,a2))*step(a2,2.5*spacing);" - "float sinvalue = forces.x;" - "float quadraticvalue = forces.y;" - "float linearvalue = forces.z;" - "x = co.x/co.z;" - "float f = (sin(x*3.1416)*sinvalue" - "+(-4.*x*x+4.*x)*quadraticvalue" - "+linearvalue)/maxload;" - "float mask = step(0.,y)*step(y,f)+step(y,0.)*step(f,y);" - - "float top = step(abs(y-f),0.2*1.2*spacing);" - "float d = clamp(top+b+c,0.0,0.9)*mask;" - "if (d == 0.0) discard;" - "FragColor = vec4(color.xyz,d*color.w);" - "}" - ) + "void main()" + "{" + "float y = co.y;" + "float x = step(0.,y)*(co.z-co.x)+step(y,0.)*(co.x);" + "float abs_y = abs(y);" + "float a = abs(mod(abs_y,spacing)-0.5*spacing)*5.0;" + "float a2 = mod(x,3.0*spacing);" + "float b = step(a,a2)*step(a2,1.2*spacing);" + "float c = step(0.8*spacing,mod(abs_y+0.4*spacing,spacing))" + "*(step(1.2*spacing,a2))*step(a2,2.5*spacing);" + "float sinvalue = forces.x;" + "float quadraticvalue = forces.y;" + "float linearvalue = forces.z;" + "x = co.x/co.z;" + "float f = (sin(x*3.1416)*sinvalue" + "+(-4.*x*x+4.*x)*quadraticvalue" + "+linearvalue)/maxload;" + "float mask = step(0.,y)*step(y,f)+step(y,0.)*step(f,y);" + "float top = step(abs(y-f),0.2*1.2*spacing);" + "float d = clamp(top+b+c,0.0,0.9)*mask;" + "if (d == 0.0) discard;" + "FragColor = vec4(color.xyz,d*color.w);" + "}" + ) elif pattern == "DISTRIBUTED MOMENT": shader_info.fragment_source( - "void main()" - "{" - "float x = step(co.y,0.)*(co.x)+step(0.,co.y)*(co.z-co.x);" - "float y = step(co.y,-0.00001)*(co.y)+step(0.,co.y)*(0.-co.y);" - "x = mod((0.5/spacing)*x,1.4)-0.7;" - "y = mod((0.5/spacing)*y,1.4)-0.7;" - "float abs_y = abs(y);" - "vec2 st = vec2(1.9*x,y);" - "vec2 orig = vec2(0.,0.);" - - "float circ = step(distance(st,orig),0.33)*step(0.27,distance(st,orig));" - "float tri_mask = step(st.y,st.x)+step(-st.x,st.y);" - "float circ_arrow = step(st.x,4.0*st.y-0.75)*step(0.25*st.y-0.34,st.x)*(1.-tri_mask);" + "void main()" + "{" + "float x = step(co.y,0.)*(co.x)+step(0.,co.y)*(co.z-co.x);" + "float y = step(co.y,-0.00001)*(co.y)+step(0.,co.y)*(0.-co.y);" + "x = mod((0.5/spacing)*x,1.4)-0.7;" + "y = mod((0.5/spacing)*y,1.4)-0.7;" + "float abs_y = abs(y);" + "vec2 st = vec2(1.9*x,y);" + "vec2 orig = vec2(0.,0.);" + "float circ = step(distance(st,orig),0.33)*step(0.27,distance(st,orig));" + "float tri_mask = step(st.y,st.x)+step(-st.x,st.y);" + "float circ_arrow = step(st.x,4.0*st.y-0.75)*step(0.25*st.y-0.34,st.x)*(1.-tri_mask);" + "float circmask = step(distance(st,orig),0.1)+step(0.5,distance(st,orig))+step(st.x,0.);" + "float body = step(-0.03,st.y)*step(st.y,0.03)*step(-0.3,x)*step(x,0.576);" + "float body_arrow = step(-0.5+3.*st.y,x)*step(-0.5-3.*st.y,x)*step(x,-0.3);" + "float d = clamp(circmask*(body+body_arrow)+circ_arrow+circ*tri_mask,0.,1.);" + "float sinvalue = forces.x;" + "float quadraticvalue = forces.y;" + "float linearvalue = forces.z;" + "x = co.x/co.z;" + "float f = (sin(x*3.1416)*sinvalue" + "+(-4.*x*x+4.*x)*quadraticvalue" + "+linearvalue)/maxload;" + "float mask = step(0.,co.y)*step(co.y,f)+step(co.y,0.)*step(f,co.y);" + "float top = step(abs(co.y-f),0.2*1.2*spacing);" + "d = clamp(top+d,0.0,0.9)*mask;" + "if (d == 0.0) discard;" + "FragColor = vec4(color.xyz,d*color.w);" + "}" + ) - "float circmask = step(distance(st,orig),0.1)+step(0.5,distance(st,orig))+step(st.x,0.);" - "float body = step(-0.03,st.y)*step(st.y,0.03)*step(-0.3,x)*step(x,0.576);" - "float body_arrow = step(-0.5+3.*st.y,x)*step(-0.5-3.*st.y,x)*step(x,-0.3);" - "float d = clamp(circmask*(body+body_arrow)+circ_arrow+circ*tri_mask,0.,1.);" - - "float sinvalue = forces.x;" - "float quadraticvalue = forces.y;" - "float linearvalue = forces.z;" - "x = co.x/co.z;" - "float f = (sin(x*3.1416)*sinvalue" - "+(-4.*x*x+4.*x)*quadraticvalue" - "+linearvalue)/maxload;" - "float mask = step(0.,co.y)*step(co.y,f)+step(co.y,0.)*step(f,co.y);" - - "float top = step(abs(co.y-f),0.2*1.2*spacing);" - - "d = clamp(top+d,0.0,0.9)*mask;" - "if (d == 0.0) discard;" - "FragColor = vec4(color.xyz,d*color.w);" - "}" - ) - shader = gpu.shader.create_from_info(shader_info) del vert_out del shader_info return shader - - def get_point_shader(self, pattern: str) -> gpu.types.GPUShader: - """ param: pattern: type of pattern + + def get_point_shader(self, pattern: Literal["SINGLE FORCE","SINGLE MOMENT"]) -> gpu.types.GPUShader: + """param: pattern: type of pattern SINGLE FORCE, SINGLE MOMENT""" vert_out = gpu.types.GPUStageInterfaceInfo("my_interface") - vert_out.smooth('VEC3', "co") - + vert_out.smooth("VEC3", "co") + shader_info = gpu.types.GPUShaderCreateInfo() - shader_info.push_constant('MAT4', "viewProjectionMatrix") - shader_info.push_constant('VEC4', "color") - shader_info.push_constant('FLOAT', "spacing") - - shader_info.vertex_in(0, 'VEC3', "position") - shader_info.vertex_in(1, 'VEC3', "coord") - + shader_info.push_constant("MAT4", "viewProjectionMatrix") + shader_info.push_constant("VEC4", "color") + shader_info.push_constant("FLOAT", "spacing") + + shader_info.vertex_in(0, "VEC3", "position") + shader_info.vertex_in(1, "VEC3", "coord") + shader_info.vertex_out(vert_out) - shader_info.fragment_out(0, 'VEC4', "FragColor") - + shader_info.fragment_out(0, "VEC4", "FragColor") + shader_info.vertex_source( - "void main()" - "{" - " gl_Position = viewProjectionMatrix * vec4(position, 1.0f);" - " co = coord;" - "}" + "void main()" "{" " gl_Position = viewProjectionMatrix * vec4(position, 1.0f);" " co = coord;" "}" ) - + if pattern == "SINGLE FORCE": shader_info.fragment_source( - "void main()" - "{" - "float body = step(abs(co.x),0.2*spacing)*step(2.*spacing,co.y);" - "float arrow = step(3.5*abs(co.x)+0.02,abs(co.y))*step(co.y,2.*spacing)*step(0.,co.y);" - "float d = clamp(body+arrow,0.0,0.5);" - "if (d == 0.0) discard;" - "FragColor = vec4(color.xyz,d*color.w);" - "}" - ) - + "void main()" + "{" + "float body = step(abs(co.x),0.2*spacing)*step(2.*spacing,co.y);" + "float arrow = step(3.5*abs(co.x)+0.02,abs(co.y))*step(co.y,2.*spacing)*step(0.,co.y);" + "float d = clamp(body+arrow,0.0,0.5);" + "if (d == 0.0) discard;" + "FragColor = vec4(color.xyz,d*color.w);" + "}" + ) + elif pattern == "SINGLE MOMENT": shader_info.fragment_source( - "void main()" - "{" - "float circ = step(distance(co.xy,vec2(0.,0.)),0.33)*step(0.27,distance(co.xy,vec2(0.,0.)));" - "float mask = step(co.y,co.x)+step(-co.x,co.y);" - "float circ_arrow = step(co.x,4.0*co.y-0.75)*step(0.25*co.y-0.34,co.x)*(1.-mask);" - "float d = clamp(circ_arrow+circ*mask,0.0,0.5);" - "if (d == 0.0) discard;" - "FragColor = vec4(color.xyz,d*color.w);" - "}" - ) - + "void main()" + "{" + "float circ = step(distance(co.xy,vec2(0.,0.)),0.33)*step(0.27,distance(co.xy,vec2(0.,0.)));" + "float mask = step(co.y,co.x)+step(-co.x,co.y);" + "float circ_arrow = step(co.x,4.0*co.y-0.75)*step(0.25*co.y-0.34,co.x)*(1.-mask);" + "float d = clamp(circ_arrow+circ*mask,0.0,0.5);" + "if (d == 0.0) discard;" + "FragColor = vec4(color.xyz,d*color.w);" + "}" + ) + shader = gpu.shader.create_from_info(shader_info) del vert_out del shader_info return shader - + def get_planar_shader(self) -> gpu.types.GPUShader: """shader for planar loads""" vert_out = gpu.types.GPUStageInterfaceInfo("my_interface") - vert_out.smooth('VEC3', "co") - + vert_out.smooth("VEC3", "co") + shader_info = gpu.types.GPUShaderCreateInfo() - shader_info.push_constant('MAT4', "viewProjectionMatrix") - shader_info.push_constant('VEC4', "color") - shader_info.push_constant('FLOAT', "spacing") - - shader_info.vertex_in(0, 'VEC3', "position") - shader_info.vertex_in(1, 'VEC3', "coord") - + shader_info.push_constant("MAT4", "viewProjectionMatrix") + shader_info.push_constant("VEC4", "color") + shader_info.push_constant("FLOAT", "spacing") + + shader_info.vertex_in(0, "VEC3", "position") + shader_info.vertex_in(1, "VEC3", "coord") + shader_info.vertex_out(vert_out) - shader_info.fragment_out(0, 'VEC4', "FragColor") - + shader_info.fragment_out(0, "VEC4", "FragColor") + shader_info.vertex_source( + "void main()" "{" " gl_Position = viewProjectionMatrix * vec4(position, 1.0f);" " co = coord;" "}" + ) + + shader_info.fragment_source( "void main()" "{" - " gl_Position = viewProjectionMatrix * vec4(position, 1.0f);" - " co = coord;" - "}" - ) - - shader_info.fragment_source( - "void main()" - "{" "float x = co.x;" "float y = co.y;" "float abs_y = abs(y);" - "float a = abs(mod(x,spacing)-0.5*spacing)*5.0;" "float b = step(a,abs_y)*(step(abs_y,1.2*spacing));" "float c = step(0.8*spacing,mod(x+0.4*spacing,spacing))*(step(1.2*spacing,abs_y));" - - "float mask = step(0.,y)*step(y,0.98)+step(y,0.)*step(0.98,y);" - "float top = step(abs(y-0.98),0.2*1.2*spacing);" "float d = clamp(0.2*y+(top+b+c)*mask,0.0,0.4);" "FragColor = vec4(color.xyz,d*color.w);" - "}" + "}" ) - + shader = gpu.shader.create_from_info(shader_info) del vert_out del shader_info diff --git a/src/bonsai/bonsai/bim/module/structural/ui.py b/src/bonsai/bonsai/bim/module/structural/ui.py index 23e075613c..fdea8b074c 100644 --- a/src/bonsai/bonsai/bim/module/structural/ui.py +++ b/src/bonsai/bonsai/bim/module/structural/ui.py @@ -444,6 +444,7 @@ class BIM_UL_structural_activities(UIList): row.label(text=item.name) row.label(text=item.applied_load_class) + class BIM_PT_show_structural_activities(Panel): bl_label = "Show Loads" bl_idname = "BIM_PT_show_structural_activities" @@ -463,16 +464,16 @@ class BIM_PT_show_structural_activities(Panel): row = self.layout.row(align=True) row.operator( - "bim.show_loads", - text="Show loads" , - icon="HIDE_OFF", - ) + "bim.show_loads", + text="Show loads", + icon="HIDE_OFF", + ) row = self.layout.row(align=True) - row.prop(self.props,"reference_frame") + row.prop(self.props, "reference_frame") row = self.layout.row(align=True) - row.prop(self.props,"activity_type") + row.prop(self.props, "activity_type") row = self.layout.row(align=True) - row.prop(self.props,"load_group_to_show") + row.prop(self.props, "load_group_to_show") class BIM_PT_structural_loads(Panel): From a2bfc006b741290614a730de67b55533091b8228 Mon Sep 17 00:00:00 2001 From: Lucas Nascimento Date: Wed, 18 Dec 2024 14:59:50 -0300 Subject: [PATCH 41/61] black formatting --- .../bonsai/bim/module/structural/shader.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/structural/shader.py b/src/bonsai/bonsai/bim/module/structural/shader.py index c866819bc0..389ed34839 100644 --- a/src/bonsai/bonsai/bim/module/structural/shader.py +++ b/src/bonsai/bonsai/bim/module/structural/shader.py @@ -19,18 +19,24 @@ import gpu from typing import Literal + class DecorationShader: "shader for the load decorations" def __init__(self): pass - def new(self, pattern: Literal["PERPENDICULAR DISTRIBUTED FORCE", + def new( + self, + pattern: Literal[ + "PERPENDICULAR DISTRIBUTED FORCE", "PARALLEL DISTRIBUTED FORCE", "DISTRIBUTED MOMENT", "SINGLE FORCE", "SINGLE MOMENT", - "PLANAR LOAD",]) -> gpu.types.GPUShader: + "PLANAR LOAD", + ], + ) -> gpu.types.GPUShader: """pattern: string description of the desired shader Possible values PERPENDICULAR DISTRIBUTED FORCE: pattern for distributed force @@ -70,9 +76,9 @@ class DecorationShader: shader = self.get_planar_shader() return shader - def get_linear_shader(self, pattern: Literal["PERPENDICULAR DISTRIBUTED FORCE", - "PARALLEL DISTRIBUTED FORCE", - "DISTRIBUTED MOMENT"]) -> gpu.types.GPUShader: + def get_linear_shader( + self, pattern: Literal["PERPENDICULAR DISTRIBUTED FORCE", "PARALLEL DISTRIBUTED FORCE", "DISTRIBUTED MOMENT"] + ) -> gpu.types.GPUShader: """pattern: type of pattern PERPENDICULAR DISTRIBUTED FORCE PARALLEL DISTRIBUTED FORCE, @@ -194,7 +200,7 @@ class DecorationShader: del shader_info return shader - def get_point_shader(self, pattern: Literal["SINGLE FORCE","SINGLE MOMENT"]) -> gpu.types.GPUShader: + def get_point_shader(self, pattern: Literal["SINGLE FORCE", "SINGLE MOMENT"]) -> gpu.types.GPUShader: """param: pattern: type of pattern SINGLE FORCE, SINGLE MOMENT""" From f0e1be765d9b2c80e39020b21503b37f7ee2064e Mon Sep 17 00:00:00 2001 From: tim Date: Sun, 20 Oct 2024 22:43:57 -0400 Subject: [PATCH 42/61] New Roof and Railing icons https://github.com/IfcOpenShell/IfcOpenShell/issues/5375 --- src/bonsai/blenderbim_icons.blend | Bin 230451 -> 244674 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/bonsai/blenderbim_icons.blend b/src/bonsai/blenderbim_icons.blend index d9535415ba3717b8fd54b7447e83ed89ac810090..40c4ab9809664ed905960059f1942a644afb274d 100644 GIT binary patch literal 244674 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

    Qdn2nFQWkKi`%%*9)y~h5uMU@|xu5%C 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�HY89z`zl4G$0WQ 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 literal 230451 zcmV*gKu^CYwJ-f(^p9oq016_#J6V7f)p${vmDw)mG*z=(%_g3y?y9@YgaAYM;8}uK zEAV@UJiR*~^u2D|wr$%mg@Hja7?ul7{6{n|?SK1el03_@EX%Si%d#w+{t+!C?!v1BnBi0~(DclgVs08;wSDkH_;)r_;7=C=@!uQoY4U{rP-YES8Ch35&(z za5$UI1_T1l^GwsUmVqBb()+%r(`jU6e$7bzLGNA|fIpCQ_()8_(ai4Ftind{2VyHJIyI zhFy)-R81d>;@$TR!PvIlwk?T7DwRqw439>mR4OIQ@;uLR9D^YEzOPG*4zfpwVfgd; zh^TmQ1TTu>d7dPd>K{oSEX#l6c+3kgn=Jl{Czs8W&*#Z8AsrNx)mfZirBW#t7M8lM zZQH(aRrXkKBArpbg;exAFbc_9mlb4+iz)Uc`B9SI4(_79XfQJ2M-?i z;loE9$H%tso~!zGU9RiaHT{$gdL6SY`|tZu6x}`_5*@k(-u5&|pmmT(se+>QloKTv zi9}baRH;-71r$&~0R2%J~WWMiP%k&K>Yq-h{3tZa~V`XLK zELgC3CX*pSg2d@`0=Mk<8iIg;oU`Vl6nb{0I;;9fNJ!>+#$YflTD16RG&**DzI`|y zjl{V!TI>9yggx_jo?fWH`UBE6cJG zBSv_h7lz?E91aN*Bz|32CX*om0SIswSYRQA6jJyKE3EJ|O@BI_e&6>^(|o6+UBlL6 zFqrGQHk%CwgTY`h9*+kE!GAs<5D<_NBSt(VBqWo`{JO3XAwq21c3l_8ah~TLgTZt< zoo(AVj>9l4%QBD0$%2lmM{#LN~JiC>$+yKSf**3rU{PkK=LAM zpW`?%1mDi)yKh5Ll;b!QMbGopG%XB6(=<^~P;T3HDwUFDnJmkbaq1|Fj^p^+vnMbYp3%Cdang%|FE3oaamLY0)1$g&&?g-~@pD*|I2$4~@sGEonX zoN1aM*md3aeO=ex_g&YuD2gk65CvV^I35#NIV+o<=cQ?Cnr2y+EX$tf*|u$2mZB(f z95)(`R8{RdS(d?a{WqfjLh@bLiJ}-1NANOo2%VipP1Dje1wl|%RgUAbEE~ts^E?iR zqiLG!x}qqS>G#g#uIsw43q?^71WA%S&r?;^aU92SG?`2!NuF!?9vfJl9tp4O>U277 z+s^Y`*Y$axrBaFGIFU$X+qNvrWm&Q;d!8prk}S*Cb*<58!Vr8+8qaZC7;f8^rm5$7 zD2iejR+i<%Fubk{MbY1`iP2s zw1Ve24g^7a1_1%_csv@7#!SP@FandysPP~Oe&1J?W!H5a4(IGX&tNc{%?5+PgoK2A zKA&ydI2?{fqajJMP0x{e7LcPitqcvFnnEC zr_%{9hF}th^*^+P1Ck*LxBQ?iHQjb3CVR`UDtV@_r7nMrdgJCIvtv(=XuU#GNx(n*s

    $)t8U}V+#e3Vf_jo#$ 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

    2Nh?a_Z3vuT;${y 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≪VZ$RVeRi;ZA*qmj<_hwAyw~JtK`=&@i+k^&ATbA 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 From 59c1d7fa54cb6fd3a222d74aa00bf2988450b1cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Louis=20Tr=C3=BCmpler?= <78563314+louistrue@users.noreply.github.com> Date: Sun, 22 Sep 2024 10:50:35 +0200 Subject: [PATCH 43/61] Add AssignConstituentFractions recipe --- .../recipes/AssignConstituentFractions.py | 159 ++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 src/ifcpatch/ifcpatch/recipes/AssignConstituentFractions.py diff --git a/src/ifcpatch/ifcpatch/recipes/AssignConstituentFractions.py b/src/ifcpatch/ifcpatch/recipes/AssignConstituentFractions.py new file mode 100644 index 0000000000..42726cb2ee --- /dev/null +++ b/src/ifcpatch/ifcpatch/recipes/AssignConstituentFractions.py @@ -0,0 +1,159 @@ +# IfcPatch - IFC patching utility +# AssignConstituentFractions Recipe +# This recipe assigns fractions to material constituents in an IFC file based on their widths. + +import ifcopenshell +from ifcopenshell.util.unit import calculate_unit_scale +from logging import Logger +from collections import defaultdict +from typing import List + + +class Patcher: + """ + Assigns fractions to material constituents in an IFC file based on their widths. + + This patcher calculates the widths of material constituents based on associated quantities + and assigns fraction values accordingly. + """ + + def __init__(self, src: str, file: ifcopenshell.file, logger: Logger, *args): + self.src = src + self.file = file + self.logger = logger + + def patch(self): + """ + Execute the patch to assign fractions to material constituents. + """ + unit_scale_to_mm = calculate_unit_scale(self.file) * 1000.0 + + for constituent_set in self.file.by_type('IfcMaterialConstituentSet'): + constituents = constituent_set.MaterialConstituents or [] + if not constituents: + continue # Skip if no constituents found + + # Find elements associated with this constituent set via IfcRelAssociatesMaterial + associated_elements = self.get_associated_elements(constituent_set) + if not associated_elements: + continue # Skip if no associated elements found + + # Collect quantities associated with the elements + quantities = self.get_quantities_from_elements(associated_elements) + + # Build a mapping of quantity names to quantities + quantity_name_map = self.build_quantity_name_map(quantities) + + # Calculate widths for constituents + constituent_widths, total_width_mm = self.calculate_constituent_widths( + constituents, quantity_name_map, unit_scale_to_mm + ) + + if total_width_mm == 0.0: + constituent_set_name = constituent_set.Name or "Unnamed Constituent Set" + self.logger.warning(f"No widths found for constituents in set '{constituent_set_name}'. Skipping.") + continue # Skip if total width is zero to avoid division by zero + + # Assign fractions based on widths + for constituent, width_mm in constituent_widths.items(): + fraction = width_mm / total_width_mm + constituent.Fraction = fraction + self.logger.info(f"Constituent: {constituent.Name}, Width: {width_mm:.2f} mm, Fraction: {fraction:.4f}") + + def get_associated_elements(self, constituent_set) -> List[ifcopenshell.entity_instance]: + """ + Retrieve elements associated with a given material constituent set. + + :param constituent_set: The material constituent set. + :return: A list of associated elements. + """ + associated_elements = [] + for rel in self.file.get_inverse(constituent_set): + if rel.is_a('IfcRelAssociatesMaterial') and rel.RelatedObjects: + associated_elements.extend(rel.RelatedObjects) + return associated_elements + + def get_element_quantities(self, element) -> List[ifcopenshell.entity_instance]: + """ + Retrieve quantities associated with an element. + + :param element: The IFC element. + :return: A list of quantities. + """ + quantities = [] + for rel in getattr(element, 'IsDefinedBy', []): + if rel.is_a('IfcRelDefinesByProperties'): + prop_def = rel.RelatingPropertyDefinition + if prop_def.is_a('IfcElementQuantity'): + quantities.extend(prop_def.Quantities) + return quantities + + def get_quantities_from_elements(self, elements) -> List[ifcopenshell.entity_instance]: + """ + Collect quantities from a list of elements. + + :param elements: A list of IFC elements. + :return: A list of quantities. + """ + quantities = [] + for element in elements: + quantities.extend(self.get_element_quantities(element)) + return quantities + + def build_quantity_name_map(self, quantities) -> defaultdict: + """ + Build a mapping from quantity names to quantities. + + :param quantities: A list of quantities. + :return: A defaultdict mapping names to quantities. + """ + quantity_name_map = defaultdict(list) + for q in quantities: + if q.is_a('IfcPhysicalComplexQuantity'): + q_name = (q.Name or '').strip().lower() + quantity_name_map[q_name].append(q) + return quantity_name_map + + def extract_width_from_quantity(self, quantity, unit_scale_to_mm: float) -> float: + """ + Extract the width from a quantity. + + :param quantity: The complex quantity. + :param unit_scale_to_mm: The unit scale to millimeters. + :return: The width in millimeters. + """ + for sub_q in getattr(quantity, 'HasQuantities', []): + if sub_q.is_a('IfcQuantityLength') and (sub_q.Name or '').strip().lower() == 'width': + raw_length_value = sub_q.LengthValue or 0.0 + width_mm = raw_length_value * unit_scale_to_mm + return width_mm + return 0.0 + + def calculate_constituent_widths(self, constituents, quantity_name_map, unit_scale_to_mm: float): + """ + Calculate the widths of constituents based on associated quantities. + + :param constituents: A list of material constituents. + :param quantity_name_map: A mapping from quantity names to quantities. + :param unit_scale_to_mm: The unit scale to millimeters. + :return: A tuple containing the constituent widths and total width. + """ + constituents_by_name = defaultdict(list) + for constituent in constituents: + constituent_name = (constituent.Name or "Unnamed Constituent").strip().lower() + constituents_by_name[constituent_name].append(constituent) + + constituent_widths = {} + total_width_mm = 0.0 + + for constituent_name, constituents_list in constituents_by_name.items(): + quantities_list = quantity_name_map.get(constituent_name, []) + for i, constituent in enumerate(constituents_list): + width_mm = 0.0 + if i < len(quantities_list): + matched_quantity = quantities_list[i] + width_mm = self.extract_width_from_quantity(matched_quantity, unit_scale_to_mm) + constituent_widths[constituent] = width_mm + total_width_mm += width_mm + + return constituent_widths, total_width_mm From 79fe1bfcfc8aee0cf59e1f7363d595e61f054479 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sun, 12 Jan 2025 17:45:43 +1100 Subject: [PATCH 44/61] Minor fix from new patch recipe in PR #5441 (src no longer required) --- src/ifcpatch/ifcpatch/recipes/AssignConstituentFractions.py | 3 +-- src/ifcpatch/ifcpatch/recipes/RegenerateGlobalIds.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ifcpatch/ifcpatch/recipes/AssignConstituentFractions.py b/src/ifcpatch/ifcpatch/recipes/AssignConstituentFractions.py index 42726cb2ee..bbcde73316 100644 --- a/src/ifcpatch/ifcpatch/recipes/AssignConstituentFractions.py +++ b/src/ifcpatch/ifcpatch/recipes/AssignConstituentFractions.py @@ -17,8 +17,7 @@ class Patcher: and assigns fraction values accordingly. """ - def __init__(self, src: str, file: ifcopenshell.file, logger: Logger, *args): - self.src = src + def __init__(self, file: ifcopenshell.file, logger: Logger): self.file = file self.logger = logger diff --git a/src/ifcpatch/ifcpatch/recipes/RegenerateGlobalIds.py b/src/ifcpatch/ifcpatch/recipes/RegenerateGlobalIds.py index dec1a1db10..63c595ca9e 100644 --- a/src/ifcpatch/ifcpatch/recipes/RegenerateGlobalIds.py +++ b/src/ifcpatch/ifcpatch/recipes/RegenerateGlobalIds.py @@ -22,7 +22,7 @@ from logging import Logger class Patcher: - def __init__(self, file: ifcopenshell.file, logger: Logger, only_duplicates=False): + def __init__(self, file: ifcopenshell.file, logger: Logger, only_duplicates: bool = False): """Regenerate GlobalIds in an IFC model All root elements in an IFC model must be identified by a unique Global From 03d3b1e52c107763b1f0e94fb38311b783838081 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sun, 12 Jan 2025 17:51:32 +1100 Subject: [PATCH 45/61] Changed my mind, remove AssignConstituentFractions patch. See #5441. --- .../recipes/AssignConstituentFractions.py | 158 ------------------ 1 file changed, 158 deletions(-) delete mode 100644 src/ifcpatch/ifcpatch/recipes/AssignConstituentFractions.py diff --git a/src/ifcpatch/ifcpatch/recipes/AssignConstituentFractions.py b/src/ifcpatch/ifcpatch/recipes/AssignConstituentFractions.py deleted file mode 100644 index bbcde73316..0000000000 --- a/src/ifcpatch/ifcpatch/recipes/AssignConstituentFractions.py +++ /dev/null @@ -1,158 +0,0 @@ -# IfcPatch - IFC patching utility -# AssignConstituentFractions Recipe -# This recipe assigns fractions to material constituents in an IFC file based on their widths. - -import ifcopenshell -from ifcopenshell.util.unit import calculate_unit_scale -from logging import Logger -from collections import defaultdict -from typing import List - - -class Patcher: - """ - Assigns fractions to material constituents in an IFC file based on their widths. - - This patcher calculates the widths of material constituents based on associated quantities - and assigns fraction values accordingly. - """ - - def __init__(self, file: ifcopenshell.file, logger: Logger): - self.file = file - self.logger = logger - - def patch(self): - """ - Execute the patch to assign fractions to material constituents. - """ - unit_scale_to_mm = calculate_unit_scale(self.file) * 1000.0 - - for constituent_set in self.file.by_type('IfcMaterialConstituentSet'): - constituents = constituent_set.MaterialConstituents or [] - if not constituents: - continue # Skip if no constituents found - - # Find elements associated with this constituent set via IfcRelAssociatesMaterial - associated_elements = self.get_associated_elements(constituent_set) - if not associated_elements: - continue # Skip if no associated elements found - - # Collect quantities associated with the elements - quantities = self.get_quantities_from_elements(associated_elements) - - # Build a mapping of quantity names to quantities - quantity_name_map = self.build_quantity_name_map(quantities) - - # Calculate widths for constituents - constituent_widths, total_width_mm = self.calculate_constituent_widths( - constituents, quantity_name_map, unit_scale_to_mm - ) - - if total_width_mm == 0.0: - constituent_set_name = constituent_set.Name or "Unnamed Constituent Set" - self.logger.warning(f"No widths found for constituents in set '{constituent_set_name}'. Skipping.") - continue # Skip if total width is zero to avoid division by zero - - # Assign fractions based on widths - for constituent, width_mm in constituent_widths.items(): - fraction = width_mm / total_width_mm - constituent.Fraction = fraction - self.logger.info(f"Constituent: {constituent.Name}, Width: {width_mm:.2f} mm, Fraction: {fraction:.4f}") - - def get_associated_elements(self, constituent_set) -> List[ifcopenshell.entity_instance]: - """ - Retrieve elements associated with a given material constituent set. - - :param constituent_set: The material constituent set. - :return: A list of associated elements. - """ - associated_elements = [] - for rel in self.file.get_inverse(constituent_set): - if rel.is_a('IfcRelAssociatesMaterial') and rel.RelatedObjects: - associated_elements.extend(rel.RelatedObjects) - return associated_elements - - def get_element_quantities(self, element) -> List[ifcopenshell.entity_instance]: - """ - Retrieve quantities associated with an element. - - :param element: The IFC element. - :return: A list of quantities. - """ - quantities = [] - for rel in getattr(element, 'IsDefinedBy', []): - if rel.is_a('IfcRelDefinesByProperties'): - prop_def = rel.RelatingPropertyDefinition - if prop_def.is_a('IfcElementQuantity'): - quantities.extend(prop_def.Quantities) - return quantities - - def get_quantities_from_elements(self, elements) -> List[ifcopenshell.entity_instance]: - """ - Collect quantities from a list of elements. - - :param elements: A list of IFC elements. - :return: A list of quantities. - """ - quantities = [] - for element in elements: - quantities.extend(self.get_element_quantities(element)) - return quantities - - def build_quantity_name_map(self, quantities) -> defaultdict: - """ - Build a mapping from quantity names to quantities. - - :param quantities: A list of quantities. - :return: A defaultdict mapping names to quantities. - """ - quantity_name_map = defaultdict(list) - for q in quantities: - if q.is_a('IfcPhysicalComplexQuantity'): - q_name = (q.Name or '').strip().lower() - quantity_name_map[q_name].append(q) - return quantity_name_map - - def extract_width_from_quantity(self, quantity, unit_scale_to_mm: float) -> float: - """ - Extract the width from a quantity. - - :param quantity: The complex quantity. - :param unit_scale_to_mm: The unit scale to millimeters. - :return: The width in millimeters. - """ - for sub_q in getattr(quantity, 'HasQuantities', []): - if sub_q.is_a('IfcQuantityLength') and (sub_q.Name or '').strip().lower() == 'width': - raw_length_value = sub_q.LengthValue or 0.0 - width_mm = raw_length_value * unit_scale_to_mm - return width_mm - return 0.0 - - def calculate_constituent_widths(self, constituents, quantity_name_map, unit_scale_to_mm: float): - """ - Calculate the widths of constituents based on associated quantities. - - :param constituents: A list of material constituents. - :param quantity_name_map: A mapping from quantity names to quantities. - :param unit_scale_to_mm: The unit scale to millimeters. - :return: A tuple containing the constituent widths and total width. - """ - constituents_by_name = defaultdict(list) - for constituent in constituents: - constituent_name = (constituent.Name or "Unnamed Constituent").strip().lower() - constituents_by_name[constituent_name].append(constituent) - - constituent_widths = {} - total_width_mm = 0.0 - - for constituent_name, constituents_list in constituents_by_name.items(): - quantities_list = quantity_name_map.get(constituent_name, []) - for i, constituent in enumerate(constituents_list): - width_mm = 0.0 - if i < len(quantities_list): - matched_quantity = quantities_list[i] - width_mm = self.extract_width_from_quantity(matched_quantity, unit_scale_to_mm) - constituent_widths[constituent] = width_mm - total_width_mm += width_mm - - return constituent_widths, total_width_mm From 2d38d8520c87b061eda5cc14297a47df55caf489 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sun, 12 Jan 2025 21:47:42 +1100 Subject: [PATCH 46/61] Fix regression where you couldn't move spatial elements from the new aggregate move override. --- src/bonsai/bonsai/bim/module/geometry/operator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bonsai/bonsai/bim/module/geometry/operator.py b/src/bonsai/bonsai/bim/module/geometry/operator.py index c27d4d25c5..02664b0193 100644 --- a/src/bonsai/bonsai/bim/module/geometry/operator.py +++ b/src/bonsai/bonsai/bim/module/geometry/operator.py @@ -2950,7 +2950,7 @@ class OverrideMoveAggregate(bpy.types.Operator): obj.select_set(False) continue element = tool.Ifc.get_entity(obj) - if not element or props.in_aggregate_mode: + if not element or not element.is_a("IfcElement") or props.in_aggregate_mode: continue parts = ifcopenshell.util.element.get_parts(element) if parts: From 8364c87777736ad5ee3cba62e240e7a473f34557 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sun, 12 Jan 2025 22:39:32 +1100 Subject: [PATCH 47/61] Fix #5941. Context override when adding objects should only have one object. This is a temporary fix. The proper fix is to refactor add_door and friends into core. That way it can be properly reused instead of this hacky context override. --- src/bonsai/bonsai/bim/module/root/operator.py | 10 +++++----- src/bonsai/bonsai/tool/blender.py | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/root/operator.py b/src/bonsai/bonsai/bim/module/root/operator.py index 7cde90af05..8a606ddc9b 100644 --- a/src/bonsai/bonsai/bim/module/root/operator.py +++ b/src/bonsai/bonsai/bim/module/root/operator.py @@ -532,19 +532,19 @@ class AddElement(bpy.types.Operator, tool.Ifc.Operator): "material.assign_profile", tool.Ifc.get(), material_profile=material_profile, profile=profile ) elif representation_template == "WINDOW": - with context.temp_override(active_object=obj): + with context.temp_override(active_object=obj, selected_objects=[]): bpy.ops.bim.add_window() elif representation_template == "DOOR": - with context.temp_override(active_object=obj): + with context.temp_override(active_object=obj, selected_objects=[]): bpy.ops.bim.add_door() elif representation_template == "STAIR": - with context.temp_override(active_object=obj): + with context.temp_override(active_object=obj, selected_objects=[]): bpy.ops.bim.add_stair() elif representation_template == "RAILING": - with context.temp_override(active_object=obj): + with context.temp_override(active_object=obj, selected_objects=[]): bpy.ops.bim.add_railing() elif representation_template == "ROOF": - with context.temp_override(active_object=obj): + with context.temp_override(active_object=obj, selected_objects=[]): bpy.ops.bim.add_roof() def draw(self, context): diff --git a/src/bonsai/bonsai/tool/blender.py b/src/bonsai/bonsai/tool/blender.py index d736599384..051dfa9dc3 100644 --- a/src/bonsai/bonsai/tool/blender.py +++ b/src/bonsai/bonsai/tool/blender.py @@ -144,7 +144,7 @@ class Blender(bonsai.core.tool.Blender): @classmethod def get_active_object(cls) -> bpy.types.Object: - return bpy.context.view_layer.objects.active or getattr(bpy.context, "active_object", None) + return getattr(bpy.context, "active_object", None) or bpy.context.view_layer.objects.active @classmethod def get_selected_objects(cls) -> set[bpy.types.Object]: From 04092d19be8aeb2bf66e488d7c76d7bb1e70ae51 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sun, 12 Jan 2025 22:43:34 +1100 Subject: [PATCH 48/61] Refactor common function for parametric objects into tool.Model --- src/bonsai/bonsai/bim/module/model/door.py | 24 +++---------------- src/bonsai/bonsai/bim/module/model/railing.py | 9 ++++--- src/bonsai/bonsai/bim/module/model/roof.py | 3 +-- src/bonsai/bonsai/tool/model.py | 17 +++++++++++++ 4 files changed, 25 insertions(+), 28 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/model/door.py b/src/bonsai/bonsai/bim/module/model/door.py index 94ba825413..d8208feaea 100644 --- a/src/bonsai/bonsai/bim/module/model/door.py +++ b/src/bonsai/bonsai/bim/module/model/door.py @@ -19,8 +19,6 @@ import bpy import bmesh -from bmesh.types import BMVert, BMFace - import ifcopenshell import ifcopenshell.api import ifcopenshell.util.element @@ -169,22 +167,6 @@ def update_door_modifier_representation(obj: bpy.types.Object) -> None: tool.Model.update_simple_openings(element) -# TODO: move it out to tools -def bm_sort_out_geom( - geom_data: list[Union[bmesh.types.BMVert, bmesh.types.BMEdge, bmesh.types.BMFace]] -) -> dict[str, Any]: - geom_dict = {"verts": [], "edges": [], "faces": []} - - for el in geom_data: - if isinstance(el, BMVert): - geom_dict["verts"].append(el) - elif isinstance(el, BMFace): - geom_dict["faces"].append(el) - else: - geom_dict["edges"].append(el) - return geom_dict - - def bm_mirror( bm: bmesh.types.BMesh, verts: list[bmesh.types.BMVert], @@ -208,7 +190,7 @@ def bm_mirror( for v in verts: faces.update(v.link_faces) duplicated = bmesh.ops.duplicate(bm, geom=list(faces)) - verts = bm_sort_out_geom(duplicated["geom"])["verts"] + verts = tool.Model.bm_sort_out_geom(duplicated["geom"])["verts"] bmesh.ops.transform(bm, verts=verts, matrix=matrix, space=Matrix.Identity(4)) return verts @@ -242,7 +224,7 @@ def create_bm_extruded_profile( extruded = bmesh.ops.extrude_face_region(bm, geom=new_faces) extrusion_vector = extrusion_vector * magnitude - extruded_verts = bm_sort_out_geom(extruded["geom"])["verts"] + extruded_verts = tool.Model.bm_sort_out_geom(extruded["geom"])["verts"] bmesh.ops.translate(bm, vec=extrusion_vector, verts=extruded_verts) bmesh.ops.translate(bm, vec=position, verts=new_verts + extruded_verts) @@ -304,7 +286,7 @@ def create_bm_door_lining( extruded = bmesh.ops.extrude_face_region(bm, geom=new_faces) extrusion_vector = Vector((0, 1, 0)) * depth - translate_verts = [v for v in extruded["geom"] if isinstance(v, BMVert)] + translate_verts = [v for v in extruded["geom"] if isinstance(v, bmesh.types.BMVert)] bmesh.ops.translate(bm, vec=extrusion_vector, verts=translate_verts) bmesh.ops.translate(bm, vec=position, verts=new_verts + translate_verts) diff --git a/src/bonsai/bonsai/bim/module/model/railing.py b/src/bonsai/bonsai/bim/module/model/railing.py index 1dc6638b5c..edf4eae35d 100644 --- a/src/bonsai/bonsai/bim/module/model/railing.py +++ b/src/bonsai/bonsai/bim/module/model/railing.py @@ -26,7 +26,6 @@ import ifcopenshell.util.unit import bonsai.core.root import bonsai.core.geometry import bonsai.tool as tool -from bonsai.bim.module.model.door import bm_sort_out_geom from bonsai.bim.module.model.data import RailingData, refresh from bonsai.bim.module.model.decorator import ProfileDecorator @@ -47,7 +46,7 @@ def bm_split_edge_at_offset(edge: bmesh.types.BMEdge, offset: float) -> dict[str split_output_0 = bmesh.utils.edge_split(edge, v0, offset / edge_len) split_output_1 = bmesh.utils.edge_split(edge, v1, offset / (edge_len - offset)) - new_geometry = bm_sort_out_geom(split_output_0 + split_output_1) + new_geometry = tool.Model.bm_sort_out_geom(split_output_0 + split_output_1) return new_geometry @@ -175,11 +174,11 @@ def update_railing_modifier_bmesh(context: bpy.types.Context) -> None: ortho_vector = edge_dir.cross(V_(0, 0, 1)) extruded_geom = bmesh.ops.extrude_edge_only(bm, edges=[main_edge])["geom"] - extruded_verts = bm_sort_out_geom(extruded_geom)["verts"] + extruded_verts = tool.Model.bm_sort_out_geom(extruded_geom)["verts"] bmesh.ops.translate(bm, vec=ortho_vector * (-thickness / 2), verts=extruded_verts) extruded_geom = bmesh.ops.extrude_edge_only(bm, edges=[main_edge])["geom"] - extruded_verts = bm_sort_out_geom(extruded_geom)["verts"] + extruded_verts = tool.Model.bm_sort_out_geom(extruded_geom)["verts"] bmesh.ops.translate(bm, vec=ortho_vector * (thickness / 2), verts=extruded_verts) # dissolve middle edge @@ -187,7 +186,7 @@ def update_railing_modifier_bmesh(context: bpy.types.Context) -> None: # height extruded_geom = bmesh.ops.extrude_face_region(bm, geom=bm.faces)["geom"] - extruded_verts = bm_sort_out_geom(extruded_geom)["verts"] + extruded_verts = tool.Model.bm_sort_out_geom(extruded_geom)["verts"] extrusion_vector = Vector((0, 0, 1)) * height bmesh.ops.translate(bm, vec=extrusion_vector, verts=extruded_verts) diff --git a/src/bonsai/bonsai/bim/module/model/roof.py b/src/bonsai/bonsai/bim/module/model/roof.py index e60fdc65a7..d31a251c94 100644 --- a/src/bonsai/bonsai/bim/module/model/roof.py +++ b/src/bonsai/bonsai/bim/module/model/roof.py @@ -26,7 +26,6 @@ import ifcopenshell.util.unit import bonsai.core.root import bonsai.tool as tool from bonsai.bim.helper import convert_property_group_from_si -from bonsai.bim.module.model.door import bm_sort_out_geom from bonsai.bim.module.model.data import RoofData, refresh from bonsai.bim.module.model.decorator import ProfileDecorator @@ -327,7 +326,7 @@ def generate_hiped_roof_bmesh( bmesh.ops.delete(bm, geom=bottom_chords_to_remove, context="EDGES") # add roof thickness - extrusion_geom = bm_sort_out_geom(bmesh.ops.extrude_face_region(bm, geom=bm.faces)["geom"]) + extrusion_geom = tool.Model.bm_sort_out_geom(bmesh.ops.extrude_face_region(bm, geom=bm.faces)["geom"]) extruded_edges = extrusion_geom["edges"] extruded_verts = extrusion_geom["verts"] rafter_edge_angle = pi / 2 - rafter_edge_angle diff --git a/src/bonsai/bonsai/tool/model.py b/src/bonsai/bonsai/tool/model.py index e69531cce4..da720b755e 100644 --- a/src/bonsai/bonsai/tool/model.py +++ b/src/bonsai/bonsai/tool/model.py @@ -1263,10 +1263,12 @@ class Model(bonsai.core.tool.Model): if stair_type == "WOOD/STEEL": builder = ShapeBuilder(None) + # full tread rectangle def get_tread_verts(*args, **kwargs): fn = partial(builder.get_rectangle_coords, position=V_(0, -(tread_depth - tread_rise))) return [Vector(x) for x in fn(*args, **kwargs)] + default_tread_verts = get_tread_verts(size=V_(tread_run + nosing_overlap, tread_depth)) default_tread_offset = V_(tread_run + nosing_tread_gap, tread_rise) @@ -2011,3 +2013,18 @@ class Model(bonsai.core.tool.Model): @classmethod def get_booleaned_obj(cls, boolean_obj: bpy.types.Object) -> bpy.types.Object: return boolean_obj.data.BIMMeshProperties.obj + + @classmethod + def bm_sort_out_geom( + cls, geom_data: list[Union[bmesh.types.BMVert, bmesh.types.BMEdge, bmesh.types.BMFace]] + ) -> dict[str, Any]: + geom_dict = {"verts": [], "edges": [], "faces": []} + + for el in geom_data: + if isinstance(el, bmesh.types.BMVert): + geom_dict["verts"].append(el) + elif isinstance(el, bmesh.types.BMFace): + geom_dict["faces"].append(el) + else: + geom_dict["edges"].append(el) + return geom_dict From 0eb987fc0759c46c0a2babefe108442fe39d2ea0 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sun, 12 Jan 2025 22:43:41 +1100 Subject: [PATCH 49/61] Black --- src/bonsai/bonsai/bim/module/model/prop.py | 4 +++- .../ifcopenshell/api/unit/add_derived_unit.py | 21 +++++++++++-------- src/ifctester/ifctester/facet.py | 13 ++++++++++-- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/model/prop.py b/src/bonsai/bonsai/bim/module/model/prop.py index 4325a3e9fb..afc93db5d3 100644 --- a/src/bonsai/bonsai/bim/module/model/prop.py +++ b/src/bonsai/bonsai/bim/module/model/prop.py @@ -167,7 +167,9 @@ class BIMModelProperties(PropertyGroup): rl2: bpy.props.FloatProperty(name="RL", default=1, subtype="DISTANCE", description="Z offset for windows") # Used for plan calculation points such as in room generation rl3: bpy.props.FloatProperty(name="RL", default=1, subtype="DISTANCE", description="Z offset for space calculation") - x_angle: bpy.props.FloatProperty(name="X Angle", default=0, subtype="ANGLE", min=math.radians(-180), max=math.radians(180), update=update_x_angle) + x_angle: bpy.props.FloatProperty( + name="X Angle", default=0, subtype="ANGLE", min=math.radians(-180), max=math.radians(180), update=update_x_angle + ) type_page: bpy.props.IntProperty(name="Type Page", default=1, update=update_type_page) type_name: bpy.props.StringProperty(name="Name", default="TYPEX") boundary_class: bpy.props.EnumProperty(items=get_boundary_class, name="Boundary Class") diff --git a/src/ifcopenshell-python/ifcopenshell/api/unit/add_derived_unit.py b/src/ifcopenshell-python/ifcopenshell/api/unit/add_derived_unit.py index 90271acb4f..8a68e5727f 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/unit/add_derived_unit.py +++ b/src/ifcopenshell-python/ifcopenshell/api/unit/add_derived_unit.py @@ -20,7 +20,9 @@ import ifcopenshell.util.unit from typing import Any, Optional -def add_derived_unit(file: ifcopenshell.file, unit_type: str, userdefinedtype : str, attributes: dict[ifcopenshell.entity_instance, int]) -> ifcopenshell.entity_instance: +def add_derived_unit( + file: ifcopenshell.file, unit_type: str, userdefinedtype: str, attributes: dict[ifcopenshell.entity_instance, int] +) -> ifcopenshell.entity_instance: """Add a new Derive unit The supported types are ANGULARVELOCITYUNIT, AREADENSITYUNIT, COMPOUNDPLANEANGLEUNIT, @@ -68,13 +70,14 @@ def add_derived_unit(file: ifcopenshell.file, unit_type: str, userdefinedtype : """ settings = {"unit_type": unit_type, "attributes": attributes} - + derive_unit_elements = [] - for named_unit in settings['attributes']: - derive_unit_elements.append(file.create_entity("IfcDerivedUnitElement", Unit=named_unit, Exponent = settings['attributes'][named_unit])) - - return file.create_entity("IfcDerivedUnit", - Elements = derive_unit_elements, - UnitType=settings["unit_type"], - UserDefinedType=userdefinedtype) + for named_unit in settings["attributes"]: + derive_unit_elements.append( + file.create_entity("IfcDerivedUnitElement", Unit=named_unit, Exponent=settings["attributes"][named_unit]) + ) + + return file.create_entity( + "IfcDerivedUnit", Elements=derive_unit_elements, UnitType=settings["unit_type"], UserDefinedType=userdefinedtype + ) diff --git a/src/ifctester/ifctester/facet.py b/src/ifctester/ifctester/facet.py index fd23006b43..15562454f1 100644 --- a/src/ifctester/ifctester/facet.py +++ b/src/ifctester/ifctester/facet.py @@ -998,8 +998,17 @@ class Restriction: for constraint, value in self.options.items(): value = [value] if not isinstance(value, list) else value for v in value: - if constraint in ["length", "minLength", "maxLength", "maxExclusive", "maxInclusive", - "minExclusive", "minInclusive", "totalDigits", "fractionDigits"]: + if constraint in [ + "length", + "minLength", + "maxLength", + "maxExclusive", + "maxInclusive", + "minExclusive", + "minInclusive", + "totalDigits", + "fractionDigits", + ]: value_dict = {"@value": v} else: value_dict = {"@value": str(v)} From 6aec2f7a025acca51642f7f5e28aceb3f98b56b9 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 12 Jan 2025 14:45:25 +0100 Subject: [PATCH 50/61] pyodide/app-demo --- .gitmodules | 3 + src/pyodide/demo-app/context.py | 339 +++++++++++++++++++++ src/pyodide/demo-app/index.html | 405 +++++++++++++++++++++++++ src/pyodide/demo-app/propertygroups.py | 152 ++++++++++ src/pyodide/demo-app/style.css | 93 ++++++ src/pyodide/demo-app/wheels | 1 + 6 files changed, 993 insertions(+) create mode 100644 src/pyodide/demo-app/context.py create mode 100644 src/pyodide/demo-app/index.html create mode 100644 src/pyodide/demo-app/propertygroups.py create mode 100644 src/pyodide/demo-app/style.css create mode 160000 src/pyodide/demo-app/wheels diff --git a/.gitmodules b/.gitmodules index 9fbc1888bb..017cd2ae8e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -20,3 +20,6 @@ [submodule "src/ifcopenshell-python/ifcopenshell/simple_spf"] path = src/ifcopenshell-python/ifcopenshell/simple_spf url = https://github.com/IfcOpenShell/step-file-parser +[submodule "src/pyodide/demo-app/wheels"] + path = src/pyodide/demo-app/wheels + url = https://github.com/IfcOpenShell/wasm-wheels diff --git a/src/pyodide/demo-app/context.py b/src/pyodide/demo-app/context.py new file mode 100644 index 0000000000..3ad8b45464 --- /dev/null +++ b/src/pyodide/demo-app/context.py @@ -0,0 +1,339 @@ +import ifcopenshell +import ifcopenshell.geom +import ifcopenshell.api +import ifcopenshell.util.unit + +import numpy as np + +import propertygroups + +O = 0.0, 0.0, 0.0 +X = 1.0, 0.0, 0.0 +Y = 0.0, 1.0, 0.0 +Z = 0.0, 0.0, 1.0 + + +class Context: + model = None + body = None + storey = None + + def __init__(self): + self._create_empty_model() + + def clear(self): + self._create_empty_model() + + def open(self, file_content): + self.model = ifcopenshell.file.from_string(file_content) + body = [ctx for ctx in self.model.by_type('IfcGeometricRepresentationContext') if ctx.ContextIdentifier == 'Body'] + if body: + self.body = body[0] + else: + context = ifcopenshell.api.run("context.add_context", self.model, context_type="Model") + self.body = ifcopenshell.api.run( + "context.add_context", + self.model, + context_type="Model", + context_identifier="Body", + target_view="MODEL_VIEW", + parent=context, + ) + axis = [ctx for ctx in self.model.by_type('IfcGeometricRepresentationContext') if ctx.ContextIdentifier == 'Axis'] + if body: + self.axis = axis[0] + else: + context = ifcopenshell.api.run("context.add_context", self.model, context_type="Model") + self.axis = ifcopenshell.api.run( + "context.add_context", + self.model, + context_type="Model", + context_identifier="Axis", + target_view="GRAPH_VIEW", + parent=context, + ) + self.storey = self.model.by_type('IfcBuildingStorey')[0] + + def _create_empty_model(self): + # Create a blank model + self.model = ifcopenshell.file() + # All projects must have one IFC Project element + project = ifcopenshell.api.run( + "root.create_entity", self.model, ifc_class="IfcProject", name="My Project" + ) + # Geometry is optional in IFC, but because we want to use geometry in this example, let's define units + # Assigning without arguments defaults to metric units + ifcopenshell.api.run("unit.assign_unit", self.model) + # Let's create a modeling geometry context, so we can store 3D geometry (note: IFC supports 2D too!) + context = ifcopenshell.api.run("context.add_context", self.model, context_type="Model") + # In particular, in this example we want to store the 3D "body" geometry of objects, i.e. the body shape + self.body = ifcopenshell.api.run( + "context.add_context", + self.model, + context_type="Model", + context_identifier="Body", + target_view="MODEL_VIEW", + parent=context, + ) + self.axis = ifcopenshell.api.run( + "context.add_context", + self.model, + context_type="Model", + context_identifier="Axis", + target_view="GRAPH_VIEW", + parent=context, + ) + # Create a site, building, and storey. Many hierarchies are possible. + site = ifcopenshell.api.run( + "root.create_entity", self.model, ifc_class="IfcSite", name="My Site" + ) + building = ifcopenshell.api.run( + "root.create_entity", self.model, ifc_class="IfcBuilding", name="Building A" + ) + self.storey = ifcopenshell.api.run( + "root.create_entity", + self.model, + ifc_class="IfcBuildingStorey", + name="Ground Floor", + ) + # Since the site is our top level location, assign it to the project + # Then place our building on the site, and our storey in the building + ifcopenshell.api.run( + "aggregate.assign_object", + self.model, + relating_object=project, + products=[site], + ) + ifcopenshell.api.run( + "aggregate.assign_object", + self.model, + relating_object=site, + products=[building], + ) + ifcopenshell.api.run( + "aggregate.assign_object", + self.model, + relating_object=building, + products=[self.storey], + ) + + def create_2pt_wall( + self, p1, p2, elevation, height, thickness, container, wall_type=None + ): + p1 = np.array([p1[0], p1[1]]) + p2 = np.array([p2[0], p2[1]]) + + wall = ifcopenshell.api.run("root.create_entity", self.model, ifc_class="IfcWall") + length = float(np.linalg.norm(p2 - p1)) + representation = ifcopenshell.api.run( + "geometry.add_wall_representation", + self.model, + context=self.body, + length=length, + height=height, + thickness=thickness, + ) + ifcopenshell.api.run( + "geometry.assign_representation", + self.model, + product=wall, + representation=representation, + ) + representation = ifcopenshell.api.run( + "geometry.add_axis_representation", + self.model, + context=self.axis, + axis=[(0.0, 0.0), (length, 0.0)], + ) + ifcopenshell.api.run( + "geometry.assign_representation", + self.model, + product=wall, + representation=representation, + ) + v = p2 - p1 + v = np.divide(v, float(np.linalg.norm(v)), casting="unsafe") + matrix = np.array( + [ + [v[0], -v[1], 0, p1[0]], + [v[1], v[0], 0, p1[1]], + [0, 0, 1, elevation], + [0, 0, 0, 1], + ] + ) + ifcopenshell.api.run("geometry.edit_object_placement", self.model, product=wall, matrix=matrix) + ifcopenshell.api.run( + "spatial.assign_container", + self.model, + relating_structure=container, + products=[wall], + ) + if wall_type: + ifcopenshell.api.run( + "type.assign_type", + self.model, + related_object=wall, + relating_type=wall_type, + ) + + return wall + + def get_element(self, guid): + return self.model[guid] + + def get_model(self): + return self.model + + def create_fill(self, ty, pt, wall): + if isinstance(wall, str): + wall = self.model[wall] + if not wall.is_a('IfcWall'): + raise ValueError("Only 'wall' hosts are supported") + if ty == 'door': + props = propertygroups.BIMDoorProperties() + elif ty == 'window': + props = propertygroups.BIMWindowProperties() + else: + raise ValueError("Only 'door' or 'window' fills are supported") + si_conversion = ifcopenshell.util.unit.calculate_unit_scale(self.model) + body = ifcopenshell.util.representation.get_context( + self.model, "Model", "Body", "MODEL_VIEW" + ) + representation_data = props.to_dict(si_conversion=si_conversion) + representation_data["context"] = body + door_representation = ifcopenshell.api.run( + f"geometry.add_{ty}_representation", self.model, **representation_data + ) + door = ifcopenshell.api.run( + "root.create_entity", self.model, ifc_class=f"ifc{ty}" + ) + door.OverallWidth = props.overall_width / si_conversion + door.OverallHeight = props.overall_height / si_conversion + ifcopenshell.api.run( + "geometry.assign_representation", + self.model, + product=door, + representation=door_representation, + ) + ifcopenshell.api.run( + "spatial.assign_container", + self.model, + relating_structure=self.storey, + products=[door], + ) + + r = [ + r + for r in wall.Representation.Representations + if r.RepresentationIdentifier == "Axis" + ] + if not r: + raise ValueError("Axis representation is needed") + r = r[0] + axis_geometry = ifcopenshell.geom.create_shape( + ifcopenshell.geom.settings( + DIMENSIONALITY=ifcopenshell.ifcopenshell_wrapper.CURVES_SURFACES_AND_SOLIDS, + USE_WORLD_COORDS=True, + ), + wall, + r, + ) + vs = np.array(axis_geometry.geometry.verts).reshape((-1, 3)) + es = np.array(axis_geometry.geometry.edges).reshape((-1, 2)) + A, B = vs[es[0]] + v = B - A + P = np.zeros(3) + P[0 : len(pt)] = pt + AP = P - A + AP_dot_v = np.dot(AP, v) + v_dot_v = np.dot(v, v) + t = AP_dot_v / v_dot_v * np.linalg.norm(v) / si_conversion + + opening = ifcopenshell.api.run( + "root.create_entity", + self.model, + ifc_class="IfcOpeningElement", + predefined_type="OPENING", + name="Opening", + ) + + position_3d = None + if self.model.schema == "IFC2X3": + position_3d = self.model.createIfcAxis2Placement2D( + self.model.createIfcCartesianPoint([0.0, 0.0, 0.0]) + ) + position_2d = self.model.createIfcAxis2Placement2D( + self.model.createIfcCartesianPoint([door.OverallWidth / 2.0, 0.0]) + ) + + opening.Representation = self.model.createIfcProductDefinitionShape( + Representations=[ + self.model.createIfcRepresentation( + body, + "Body", + "SweptSolid", + Items=[ + self.model.createIfcExtrudedAreaSolid( + self.model.createIfcRectangleProfileDef( + "AREA", + None, + position_2d, + door.OverallWidth, + 1.2 / si_conversion, + ), + position_3d, + self.model.createIfcDirection((0.0, 0.0, 1.0)), + door.OverallHeight, + ) + ], + ) + ] + ) + + ifcopenshell.api.run( + "void.add_opening", self.model, opening=opening, element=wall + ) + ifcopenshell.api.run( + "void.add_filling", self.model, opening=opening, element=door + ) + + z_offsets = { + 'door': 0, + 'window': 1 + } + opening.ObjectPlacement = self.model.createIfcLocalPlacement( + wall.ObjectPlacement, + self.model.createIfcAxis2Placement3D( + self.model.createIfcCartesianPoint((float(t), 0.0, z_offsets[ty] / si_conversion)) + ), + ) + + door.ObjectPlacement = self.model.createIfcLocalPlacement( + opening.ObjectPlacement, + self.model.createIfcAxis2Placement3D( + self.model.createIfcCartesianPoint((0.0, 0.0, 0.0)) + ), + ) + + return door + + def to_obj_file(self, fn): + st = ifcopenshell.geom.settings(USE_WORLD_COORDS=True, WELD_VERTICES=False) + it = ifcopenshell.geom.iterator(st, self.model, exclude=("IfcOpeningElement",)) + sr = ifcopenshell.geom.serializers.obj( + fn, fn + ".mtl", st, ifcopenshell.geom.serializer_settings() + ) + if it.initialize(): + for el in ifcopenshell.geom.consume_iterator(it): + sr.write(el) + sr.finalize() + + +if __name__ == "__main__": + m = Context() + w1 = m.create_2pt_wall((0.0, 0.0), (4.0, 0.0), 0.0, 3.0, 0.1, m.storey) + w2 = m.create_2pt_wall((1.0, 3.0), (1.0, 0.0), 0.0, 3.0, 0.1, m.storey) + m.create_fill('door', [2, 0.0], w1) + m.create_fill('window', [1, 1.5], w2) + m.model.write("out.ifc") + m.to_obj_file("out.obj") diff --git a/src/pyodide/demo-app/index.html b/src/pyodide/demo-app/index.html new file mode 100644 index 0000000000..555b83bb99 --- /dev/null +++ b/src/pyodide/demo-app/index.html @@ -0,0 +1,405 @@ + + + + + + + + + + +

    +
    +
      +
    • arrow_selector_tool
    • +
    • diagonal_line
    • +
    • door_open
    • +
    • window
    • +
    +
    +
    + +
    +
    Loading...
    +
    +
    +
    + + + + + + + + \ No newline at end of file diff --git a/src/pyodide/demo-app/propertygroups.py b/src/pyodide/demo-app/propertygroups.py new file mode 100644 index 0000000000..4ba73b8efb --- /dev/null +++ b/src/pyodide/demo-app/propertygroups.py @@ -0,0 +1,152 @@ +from dataclasses import dataclass, field + +# From: src\bonsai\bonsai\bim\module\model\prop.py +# Adapted to use dataclasses instead of bpy props + +@dataclass +class BIMWindowProperties: + non_si_units_props = ("is_editing", "window_type") + window_types = ( + ("SINGLE_PANEL", "SINGLE_PANEL", ""), + ("DOUBLE_PANEL_HORIZONTAL", "DOUBLE_PANEL_HORIZONTAL", ""), + ("DOUBLE_PANEL_VERTICAL", "DOUBLE_PANEL_VERTICAL", ""), + ("TRIPLE_PANEL_BOTTOM", "TRIPLE_PANEL_BOTTOM", ""), + ("TRIPLE_PANEL_TOP", "TRIPLE_PANEL_TOP", ""), + ("TRIPLE_PANEL_LEFT", "TRIPLE_PANEL_LEFT", ""), + ("TRIPLE_PANEL_RIGHT", "TRIPLE_PANEL_RIGHT", ""), + ("TRIPLE_PANEL_HORIZONTAL", "TRIPLE_PANEL_HORIZONTAL", ""), + ("TRIPLE_PANEL_VERTICAL", "TRIPLE_PANEL_VERTICAL", ""), + ) + + # number of panels and default mullion/transom values + window_types_panels = { + "SINGLE_PANEL": (1, ((0, 0 ), (0, 0 ))), + "DOUBLE_PANEL_HORIZONTAL": (2, ((0, 0 ), (0.45, 0 ))), + "DOUBLE_PANEL_VERTICAL": (2, ((0.3, 0 ), (0, 0 ))), + "TRIPLE_PANEL_BOTTOM": (3, ((0.3, 0 ), (0.45, 0 ))), + "TRIPLE_PANEL_TOP": (3, ((0.3, 0 ), (0.45, 0 ))), + "TRIPLE_PANEL_LEFT": (3, ((0.3, 0 ), (0.45, 0 ))), + "TRIPLE_PANEL_RIGHT": (3, ((0.3, 0 ), (0.45, 0 ))), + "TRIPLE_PANEL_HORIZONTAL": (3, ((0, 0 ), (0.3, 0.6))), + "TRIPLE_PANEL_VERTICAL": (3, ((0.2, 0.4), (0, 0 ))), + } + + is_editing: bool = False + window_type: str = "SINGLE_PANEL" + overall_height: float = 0.9 + overall_width: float = 0.6 + + # lining properties + lining_depth: float = 0.050 + lining_thickness: float = 0.050 + lining_offset: float = 0.050 + lining_to_panel_offset_x: float = 0.025 + lining_to_panel_offset_y: float = 0.025 + mullion_thickness: float = 0.050 + first_mullion_offset: float = 0.3 + second_mullion_offset: float = 0.45 + transom_thickness: float = 0.050 + first_transom_offset: float = 0.3 + second_transom_offset: float = 0.6 + + # panel properties + frame_depth: list = field(default_factory = lambda: [0.035] * 3) + frame_thickness: list = field(default_factory = lambda: [0.035] * 3) + + def to_dict(self, si_conversion=1.): + di = { + "partition_type": self.window_type, + "overall_height": self.overall_height / si_conversion, + "overall_width": self.overall_width / si_conversion, + "lining_properties": { + "LiningDepth": self.lining_depth / si_conversion, + "LiningThickness": self.lining_thickness / si_conversion, + "LiningOffset": self.lining_offset / si_conversion, + "LiningToPanelOffsetX": self.lining_to_panel_offset_x / si_conversion, + "LiningToPanelOffsetY": self.lining_to_panel_offset_y / si_conversion, + "MullionThickness": self.mullion_thickness / si_conversion, + "FirstMullionOffset": self.first_mullion_offset / si_conversion, + "SecondMullionOffset": self.second_mullion_offset / si_conversion, + "TransomThickness": self.transom_thickness / si_conversion, + "FirstTransomOffset": self.first_transom_offset / si_conversion, + "SecondTransomOffset": self.second_transom_offset / si_conversion, + }, + "panel_properties": [], + } + number_of_panels, panels_data = self.window_types_panels[self.window_type] + for panel_i in range(number_of_panels): + panel_data = { + "FrameDepth": self.frame_depth[panel_i] / si_conversion, + "FrameThickness": self.frame_thickness[panel_i] / si_conversion, + } + di["panel_properties"].append(panel_data) + return di + + +@dataclass +class BIMDoorProperties: + non_si_units_props = ("is_editing", "door_type", "panel_width_ratio") + door_types = ( + ("SINGLE_SWING_LEFT", "SINGLE_SWING_LEFT", ""), + ("SINGLE_SWING_RIGHT", "SINGLE_SWING_RIGHT", ""), + ("DOUBLE_SWING_LEFT", "DOUBLE_SWING_LEFT", ""), + ("DOUBLE_SWING_RIGHT", "DOUBLE_SWING_RIGHT", ""), + ("DOUBLE_DOOR_SINGLE_SWING", "DOUBLE_DOOR_SINGLE_SWING", ""), + ("SLIDING_TO_LEFT", "SLIDING_TO_LEFT", ""), + ("SLIDING_TO_RIGHT", "SLIDING_TO_RIGHT", ""), + ("DOUBLE_DOOR_SLIDING", "DOUBLE_DOOR_SLIDING", ""), + ) + + is_editing: bool = False + door_type: str = "SINGLE_SWING_LEFT" + overall_height: float = 2.0 + overall_width: float = 0.9 + + # lining properties + lining_depth: float = 0.050 + lining_thickness: float = 0.050 + lining_offset: float = 0.0 + lining_to_panel_offset_x: float = 0.025 + lining_to_panel_offset_y: float = 0.025 + transom_thickness: float = 0.000 + transom_offset: float = 1.525 + + casing_thickness: float = 0.075 + casing_depth: float = 0.005 + + threshold_thickness: float = 0.025 + threshold_depth: float = 0.1 + threshold_offset: float = 0.000 + + # panel properties + panel_depth: float = 0.035 + panel_width_ratio: float = 1.0 + frame_thickness: float = 0.035 + frame_depth: float = 0.035 + + def to_dict(self, si_conversion=1.): + return { + "operation_type": self.door_type, + "overall_height": self.overall_height / si_conversion, + "overall_width": self.overall_width / si_conversion, + "lining_properties": { + "LiningDepth": self.lining_depth / si_conversion, + "LiningThickness": self.lining_thickness / si_conversion, + "LiningOffset": self.lining_offset / si_conversion, + "LiningToPanelOffsetX": self.lining_to_panel_offset_x / si_conversion, + "LiningToPanelOffsetY": self.lining_to_panel_offset_y / si_conversion, + "TransomThickness": self.transom_thickness / si_conversion, + "TransomOffset": self.transom_offset / si_conversion, + "CasingThickness": self.casing_thickness / si_conversion, + "CasingDepth": self.casing_depth / si_conversion, + "ThresholdThickness": self.threshold_thickness / si_conversion, + "ThresholdDepth": self.threshold_depth / si_conversion, + "ThresholdOffset": self.threshold_offset / si_conversion, + }, + "panel_properties": { + "PanelDepth": self.panel_depth / si_conversion, + "PanelWidth": self.panel_width_ratio, + "FrameDepth": self.frame_depth / si_conversion, + "FrameThickness": self.frame_thickness / si_conversion, + }, + } diff --git a/src/pyodide/demo-app/style.css b/src/pyodide/demo-app/style.css new file mode 100644 index 0000000000..8746ab660e --- /dev/null +++ b/src/pyodide/demo-app/style.css @@ -0,0 +1,93 @@ +* { + padding: 0; + margin: 0; + box-sizing: border-box; +} + +body { + width: 100%; + height: 100vh; + + display: grid; + grid-template-columns: 80px 1fr; + grid-template-rows: 80px 1fr; + grid-template-areas: + "menu menu" + "toolbar main"; +} +.msg { + padding-top: 25vh; + text-align: center; +} +.msg { + display: none; +} +body.loading .msg { + display: block; +} +form { + display: inline-block; + padding: 1vw 5vw; + border: solid 1px #eee; + border-radius: 1vw; +} +form div { + margin-bottom: 3vw; +} +canvas { + display: block; +} +#status1 { + font-size: 150%; + font-weight: bold; +} +#branding { + position: absolute; + top: 16px; + right: 16px; + text-align: right; +} +input[type='button'] { + padding: 8px 64px; + margin-top: 3vw; +} +ul { + background: #fafafa; +} +ul, ul li { + padding: 0; + margin: 0; +} +ul li { + display: inline-block; + border: solid 1px #ccc; + cursor: pointer; + width: 64px; + height: 64px; + padding: 16px; + border-radius: 8px; + background: #eee; + font-size: 32px !important; + margin: 8px; +} +.tools li { + display: block; + float: left; +} +ul li:hover { + border-color: #aaa; + background: #ddd; +} +.menu { + grid-area: menu; +} +.toolbar { + grid-area: toolbar; +} +.toolbar li.active { + border-color: #888; + background: #ccc; +} +.main { + grid-area: main; +} \ No newline at end of file diff --git a/src/pyodide/demo-app/wheels b/src/pyodide/demo-app/wheels new file mode 160000 index 0000000000..33b437e5fd --- /dev/null +++ b/src/pyodide/demo-app/wheels @@ -0,0 +1 @@ +Subproject commit 33b437e5fd5425e606f34aff602c42034ff5e6dc From 6deb7121cc668e8cfd6ec75638d63902c876a3e8 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 12 Jan 2025 15:00:54 +0100 Subject: [PATCH 51/61] demo-app/CNAME --- src/pyodide/demo-app/CNAME | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/pyodide/demo-app/CNAME diff --git a/src/pyodide/demo-app/CNAME b/src/pyodide/demo-app/CNAME new file mode 100644 index 0000000000..17459c2a49 --- /dev/null +++ b/src/pyodide/demo-app/CNAME @@ -0,0 +1 @@ +wasm.ifcopenshell.org \ No newline at end of file From 6ff1d06938121ff36cf195d11cd2084fd7b1e3e6 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 12 Jan 2025 15:07:44 +0100 Subject: [PATCH 52/61] Create publish-pyodide-demo-app.yml --- .../workflows/publish-pyodide-demo-app.yml | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/workflows/publish-pyodide-demo-app.yml diff --git a/.github/workflows/publish-pyodide-demo-app.yml b/.github/workflows/publish-pyodide-demo-app.yml new file mode 100644 index 0000000000..8646a31720 --- /dev/null +++ b/.github/workflows/publish-pyodide-demo-app.yml @@ -0,0 +1,30 @@ +name: Deploy Pyodide Demo App to GitHub Pages + +on: + push: + paths: + - 'src/pyodide/**' + - '.github/workflows/publish-pyodide-demo-app.yml' + +jobs: + # Build job + build: + # Specify runner + build & upload the static files as an artifact + runs-on: ubuntu-latest + steps: + - name: Upload static files as artifact + id: deployment + uses: actions/upload-pages-artifact@v3 + with: + path: src/pyodide/demo-app/ + + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 From a696c7bbb5cbb8ef958e2abe6b1088cb3578267f Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 12 Jan 2025 15:10:59 +0100 Subject: [PATCH 53/61] Update publish-pyodide-demo-app.yml --- .github/workflows/publish-pyodide-demo-app.yml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish-pyodide-demo-app.yml b/.github/workflows/publish-pyodide-demo-app.yml index 8646a31720..6e7e0ce3e5 100644 --- a/.github/workflows/publish-pyodide-demo-app.yml +++ b/.github/workflows/publish-pyodide-demo-app.yml @@ -7,11 +7,22 @@ on: - '.github/workflows/publish-pyodide-demo-app.yml' jobs: - # Build job + activate: + runs-on: ubuntu-latest + if: | + github.repository == 'IfcOpenShell/IfcOpenShell' + steps: + - name: Set env + run: echo ok go + build: - # Specify runner + build & upload the static files as an artifact runs-on: ubuntu-latest steps: + - name: Checkout (recursive) + uses: actions/checkout@v3 + with: + submodules: recursive + fetch-depth: 0 - name: Upload static files as artifact id: deployment uses: actions/upload-pages-artifact@v3 From 590c6eed0a0dc04188c15bf1eb3319a756d92f3d Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 12 Jan 2025 15:12:44 +0100 Subject: [PATCH 54/61] Update publish-pyodide-demo-app.yml --- .github/workflows/publish-pyodide-demo-app.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/publish-pyodide-demo-app.yml b/.github/workflows/publish-pyodide-demo-app.yml index 6e7e0ce3e5..fdd5cbe81f 100644 --- a/.github/workflows/publish-pyodide-demo-app.yml +++ b/.github/workflows/publish-pyodide-demo-app.yml @@ -1,5 +1,9 @@ name: Deploy Pyodide Demo App to GitHub Pages +permissions: + id-token: write + pages: write + on: push: paths: @@ -16,6 +20,7 @@ jobs: run: echo ok go build: + needs: activate runs-on: ubuntu-latest steps: - name: Checkout (recursive) From 936984dd315865d7a7cf99359dc6731cb80e3d77 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 12 Jan 2025 15:16:57 +0100 Subject: [PATCH 55/61] Update publish-pyodide-demo-app.yml --- .github/workflows/publish-pyodide-demo-app.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish-pyodide-demo-app.yml b/.github/workflows/publish-pyodide-demo-app.yml index fdd5cbe81f..59fcf5c9f5 100644 --- a/.github/workflows/publish-pyodide-demo-app.yml +++ b/.github/workflows/publish-pyodide-demo-app.yml @@ -24,10 +24,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout (recursive) - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: recursive fetch-depth: 0 + - name: Setup Pages + uses: actions/configure-pages@v5 - name: Upload static files as artifact id: deployment uses: actions/upload-pages-artifact@v3 From 65ffbe081bd0331ee8ca6cd11074e9c9e09cb719 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 12 Jan 2025 15:40:51 +0100 Subject: [PATCH 56/61] Pyodide app readme --- src/pyodide/demo-app/README.md | 65 ++++++++++++++++++ .../demo-app/fzk_improved_accessibility.png | Bin 0 -> 46328 bytes .../fzk_improved_accessibility_bimvision.png | Bin 0 -> 225587 bytes src/pyodide/demo-app/polygonal_walls.png | Bin 0 -> 36652 bytes 4 files changed, 65 insertions(+) create mode 100644 src/pyodide/demo-app/README.md create mode 100644 src/pyodide/demo-app/fzk_improved_accessibility.png create mode 100644 src/pyodide/demo-app/fzk_improved_accessibility_bimvision.png create mode 100644 src/pyodide/demo-app/polygonal_walls.png diff --git a/src/pyodide/demo-app/README.md b/src/pyodide/demo-app/README.md new file mode 100644 index 0000000000..1b5681e04c --- /dev/null +++ b/src/pyodide/demo-app/README.md @@ -0,0 +1,65 @@ +# IfcOpenShell WASM + +Live version: http://wasm.ifcopenshell.org + +This is a technological preview of an IfcOpenShell WASM python module for use in [pyodide](https://pyodide.org/en/stable/). It uses [emscripten](https://emscripten.org/) to compile the C/C++ (of the python interpreter, IfcOpenShell and its dependencies respectively) into a WebAssembly (WASM) module. WebAssembly can be used in the browser or other JavaScript runtimes such as NodeJS. + +## Demo + +#### Draw polygonal walls and place door and windows by using the tool panel on the left + +![](polygonal_walls.png) + +#### Open existing .ifc models and improve accessibility by adding doors + +![](fzk_improved_accessibility.png) + +#### Save .ifc models and import in any compatible tool + +![](fzk_improved_accessibility_bimvision.png) + +## FAQ + +- *Is this some half-baked attempt to compete with Bonsai?* + + By all means no. And, actually, it's the same code under the hood, namely the IfcOpenShell API calls such as `root.create_entity`, `geometry.add_wall_representation` and `geometry.add_window_representation`. + +## Approach + +This approach of supporting IFC within the browser is rather heavy as it depends on a python interpreter loading the wasm-compiled monolithic IfcOpenShell wheel on demand. But nevertheless, we see this as the most powerful approach of enabling IfcOpenShell in the browser. + +Over time, Python code has surpassed C++ as the predominant language in IfcOpenShell and has become the defacto standard for the IfcOpenShell API. We wouldn't want browser-based usage to require duplicating this powerful set of APIs. + +Wrapping the full IfcOpenShell-python module results in a feature rich module, that makes for example, IFC validation, visualization, but also **authoring** a breeze because any pre-existing pure python module can be leveraged. + +## Technical usage + +### Pyodide proxy objects + +Allows direct usage of python objects in JavaScript code. + +```js +let ifcopenshell_geom = pyodide.pyimport('ifcopenshell.geom'); +let s = ifcopenshell_geom.settings(); +s.set('weld-vertices', false); +``` + +### Python code evaluation by Pyodide + +Allows running actual python code with the ability for JavaScript to easily reflect on global variables. + +```js +pyodide.runPython(` +from context import Context +import numpy as np +modelObject = Context()`); +``` + +### In-line python code using PyScript + +Allows running inline python code in HTML script tags + +## Limitations + +- Performance of loading and running code is not optimal. +- C++ exception handling in the IfcOpenShell dependencies seems to cause issues in WASM, because the OpenCASCADE failures do not inherit from `std::exception` diff --git a/src/pyodide/demo-app/fzk_improved_accessibility.png b/src/pyodide/demo-app/fzk_improved_accessibility.png new file mode 100644 index 0000000000000000000000000000000000000000..8179f532cd6f3f66a1c73f44d2e213b20362aba2 GIT binary patch literal 46328 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

    vI&* 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

    C;nh#&N8y1p*{nm~8d6lG&;ScxN0%s|KaJJId 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 bH2z0ANmrO6g|7!>qO(Y1T$=RUQknAK(Y8za literal 0 HcmV?d00001 diff --git a/src/pyodide/demo-app/fzk_improved_accessibility_bimvision.png b/src/pyodide/demo-app/fzk_improved_accessibility_bimvision.png new file mode 100644 index 0000000000000000000000000000000000000000..18335c853ee3b290ed9468edb03b17b50a72d35b GIT binary patch literal 225587 zcmcG$Wl&sQ(>4kO3Bf`LZb=|WaCb;T2<`-TcXyZIGQph*!9s9%26uNK++oleV30Gp z-|zYE_xW|IPSsfy!=A1^8}{0(yRW|bT0|--NaDO8dx3<6gd;8WMFj~7BM=D*mH#<9 z!m>ZzDUO7M9BL<|Tok{>IVS!Q9H$3<-%L-Y;H6s$1!GsG@4YyKfjmubl>zvP(mv z_)|U*b$+&Dsy#Hkm=d#``jOwr|DqfXBY>y`mvyXJu<=FkI$lJ}dj9^q_iL%IwR=1_ z&PB&s_RiM)0w+p2XOAP1|Co~=e9;}*(dg}9@_lan(nwBbWF|4ams$AeD5tsj^q25( z3uK&3=>^?0-*-+i2VoMepM+bi4zgg8;-$=tJ$pR_=z2eH;*Y9_9kOI`v4puyO{Xt= z-WpfU^g0vQROh}Le<}I;Tb}RRz3MKn=o;;^8mP!ERtTEi`))VwJSjs=>HIgJzfuya z8NHQh`5G0;o!u{TPZK95!J4j1$nMPi6P++&3*#vST*DJRt!l5rj(gR<0PQDvxqzmP zv-~Jpe=>);9)Mn68wZ+0-4&H~aIGD{XRpQ4)%D=^!fRYX?owMEh> zD(+xsXJ+q;B<^fx2|h@{Odlypl!`E-@0)8zkv3pVT~;j#qtrlXkM7p5{fk z(g)LDj`d5wiRk=I@*2->TGRRuOMLI?(rMxH>v~qbd7ei57M)Ug)##&U8?=DA6!+*% ze_6cxk$%)1Gd89`fd5~kX?;=K*Wca49pA1d-WJg19QF+5V`6{w@}7xwX$Wnm+X`x4 zb$fQL)j5)@*8_LGk7r4J@`L1(l?PlZCf4{di9cmT-temmHwSdG*yqj5j-%^M_m*={ zVN?`kW+E)y@Q}1L5?fyKFeB8X$=T5E4U(oVQX)BQ>}k9}D@|mAZtN_V>}Nqpg;rry zxvFGe_l>GFD>a#$t0lhtJGOtB+6v7X>I=LL5}1U(rSu#)**KX?WR{JgypV2i0FOaW zmd|f}bM4$)vhVMG%iEw!%2<8Ge63y0$*CM7jA5x_mgXMW(Y0Qxn%sPm{NbNmT7ccL z*{vFGF|zc6Hw&#_REqilmZTz7c-h(6p2Aed#>Np*QC-$`ub!hiwyZX;+W*SSi;Ru! z-Me(Uzj4Y^*z;mbjr>$Z-%(Scb~YB??|DY;fU&G%(ZjfO(qvAa7q9M{i19h-F13L|@sI}vw9Nf|qTR8UZW1{|Mf8uVWy zA#zurIbTkNo!^!Y-(-@rVZ|c(Tgv0Mi181J>pXUq@iA|2rH+$2zw+$*j`;wr_epXA z+l`Kn{?~&t{X$4cm|b61S?M@4#6HnPv$$t$Q}h^PY8w?5g>F}oo6^fUN#(ZmmEa6j zPVfO)xNz`eG%C!)mKHI)Rt^q(fPi}%(9;9t_5l*0C@G1dS}3_oRDaF zrXz50_{$fpj7uThdEVzPsL*U>=c4NOJAD-%H|0Gg5p89(yyhLpiVs_~)MmGLHCgy+A!#H{i=Z$Hb!4=iVq;mZvBL*w1`L6I0yTDD5acTZH+4QPR@BXZQM* zZK5w$0n!+cI#Q`5>GNVtwaUn~0tQVC=udNVU_UFFjheN_iH*31KWH)&p#*i@QX|`T z-IGfDazPR`&rHaO;<(+F{3~%wj2vf!Nk^pOx{WZ;AOV@7or@J{E0dF-jE w@_w| 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 z

    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°uJy-mfg3b`XFe@)2v=|(ppj>Na9FzWBIJ8~ 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�q3=i$pF~|9wC57b093CJ%fe4tpWtZnVkg>(E7e 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

    Q|IYX1}TKhXF`bG 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

    +>Y1ovW*MvxL$xkGkxmu0U#R&TwKhgE z<9FMN*Vbn~$aHw)qVs!*KRF6_DmqtliRZg?BKRkwlCUWhj+31Ae3FF4)#O9014LOc z_~^XmTP;H^RH20bM>}2|q5Yqig+(V$jUR%pJ)PE;zg3v7>Op_c?9#b;wAgA4*Z;ph z+Eb)2FR#3MiNZe0l)qo+two2iwatm#jbm>K8f~fuTx`y+#EgA<>cz(xjYSlKn*+xs zK2v>*;qQO!^;qlCXPrUR2fygFO_3R9+72>q^}yW7hw&Nmf#OFqh<<&KrH#A2CG3J< zYFQ*5P=4Lx>w|FBWQZSB>8EP2U##1v^aZ5I43(SSA7)HJdk0c>lcgAXi6&(*7h?t0 zX+%BxZFQxS?qk@|2*82Y>bYV2qiu((2h3^E>7}K_fQ>wcM0Mj+&gel*BDrKu;5Zh( z@sDG>6#^mpuacv5?5*PSaGHZ$e=gKaM4jLA7;(UFR*tM(uh*Ed%k9%wylo$k+dF>z zkv^%j-XJ(Ocb|JzFh&ntoAxpDL*O{MJP-gVak#SMx8ms|0I%`_wjjhLg)m z+pk;58*J!U7WYhNfM?OHSO>`Z+B55|&0MK=kli>%LiW+a8RrA&+^1_5=cMi@PIs^v zMlN~}CY*L2TlWmX@6# z34C1gSOJU3Z`=n3rtznUOo|*y6uBI0uZGC_Q`6QTxMzmV>9LaL278)G(zJ&Z) zuQC!MP-$djx1FNd|1&PQK^^VbRBU^w_3T&Bu5Rz6<7q-b_Pw#eRN8ff1#ZZadt7YF zB5E6K2}Jd)6aFaZr+)&(^mwOwDjlbX0B>me-`jc8chtERucvQ0-)g)wdU2+G&?;*4 zZ(UC1xU6xa!t39*^MTa~qyl^RaZ8b9MABd%cJGVk3%^ zW%zL*+IhsU2H)08aY+KVMgUVugT=i-054GRd{pOWSO8l_b^den6kSun^1b=)VN8B^+0fax5wM?z@;Y8I21h*YLY=ofJl?=YpD!16PTB%&~_30vWq-xW{&t|dmKfrntk zPln<%^=exoiP0HwiVbedqiW*gl*z4J*|`igBoLu*^U{<^E5*64rRbG@tpOPS)-&e| zxg)T9QQ!&u&p1a2{6NuWCtTm_;1tpq{%{uE&>+bBtSdO|snWeFD|A0a`&;`Dz7ktH zKo*`-n{zgXTy=kW$(`w5@cGvk18dNb$SznmHe2nr;Kc8~@!Bq&i0%8z@O&c~w{c^N zbl0+45=E5v4JB$ECC41RRJ56C*{$ z{6?&D18)C)dH-h{{@6{llQvvH@TmAfm7#+ssEBOBN`fg*rCTs`|uJp*l_!|FaPWHoMx0$^Y7rCX18&DGUPAY z$#kQLg{?OinI3|lQgv!_x`pV~dmK-u>eIGFv@uJ4_KsA)^s(FqBJ%ec?i~V7hGfsk z-`wUmY+g&A{Hj4ZX!o9u%=HYal;z{7yjgZM0SB@Fej?jL)|ne&#>dKJwmKGx+T0Bvu~GYDr4XjhyMp6J6Yz|Gy&BvjMO(8`cy@h(tUr0}&u2U1C>XOE9#9bUtkhJnICZJ39Uap1S4Uez zUoq|#3L3|2-S7szGoVh7daL&PZdfXCw>s$F7qwH!l6mH-G!(j9d?Z>S{z7qQr@+EK zHG@bRVSFuRYsf$NCI^&O5(H0S&5N{Zx4qFPKvIy+&*G|MzxtV+WzD}|9&B(}nA#-# zPQ*c3{tfQ2P!4!sAfY@_R&~N#zDvbdaadtg4ENVA#+$viRB{O#g!Z^Znu}Ejxq+Om zMLcb?*+;N^Bvp6vylz&pVutOH2xUv}`d6EYU$4|N$NkaNo;2DRv%M)tYN1M)t+;U7aZzt|%t8*@B?9;a|g$&achY$^~giQ_AMUqY@r$NcpM>Xj} z6Hg$O;G8~$Q)0IrUV}t(Wi3J?9~{I-iWl>l@Iyxy$ZDYD?~vmnFCf11c@&v5?tnU! z64&{nNifaLAED=|JU`=1aj%PkO~wdq+Lw+wLr;DcUTohhx4G?4EP28MbA@iPv{r3Z zpNzh$^^gr0Irk5IR=ZV-t{GXeJzeERKOztKdx%h*wXOrWdX8wed4_<;%Da>@3jabe zm7){~UYH%rn6y=CC(%lJcb!w1*@lCR&z@Q$Q9TimC!-GY07 zG?~RV-QthrCydi~@$8!g0R*Eu$}TzoF-<6vvF3tSa!8nSzA0_yOZg)9L(=pf0UIU@ z0GSR^Pe*ViF6zBanoJWm_l-^EnKi~QW$3*eGC2L_qRrXQxryXXtPD~iK>o8NXKPeG zCU|uKd`u%#j<21Z0?rJVz^V`S=tvf3UP)lw7(pQm2-%+eJ6N*SSaj=p4Cr+JKZnBu zeCm$&0CX)hJ{;gR%y7T80Q&QQ}yYru#lcO9_P&evWeM?gd$J&hauuqPphj&0{P zW&(GqnBD`m-~>78`;W-Phw~1D=Yfmn-p=`+sM5_v8$9TZItpZKIxh?n7xf&iqrky; zko;;a6FX82b_(99ItLL9MM!u~;HS4g)F3@-*Mjel*e!#)k-#gQE9Q)rp=zUL! z2heE#^G~`SHZZgvCx8BTd?1m(ZQJ%g6>P77)+2}MdvHO#CNWAW;`ED_{#5^Y-_o%D z@uiSjyu(8^+p#~->m5!dyRJ_Ppq;B8{Q{%5)()?m}+2|Ys`>k6t zsXuwxd>aZb${ECxOzm} z&~^*i7mEuU29MLNTBb&aBoUF<@7u$eE*W)dSacftWW8n^d@6J|P2`8d6AkTuVb}bF zFTuz;*tRL>X_!T&V(8zvsY^(hZsGjjMtLfY` z{BH%d+&4rLi-9(3?lj!#oab{axU|xGUZi}=j;G?Y2K^;xlgs@`0s&u2*0k1A zTe~huy8eEDc?{u*bLptHKZK;7M9Il)@s#-ONV4LW0e4L}Q z@bU4};l)EEw=Iy$Yw;g2Yn_O){r%5fj}20{aylK$8@Q(jgV?11dLH~&0cDTpXEmk? z1yxiL;Zc+tnsZkDxK|QePsJrZkQ$-Ypqb-|6O6D&mMc)pOGQCR)mpDrzG>}D`X5g_ z7)--5A7l4SSHAit4{70r%CQElnnw7ks$Czc99t=3X?K-;)XJ2PWa6b-5hRFwNR4AH zbno{tJCzH2MBH7y0wWQTc4t8cd5a|{jgLz$%Rsr03Q2YR=Vz3claHmLg)}7J@us3W zZ*8yh0W9kGkAyy1-8?ai=mDDew`gZ8NTG3LXWj~U>gvs$E2HfFA?8}h!Gt*SPr}UX zq}Sh5;5B<$Fb3w=TzOGklsQZVa{1|WbFR=WqeZ#9d%J1==`Z)^LLl{2eMkM>_hx^j zCt|qre^~%9+4W~xM%mx;xBgq1#H7Y(vuRFKr58s#?ScLm=DkU`@Tal6;Mkf7e8Q19 zcr;dzao%7h!)FEN3ce#wVDt6?oiSr#YwC)ApzNFM(8`g<$UH%^5T%DYHrJPwp~Tne z&AS7)0bVznkU{H#G{=UVf%$otQg#rT^`8oKQ(qE2oY?Ye1n_j}vb z!e0mP5lp`eNbQ*_+$Z2m)z9=p3I(qhsG$->LmB1;!E)qdIj+lNDCnGCBgl8YVEq!9 zH=pbI(D6c5+|ngKED~JOwo`6M7u0?J_f>96J<+Ja@jI{thF ztHMm)H9$MQD#AS_VdiP23wN8o7PgvY;nhlK>#~4UF^t8cK*9!SH@&Lp5X?PSgo~-| zf4PF7;M07H>X2rBZsykBJ5W+V4!#Ji<&pm**yO(u8xSV4;M+P;8SVPVi_R7dfzi#o zf_Gd0Oq8O0O^LQacUDK;C`|mnh!~rpDzP`M4(@}Unp;FEGV!XwHCY?+m&dV9=wU&A zKLZ1RulBTw{+l8ak^~e|)W(Aso}riy$KOH6r!SGit*?-(HqZHWz%Tf_q=j@#zuecP z0R_j>$TAx)QWaM*4UL}bF&?yORxee_BvcE6&fg`>qT8Lq&iUGv129*6AkmdP3VgyO z@Q`)DSUl}wff_(fJO@Gb!&JVAgb=bb1QVk%rm2};$i*lT%8{cka?SsyDD7OlYWJy* z7NpK*7JE=JIH5gZuEcR6H}&bJo^J=trTTH12g8(^hdPk0k^6F=5sj1g%KbH?O7r>8 zk7R7G65SS|vb%)$-XH8Gb%X;wHJ_KmiWfck#m(q{_vqf|wqXjNK9Y!0+;&g?4p;bFYnRlckDYXq5rC^W5ksWJ) z+px^qt~F~yS0zpnW6sy@p-eWGO7>&02`L?=Mv+tZ4h!}Dpv3ZPk{xI#o@J)rg)*?4 zz5HR3Q(NRMY$3yAy-`FGfrtFpLD;c`=6B9g6e*c`@?#J6B<>}O8eF3rH1=bG3Sj{u zEGO(XYEWu1wu;=hwdZUp{x52uXFa_A>D=rw-{BSav9&|DImV#0Zh-QLhPrhOIc)H8 zIi&QFuFUD8wgs5u7TrN!CK z-}a5mWk`iE<8p?|!~3S_TL6o+cC&jr7(L+gz|S_84LpC`?4e-0sl@PEzb}nvxPCaU z1K9o=913}{p0yvp|DAuq`kv>wm+^()Pk2vflj?*zHM= zXLV8b$ep_ZD#AM+BhzcNTvc4CbB$!clWEIaq9fEo#33hY%HL*a)kcXXwV*4-Q+`v6%SbNvrO3YXOi8(ys(#%tJb|NPUclPPtQ$s{ z$08CNT@zo!!X;tlNu7CJ&;9f%w)lxvq|EL6g{JkrZytu;xVkyZ)}BW#3JLfPS{=~ip6vp=b+3!J7qBVlNrmv{-tf&ASs*N zZbhhw1P?3a4wRwBG3U2}T?^U2gW#HQ{-RHx`xx8l7CGB=Uq2SBV^=Bkm>CT4Fdvaj z>eJ4+rNS~Vn$OVRQWw{mgt-~oaQj%MRhF_+;k}GT<)6w&{|QSg`OQ)994%2zcwpYk z_wQLly*8=k5G&^s#WgPGuNtz)V>Y%PzdyMQ`(tQ*#6!!;Wk2Sx*oq0y5BBKyt#{TB zTaxk_KLs;Irkn*u_nd}ZfSiGLmJ7E#NiE&?h3(&|j~Cw+m6VW$w_r(UM~<*F38^#Y zp-Ga;OXAIZR-7A?b-H&E$T@cLGFxT;tsxd(eJl4ei!29=JXh(yuk|HoZ21|c5i9qjmzBooT?NXPV?%i=?6tITTIYWQw;?E$KzmMmmHse#;n% z&g%PHLa38t9{+QbYoLIkgB%=kL{$Dyij2)Z3seaZG4*|ZI?_%xqE$Eb1Qatn`8I<@ z@Fb(n(V4sS-NL}lpA}eN7{jw_47s}jtF9Z9pV8o9#%crX%LO%)`Zb0i@h zybr3&hVfP%FMXVH+4#jFHKDW~SK_oh{V5^ff$9vhr|`#ck(`w=cm)6ggXjdYYeLL= zazc}dAjWU6frJBK=MEBx{GXXCFeg$1H$O)LD`RrwMG;X!gwiB+!ht0N+VDj%Er63o z(}R4Vu>6#B#D%!tVNh{ZW#(6SL5`gF1+xBY@n0-+qqpU46_~*(WMaUxjize6>eXb+ z9sK}4|I}dqgU&+w%<4xlQ*+a+(+|8KBT!U7?5jAvFDL|^A@my0<6*rU4GOGC!5DQb zj*`LWr^pFUhk{0)k+aB#xcEA1XWDp@W|cUb6MXy^Vi8{wW8yo@Y#uNQ9J) z`gsZTgS|6n{8Kg@k~FcCOH%W}on{`MPM*3HlcleBj~$-KL)q3TnXr2?$mVYzsj7gA zmiPOx!=AA7$2H&1DT&Rf0+2W78F0fJXmwQ$ujLP`8IptC!g6okO9!5-NQZ8^2SPWJ z`b2sj@*KBR<>2Ieh^d6Sixw$#vgRZSz~^MKCj5m*+r7`)O(ke|lON$pY3sF07qI<{ zqpGidxOV7(4=$)9W6!&BS&G^r2D}p@Ha!px+P2@*V9aA=HrgBd!r%Y)D1Q7e^a-^o zn);_t5WW&{lVq4VX}PoFh3f$cm7fP!X_fl7(I+`M!xnbA7qYtvb#AfbOuR*tcA&9e zhI}tWXBL<>;Kw5Ef>h{5lorlt60BWGYlow-Zoj9inIfaLm+jxxqejECL|E9~nKA`z z&2=%HMayzY zaEUL)06sphmtgZ%wu@no^Cf^9aI)@01UZ%P?gfc?C3>4!vg~D#N~oM;H~U(!J&d~+ z86t}ImnIs!(y8~oQJY@=yc)J00Ux^ktu-(i8`>P~`^x3|RrzV`Ri*`h;*@;Jw>s%5 zS3-v~tG(qCWwYEP#(mJ9&r;VW=2tsC+(j5(hR8lFaxX%c)J&ZZ|L1`Q-?zQIIN#%A z$}0lV{1=+bvkf}6BHz~przH2olmQCFRou$XIcxo|q#FFc-OlDb8Ib*5m4p4+^@YnD zGSmVMC)+I-+wI!w6Mf$CFCN#hloZ>kje67W%kWbG4j12_`nDLrUUqvwI5?ZJTlN6TWw=xQuSK2@hEMaVqDjCRNah&vqd5v&uhHynfX}@15%bvS^?eDyupkR z_Q+kAlIMGCPfsD0r`$nkgMCea($vY|HVuDY21h}BJlin&<<^rZn}$j8lgU^s@aM6_(SI+P(iT7tP@a8VvD zNr9SjssdIVm?urYBQiijbVIJzTqz#B+6!i~&tv6ms9J>~!4)U<&r{?`DChxux6O7s z5ah%L;Wbxcyk?ompZmaIe3PE7{m(dyuqgZ%$oVbVd~;iXBnZg&qFtb?Cv*6m3$Zxx zx>GXq-n7qV(i3bEHbJ%lDKOvyDYpTrB3XbbDWv8E{=ivY;wyOBR5*IUKE z<@0_c{vNDN#4QZr581z#J0F!J3WN`_ZT=GDyYmp>PkPn1B~;KKUmGeR3*UzP;-&FK z#mn@-WUHk2qtSt)1Pbe`Zdjjb!hgjhbnB!M+MEDMN`TzaWdWY%mlj=jN#IB^;NS7Z z?l@S|6;bA+w@rk*m!kFR^H4e_Pm!YCQA6U()H=Og`(i>+6`Og(nRy1m*EIqsl5eaO ztaA$`dfS|jv?}gzUC%FG3R)_uX}lY?6`o(%iP7QPQ%^6P`}c>rPFNj-pMj}ZvZ*6O zcGmKhmyhLzYoYJRxw>{E& zh6wrr+g1AE1k1pt08+!NWdp%Jfqr#E1bsN}hJ;DRyGe^Qe><)q%Q4E5L%s8ld&#;! z(E7!HftT$K0rH^W&xM z*HF>_nnt%_MNW7)He)(U_F&pnQq+;ND(%xbhCz5I)+fQ)zer`NyWG$sROUU2frSN3 zeoS9&hj@FXB;dK4wn@>lxbG@`oVtC@H=VQnKhO1m^ql z%8nojFhSYxP3&Dkt$iGrtYG4}7;m4*H;SFKJa@Z0MubuGPDRjB*9qt%{0yMqb6h4F zhY~p!#6l#Fi_ju&-*ldz6LtWLcH_F83je+$X(}^QX`1>}&J9EwQ-@ZZ% zTyBW|V$DXBDWpAr!`DAsHx@_Xj-LMW&@>E9yFb!S=isN ze%7%`_u1FcGI{=WvHC^Fq{3&{>2pONiILar9DezjrTI+S=$Ks-U2;{`E^-uv)(3f2 z1}e4oVtM8JalW$OvKvObh1*1sB4b1NL)r6^?03#bzWMRLh4$D0=bRsN|E!LSRvp|> zC|!?g7<_Q?!15N9(IrKB3wS^9yyyEeIJHVRkf6WRm3hxM%+pHvoLz}xy}{$s*B0@l!{i=TK0VDq zk(hacYi)ajc>!&rb}HdBTf06|+8%^BrCByl-X{P{xx1aZ@yW5Jp^1q6LLD$%L$IGr z3)iLy)WZm9ik6bbRe76R?}VElPTCfJ%xoS6voU`-#-^mvP5rBa<)WPpyn_~CxegS{ zMTv*s8N-IbJI6=!FrY*x?7bX499aTKFFz}Q41S6U zKTYAsJ!_{aox3^se#2qD$hkCz6_WLXzHm>D)BWcS_!zOuD8RD^T0rMt>4nkxBP*wF zh9MWtwcHP$Q6gpdVhckb*2!3ID|Y*)(_q>c0i7Pe+j_;4@5<%2xvVYry!O_28piq=Z!C12_-hdLw+va0fsFX(ZUI3`$T@?oT`8{Bu46Y&qrx&d41Gd%*G_0NHGQ9 z>Qs&vDqD!iV5Ki|7n$z0UBxmA?nZ#~Rb%FVgk;9z%%T(jk;I^8d!53``)8EWiOy)`~Mas@E*A4!ZWe&)8BCc&kX@~j?QK+qwH9p-_k`{Qn>Anjp>`! zw1YWw0wYIcCe?yM`jYP2QELLq<8MXlGVur-jDH>XsedmpLru|H1RpXtss$N(eIaoR zmD5{Q%b%yLY&Ej`|Ju6pc&OU6NEog7quT#qdA1qowIkm!$<8k! zPBs>utaPY}%}D~Hv<22P4x-e3{eDCIadXoLhh`)p#Jn8nW=pv+R$mCX2S?0%{J_+6 z&7fDLEW7pOKL|c|0YD|J=2IOQ7=r!PIPa_Q?XZ@Xmg;7B6xW*q-1yO-99rfA;P1uPinA)*`nHpXc z(AWUcvQtX@ty}9Zs>NmRleYMg<*Qnkg#BJVGV6n0tQ~(zho=kK9QdxoPTBV#` zwiv(ILeAFFEuoBX`v6W8E48!xeq;c@Sm1O{^vBH)r%7$gce1d1GzM;*eAJH=<&_l0 z(ca|l9ao*nwN1F&Uaxm5j{^?A5y++g=6Ri$K2Ix{FVM8nOxt_T|Vt_ zGp*Sap&xbQCqd;sOf9cn!;G&P0AK{~W+E_bwf95~a_5oc;x96|fm#jjBs zc-z`_Ki5#bgM1U68cl}}15h^rEm_{~?D~{W?#O1Tx_!IKz<6&rpK8NsoCG3Ufu6kQ zckkW1cb_@Ji#(>m!}I*jI{bX!7nBJ#YL_VOX5DX6@48N=h6BlDRC_vRI=oMK4;!!c zOwnXvo7w{3;|KZ+bE8Jz@lgC>E!B~?>s{vxdu1;}+V)cde%x0CP4^cK`M5Vv{1{(O zABWnWNUYD1Y*u9Ue&jkSrZZJYyKwe=q>1NLfvYvo)o88xTjj4sxI7!;Kg^f$7OM2A z6Ks)g=!?Q1`YKjW$K@ev?Sfl!RA&MR^Zesi-9V}#_^Vf5g!IUMoADv|#2@rNK2xh2 zcqKy)Brj0tjpw~s{lIzp zrtReq2w2{;d?q?|0&zO^l8K3loR~7;{8Y><7RkMeUI9dQl}n7W+g#9Xi_gX7ROYie zb)rihs7R{H9rTa^sPr2uJdP!6UiilC?ZDB$d+PtBg?)?d;7(WVr(}9=IIU}mC?ZUm z(iFqW3MG+*(QGwMAbH*E&$U&fxOGhMhF2Top?qNb8=BQL9NgCK%|`z?MmajZ$dR=z z>igQ&noE7G|5SrNvGFKV)_dQ-UrwIiSV>wX^j6*KJu_P2ffJ{tmmqH4XEqEHpH7(a zGXsNs%~~r(#J-g3BT4y^gFT!odT%i1soeCboXa=S zB@z01N;Y_X7HO}-xW(|7g4l2y#~JAc$aPlC(YisZe?qdAhx7r)3{7{P7+fjVip-E=ZQ%9*P z0oXVm22&YPV5D@VWy4%}fSaoVJR4neN1WjN7gA}8;n1p&{(H+JY0Ay)jknBCjOKNY z4eK3%y}k8~gn8 z8;c|O4Rhe+cdzf)icydsYsb7>!>O@Rnkl>GqS4tR`N9)I=mYL20qGJhVy{lA+Sxs| ziE%t~Gch+bM$={SwHM-L`k9ut@VUP)CBGZ(D0cxc?4-MH0A;Qr}23Qe+( z-4k_w+DyiGd1h#hMw*utJKES)q_Ve9)Hjo~Hz8kx)M!gDxc{Qcu1-UKcAY?y-6sOc z991x!9^%dI>!6SmO`$gLE+<|}&|35TxRfWVO0oN|LjO-7F$y$H>#u%IC)RO6g7w*^ zJ3;rj2W=k9JRs6mpe+D+$=u;C8PI9Sh7@ay6+Ez9VpO`U zsti43*!E7q#p5yO&T_W(whTuNlwMUr+{JIP9xvrfE_JOaU_;$Ft(pD{Nqb7|RR2Y^#7r`QbSaD1*3lXx$iwI7PeCCMB&KZEd zfatbIY{)W@Jy^>VZTDEj<1ueIbB6Kr?$4v54$Bcz^bTTZ!}!OKf8#v^;AmmLK`jiB zzFjpWj^c9ovRzshxpP8`19&FAN6d{PlM`bfXYIhXG>P$d4wqh$Zuw(2(U7~u@ctUj zJ<}iTep1GA=1Twm2pavnZ2Y4?9M?Ulqe;W6r3Q4V1uQMnKmcEH?YeD<-S@P5CBlT$ zk^NpdHtE$@_N-#?p!rX=$23>9VX9R#VH#(GJ{n-KX-4sZXo5XdynUeI)eTxjmuKbpkcD3ez!8Fl`$?*VJkFZw3 zq)+;bix1#4KkZ&QG)z5($xN8MTYQ`K4$2`n1o<4D^D`MAzfv^@N_AXQnIo{BO7^Lt ztliPrfP8G(x0(y`LL|(WZ7)%_k&If>U39e#Ml{ z>@mQp%5XXUs-5em98L`=3qoAId|qF|8w7v!BBp2JfIG!wgXDft3Xy1Dei959Sy5GVD4!&TelX6@#4%y2sb^%6<&Eic zvZ2y4(t%I0>0Lc8-zj;a-GUr{bnxSosPzJ@+yo`L$uL?tAwk#rVWdZCOlNk*hWkKZ z%)dmx|3n64#l|;sNOqL?Bc7NzPOp;&xjQngJ*Nz`rARK6`rY$A#95*xP_Y_#54qu0 z+_>RnAdNW0rQbx^f;{-r+de=Eiqt1qloa}rK_3!`F zz;#l+KO=j8&6sdc`7I+Uuj_df)05V+m#QXiCcfgsg?ES>{hDRoFB+j1>gT(Dp|wcI zwTw*Il+@cVlq3p&&QPDd-O5YiXdWSzBVb0$pO$GNsBx3JPWyh#{V3Yf!W6h>40-mY z&F4(%lm$(My1;;3{r4&f_;FQ^30%&L2UihaPI?&ill!MKf9Wf?)kyc`V>`1QWDOVL z1uBJzvV(|d<&Mhpo@mKn7;NK$EilIC@Rit1Iinxmrf+y=9($_#8jaRXnfHR7`7glx zN8;U$HvAmhQ;PYVLhZnqO-s*^HLg>(=HN->_v4^*?;V3{v@mj(xJAwYSu5Svsre4# zLL#QFDOFCCgR+m;aD2_Kb7Ve{w;nt3j^xY_9fXw-;!v;+cU&jNJ{_CPD9jD> z^(5wPd%)yA!$s^8Yv4#yP`kJoShfJa&;XA|;RE%oRFIRz4RkMMe)XPBG5qBWyi45} z>3_Du3zs6C9?XEF*q?>y7>(@!o(+!ewAU0_@Gs1X9h?)JQ3-Sj0h`2P9kAqavqQJ& zZ|5#eIe?ukmgwYUI#K*@{s$6c(>Q`5asKlw`C`9^Cs);ZT4IY zJ3o!4_-HIplC~h~yTaFF(#T6n$j4K%;{E0XylMQ_W?zb;HagruJln_CLgsBr)talD z0@b3^P?qir`nx$yIOyfmvi(+Tm$L0hIzLy}eR2l_-?2DD0*3TT@^x3n?s#nKt{hcm ziTVcUaC|K+NMn0Ozq<#mkf4e=#@jak&m7#v<{y(p@rySX{XerO(~BGOVh8(}sFS+p z(ccSdEY3~CSHpqYP>j-Cg?q7ud2Fa1$hv;<>491*1yJW%+=?J&0mt$xsHOIoz)LaoEwOL&|YR6;Y}~G*u_2UMJiq zc3;QjhNV@e%&8r7iks&Y<vgz)ZZs* zj}ScEh9PDrl|U~Cw!OvyN-VM|yb>_LW1Itk)nB84{AKTs2?l1QnN99kWWzZf&OGgp z!&mH#ywIodO={aJ%SqWDo9etyC2=)ISHj zHL>&9`gllh^=yYtuQXo2&qaS4P43>JRm+MNc|SPzC{$2Xyzf_*OUhOPYOB6Spw%c+ zK#^%{s4si@^S?jl{tIA#Km7{L3v?FH&;&UlEReU)aRK>s?*i|tpKZi6C$^d%d+byr zT!(ih1sH|ervboD7$CN7S#~YvM(c1 zBrD&~B|1#GRmIC6Y-R<^!aCsfZyJ5Q5v=Q{dtLk*ST1!F zVOr^n+>>B@y-&!b*(++uB{dr1pir9DDZ{Y%q7u6o;yA2(vh+RpU7qWDJRfpe=HCqQ zf1X_iI5!L5x2Oc6;e<$VX@LI?uzYfDReD$AU`SDa^B3GFW*W2+UivdFtk12m-RP0= qIUY8C0P0G{-2ywTH^ztXrkhoL_5N{Q~Bu>S+?CT*+$ literal 0 HcmV?d00001 diff --git a/src/pyodide/demo-app/polygonal_walls.png b/src/pyodide/demo-app/polygonal_walls.png new file mode 100644 index 0000000000000000000000000000000000000000..ba99e4e961c9000098ae9e1460081c8ecb41a3ea GIT binary patch literal 36652 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 Date: Sun, 12 Jan 2025 15:45:59 -0500 Subject: [PATCH 57/61] New furniture icon Chair icon for furniture --- src/bonsai/blenderbim_icons.blend | Bin 244674 -> 239364 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/bonsai/blenderbim_icons.blend b/src/bonsai/blenderbim_icons.blend index 40c4ab9809664ed905960059f1942a644afb274d..8d11a5ffdac214d4826126b767e1ddd049fc04f5 100644 GIT binary patch delta 203495 zcmV)jK%u|F_YQ>44u2@MFa2QjYZZV1N~O>tQ;?L^JPbX%R{-BBhOegc3i6qJI zM5Sr^y3}vm)^REMF8rQl83=+HV-}0`85irVM%BH(_*%29@%4InAGkqLKvOMpNd+*GmUvt8v z7(zNv3@u-OJbxC&cy-0-TJ^HlYnq0lXc&g0(a1E-aU3@d`OFHBG2UB!t3zIGmB$#P z`24nQ-}jwPr!-An*F{lO6h(|N#u#JFnvuDtX`bhGU00SRNs?Jjk8%1;p5nJ{3&Swy zT$W|2R9e^lln$1+F1Bl}PxO4(b)qPmrg;=a(=<)xq<>!#!*|yPjOTfprjaCxF+QD6 zCy_|H=KDM39lyNioY!^57++QObEA zpQdTf`K3~6UDtJ8zxV#WFAT%cXvA@x$z(DyF*yi=d+)vXRaL#`c_b3)qtWQZi4!p~ zFB5GK|w)zd3kwEOw3_mU`|d>4g&-8mzNg|!$J(hF2FFX z1Qx*15JL>Wum}vWscCI67DFsl)Lh^F^Wy}jn62gN73G%)3b#R2nT?AP@*LbLxdLR+> zRXup0SFupQWi((pS>u4Cd(2n$=o49C$cJVO{oTpeS_>hP!gC~bEZDq9~q3@!sjaR4S!ux>~K?_eG&lUw_wC(=@in19zDK!Py`WzvEXFls+?Kb5@U+ zWA!cuCO>lI$U|76$JH15MSlX4AOGM35WaQ5XS|P7wFVK_W6XeY%n~uy_ff%n(GKZ< zT+p7bC)W6F3Id$mf!!n&z)^i(>ow=ccobytaU3n=9OZLry&eM$dOXMrIKB?OJbz8K zX1~?F+p8-3ocC8f<+qL7I`Cf!-qd|2dri~EaWqZSb=@q>POp`ptIaKCWO#2UXnEH7 zS?9A7oOq5LISwO-(De@IqGv($^HeHz?GmrGUVl3L{4;vWj>j0M%%1@^Ifav5*Ilhv zCUXB1W8QV$IF6s$e&5%b#58@|wtpDomz9)zp0`@9+O}=mR%@-(r!(7Aedd+pIFtA9 zB!3dUtEw8J?ln!Tpn?isCixydFh4^O`VC-6v{l!a~zjt znfMdxUDGsC6upvtsZ`R@(K+GMIT9qi@EVG^;bsm*-1e3flzX1{zOPE9YJc0d#Q`zK z8Nc-+z3S$?I-PZ)f4yET9QSPtKTT7Y>6)f(+s1kS%JCn_foDsSqN8|1*8~FodH}(@ z6$9KvnOH&lI5;?O(W1pwD%Fe&^+Y4wJVpjQPxYABT1!yGlV#buWq)3lWj0@;CX2=D z>FKGdsrl>m(prb$_?MT=b=|gYUm)>28i23iwuv1l)-BP7)K~m-88`c@dV^*g_fsyvaoYFZCevs%DwRsAs{Z`^JSQgy zZJ{`h(=@GA`YGdcUFMnW>2zwfT5a31EE^LO6NVuOnx>gbrCit5TI-zii=!_ifqzkT7dELAEMsg!;5xO?R3nwFhdmStgKVOds3N9X3|Mx|20KtqwEFibqN zX9|S`zC$FtIfH?pEy(7lf>?LWc)!-H&bIKjZQQ{!y?KJD`+Xltl4V-voH>(s6cv|u zUDtJ;X@8+C*_cJX3Qo@!gv=yxe4Hh$b%!6p#@K_hT zqIQ}5XwaN$_Ytxu0kr15WFlqe9h>rZ>2ot8KYx?@-^>2zM|-%PCuFOEJ7VkLynpcP zolZO*-ZcAP+V#($dA=A%+7I-9aJiG{|GUSp|K==D&at!3y^QE@foOgO@?GXUG)BJ) z)vLSDkcO1HbVPNW7Hj{~+4%OL3vHel$JYng<)}xa9q@f8?G%6r4N(66rg*yv!~qww zbbpY{mwmqk7%|Bnq~Ug*zwcmn16%-d>kR>e;E#xtgqz!oO7B3^C(ZyMXR)*P@(oU| zZj7Tj117(p{`U_+dLA$a`=A88-n++^U;wzscl;ZLEPoZ9+md^J^ zKOf_tJ^<8n=>y{agX}f*S*d3xCFrP z0f{Hy`_F}==D>>gyN9BL3ey1`>&gD7H!cE>f)k6LxotFpr`luP!B*ZMd4HOCPhr;M zzo{oUO6F?{H+Le?0aS;ZbU#3RBoNgDi~|lP?7jo>jot-CR`&uI)(?CKuoZEYl_g+=;IN@T*KNRZGWMS7{AsQXbq@wK*uNBkllgQ6H0#kARC-v4Zj$!`T^Vk(d)PM`~Sc5{gL-} z!It+ z`bi;=>v7&kJu@C)nmRa7@VMXyfe3EE>)6@d*#>}2A9(8u>j0RSk#4Br&v4G#$P2EK zho<$qC)*v-ExS~X0eelz^~6c~al%D!pqwKZOF2EbJxB-)<-pg%%%@_*`}<5QD%azj?hRpkqe-UmR1G>~0?%~XMPh6&1RF3inST?}?f}gp5H~;oZsPyKz#o`o#{KF(z(L!8kBpLye9{AmAFaR-mx%*|iu$k5 z*B~Do#(y)>%zr1mpZs%R-Lg3wUM}!aJPX5JyI1}+3BD=*b6Mjq@EKu?9 zZov6Q`v7AmSur0{dmpCnq!`e0x73~qxyHSqV^F;io_`G}L50v6U}@%OpaT{@4x1mO z*52x_4xZ<|zwg?x~jKg&H4dJI& zL$@r30lZ;AkkE&edvOPJA~in>?)Cwp!^w;=ItSc7IS0Jtn}4hjJv-(>x_UXu3!#Tu zuMLI)tWGju9h057Z>?E;z`2nDKS;Y486c`V;D4Pu^Mi~3v=}dBHfvESJk5G!Kv6X- z+YNwSI5I#E)1Z}bK(`bQ0D5--=sYkHw*6qc!j6qOK%L-ZG7Se%3+v7!GU7gtiS>(c z5ce>-^OOzNRC!qc0JWKw9vLun9l*-^*5d;rT`{v6k;L9UeN4Mw2?Gz#%BLFa2N` z6ult;#++|T;IK?%=mJoYex?!lnWf2IkHJ<{hh$(@7K{LA9!7HNnj2J)*};J+%t6mx ztTRULW5WY;aX0+1z*U#cm=Io4o7k(_pno6|DP;;+0A2uH00I6E8!XeRv}P@mT=^56 zYCiu}Ds#0mV>BjKmL&9Jd=HM%GEnnH z&Q|Im&`R2mDg3txW>)mS;o&c70R~PDW1smft=dKvRJEA(Eg`&TzG>ua;Op&J#D548 zAj>^7W)y*@1PTN*juBNnM0oeeeh|%X?Qf5*^_W04YEF}LL|CA2=uK_D7s6fM>=fJt zTPy{KqQjM#H2m}qC^?$7OoN1(^l~%~ISDOJyp>G;0NE6&{HODGF#c_&KRL5WNU_(7 zoJ&SlP-kWe`}+WjmbObylu!oX2!A6(|Ld9p`7aWQ9~3_n-Q9LK4K!_3)4_pJO+S{_ z(i;E&e{|ZjmlH27Fdq*E0?i{jENX1Iv|Lb{yfN)NYOK96goHTbX!IW?3IV1pX$x#c zBLBA_5x@mGsX}GFa9DT!Kgj_%1VdyOcW7(xT!d7nE{sd&_X9Z+fpMtuEq_%MBq^lL z;ROmA1dY)H62PHAjc14;V~`>uBO($=AR;0XBuSb!1JuJjPgUyBmb8PApVGJD;3YDd z{@_3XTc_6~*_x2K0T~W7%!7#ZZ~^P$oy)FSm(ge=yKAW5xOx+Fs>i;iLH|v?oIgAF z+qAE%<*kpaKb3QU>|&!ISbsc^_GErJGhuCEbVqXbP2R$b8hOlNgMxwyJg1i%`Gya` zj~>mQTpoL}x3Icl74vSV!F&B-=`amq4K3(wcD~aGCTTbj8jG7zi|&+htx8xx{4}NG zVK8gA9z0Uy;rq03`2_W>+7k{uVIl5yN~_zlx5jdLRB~^#y45L4F@JxMGtEX*!OaK| z{|!vns{*fwmXM%;oohJtq~!kk$p6iJZkAKl6qk?0`0|^wtu)D(tucaS3KBj9u@5j- zd-O}MD{Pq;Wy6u3NN@Hb8Q(vT7{m;BgT2j?IUQ`geA}E&;8q!GVVBIHwKd*s3LgOY z??(6XO*Rp;(GTst(SP=9GmB0TXlo(|Ptr0Q6E>%M&^yobvCYetW0=_AVN)=0rdz># zr@n~QH@6_vl)WmnJb~Y@vv6!PI4=NHFidL(#0^kwT8nR;#b{N7Y_uC8rN%t{X*&W3 zEOvFdg}lI$=`EVWq~JhAv*eS>mpxRjZ7sA`aQ1Rn-08y>Sbv^H0d}TwB|H0DQ_#y! ztOlXKQv)>8LVc8ca%`G4^3V|VWlHwQl$T4wjFWhDuzOYcu~&?HAMwtwquau>Jw;}D z9sZgUwryQLySSkbwZOYhq*hBA?iYYDpDGg&y;!&JA_|#kdFbx0DoFV;0{Evo;YKy-E_2#oh7KcXiJtZ*}*Q+|MDN>^-pl?kMseTEMjF} zNUXJRn~ZtWAcQT#?E$aNq^J4`G={T(xeB`Yw>t&W0NVi90H*&49)|Z}crAvZryYMu z$rSHrCLZm1QR~x&7d(v_Wi_88X&Pov5R2G6k@*xe z3N!JN@k8ZOtzP$j;Jj*_hXM+9Vj$;2jnw(PVD&6e8<(vyh0m(x;fMO; z*447B3PC;`KzKcHC91c~hU;pUdY56gc%vqXt%>uwajAD{V|d#UpXQMH6ZBue3lP~X z1b^o}HA!CYMQ!7d%;FH3$GpoOD4~3UcjJ@HcT_BbJA*l$?TyKe3SodvhYf-)rOP3< z0q|*hw$uXfDy@sfvN=+Tmx;`!d1s|~ttjT0E%gphfEV_EgaL<%=J0M11@3;lW3XCy zyLok`hgVW(8Q#{0Q{o-BCM_02^3E)nH-9Fv%!*o{Bb)3?*jCW~g zCLW7MH`=6%UMC9LQfqO=TBS;r8*54xu@Hu-Ke0(>Dwl$@=d~ETF&l~*g$;?iobsI; z3q@I@q@dh(SQZEptm~>~I<0jYoKA9be5cb22GM_S^&;m&UDwlT2F^lwf4214pnr5} zN|G8Anw&PxE1FT&)Xa6bwaiB*Yhp04%hHJs*|ENWYhQduS5taD5 zu4$Ik2sKKt>{2T=Q`%ZT94XD|QhyA)RQ9DaHN|rKpTLqvH8cpMDV@hNB?8SBr1Zap z=6cQ}qBn+DcGlo}QiS+V61tu1_u+bE$bO>#;ecVp&9hNC4uo!~GmBk`hGt|W1xeBv zLl?l17)TTmrcyIL6F`E(1Ou!f3W8t=Ll6dG7>q&?L?Hsg2r&i`qM(Ar2Y+w^L%coB zVwN!A4Gg0#+y_9q>K}Mp;}4BzNH6~_VK65rQH)xFleCByEqMEY3pKd}p(kPKVvjx)-Q(7#8-)Tr0u3<+2wQuOVy(ck6 z9LMLloi0x3^l`8=+yA6EIe!+=J#A8mdhd@pf(f8L!hYAJc#~&+Xx>5mbCUQEEXF9l zds0&%_CKJ7*=0F8GI?m6v~7s@(c%izko3tY?DimV(z%onfXk$hwDTb{Z)ctMp=_;= zWk2XU5IIJbC*$%A4BJ)PreMUSwQ96de!?GfJ(gTmyzimnC8)DO0)N6ujq`P-W*3cblx>vU~9e1rfPlSF*i=T zmfy4%+<)fuMLF4)SkYI^e;-}3*6T1Tm~%YQJ*+sIqGxpMQ}-Pu>(rFA$iZ{l+jA1o z=Rn#nn~ZM^S+;G`*ni1S!`+J;9}>5x4bDvQ{17X#5_t&Pk~<;I2*WS#61u~DQaLOG zwxtf{a2A7$nM~iB#-w@Re)d6>!&b$&%6PK~&>*(v1f6`4sQ>fDq_-Gw_#d-^`ZkRf z#h8I`Z!$qH|N&0puZ;?1*W@_s}Pm;W}$Q|#LF@ZPF{&V}BnH|NEtsW+6Dvk?xTY50l zoIJa@*V@!naDU5BW80SK$=8;9FKnijc`Dp-O|K)-)2n!gnAD@K)WC~%7fK~wbi>Nz z6l0ao<|?}^n{P;^`pi;HQ|W9&a0Yr6{z;;!@2*V6aZ8p1X3RYv8o=Y`fSeM_X}syS za$<~oR36#fb{a&kXcp(XV<1U?htIThXFIwUi9XXq?q(`{h#f?`8*QGuO`FzyX4mH33aqDnnQ`tKhlxjdRGoM z5%AJG0~PHZHCz*96Bg>u&U2EG09_9Ij?S_BK-xsf-vG_RAXd`uv5hfQAm@_=*shel6d?4IF+P z|Gv<$L)aGCGi^p$1jkfR9J!(FV%$K?IP2hJVW=<%VG=CakLM43PxdF-cKJ$$j+{$4c-L!|w z3d(lR#Ga9HaGhY>N>oSb%l}z83>vTjqsV$oDNIY4phj@g6Y?L{9C`#6M%-; zI9u75{d!tpxMJu$E|qrPI|Mt!ZwC*^KhYDE&3GCZ{uOe;!QXl^;+|bUS_kvj4ZssnO)* z55c)L0K?LGu3cyJ)?38cW&~vHNKcpgEPv%lDVOokH{`J?{ogs)U7aG05th3&&6D{+ zC=7Yg-Q9MwX80@U_4xL_V`-U8$V0@uQ~RC-+M{EQZ?WtvbsWXCj0*inQ$@rs4FV?K zZD~a$CYmG3_tA;@hzv!0M#-)?fEr`#C-#|5CA|)hRi14FOf%6Zon>>lcG$U9?|*)6 zHBv7R(hgWblokJ=G$e0l4-T@sM(zEH(7{||JT#Pt;4QXy_y-E=03pgGx*#|BO_^!% znP8Cjl>-9_wBE!1M7cipA9LJORXa_5hbpsYPzqBcE{s)g^(a>E;6x4GTl27F<~LDM zj8^1}1-5?rNr)Rdx8^PyGbiC01AkFkI$rqPvNeRv!O*caDVxEJC3&Fee0@ek9Ow_f zi_+;Mn(ap^x8WJ-+CUS6cSe0-&Gg8XdmLE+X5j5>UcYv4Ok0?0&wdZua}MVZOPX17 zK;bP2ATWBzInHeCNRC=OF`)7!v!sRWno&pC$+`8+NVXYFv(CAAW+1`HLVtfTZr#UX zBq5H;vlE=&3ew-9i8nG2)~wWgAgCj74hh?@@Xu`F;Z-I{?X{cQGiQ+7wPQ~R`57hP-h4WY zdFXaqZDV%-hmEKSz~S4rHC8p#VM0+Rd}@bnYIsp&Z(|J+j_1HERq7y3H{_#F&3mF} zejIk;Ef~jQ*4c)5)YM~f+yeK&76Z3Xi9OK>k^$!fvL%g5 zUJe!6Foz2Hp71~vP=7pl(A=5lcytDrB<)}bfozMX@8#vb6UE0gco~`E4s3A;&MCiV zo%eO7;Qk^W$4URJt|Gco(0A2L--+oy24qy^&n>tSoPUOjB9OhKuu)DW@F6Y)v-gbO2vrMf1%CU0Ru9P*rO!?bDG^h2BK z*B6=+(I6p{p?@G^kkIR(pDrC#Rwhk(% z4`>>}!04at6v8JzAMm&2loV8g0t`M$GLew{InSodoqu`8%qwi1Gi9g)#Q_lt9le-v zRiw{*jcifpO;W8P{#KS?Xh`TNpHpy&6Q?K>$p-I_Xa4OWV+8b9_edKAJzi%UD^NMv zlhla?{q*ri5`2B4L94ugL$*;qr{M31u(#wx67K3c9bSGae;37Kama6j^7(>4KgKvr z{Ie2zPJdB|K3=;SX2kj836m(NV6gWjX{SpnVq$>gXlEKpIy&Ou=!h7?0wgI1Ap{(5 zdVoGCpHhz$2srYBpUvO<*%XUK6#ki#6R;Q6W0KTc@c&kd#z3!YvVo zAMkoc5zhK@i=T&1RXJvRlw-EX3YA7|k6#^TvVYQZS*VcDm2j1>8zmPxC(tQyErc0q z!i&Mn1vf8jQL$|iVGwTdc(yOckPY8v`i{Tg1e~RD}Mxo-IO`R)`iYTgZE8xzdIg~th!q)0M@S_q>mQR*aQKnpr5~k*d4RJgGD7F>ed7cdIIDUDu z+(E|HL6#6wcY>!|9}7g z|NsC0|9^L9XZz0n?#y;)XLsM-clUjF-`#z8-`)M)ap&5#|NsC0|Nq&Jj@ykkyWMWL zZzVZi?qx~dZns;lR;zuj_P5*Z|J$v08@3XOnWxZJLlv93GfyNJ9Ps5o zHQo>9V{(dG;v}gz(D##?Vv5u4yEpv4@XKYj-mzLZ(B+a#vkWNJG1MpElBEcudOaYMb8I^B;*82-BS4HK zU@t^anS#>;-s=H(y(J$Ku(!0NX@fB*3%nwf$LdT4LWrS|2((S+&OEs;aDQVXy>zO| zF*;RW(r`G`(1H|c!igbj{17#Kbc8-SD4b5j0T%B~8^%Ewqy5~%N%DMKyl6_*wDjY6teO!YOY z?>_b2iXy}Uy73^c*m|?@Sbu%6KMT4UDwg^lp~FfNCWrLuh7@Yg8Y=t-V*u|3LxoUl z7l>fdti1SfO-M7aRV*M@v<;$uy)PS^qrM;JjNywVjQU=U_5BB{r@mGN)EBGPSE{~P zLiIJGzRz}7jF`Eg@P_E}^!rzWB~GYGKM^Jagqp?xXiVAQNTpnKWq$-gdE5XTFuDrzR#Q@fO?W@7=Apt27%x;^sIX93p+a+N949{@ z!u){X5@xxnV&J?P19DW+;DE6v&6W-v6fqK7Kscfih89$5*dPN2H?}K4>N;Rj>YA_D z0ec;=g>G=ke7=)A0zr0 z16^9s&48szmf!FKc5)U zljNHRD*jIrDG&Xkj3LPldc699q&g@VO^I2aBN&odYTAq)Z`2myjX5Qh*#2tm*&WhiaZ0T+kI zEl&T-j(r)@rmAd))sDKx#@P0NVlWR5Rt$ih5^<9tnAxD(Gh)YjTGl%r z{_W-(@p;b(j(-S``~A;H>V9o5FU%nYRa>W=-`^S*$^sdwurqr;I~3=A$U{&as+0(@N*|HjM1~I-o7SK}hPGI_bH;C(Y2AZI+Nkj0|x@m^)<5 zjwgU&bWZk#nO%%o)Q;*lX0}N_F!no>?g&qwK{^p-L`eFWp#ifE51%jAFCIL}~j z2joYuv6;3${vr^)N^5JinWnJau=- zN%IrKEeCuMZIj=Z$y(QF^dz`+QbYminG>{=#($xhSXo^tOC&#mLzo!ZCL>#Hp3mGKmmFit#CJZsPg8OPrqIZL$a*AC1+qD(=QKa@f*3S(p0Z!+a~thN&Mu&*P53Z8_`AvmNHPmaHQ+>@c3)Cl2$GvKXfOnBn_h z_YI~p({lcS89SWJiq68z7`|17ugRh)J;B@C^oUFX#>8ZtqJ{u3qJuKF6@T~t^AD*= zPvCED+?$Qq(%j8~?BKeToHoO9x*^wdzXknkDiGOsFd4oBQ0ZF$5B)b`UXBua%-JV- z&afe95EzM<%x77ITT4~ROU!d)3V zdKQPrBS?d3IT-6D68;U{!heIyVw{uPC21Rw3B`lYdGYCm$sbimOe4(T0VkoG;tZ^o z2Vgwo8V()fVHCgT5ob)BaG>FpF-a4!!PDIm7>K0Rxav>@?!IGCJ}+(nXMk!vs#vm8 z+aJU_Gb_q9&-2?_b&oR|_mF{_wK~LO%8PnG@GKfpXDx&i2pz}P8h;xaGAd3DDsz2` z!vW-RG0Zo0{C6^Dl8iF;8qw^D1_LXMb)e=ue&(ZX_e>(ri`+A_@i$&d5 z;}PxV$Q-DDJo_&;(I8it(s9J|ru@;E{+OK%F9Jq!drIF_=!G_4%t1V_(UeN)$CFzS z-wdBkzG)0V=qQ*a+kdo>%e~?O`w2{L`D2pW0}Dx7^fwK1>QFFRRJ)SW+(;oN2_+OZ zUqKtxmr-Mm1B1;aXx^@N-yqYKGjY{>x%7sv$s&CLOrttC2H=>^J6-O>7Ko8MWqbu= zKpX0dwmA{$+Kj3wL{|^!{?>NB$v2HLvz`JUS!Eb_jzL556o2DcVsSi{+gxV)yI_PYx!1 zA=sN-SmE8FoIM{t*B*Ilq#nkybkLp2HF(zd(-g|9#s*|F18&1xVHv!bF31aaE) zMXj|sV*vKC(sD!3)S}0(JlriOYpE%b!^t6IHE091X9>7ABxe^w z#;wkoZ}im|{q^jFc|Cbu*Vni)Y%%2o+>kiOExt57Impo^$GzD`#%#U=?796|?k>d+ z{eL(3w^5L#rs(Wa{P0qA{wZvFNj=_O(DUjd@rCuqf_hRrH09@ z`8D#YwB{}tp7S~i-wX?k9>_8=uyKy~ZSwGq7G zDBTyupuabiI&*;Rle#gCpDg5Do_b5m(D%3VaGm^%mFWmIqaRJ_u)`7rc&}Rk41d>+ z%q>r!I!>#P05!~M^j#q9vuOTo9v5I?X)uz=_4ikWJLBb83BvX}GcnA(A;p06Tm!Cb zcSG$Q%A4CZ8LbE8Iw@HWU)I@IGCVd-z}DPd%2E~vh~YV}qtWfKa9SYCWSIKNJqA>I z^0Ih%5{`q*BWUb~7YNie$z#R!8GmE#CmBJodqY%4?5l*I2=0d9Vd%_;6Fc3w-m`Vp zE%viH%~#F~ll73ams_9*>tEfaSzPNT&5PL66+rrB(w2Dfc7Fr(khwj6H|?_B;m;F3 zoyVXVPA!=-FBJh=vn?~DGv8ESW^G4uw>T=HY)c3b)k084;q|qA)w%F4hkx&_l$)+- zgFe^0cQiq-1lXF2D@%6>B54&jBW|Xz#TkZ-9-L*0Jrt_`4~7HG0hCl!m>_4 zb37!oj?!|&!)YZHia|rB?nz;OQBUx@B0~ZZ(1*azx!sR@7as+}wBGsMfX1})O=BwA zDf(ntdVP_Nw{uLS5zc&Ytbev?P!kIqWY6hrjk!n}VC&9dwNlV^s49G9JfJ6 zxzSwk_y9DEwA!TwnVCP}^1d$fGtXjJwJlrXY{Fs69xL0gna=DUa5D$-H8R}L8*WWc zpdpheEgjgfa&1iuqakQROwS~4gJM>zZhteGX#+e*yJYa_;RXQ-^?#M?CdspW7Jhtr zv9Ar(8zW&%`=P9q3qRX}H{8QI!95hW2+A11CJi=ONiefP$DSQNbk)RWy0&{zMJ#YA z0TY&XUY|WT8!F)d`1AREWXd`5x(8tT2WzK7qqCYX=>9XM^Xh<~$bX_LY_7QybpDf$r?P7ayYj<|?+#I$I%i||)KHDRO2A}eFp z?6?=g1J8v0c^kGK0h=09vF>{V*|0CN0mBn@BU-D&V$bf1$nbi66vsdEs*59cz5KR`tWe8b5B*WD1uAdIXCEY%y8mO~z%Y#ABlW}lm(&eISthVh6!)siHZ1&(tFrnh;Y#59FYUU8u;LO%*!V;6+djR(~Uf`7s!$*02F69dfz(}e#(_Lf7U zcA;J@n0lnjYD=ps3rj1@OYW(7a~DUtd7>ATgt8onP?iHRWg#p-CIIq(Mw#?e?cFd@ zeyZKmBS0t(2q0X~S;mEBZO?u15s@6q|K36}2m$$byI-i!e;V@+KKXiTgt0AkwD(Tm zJeqPlHh((j7dtj)=T42v%=e{qyPflj4Nepr8yuf+K2k5eo;B1J8=U{W-W401 zp4X8H15Hf9;v2Ry5X0;14qK!;T&cc8e`lIeD}TCp0CmL%NB1KYAY_{6PtXs=#s;S+ z|5HY0Jfr_w|Ju|=U9rKDI-3afxX;V`|%BDBwBJJNhss$K)dPN~U)KbXd z2OvwPKIkD}qllV4M=E?gBYplHWBw=`II!w*fHXsy^oIhA0z(k=YpW;w=%OP?8c*(N ze}Ay>z`=`YfgL^hSEJ>NF0HrrH8`gHpCh(6QWY&(_8IjMdf|r{5v1V!0H;R84#hP* zrs${<$=FOqp(E%$9#eFrh-7ToM4=<-1q+hgUJofSMFCOfO=~9Qq`H9J4m4{6^!>rNXTpJ00E#z@jFqAT!yC2$u zU#~x}#c!f`A!PKTosm#JK&S*&7+ETgiUJ=DzBcKv(aQ7?XGiRf*P^>NP;{yQM1LBR zQ9#kpYjXl5O;k(907G2jj-pUFJg)ZXo;D1qt!4_nA@N^lV)YXLtPw-5We1U0gUi+$4)1(`Y z!;eD&CCnAH3+4*ig%->*F8n%7tJFUnWZfJ&4QXhbIUMclINDNveyT9((Q?esmor&d z!s5Qhj|<22RBJQ$9PQnalG@K}GY`{?k#nwafbZHjMh@w^%o(QZEoE5TUVlFs2v0Ls z^ON&ua>iWe^#*L`^%fyo*YeKmDCK!AJaJyHP{WvO-+5j$VCLk3=Da>2h4Wf&zP>?u zy@KlJx(t`L>m=uOmGgQ_0$9$no^sMfp@% zO5i97tLv+x>rjPJs1yaX8GqqF??(_IC&;*+p({jZAjtu^#rS{1uOZlb`R6}xZGHSu z3V?_JtG;Vd4f>c%h$A95gO8Iy=75}@;z|s{UqSZmdOAl?8uHg`jem`74_^ppRtEg% zy<#!js>mihQZY|J9I z%sGUd&s^&cjVu}mS0?UzM7Od~B34sQAMmP{@PFPBg<~~_QB`PM+peawiy2iOF`?Uq z3Ry4qW%8LV{g#^*B7apJ=@zu9vshu&%gBnYUku1vfKo?0;2;Z&5s&kYWEMBy?$2V4 zNE=El#Q#Zt{bTR_wHntTT%_uEWP$lgT+G6tK?~dp8GN=HXBDOQf&|IE(eQ0>cAQ(X zE!)MyEZ9=2!IQgW0TW~Oh#Flsc8dzgRMv{SYt7{e8r2v!vVU^|NiwdMNYo0hZR-YS zDCY~_zJB&IJO6oVyS}rGPYD~_dnv(xA~kMTVGJp}7$*~rVSa0M=H#MM))GN@9qVGuNAr_duBblkkSR#GT*g&k9!}ycWmw zKZLBs=k^rEU^F(e>M?AM-xciV*lDFi;z%c^wtq*M6*h1tWWa|*w{6v-kf)uF|GWUC zRBI-Y7a51G@e}#Sr5g&@piu=As_0BXQtD0bK1K}2suOqumr(xm+7(8LF!JpRJA*92*uDQmtXlj@WgT%q3+n+Vz8`4+cldQ@ zdw(yJimy9_jp`etK7dI1JKd(+_FfwKPXxEF8-t}i+>oyG?7hcY*Nv&19;mWPGRH|C zLi==^sDZmL29$8V;$fU+x<-oi#a+J{xaaB3~R&3%qc$ zvS90bbkiGaHQv10J=_*XTQ+E1k6uRE27lN89#W+6SiRI@U}WNS&Cevh&EDE69Xtp@;|Xb*JubV>CEWN{6FqJcV$5`0p9hs3jZNg zBKhxrKT(gNB}Wb|Ir5KDR2h;0b<@KO>l6=0RNUP7r{+Ls?@B|P_p|vC)6t$P`hO8V zB|K@6-vCo(=lw|LkP&N&NTX(GqY_~N$x$@4(GBvSWHHHQt?W#0?xW;`bfS@mj5ylA z*1G}F%s+J8%;FZh(2f_Unf{*$n#Ce*I2V|!qF}CyULn~VF0L^w2BTLuKmg2&JK;|7b_^2Y2%nLe4loB( z;y)4F9$_QW5=%}=V^*+6l^CnXB4i>oz59yBuNuQB4@ki&m>U9HyU>}08zAMJ1B^@pX-}tY zzHzLgM0hRkpv=RC#EV+gVeWt7ZR>bUqr-U!I|7Ex;hcF|Cy1?I=z3I%Fb=*Q%#2)# zbYCwNPpZRG)(tWaXj1+)yCv}eF-TfqZN*}EUEkpyenv5PnxM7cI8zkPaCgpQ_H8(6Yli=Nu&{He#X|+oExBeOZ5@k)4yqIg_uP zxI&c(%aPlj##&Y-#!1$&R>3#;Ph@=8W1A8VR{(xOY{N{$+moa(*^q6Q4WA*5f}|y% z;rgO$P(8w^ab4daTMcmD@Fp<&PxP*FtOjAU3kk#V$zUdS8!J0Rhb~HtkE@U^jbSP5 z%5~c=8e}(UPLkfj$Toi%bkW$jvRy@WhGZKcn2`;nJr-3MU01MmeWO%E)~Ip9|F6wT z;t4q~FuVrc_lU-@dt7^3oQcb&DXKD@YRJ4)qgq7MD8Y~#X&7=jJO&?{vl2-zj&2Zk z*LRI!H}aXM-A@e0>l?%9T4ZAv*4QY8l!QV3Co-yPZIWs&aP5E2!+EIlpGYmfuG(zo z4eMRmAuDu?YF{CY#sdF&0lG>5yr~_2ig)MONehCHnN~)_5NR`-r(Tb!2zv6-A0c0o z=QL&V;DK75Wsj*h>IWqVN5o+x3g>e=oWXP2?IAnIn z|I9lHzmjz~y48J%=8+Jk=#3NruCsKmgfg8xvEbtQcH(qu%& zN*+mVoQzKSYb_$oTW6BcC`=h?Y;138z}H3zsc$Q_wC$#?E2OEXKFxWnjwm`m$%yK>t!) zx9NZ3|D})uJkw|YUF^N&(sGKKUw#vc3%%ZjDI~W@(WZ=iskb(CeyKMydIA8AqD*Y+C|<)`Y39y=MGW!LnZP(nD5HYO|n7&`D6Wje!1%46Gme9tzyiF|BwJkCi! z$16vlA3CldH|b`%A7dP&OpQoO%HwgVcz%Cr*Q8T39Xh(ql`%*$xiZ)ojJv>=}z)aiaQrvfX9y}QG#6Ni?iC=lF8%o z{ny|~d;pnH0xB^BD*6pGAl?axgb&az1*DU;dDGlo^FdN$1qC%PctB(VHDqmidKG`r z!0WSj5H4bK*2q5;5W_oCEVL~YSxehb%BZo>!3x;D|rB#)Ml_g86c}KL;(@*qNg087Y zf{uxVre7CBfi^RKDkEPYxj}1emG!J2X1lk&mtOyQPS6LctdjUxnlVG_cXgx(8Wz?z zfCsRHgW!S6E$NuMJWgPrP0FzbJ!bjkSMh zcQ0~!;1@|nNrP+ss=(WSFTa-BTTt6q&~4EK!pJZ<&p`be#@Xe-#Ad~ef--nTb3(7xJp|7%$RmEJR^&Cm2qukkueS8$LIRK zu{<_>A66`-SLvBy)gUOoSA>{rbxSVD?4|B6evO->T4Twc(@wu(I^t+G%T_t8BcE3p z-G|b3!lb4Fx*_=o)w_ST^tzC$H(bimc@NYP$scV_GuvCOziB=-T!HGy)KXJ>qo;Xb za){gkIB#1!2e;rG8`(?vd&XUDe<;Y6jiDvZTAfx;J(+9QZEQ|WMmE0|?tGvd+2r0h zX!02PfXNbKiQpeH_*h>Dk4#&?P}0?l+#Sd*PfWaVs-;PGgOTD!>b)l6NjDhDNu1`qK5ebY{2_G^|3w$V222la801 zLU7Y$-FwUAn&q%~Sm<<&dA8*8FVh@u7Mj7P-1Nq?7d~OgYbGOW%C+#o?I0^F(1U;{ zkKHPK!NokfL+^hd7B}4VP zF~vZPzIJT^+HcD$CdG+c1|!$uM-VrM^^Is@49a+^>UDoTzn3G1O_M1d4z{bkPHbD4 zaOx@+Q?gDrgVV&8hAF|sRx#)lnL8EhaeZOe42`l3HVeBY$&K?yYzvY&zky}0L;(c{ zlG78A!JJk0WkYk;;RRc!YXN@D+5i-DzF4`uC>kE!D_k5hRR$t7JI1F zIpE;()1!ZY;x!z5cAUr0b5YLzZgNgnvb#Njc+Mzb`Hupp0c~`*r;6s-BFk|gNW;=< z?)Ib|=IQ~KdGg@JX-{{1>UfScx*P?7wA6vY?)JR0yWGdi4GXpzFk~5l!{bU-E@{kk z0i(M;`(xj{JZCU0EUIljhRXs5;#aECG)Q(Eqhx=++smPen1wqx?V($8k!dj~cTXl;9p)AU0Q>Sb@Vd{if#F?v%dNckoTaTo;1DW;2RfkC)2r5^i@& zx|EcuG+NzND`#^y0}Z1+3rCueO*JtK&1@~&p45Ec$l8mc|KSZj43@e|;F5eaRFllE zSB-zj^RO|^*p^}bbd@t$uHi02{aH7A5oR-hU>pqU&=uxQ-_{;|(n4v0tJSfiSlwYZ zG9_oOz!qROV=?%Tw`D5vi7>-VcUZ}aCEB>j-VwXM7bS-~H-saGXC4oW?s50+!mQL1 z5m(v4t_(MupQ@(t2XVSpCvRaVb)klstvG-GlRHCs43m}w*<0WZ(soar@(j54aJ*Sm zGetDSG{@@pOl}9uo?%-U^>kKo5HnDf;W*qP?N+(#iPukWN)gUbTznpitvCB&UsVg4 z(YQJRXWNFjt<|5C(?hRA%=Y}>$sc%Yx%9G8aT@@4e)6DTVr)=EwHO=_Y(P~{Jr95R z%VL!RHS-1}VGEjx`AvKew&SFanMuCuXj7T{{bN;ogVYSG*|~7uYMqlImSbNov(|Ix zPbYV#QZM~oR8sUPCUe0W`nS= z&Q^|X5@p-eUKGo*I|fy0QlQY|3GVCMSfEJ%yJG7ceE8#5?|Rq!Fw9IVcb$K$OdM{u zm1F}4oifjC&CuRG*v74Qz%_@PX}zp>h84riEZsdpBZ6)Kkl$0kCk0Ae@T;5Z?$%La zv;Tck0G+?B%Yo3ocN{lP0*sX}zJVAY?vsB(ypcIBlF{F9 z8Mtq6UAx-?QJINToS<;$h2!-0Oho3cDIXrK{U9?p{D#CTFL~54-eYgOUB0K~X6yGg zGYj}gX2q&|^Mi<&xv*%h@w_6< z;f7H4!=AIu3ZK(rq+jmfXs_M0iG2H-h3i6^rid1n!P<}Zn6IGuv4@FI>D!-VD8jS=AdbOArj`*ie6DmY(-b@ZoHt73a`7 zgO&lqY-6t%06Bt77QusM=)NZEQOh_2DSv&^6FJY`jsIgjaun_p3J!9twCZc@$KN3 zI6_F;y}P=N)S7=A>}{wnpK6t5igOfGDG{@$$^^<`EpQcIy6Fg6j|3QM+_&+S){$1uG~D%V z8Cr4MF_Wb~t`znK`%WmHj3&&Y_tvr}? zn~{QYu91K8n9H|h)-4qcD=dXVbu`T#7L-m66zSvH`~@3~%k)`O<%R0N+kVKrrv?_= zB-1kI4jqsC@1p3OPPz$!LhaicU^uh7Q)g*l`PRU)q&G!*V^L%c%?9G}ZEoAtE4>ek zN6o2tXtMT@{hIiu^IHg6-Y=mH&-J-U&Yy^ct)PGGd5fAJ6>^Km7;l+U*?-mh*`6n6 zyS-;^$}nbda93m}71jhdkB#ix{f%mXcM|M%Tfay>1sy{xtcCO^^6hXMOeOm=6aRcV z<15VG7$0R#$!*3P7oeLI99`U&S}gj^>>y$0 zX1jlLmP^(ziI?U+zp5D`W@aJhBfkleOBqQkY^V+aXND*fJHehq+Sbu-YE5!zzU2Nn zfoW}6VgZtqoM&LmI@m#0+bh#;LQd(&P-Ew9eazh4Xd6X>cS z-}652rFtTo5QZk4ZTUA3^>(QAx%wdk5d(aUTwRDv| zqt7;d*#+h@AODr<3&?()?Mz}G4=00t#{Uy^sb^3c!W=#fz)?67QY z@ncJyyC~Bw^9s+#%Ru3Pkg(~2bwqzatw(9DE~Gg(z9m80LhXEQn%9l=S(qDz4CgU= zEv@q)_)_5K&GXI|6Q>7aJznYWRQ8z-BQFWcS9aPTwSSGTA>JJWngQ4@3y z-s24l>DAb}cKwQM>60>_z{`I?4G0I>A%>*=>gG+{HeT%cn#DfR>>ipMOg+%A;l#0| zSs1OfHdEY7Fg!8;KDlJ&W6vwkGD8GKps$sXvtyeN94>1okj~Kb_(g_}EL2g~_6;watsUL5hFO1~8>0;z>&O;( zHf0EsfvwCkBC6dUPD*N%S!kG>LUwZQ4{v!>;6`G}1TmgiK!UO5FrTttUMR3-(uf9$ zzD|iC+62!Z_?A|c*n&vIH2WS0qU4K~t9jSQQeuH~kY9jgn@6PQ`<_G3US3|zDaiwA zyMfw1WUg+v{Ml!@4u5~y7nNm6ht#>FkXzQC8$2zSZsElO$ltbZ!Rc&(p~OA>iTRA( z@=k&MNRsA~w6V_M5=&HSY(iFI8!j_HG45KzjwpAlDm+Q{X(SC{9$(XIkgUgt{op}W zn+v36`MqYI8~w4RJICPO_Z$C_5^oU%Q6h#NF7!isMil$F#le3q`{SPQgz$T_X>K!PkeAs#hnzP;Qn zvv~^7tlVUpgKkFV^LXAFzvSP*?b6C-C69z<>B0dK^t^%da)W`@Yhk++#X^)n!W>{6 z$-8_&%bjdiJ`aB^+RsFF6ia%v0%(`?5wm_6FwP zuuF$+f43(=n2<-#2?E|$6g!_@5^*fMdCt|cR}aFGNG70a zRN%I?O#380Fw7hkwEdBRrdbCy2qYYQ8`+-oiGWwqTZ!H&z6J^c^=`WG>0izhWSBAA2$9v)z;=|-g~*6S5YTx?AZf1 zcz-2L$9lzlo_T3efoVtNq@SsZK?-Y{WA805Ae>t>VTtrml-K6fHuu6^7S}wP&odcV zfx87JmfS52Uome#-w=cJSOjp8peW7AZ?Glq0yKZcRaX-{OtlQ@^LP8i_>7?stkt#k zo3v#9=FP;!My3jPlvW1O8xLZ#JzPteKY!e_bZvlxpE93d^*Oz8nJ>I9|8`mQ*TC~I zMzvzDvU1t{#{zB#qU3H=%Fb7AmI)2iS+*}o%1@Jh;KrXfPbOcQ6p>t<^c0pvTDM+Q znnQnK9$ltRSRKeGhiX!o!0GSVD?4iABqt`(LxD5P{2=g5i;Wv_@rGR1vLOp0$Rx}n zYCPMc!rja>@9X*OMyg4&lm_3VbL~O%XsKMj9>ElYiN2RMI{k%^#5lca&JR8BO7H|$jI4`g5Vjj{A&$)TvZKVu_P@RiH-3hYf^dP`or()M|tW%L)M;y@laJnMCK z`mWvGiWzEo+zdG4Z843Q`QX%Y#$B3Qdg|q#Eexkt_!@TQcuXg6I$0~mIyCm$D-c_L z&*x?75|Wzf(0UFfO7+j)Djl!`I@f;+TwWL=Mb4s5slfkT-6t_;{4Q4^fiE{1Ij z=k7mC)(qG*syYk2JKe4W5oFd#lU@BCgnX^Oz@*_oI6Z&zx?`kY z@Q^ZZ(QLe|pdA<(I0T?ZYINCWv3IoWQzM$A6Oys<`)9uJ$BN0C=~Ppk}Ux5FKC04AZtt-WEf zZ$r)ypY7}#Ps^~Jyz~KhDPVtc>kaoUl(WEh$hS@136A7M`ir2RZ;N<9SM!6{<*pq0 z#hbGN!Qxa4Sm72t zE*(g#=IH>-0Gs`NhHkP~AJ)?ApyL3SE%uT8;+9f>$jz|ZbWb z1)S}^O^Rsh+Mlr3C6-SeVEP-qm|F{21&V|>Tebp}#c`X*D4D{9{FJi8b+tlm)!XtZZyR0B$x5_UyZveF1WMJh`8(w9~{Cq)t85_dcy(YcN8q@Ow;N@Zx zTMcTq56Vo=^-`886|jHJzob_Qjco#9?G5sIpO1hRTXPY49}wHy(&yaYwAU`j4O`vZ zhP?TLM_uJ@XHMDX0&{fUn^3-#_bVJa5y691@{!6hm?dqiepA3?c*WQqs+kEA1I%@E zEE%z{Y9tqrmZ%lD+1EigL+8tJtJI~96Ot+7 ze)!E$&2Z)@yAF2qm~BGbz@OwyW*^^VrUqFqug!Dh16WqFZJ&L>dFdj#kTp$X%5VcK z$;<|0?$)_HWZU$q)1ysi*Yaq3qV_23-80d02an66^KXA2uqnxsEXdS$er@G=)wAs` z8oNm^FG((Qt;&!^?j6mkJS6%UkA++VU`% zzz)yzwl06?A8ln9#eeT}7JLzX+1#7pf?F9A?g2JWqH5MP^L5u>GW3JDz5YM;9SGk-%v*0KITgwO- z6qePXqb+LH=|i`&Qp>K>RroA=c$&`<E0&hsI*<=v9=uL`rpj*4=kZ(W9=r(^5yW1y6t}`jZsixoNOI(rEi;T=c^!|Z*Qf|sQyFK z1Fy_}4z@Y_9X3X{CbC)y4~dB{SYht2#7q8Ilhb27l)Wtd8-q*{=XwupShhRR7R-{I z?%-~;mEXD+5W1qj7ph&#!WxYxBuyWPfd%=oMHa&kK z?fz-0TBcSQNO62@GwYXHhN08OXPFf9!%AHyz^+Du--ydc(sOAoD!h7;zqI9w5*w&2 zv(}*VFDUa7V)nF{bxxANrfmm<7~QX6EW73r9N)FOd>vH!1p&gLT0)ipkpsL}=AKKx zlTWz{H*VkOsVw_NZP=_7-tQf@Xl#GMgZlQd%)E(_kWiR1UUv>H?a|NXXbu>sC-Gwh z--Ri?X>}g&K{e+sVEg2Kz3=mN>j=9~ucilvCO16+k+qaEUQ+Kr=`#8GyWnQ=FYSXF zHsFn&(?M5U7nx>6Lzsq5K>+AfZnB$xlhGz8exkyY3tQ^{czc#|!FM;VQ>cG$F~8^x zn%(;lsaQ*G?dyb#E-D+p^ytiME+jR^cY^Bz!Vk}|reOCTt$ZZYc(kqG1j?lKm5a|6 z2qj>MO$A4X*RQ*cr{Oj%uRXO$ay8%IE~Fb6z=dEU;1b}7r^87ZM$sW7#7)CTxdjBV zAb7e}Z5rUa_lID;Dax?n=zxFBYonuI_eAh@j6>yelea`T#IyOW@2(ZD*n{6Jo3_ZY zzFvl;)|ZW8se4{~cerd7zqUn(J;}0_i&SU$dEM-jc3V1gS;LaCI29g%MSRSMJ?EYw zD95@s@O>-{OhnnvoY8+hHfQ5bzImPA=0RK5{XE59`!>+58?vod+0ldN86~W_U0vb=^Y%T~E?S%66;xSJW|x7t?b&_12_YwO z!k2e$BFbox`TbiwU0JsMa!i@$2by}7-6iJG$*sMH4#W_(TO)sB-1Y_Plo4AuT#kmN zdNZ?=Hg3!>o1g^o`hKM*&hvxAZDUF{mGZraf@R&`y$@{4Jkj1BjP#^dXwx$JA^{H2d%OP zd|14V|9cQ#WGa6h|J$|hu=RPyAS6{7r^@(oW-)|>5ktkAEMtBj6As16!EjNB9$sKQ zpreflHzd>`OeQ?ucL!)jr_W2KtY;Gg@sI9|{FvVPphuABHpa8(Br~V~jg7d0PJ5e~ zr_Brzce+W_*@w_GzZyLqaXeBt<$ESa7@2`DfDz@LoR~%oeC}lD zP%sOv;kdGvI3Nz~eX|M4u%Fq(kKD|VJmfZc^+-+!t)4}PFr76`Ak0J!-XD144D5 zbm);e(&-2@=-|9@cS11ckj96eHJB9O5&y6umYYuvykeaNV#bt*Cu&NwR1{=kJKEfh z>~6-t6Y7}0^I7fz93$J%qPtl*XV)j%Nn4G04D^4qG<}dBl9rL;GkLtTxq-$%ZIDi5 z^&7}%wrn)I>kO$yJdv7hpv;|>Y9!IDg}L{9GM^Z(iAo&cvW#c05}aK`qvQT|*1g&A zFsCJa=#~v} zOh^xHnGlW>+E2haD{+98X^HETlat2!GNVS^w9t{AvHm_T?Wy63?#EQwxTI_Y{TmRN z(^rS#Q@2~sxE?-H-B8K0vvZqdGYT4J6b^p?`;zX`hDu^o*tsL^6e+QKq7} z(RW~!O>@t=2i%Q_ox&T}H=OT82qp*2D@-WnXU=Z(%shTdBTUE>CPuIwNMq7Cq2a+g zI6y~J1LCj!0NY38^xg4kOQ-*IlQVjYJGq;`=f?C#uk74;{PLt}Vw7X$bVOsHwT6Gb zU#2dd5yNI`CnjBM&REZ!7}}r|P^Y~IW)VPo8&3ojw*ksCaYjxM5QFQ1F%qw2nUjDcmv?`t4kFQx zRAk-KqUw_fTTRwzzafF{11%LtyPdsv)Bl^${kg&+@7S_L)SCY{cL$5^ z;3<|ik*uoK|F_}~cy;yjv2wI`MB95~aXR#Avl8b2&1Kg_NCD*Ry>%Rsz$2a&3EPS1 z|C^7B>UW1VLb(#~{}w|VmYaWZ?Gy9ad5K`kxSg=~7$F%3cnDt7cJiwe%RxAmu5;{N zB_sn8L?H`-dW4GVg+HYOAgQ)tu0JG~{^$P;dv94$%kk$He{@(Ma4nL4{bFxw0RG?H z7UsCX!;(qM=)${$E`^w>1}(rjG;jZl*t>co>sO@mu@K9>6$fGmU{-(72y|DF4?S_( zhiMNh+z?X5vATl_Ya!c_4r4O7SR0hKPhF(Y){rZrX*6T6oRc#$mM^6WZl_I9q?PcJr;b_|^t3i^Fjm;0(jQiMd9QrKDy>e2X?aoG(`b_FDhf z`v0}oT5GMf)>><=$;|PRlY`8mwboi|olB8I51C{?QNJGkdYIx(R-o}bqfccoX3t-L zz0gLo7usmX#z^Ku8~xu#>~|i#e`@-R-tXv4e{D2F)Iu8_iROQUg>xt7b#m_1ylr3* zVi8`MP8-o?zyA7-zWha60ASDL`ik2>NToO{&brE41N{kv^C$ zj0PKI@S-u{Ds&07B~1TXrU$1XIMUy|c~xj5?Ef8{Ay$91lf1Xfu3(|z{dX{2hfZj!@7dW66s zaH>hJZG-c27N&cCzzf210u5wuDi$RMz#r(aFra_N1;idSwN!!si$^5TM?+TjinO-c z!HqO#ta)Zhnz5=uZcQMAO=E+jhJbbh<(nxA>#ITT$5e*PG2jfCBivNLh~+ap5p-NO zIAaN|**a>VZepm)* zxhR=vewN-XxuyHrdk=6K1&m}ekaLw{XqJwZwK#q7cu7A2Jq8z`L1QyboLB`YO1nI1 z1X@jLO$oqeNpfkyM0v>B}*oTqP6J~sIZl1;9th_zz#U`MT`QYxv?-l<#%PWBcf^Ix99KPDEj zIkLFr33FmP{4$h^Gsruk|0%&MO68dQ6)J($3Xv~sl%y{L+yt#2qOYdKdtsq0skVP? zIr0B)mlyg(H-&}<7g(xUXptYR5RuYxUCL4Q0MKw?>6*$rIPb+($2T|l{o zi)tp=_Q+{HzVh;5W~s3uTY-1*kW8L{vE1Z5-m5A@rn-)xQD0G)R5+x2S9`dTtioQ= zV5p9nT5aHnzqZEmMf>J-J+5RQY(Ue*p=p@^RN}aRp6t%vo7n_PiIkL+rzwB(l;2rl zV3Uxi$cQ>Xq(3;KCkjOWbFl4%N9xl5PB`Ov7<*TRkm5=yqf;na^A~C94-P|ra2PK% zo25Nq@14T-kold$G*<<$6APX9h1LZa4<2pg^*;rmuO{7N_AAw9v)L9iHzCtf2v~p& zg4>~lJ5uCW5rQ@2#XmN7C!l|oATtQX0E7ZGLhKOGBg_eeH(dW81E4HL>{kO*oE|uH zfRF+<5LFJS5U&ZaYf?N3c~4ZyV{^0PD6luvLrer1R;<((FG7xVzVNV+U&zCT7KgnV z1@6R#7AL+L1!hacAV=Cd4zTe7rh?q(Ze~S%i#CJGK+-g;*}b=!C{ce}4gZE_e`EH8 z{l8Aq)Aa9PJvaW{961Eoj(%(a#EPLjL1u5No}=&Q3r-z@Fmfd>Fbc7bzoRi|1iEey zhPq%PL4!u13ngyB6X0UN;}9q;66F<66Jk%CKyks_n6zr@S3EjdnWRQtrdU+JpizoV zku16x(%+=L;cC*~kja0$w3N|qzuvMpRd+lBt$tU&>zpMB0Cpxym+d@EmhjFlZVR5P zmT=-3i|&m)2b*s`U+Iys&cNpg>`a9ep`E8}@H_vMZs57iwTVx72y#)DpD?eP3iFpy z{m-&D6@+;TZDVuhNlJwx6pWu}6EVb+)o|}K@*2wdc=9o_qv<9;GthG{SZ5zk*8+B40O?lH&OK}{1@Fv5>575p9XU5l zJU204dDg*m!F+$l;dI}1z7cfyIwK%;tL$7O=~CM{hnv13+#Q2w7nC4d^05CubglTG zbnsHDscAOxiR!wlsi_HSQ4>@PG^Ea|2Mt)Dn2QXVwI=A-x+v>^3A47y(I~X?A#vg} z;>3zLh2=9|{ah?9cDOXpfMtrQR4za_0B%OJ1XY*BW%PfL4uw*C(sf>+M=mrv$3WV; zbiv^N(cHqY8SNU-*M+hO0}PBLf?MQvOpEw`ghVW_VA80BTCNC<#4DFL<-_q-2&Ci) znaPd8Y+9n~2xAA3<`^R6|B+inJ1-@1ERpd4NC+Z^m{H(v)Tps{bgE?4IO`E?;S^o_=FCD`(zW%8r3#IyhKmNt^&k*^dvy1p#p)3wINqn?AaRGa&>-q zYsv!%$v(ieoB?5ah-DeG039KD);t=A{@Yw04&BZfNW}izc37*y7;{`5Sm;zrv$}GD zN8b@>981n{RKj8rF`R6Nv5JfXEM00_)lg`4D2{*XXup+Tv5L^jXGn%N<=4<>VW?F% zhZdUXi0AX!=v^TzbPqBJkN*y^ zdTc^Al~s`l#SPLzV`UVO7f+4`k~aXyz=WzM@BWCPc6do1f?UUmg!UC@;4cJ+gs^}2 zHlkbUNLwNZO@LTMEju6VoMe+*^#=Dh)S~hgg}>ketqVBcjHn(j3ri{uC;+dZo6>|w zEORxbR2hL&MWUQSPXaOjzvC!8qfkE>0*h2u!r)W_YaC<*XQ7Eb!Pb-d(a{1xd1yN3 zMh+ay+>om1fDA}i*G`tU7Egz*j5|Wmnjc*hX*U z5Ma8n##I9i-x@p|pANE$4{(3pxDAJFK+pz{x4^LKQ5sSNY&iC=nqYNh2)rU)uStrF6`vg zinGPYDlC%{&zHY8MJ`W{*S@~!05RBxJ~+C>v!kODD>?NXCr^nc1^0hUpTjAS3Lw3c za}K4fQ4`5IBg~P2jh4XG=tYSjdbB)XN+g2UrZXT{1oq&fW&v%EKNmO@R{4O&A`ojR zgc8fO9t|%!I(yET&QBhdA!W#*aI7pAgaaA{D*F(u7JRTFzY6$nEZvDT*-mq+` zg#O3S+Mx46{kQWvn^ZJX)ysbv;F*RgZM*ko)`&A2oEoO2HTIr z(<5^gq}-vm#@c_-VFTq7;8AbPY5y>rG?GT5zH#9N3M!e>6XH;+ELH`U0+&Rxr{y?3D$+B0h_56!f4 zUQJ~H?aFp&_hGdAYaor?oL9%3ciy8z0haBM5n1|cP}zTu!;tOhGNHMYkrip7%djBh zl)<^v`us+PnV@O@qI6jjT}Jk+L5CQyaoYH5?Q+#+eu$&g$ z)QZxoCF($g8X0(%fsd?8EfJquq9z}?mZ-Tln@!ovYxQcq%%CyEl_aujoOl8yt?!Y& zU_&}d28e$hqp^Y>Fkp}&g}@Mjiwj&OVlj9KIn@BeP02HcMw|C_Vt~n*cg*bSjv4`& z2zg^b0h5wv3=KE$8$$t;;xvYa8?Hb{1R>_=0OG2tnX_{8%HnH`6)N%o+WYCV7Uq29 z%|)jP0hU*N9-6*CzC00W-P_lHY@uD#Lng-trZuBw zIe(@B+fnL&$*Rs*`os+o>UKyC%?6~WMsI&{P7uGPqByVGaq*d9ZEU`xfTLUR&^mA3($jx{ za2?OeXo6I*TxPxC4p}xcXIeL~Y;49cmVM}SHy^>gd02I6NT+NzKU>o$39>j_uPraq zMD1+V-xxjl0=9B$YZlX8s6Wu=L6)U}7u!2>`;5-DrS)1aZun9CM51vgjV(*uBJ_;2 zn!GE(?91NGZsD>Wh+DMDMHj$lw{?Hba|ii)s%`2&L^0sZ%kP#bW%73K3z)gtY>Cvl4!*>dqg&0A`fDx^-CUxvxufBi!9SJNGd#vK_m$G-dglSFSd?_omaA3C^eg7+zk`cWLvxU@fv@0U(w`V z-jl+IUQB#0v$OQyLtY3$24b^@=X>drRc587*(?{vV`I)tOW_=H4G6S4??GB3 zT7j*5i(%-j9S&^4aV%Hn94%gQLy6ME2|xZ6)M=3zI_t1531WwBM)+(CdC^B_*= zmg~8Ewgu~&-FhO*1W1jTG@}=H-n(_7<#d;7tHmra zGbu66=3Jq+JpF+L*OKG(^A6xIsrf8J+Jse_IrVl|8|J}?c zbRM&_R6v7wU8N`~zZ7KcW%nyRNBb^`UB!`%jke>!3xePo-(`Qx!Z{#`r3*_z+B}X& ztqu&LxG)F4yC=3qEWkSY=k$V8tc>oR{S1t%W$iKYlPva%C{lp@Be zf_>Sq1s&TF-LHurz?FmRbi&3NxftapINf$&D{)+w<})4#^^h!y~=;kvK?aud)~mkM7R=b8l{#-)?!3& z-e$cNYZD^a)@im}i)F=_3;%OuYN;rP_N>0hOkQV>L$i!}kQ`_}zTJ?FcP)z1oS$#W z+8}npCp54jc@#2N|5{S}VT0L?Ku5MC7*%sS#pS_-8>Eio4Ih%Lu5mX`b8hkNg6Fq} zj$MDIjtgPqOgmy(vf(Ig5sO=R5v#3LXoSheCq=m2o>(7#zN6u=_JmMy4&$>_K!fW@ zNF!gv`}@^hj^_UGB@T6NfD-aHy>Glma+@Mo{--r_(T21$W=MIIqBtKRm)ROz?tfCt zD*N#R*o0~2|8iRc8Jks5Yab;Gl8&uHNsfOFV~aO2;M>bPwic?hb8e@itVCjetf`c` z%YTHlZ`ts4GAn=YwH`bI-eJ_gR(77dp{_m7;Y(Kj#P%`rU)+BiX)i0j{_6{Oi9O;b zF-GYT%8c$|^WVArIZakg3YPcml|5rmOB^Bl9qw8U5(oWvt9dv@^&*G2YP>c zcYyRp;3K;dZn(Q~M0hUP0Ctc~o6^GOq6`a+t*QkRVBEl~t+~LHnlV*9B)xqPZv#`D zomEgAOc3V@1b2rIcVFCHf-MfgU4zRaK^J$I#U;4AySuwvfDImkOW<;Mk5_edbuaVM zHB&WJT{AsB-M{}pesFf~;Hv)*ovaPKWf`t{vB6a`;lfJyLI>v+QnT>WI5O+N60`RQ zUo`s@olCy_x!_5nEZU|6E#2OW9)ajfk#%8>dHpjut4lC#M$~4(tDpJXoPJGMv2Wa1 zJttyMN&;{_u8^tv27&i-AgAJ?>zg2Tem8xy_9iup!g%9-D%VJ7O$JE%ov`MT*qc*c>NqrsRWatn20lEt5!emt%<4mh_~+ zud&~X|9EgoJ;-g}&g-#|Jwz&OoX3~$#8Vspi{W>R>aorlx}~0U4OXR-{EK7fiM1>Y&*6V z&`XIa&*^LuZ|aU-6u={G&C&TF6kF$e7s}I=$-)c1<26mUo9$13UD-DGBkR!ul^(K>9c0ke}jkMWxVscdg{2;c9TiL%j4FAh&G#T{&Wu2i6 zCj{HLG$L2G#@dF&*3~81n(4fDnNMd%e+OtWXxLNkY}c}?gANB-eXDZU!gnr9P8<;e z&y#yP=zN^2*wQpK|9A)QX-Hly3PYhLe>hl@K!Ix-^zC%s0aNU0lK(GO@c(5p>@(|4 zI(L{JUsi6>Uai3cbMrFv=N|*N7Q+|N(VecFxF$7-QI{3FNK50E_8Y4!z#!S1_Adb2 z0MH{?=nr_#Op6peVgt$~PP##6n2jCk8m0x`9=eZPSxUGPMBg;Xsu#JzHuSx8m}NNJ z`~sd8kc(s?XUHy&&QfwN1)_7sgZAl6Ce~i^oI+G4$)^@A5J7->oI!XAJrmG5-s(?@ z&qfKC4c@&~Kxr~JzsUCvjDHK-Anf5_mMwBqh<_qhFEV#gBSl8J|(y5zR$C9GW}T!i=A z*h7;awychF`WI;Ni`dR*W{Dr!An8|cM5bsmnjHV#hUtDBlyoujH}1L%w|^cS zx5Kho3EL;WDjk7q=yv1jeWrG(=_E6A9E`?<99maD5&vR!oWt*hyfe}^jH4$--cf~~ zO{EL|p5wY1eqwCgG~Dk!{GxNJ*ZA3c%Dda6!a=t7%<(_2w_s{bwBA;(^5J&$6(y?BCEg(*$P5@)kg=I&jAk`XGUJWXz|UcS7wO* zznw~>L(-Lx63i=(vF{RC*kLAKpRlu1oYRB(B2ac^zhD%#7UB2$?%_^pP6&EYaIm_b z8~lLogeSrY_}O$v9k{O^*6&#n~4Cv>pDSYZ4uiphJ@Gr|9oV}mZ3J;f#n)W7OBgaYqmN82Oy@*w0W^MYiRZNq~rTIVw24s<#B_wUUku?T7T+SM-tZm|dMeKQ>lXLWq{=(097m=I1E zX0H&4gkz;sME>o}X_C4_^tG0U%>pyjjMm~=+%-bQrDbC(!#j;^rYQwm0% zt{8q0tnp9{Rl~H8Di)bQKF)W zk_GKACSqenu+h%^YzESQhK>1Qqw%7gZ$WZMD(lekEts1WmCrsN9Z3uz#yZEgigV6Q z0cK;0w>L1;U7aWMVQ=Xo75x{ieLTNA*dh#`wi(8Kp%wM>PU)cQ_WnKPb~SrosZX0J07DSjq0H8evO~Fec^nmMbut zxl_yu*CnaJo7K)hgs)MD=Kbx}L(mm`^gFL`0$?}isd&Q0t4H4r%f#NlA>pE%rb%<8 z9tk4oob}EI{u1X~aAtwA;w*bd=uw(h|6n!g7<#afluBAK5Dc$x-{u&x#W?N|k(I0! zi-0>nqlF+(>oG#uzH^nHY(!1sjvOQbiKOwmHquIx5yD3Kl*MJHW_%z3GHmbz4D0hD zx`4Y`!u81pM|y9oJn!TSre?N1U}4bss0J&eXcnMsyP#bt-aHho_G8Nv-Pg{c%}J%H zY5OB&IsSrFn*9KDaJagNZOM`hlAB!Ijc>|+3?EY#MJ-;&M4aFqYZtszgpdoi)>tic zUeMg=q*7lV!3pKwek9Ls^nfAHBD4+>F*IMN)dbc_@l6y>f4DD@f~--no4x;9q<1$v z#yYku7b1{H#8I}xfc#nyd%PGtBk+n}Xai3H_2fM( zpMEjNu%6uv?@8a=5qYgjLb6wL1tt{%lVsTQ?ubSXJbv`C1F|-?)e-UP;ueWy#?VW8 zSa9fCpnFx$GpB}9%4F>&-rQIkP!snGB~`HcTPCV$r}c=S&85NNBQ^##iEsOvtj)eB z-`t7!XOD?kSzSlX|G;taRe69&*wwSsds__oM)x7LMYe%jM2A1OF2cZplr~pLQlBog z`@ZCvbbaO~PWh;O8)Z^wmX237-e8iz9Mld|djV&`x=p|xA0%&rNd2G=U4>8ASs^$;$7Y4l)q zezfC&4G;hNMqXX2BppB!GE;Jp`1*Y|ctl|q2@5`Nso~yi-OIX^wRL$9#Tis^83p|F zPLV>jA-gZsi=u50ZoAE@`e}@?g`~c+D)&e}hi-X#@Wq92p)mvbTu{i4iORb`vO|~uw?#|*kL^_;k$jBT7<#c+*xh4!Y$SaWh2iO zo&ubTp5@ay?(SILl02Nc-v(M&&?B61ZZ;1>?boFygddt zymfE43v8)7zUZ|LuJEZGnRZ_PLtF_EDpiOmcOxBn#m1ct`FQRPqj~wG!;4 z&b|@}#=0+zG>sH6xoali5(`+15KB+)FyB?x+cYri=9H<=VHHKZ22=>m2f=V)Nl4__ zU$IBAj8kM@EfkdcJsS2}oOZ&2lyob-iKm-P&L-UuKBLq07fPeIx3W^^d+p5nIa&2q zPm&>_;KK#qBuD;J!1!vo#?^De$IsM)w>_~Bo>{zYKj8Y4L+oU0!qs5!W`38rj@t(fDUh1sJo+}`$!zt- zDba4SvCWO81GzH&6|B2ri4wLpFbPoVFPxbsv8zFpRSS&{MbZ}rryFOWEknRul8+OZ zC543p(3O7YVAw`t;7J@9o^xey054rEd_6!S`XcteV`b{?Nk;BcCHJwbDB+Kp=PP~j zAq8d!;r6ZaUGP_nB@`&Jyd>wyrL8yVg5RGO&A(7MM-l!cuPw+zJtPG? z>um-7Xmf~WZJo#%8f0^9y(@5B=_&?yFeS+9HE&p;Ho4`Oo#7Z7PvxaKZ4!OsYlYho zb3O~Gh?P9r*iHaV{o}N>Q#;(uO0|xef4ZE=J@*kE*$d6~LxlA#d5AG3BP{`BVFH0) ziJMD{Y7qLZhD)A*G-{J z`3Y;bzP#gqP64Sv!uj`XwsiE`&BJTBFWAD7Bx^9BMhYNvUNOLfJ!^q?-%hD@8W^Wz z`met&>NWSBjypn9L%r+lWxfABL5BY!b3&PgySyT4@2bFK1M!RH)5mN$b| zWPW|hz$nLDY0?Fs#*dKZ@NO^}WeoivK41F@n+5qPS2tT>+ADgl6zfbcqlf0;jsQ1> zPay@?4o<6xq|SMK)5uWp=@y1f#?d>@l@N6MVUM)eTA>(M*{(^SJ=S6!R(2`(iqR`q z$71oiup{Jpv9+Hx?!WDeZzgkes;u7j=JznBI!1D*ITY3tN@}LI)&GIH?~EgEFLpEz zb1^r?n10%`ilb0od~^T&S! znM(TVvf2XWxWls3Pu1rHei;vD9*~f=POh1fJyj$ig0P_2q9>)_T*2NL2Qi(>bD?D~ zYG{3N%A1$_SqPpDM!{M?th*;1=p(yi`z!__DFrdrbCHsWalDLb9(Kud7xD?_QLFJQjc$SyEgE8|Emfpao?C+rdA_d~#1; z3-v{E48mjvGk8X`&&d(J-Sd_1W)m9U+v&2$=4e<*5 zQhatrwI6erV}ALvvXp^)T~feNQ~O|%torCuqaM_;sw}TVKkW9{_F#dg~Hv-OjXwStPHel$eS(1C7e9Msqu^@gN z@TtGi8V7+>wtM&*yv%sl8-GZx1fcvN$KANQ+x*Vv%Vb%&`TIAPJ?5B1Ys8}B@Jvw` z{X|~^jrTtZBy@RLcU-6&E=s&oi-%@ywgk6P9CVqcnj0%F`!wsWTa@9nQ^ECc`6q%3 z89BHtZ=iLqqCC(aBfGP8Mpk^<-b8Q7+Vkuxc2CAubqdY+8bn@X+g;b;`0hOW=!4uS z*G$Ii`b?4L_jIuwE!!L}cu6nGnnI28s(YX13g7o7C(}5ci*ioV!6(WrnVPT9-!@6# z;2j1}2r3Ck!JAGB?Flixpb^pkC?u@BNCrRZN9WUiYMjk>AT!{|d4bt>u9IFf@6}z? zQ)YMm6DrQ-tR_z39R~MGJ`U8pe6Ju1xUg>A|k~x;A;>3?U4;i zHl&W87Uv!;@{PG0wP*qO%%!K%vBc(b$I5*TJ4k&KHv~OcrzP2Srh1wMcAD<-X@mJh zK%(XVq-GR^8+Fb$ms@YeK0?d3olV5u;Hdp8WI02H>8=3_Z7X75!Hhi{Hd(B*oht=6 z;j)Bv>mD?8qYfRjpaEG=RKn^E#DX6+j2HJD@G1v~=I8J};V<|2FR&y7gj7GR2(x9F z)=v*5h~yAWIedqhQT}hl>vkyABY<55E~veYk))YOyJPvp`9*0m*2mi zgPtFPTx{@hxP76~4P(uvKe0A_F@ciZ4{xS0frc3U6$%Jl0_O`bSVi?_URP(2C6p5a zs0oQ=0FHOe3Xi*TXEA}9GISt@P@r*5K9cEZPh8)3C&$k2NYLx*oatetJ6J=Ogv1{UIa922aHtT!E)YJZF z2;HV=!{aI^&x(|()*6T#?k>25y0kgcv`K^BpQ^aW0iWu?Gc(61TagO~1`-0*L zo)tz<#8NTY)pJXmR_*`(2capvHJ8*PdpIYEEEdv8t* zCYsKFwC%pL+^^}Ie6y%^Zaqk30^bKrgl%Z`3JEfrXeW+;!$!7we)zTa$Q(#Od)?+@aC*XJ1aw2xZ>iBZ=C7(so)eLOJ83wh`;U-p3SSWuCi3&5Aj5QW6s0G&O=JkH z!<0x!y?bz=;a}nUPsmuJO)jDbc{-~Ax)&{JKDPd1rZ35YcTljK-(Xx|H|bd;+q3@B z-keBqTj&P^Qw2I+7%CgQ!8o^SfL{Ctwaw%_3RgkTStWQgkD zjmmb>Ql&hdO5&BIdeY^kf-ar+4c68wpkr6myl@hMQqiZF#p%w%>m!pd8=~dIWWod^ ztr2Y6PnT;$?)6|5B$B9`ux8WhPO}WhphNw@Uy;)z4l)V<84`q9W3mS4;N25idPA|!885~+2) zN^rh{n;yyA-^td;WY+vsf4FX(sFc_=CaY)iQ)%iuuyz6r&lIyd{nT!pn$h$pTM8j` zsQSXF^4RR*RTL(eWv6Sw|20R>R&3@`Fg#83@8uZG(>>4UNqYVfIEHP~^uyWgU-YxB z^P&hMGvp3Qd)n`K=#J$daA;ZhYdOUHT=F4Qc~UOa1SB0^E~0}!x$jjlr~ktM5M2)@ z5>1id@xva183%K(Z)MJlQ167NwAb)nO1=$~fp7Yc=q-FN#}Ufh1HRS4Z^h5S_%pmu z6Uh*W%5Gvf6x3jTuRoaUmhVs)XfqpGb6NXbvK@HGJ+eb@m@~qkpZD}OfJeM3p+;ZQ zoGarFH+(kp-FDvS_dU_l8Egi;w&^$mS0Tq|8H%z%aQ&kqXtr>I*2|~hHgdqN^c)6% zRGxn&BD8b}jmti)lv_~p$vR`bgDrTh6KoelBXAU^65b~xa-A=bx54fs?y<^!Alxt_ zaa?ve2M9Qesr4+ais=0{AKqs;foEV5&SwJo5qmzcjYQPBr)jF9RbydTi+&6}$L8`v zxNZ9Yi^$R+GV&6WOM4M1xr2RTL#+GfrI$<#1LVfq_d?7WbB3JXkU8(B@7t{7(MFyR zxEE%3KO}`c_>@&MmkY}pc-C?yQ+`s-B=Pu{-Pl+Ua|>x@NEMacaI_t8klhR^`!}N< z5~WNLj*mll1sf4ulrmL(E>Z$`AP(Om3@ zVC9^sa4tAIFXA5}nE$T6M$*_3?{Jtsz|)Mcxv8orm1!2~Sd!Tmbn9-J z6M6&wX!vQ{aR2a(nNe8iam&36jPrztLcr!~x69&B!hm_-n9)U<{h+gku!fOO_1ld@ zm+dv%mEfi%hFfmXjLSLWmT^z>W1J-!cywf1l49vTGQyRAqvL4WL7OhXoI#!(924Z&JcME*=TFp=*2)z|s)9N`6i=GZec+N+`omUK7J}T<> zC{8y^WcSnVs9vDbb!U?nHLPZWzF$hzoVI>4Fc22kj@`kn^7Uf8c_X{rJgNQ*4lp#n zoSO^LxVzX(9+lqtPZZ%|xT;`F#8K;~{R2!_eB4XA}V(-tbjrL76C-7wO=mE=S z1nugwgpcP+N30v2b(NCZee+QkEM2!`GDLLTowGg}n^)n+(hCqZq#t5*{$ePHAgr`G zJ7sJ1{m5SvZ?!}Q0~ES5uRQ8`(j%w(zWGw05YCqaE2ROZ0HfEOgr+R!@gclTt& zVrHC0a>3FlpPpiyK(~7|VUsoL0xS50pkfWlv(NFI`DFkMn-C}1Qv+Co*+sjN2B@iX zOXF$>`3_>2RzU)*`GPk%-w~^LI8ZAVK+|mWx#wYGq+tR(e{b!m!T&Y+(=)XijOAg@ zaZKX1_AUxIO0u>Gk*wihEz*$L-voAAl|B}O>#8~GuFdr{a#YMmkTu~~!P4$&E|3S=W@hS6UkF85eORdg(z2@p{u z1Q1b2ZQ{~HYX`zs8>eT^PwQ0==$h*LC&KJS6Z%MrPso-cY_}G=GPhF(1Lj7;Rb9D) z&sap&0pYo-G7dV4_nGqUooH*~n=XXwdzZtGsGyytyx*sMRqemQ$nqObWWHh|LyVg1 zy^Xmmfm(^JdB$Dn$d-or?!zpCl9eUW=9P!Dc09EyQlz8AKsi$Qdb?aILd|jlVi3u5D9rpPAmzRkg8IneqUV3qj20_1 zF2Iouha7l9ttHF;ek{=6pPO2-Df1HKJX(&N#H0(y0cQpmumAWM*LWlZ;YJsPQR>y2 z7Ct5y$gOmrj?>0KvktJ9Wj#5YOG?i82<aN0fKBs`e}$LP<}nA7V;q=0d`Gl3>Q zajruj{XuHif#i3~R0s9U=9h``o*uu7%=E->m>1KooKdkT#9rK$NK{y%zb?X^wJvTF zb7>R_U3Z&ooGN`Iehv)?HLv!cVcm%aNL5lrSQbLUwWHQ7AEWs&q$mk?OTrDM`*7J5 zM3^mqAsk|YUnC>5!WJ=!LL)_nIuSoM>Rx1~oKrQ~7=KvC8oE9& zXIwY?f$YVd>CO&Z z@kv?6+wo@~lX%rpbxsHb_|7Y(gh8+R$4^L3wc$jj)XuDvzBR^ql>G>FL-zy~I8ZHp zd)!Eb_sTbWpWqH~Rx_lU5@;i?m5NWg;*t~B1Ap>JK`u=+tKMRbV(2q%BRa^*k?0y= zUD-C0O-;dms*%JE_3Q8GBRa4oJSB(Iw$j=$O0;!qxS~-^)2sK5abqT#cVd%f^0Me3 zPSSas)o@5b6?mLX$qaP25PX(=FIh;EvNJXX#Q z)@2}C>Kz8h2A&j&m>$kdMqdOc$dbVW3?EY9p(j(VkSs37>Y#+wiX7z<{2}+Hl%5_1 zg7ao^D2}=Cy1N21Fl-t6DP4cnj0WbL0_PTde9Gee-lS1@_KZ-WRhl6wk7W0 zl*NVIZ8$k(^A_~a?w=78m47G9CM-B7!HCPo?5=W|j?S0-AOU%f8vL;cP5S8j;`;GH z^zmU4`*HKXMv9N0AK*8t|E+BQ#5qc25&M4(9|@fADU!{E;ExZl1@ll%st#_>F%|>; z{PM)@%}kV{1k%laxfwogY#NMMJ!B3>*^K@`^-!E+g>CE@GiHO|M7zOb$<1$I90XUd zUDP}d<;ni}OxuzHi*6cA2KGNC=CJz@_@r>qYt|&f$E({DdIbcU?7YDw<&N>)m8xBv2U}546SrJkOI4 z_71APf{|*>H}@K-Q=Q_VPW1X#g-*SlSDKw*zOZhybm_!?=J zyXHQm%ScA@qxo;p6`6+kvs}5S+bWYs%JPDmeHyoiv6nix8HsDD*auKQeF58o$uruJ zqn8n>6nu0fL@Ul>uc9mY!YlG;QBeQ`$fU9RSgWX>8`Bt2L&UEzIcTAv_gx7?{Z;3? zHlIrAadhN|y!?m2Kr(gU-6b~T8TQ-_Aleeo)>7!hh)&O4(YB*PrVyUC*38E@1TRu}1VJ!Z^ z4+K1hEKB5-1)d?R%*s`Oi%G+NKqQWRGB(F1RTI!RU4ZoiYKFY7V% z(JW&ZcN^IuX<^7MV^(k1RFIi^XRGtiyYUrFom1Zb?!Z|=%jy1HVobSWT)q3_y^ih+ z7A%-8qV;c8OImh^;WUVYfdS}hWTdewKBvATesf0poN4!$)?2L9jhpql(aDhx-`nGZ z$YN%up}MNn<5-==E`i?v=1gU}Dn!^wARkSD@ASOSYA-%JjZPXDl5AIv548IdCVZU} zvi!l2t3NNdG}mFZC)RnT)Q8CAO(UkFZ3RV`h`T&;j@uHGpapB+sEn2cCWLRc6} zh33yw@pD$D&d({PUNyoxeoWyI00h2W1gd`-lS(DKkCahVL248Rf*LD-4I`p^Avp+Kni4^SXIfcxG5dXJcDq_;R3a(%Ve1~rM2L#L~G+&9oT zlss%0U&hjExu;-hNTkTEqo8@aw+QVChuhkEUoqFj5onLvnlBa4BM%xvC}<2% zJ`}3MIldR?T?g4{xD|g(s{E7uD{eLl{%aDBn~-T>h&giwULYPBtL4{kJSX7tJe6;@ znuyWUF%OUT-jeW+=HJgpGTy3jMAe)|`o0#%hnL&e8yI9>_N9BmIwND_Ksi?fa(3rX za%Js)rv7*!p?I(!`(PMYJ!vf=k<&`$R%FHp*Y4+xcj8I>6AmkABQ<7JhhLSsJj#Im z8GEh#VqzD_wji%rh$dYex@ZEf@1fiqS>gXS>*9-~PAFeQY|0R_%rz^9u)?_rkgdR1 z^Ue4X-tfRx8ZhA5XbxNR8b%}dXaAw0NOr#~y+CaLVyxIR$rB(IS7|h*(WdK*ATtwu zsh5S&%xzeEHF!x#^onw!lh_&9WFX1=$+oO;nR!{vs(h}6BvS}}s{{|s8{H~*;DjlB zhP(IU^F54>SMoA!aZi+*c!el?OH>Ot)fwg1Ko;F*?eMP$lt7`tYZH0p!wchb@+41M z#mnLc8fiB3OW6#e&s!_znp;sWZC+%&OJ21F2(Aw`#R!y_QlUNymy(c|q0Jzy7R1(% zZ+0cEKvVZFOv>LWodgaxoB3id+&AOjwlqU_<5^kJ zp&YHt^4{TZ{;6rSw}Y$s!$h`dV&;61GoE_U=tonYA z-d4TCCZ-`~Mt9FO*cC_KG>RgKp6NGrsyv#hpfnozOKq`|Qa+yJmrKg%9(GVwHSo>< zgCbs2pZrI_n5?E*R|I8vu$wRz%4D#390Q(~20^$K?%21#EIf6gKk_)1Ggm&hx`v%Z zD+@Pp&43a+1y|aMm``JD)|&5y3JkHe(Iw$#BtP~5@&i^V;K>L!D}q$aZM?Ly7pllu z^gt>Dr~a?%X|{O3uEKNL8q3lq?Ud8fF)O#$e$Z~Ca1uM>Fa%x21`bF_1xQqkfBV9W zl7PdE&(+-FPi6<#CgmWTJsd?@Q77$Kt{piepCW)wi(iUbf$-l6!nuwr&S>OK?=@jV zl3{u3t?h9s75I~>0;1->wi#)&Vl84zJk2pgJQze8F|X=A2W#mb=eY zI%L0&d7TO?>`$%9=Su_rf$-=9lk?>)CYsh`*kt5IJSejWH;0w56_K*&@Vt|F>%Stvch95S!xY1{U2#PXdd?W8Rbf=7P?>N+e=C$t$zJDdRae zV5_ee_~GcRj?j&ZHwPGbh}e?GzmpWwuWt+WHUy?>34w&0r?>&ix3HHbR_uQTMP9fT z(nq}q`aXMt%`jQoROz(1_S~o1S5u>;pSXiTnCE}K zQt%sg<{7l*>a~Wy?hTm-9dybPEX92)6EK| zj(MZM5_ualAgb7S%;WeXx%5;9d^>8K%TWL^d4Bd!&_gH8`B%DhW!5sa);EZ;)O6n? zX6%%4S95*e;5Jn3?7udaML`d?5(X4i6&}bQ7Qk;=OY#$Pz@@)omS9M)~<`#+Cs{ZZwSem2>_;65Hc^77G5!Bi5* z%a|2yM4!<|bJjbRqI_Q}!tSw)eF@;(14N2<^b^okD+UT#saIz^+7p*NqGrt5+O3S@ z&l~sSmS9wq#wg)$_G;^YDTQ^^4XXK~ndwxGp^~>|8htbm-@Z`rw%e8Qoclu2 zj7a>YRASMRs!ZZ4=SVa0*xYU{q{vO=q2BWs6~zwEzKC`rvFJZ~_Ux?WUW4tgH|w*V z7vdjCOx>O$JBhk$?w8Y8?aiL21$AcK4q!<#iNr(q2Qa@9=lL@6(BW=Sw-1jLr8Fa` z?q{CGQ%3lgv-u1oFrrhisL@5qEHQ!KDAENbTpOsyK9}F`8+B@=W7Y-wYe^*j;mZNd z(0ALJngkZ7478f(m#2}4iTNx8imz`R6DNkk*Qq+NH^KKn?+suP2S9TP++~z;E(5c` zcAm)ecs5KTZ0v;#;r8ush10K$vg29Hr(Foo$a3{1q4{13KB2dF6tqq56ix_*g}B&) zaGvQdDoOWhL;?cz{d3y5*{mAqH#Xx%cu&|rfT@gX%Y9~S9V0b?X;55}6$ubew&VUPLSG$4Hz?t! zuXT&BcA!V#?;T4+ezOizFG(%c*nFB0koRMNb5326D{i=>YFEMcQ#sxHxsqvX&&V%wHuaklUC^xUWUB&;S@fB7Yt z#*T4Hsai`@`DdTu_p$mKgqEn6LeVy7w?7sb7eQ|arWjySkurb-t)E^kg;J9!*_~i_ zXIg@=fX!>zDu10{UrpRM_sILW1+fHPZ2M5=idxlT8iNNr#RvS^hLTiRI~o$6lg9Rj z5W?$GtZ?a1YHJ($(HfmJ(1;2v&F9#2x_zl8$|X??w=?va*BUFXR?sK%9G$g&R;V_w z6V>d&nMbz18%}p$jmIwj-lCxNa%+S;5H&B9I#w0aKKZGUAR!@1xINx!Z6d~I~x^YuIAh~v6^uz%ejqBQ3^(f z5-UcI`|59ee;IS^8{>>16F^hIRc~q&WLYrBR<90l*`W?y3^cAhkqbW#>THIFlL2X* zw(6d{W-50JwdNL5fYn3leFR+!$)-szj?}s>GP0p3Wj_{2z4vlSv)r3A8*@q4&sM=k z*nD%7t=T@|tC#%EIk%hZj>KqzSobz0^7#!WnB-`sLjQvxQS0NIGFE>=R+xu^pIF*8uVBoa9xQA4k zmRkqCVFtFwWC}eFso1G~K})c7f4_no*m{i)(5LhGC*1)3G0LtZ6mDMJm?SWT>Hl?q zhFZ=7vrmo}n>JA4aO7_48}#aLcUmo{(6u|EVMQfhbQYoY4^~1ZS%UXY$m=ZkA_*3m zuxZu+zP@E#prcqp4_Yx$d~6PYO(vM0_g6f%Pp|cYu?uuU+L{1yQ=2$>_zMOW_?&`B zwWhR~Yi>z)OC$j`f>Bk+Vd)RvBH*aaw9y=g9<&FbeO`!Op^;_7T`cb`Z|_%=ct|o| z{s-IT%i{m+>FW>pSHwd!FdeB-mqq)B}eA!(P90|PyrzP9j~mDn1e8E@W|h({C{ls+wTus@~ufBd_()gTk{ zwkH-oz+4hk;N12vLnnhyD+cxnZ@sm}UiQDFwcw~h22}I|OKOj+>_e=7{?OoBp3C!j z-eb^GRpdpkzwyDmt6fXwVs`ZS9wR;?XioZ?YwgZsyE0CaFoVm1D|&m8 z8&8~zou3|Lq`7`z&ngwy>exY@bA2aVemRWZ8?x#8{a*hL`eIm*Rdag1#^cgh=Q;4z zSnrrFT}5Eyhs)ULRqo_=?FEToYm&6Ld^dW0eXfy>skOWV9KcXCVn|nQE31{Qz-&%K zDVu|A)**zhmWI|0?1{=o4YVl^{-hh+ zN7IDq;em*s23&pEo4TyB;yE8KT@`Bof|_!KPb3Bp%V~OIxPa}(>vhiGpyfIk z*f0G#jXx#$>}?^4O4X-uH|yoO1aW|}Or(-97H8U;-anXgJ&JCmTxcVw3i}AWm@dnR zXu~4b8n}7j)A0x;6=`()6FFVSnFo$V-w`1ZO{@PPFQ|zJwhF6b{1eT8vNMC=mT>+N zl{Pb7jMlw^CCB1wRDTt&?WTn>?`AxW#m5`jtG3HF`4+FBX3orTo%0rw(5o7<;;t;7 z6YUc@#ke`7!S)sXbhF^9IVTp(`L2ETF|7SxiEzpu*nP03EWk1&s3g9-CH(wK!;H0U z9$xFVcykcKM1w1MFStsFmCEndI#{7juz{tiaW%VEnY*i(F6Vu+pwe3qlx8unLQ+3b z20l0<^4fuZOc$m9{YUFQ37yd>E++nz@Pt!ivu=ibVNvI3m`I`afiPU^rRoVebTkp;)10a3oycYQ7#OzmY=#%qjd=;zO(*WSI;TW% zv3xJ=1bp!k#8Z5Xlx&{=ksuA@bC2h;Wjl5RZlAdqa00RTx8A=6mo1K`?A4jL=q|nH z?~tYpO-sP#rk`AwVg^gE#gTD#kJ!b8N;98dsV^Y1{NUd5WLu4?JSfL_PC~voUND2u zwp>S`WG9?#BE&SG>hd4QB_tPu)Th_u?NsEMFezSNH9Af$SmxsOM2$h2y4TN>FDGN* z&*g-?Uf{nILXMvvZcjJE8aJw?Z=%yh_>H;z*LI9_+kUV8Xcvi3i6`>zXzp#0*!>Jk zji*`^SiX@`sO=%~<%eaCT6~Ln#k?4i_cPI`)P|+QS81HrR(=-Vu}Ux;ZMsvQ{ zHma52mE56P1qBvYlyZS645s|hY1fw-a9Crj)mIG z2v?`_k{99qvajfJ#I?{1Zn6h=QABH3>k_?-MGDfhEGM-`Hj9k_@EtWBF)w1bZII`=eEaT` z85zB)V|Si7lcUhy3{@5=pYbf}!x*WU;ca2lb1FzJ@pD6;tFOCgjS2N&L~XRfd99Tn z+|i5DSo@&{dP)pNC{c>}h;snzxR|ng6KVC39BVChZ=|Pgu(PJlY|S=pJbS~G1N_TM zrX3a8Bt2~BK<(*B749c|4iH4cEa>rW$>sf#6CN@0`BS#YN&8+QL`FAimMSXUr=}U2 z_5lp(;Q_V0)1jC!-~L(SN@U+5759unN}Kef^zC4Q1ORqTf`xYW;=qluyd5LZifuPG z$D8Dw{G;@MrNwDSA0UT*#oVpZ)aPP%C}gKZP`mPW5PA%6@*-&XffL4_=KX9>JT7L& zA1y2XxWiYULkV%2rEXE8rsHXoGWyS&PLLr$fA?lFf9QlQ$-5#$rx)_c?-csfLC0LI zbuzSZoELY!^G~O=3;Z&rpT;le!P03N0_5ON@AgwH;q03?30^J9|LK)pE?<#p(gd;j z7yT+21BGjs=YBd&eXiw!4u9aZzy1p20?zx*Rl=Wr>zzgisc<*5^SJHVV9@4M{X%RL z6Q6oPe7j+#A*!wdbSY>?ft{N$KE1gd5-N{Y4;_$;y>yd=fp-(rdASw@ZJ*9hs`Z^S z&53MVsh0(AH=~cqqdqTj97zxX_U=`Wx6RuV*y5F=lWYP~i!uH>a6e~= zi)jY92WCx#HMaVB7PaS=1J`Clbam@7n5Ip964@{u;{1$8;xuuSh&mbFgK0WXyQDBp z59_Qo7x?Ot!683RelwN+Brr{J64Bm81U{6gB^9WDkr$^#b4ph7EJ`))2a9l6TrL=A zP_0(r@nFn86>U1fB$+t=+_(NM$gLiiNYiCciD`m&A3ok|PlU!BqCBi~D{uQyXn5$J zGUiSQ&PK^JdrML0L-)k}o>Q_Gq`AcP_!-#c9DU?n1>T^P8$D2o6LuAEbXVii6oFaA zFyjob-N2RBU#-+qBkxXH7 zyEI81<<@Kku0J|2KLo>YT%O@!@K}#ZW8fVC^OquGVDk9jnW)%Gp7>S#x+Li~W2hGi zVoobDz^I!ZCV+2y=_<{aF@V}v>I9MArRQ(9Tz_?IEwuwqFBO=gt<3I>%cwT*jgLqL z+btc@J2$Vtya(W|q^Hib`Dc>uzzR*^4L@zNnH>@5L#F{jY;SHiUcMc|M-|Z*Z;j&y z^#@^gUozso<%n{BfPl;xdBN}i;peKDUQ(zx7)_GHlws9TbI4wm++aQP)5As!gO(}T zw?M1o% z1jFT%b&Ek+!z$q^d&V5CXNegFf00Jx+TA$!rsFRblg?&HBC-^&Lo;H zp9?{cl?>7&0)BSm!6Fhyf|4ehUU-cH*d5b}h`uzqNPoIF!Ss<;M&+yakcYsNBPtS> zul!-@Y_c@!t60104mes%AW($dj`@|FAL;XrGJ50?XV|LtM%Z(u@fDk?2?fyMPU+C^ z;g0p|7 zrS5o|cs#cjw`Hg4@($y)U@06knHQGJ5cm&GMPH)ti zB2SHVVYQq6P|(Vkoi)IA4kfk*PeLu}(tF`MZTzF z6opqo!{Y&-Fl@tPxg1WVS-B&u-UZeoP27O8Nm9axgSTb%5@-SYT4o`EktMIdGPHBC3k%b|`b*Pg%=;}ppkyexeuUlUe*ls|ZNF8h zeXDu?VXsRPKG59KwwP<2ma$6)rGFY*70Mar@kT%8t>rT3ajl#=1sm-`Gi`EU8AiEMFf)_#TkR`X4`D5fvxF& z=55}kU2pd;Wqj+L?z4omYVFZ6w_X+c@BA@gX&wOr*+#C|SN=OHu;}LYynp@VXNx?q z$gngl20(=B_p!-%ZiO=1nL}kSqShgwSnzVVXo0C=^?LI+@Zv{jv8@S0Dr-=Iqnash zLr2+C$8gb&vs&P-K}%4ON6K4N7F#u((3a3av23#xzej5%3(kOE|p(PB8j1O66TlpMqs<`LX&6g$EgX07} zTSzK4XIfeU``&ZQcVX{I{wOqGL~y>X*{J|?8!F^>Q4io2a{nLpH;HnaJvW6-d=}nsX$q zGeQ_=aJ<*7f|!%7FMkOL!TG{ygFEswb#YZ%zS~{-xXA*~-ZuB`oZ$bXO_lbaGLk`N z3U7vrY)9pV7W|Ulsz7M&9njLL8Z;oMv!9CyrJoyRDG73<*-fW8dP8>!mO-;>OU|<= z%$Eqg32Z5O+pJ*Y3e#a9(<+ud9&vB8<;Y!vAKOfsA4@N@EPrEF54|1_kxt$|MloOG zcU<#mwPlJ+*E{;gm^Zml*LEf`2If2hmScsm99&p&u;#tqW|tGisOO$X&M!4Z8Ou7C zaa)FA5s>E`aDQpCN0Y@lKyGQ8gH&$w_vez{6xXbCTq?`!ExR}^taNLh23+C;BLe4P z^0dg*h|D>XZGZ8l76)|B=8u^r-5J(d=6JPB>su6a&13dUJ<*J1oy)i{gK-GRa}Kn( zG}_V3!W=BOG|x{e_x$~1NoA6{F2`UKdX3?f%z$NVb2DxO%YAy#Gtc2iFEt~KX;LE-^qc@D5&nr^U>6T9K0%Q-G4+AYU8xXz1dw_RG41TiXO zr5~gj)_EB6&hx3ur&L06KL6+}8Je(WHFxe0IShrm4NV0%lGJ&i2PL3&HG{G@W9KRlQ8=BVpt z55%6)#!Sw2*uGw-Kmg6!+^Mx}W5Jr$+%0oyyofxvdCPYxhMB9Za~#&?^$taO=TLP^ ztuf+R%;oM&@c0DeoQMA{jWnsv-|P_u&okSaE`Kc{g63`hZL(x&!kX*+DRF61LO$;~ z+tyMfn^hKboZiyzK1I3b5&NaSIL2A$lGc}jSOW4q2k9-%wm40jJ@aKR2dJWoQW$ed zZ>ukxIIvXO?0N0HT4%+Gzb4L&9~T1+y_#kPQ#~cjx=D&J!WmE@rSLr_M&Zj=oaEVj`Qk=ml9bqabq!Y zRayF#VC*d+inlz`9H*mgBQ)&jn3$Y$OMhy0`(X1}eF}s{DIJS9xQ*YS_GU--=Hort zhRWE`=aadx__9bizDl*t9;ynTvpSm!-~1MMsZ}fSbPndvZbL_DY_oh0LA10+mQb)| z4p1_u`B=tSGr%j}(DjzUH={Qp{<~|1OCTIclRetmagyF0!Lu)wC!~RZu*G$ogMR?E z>==!W6J^PRaWRi>M#G`U^|vMm9PVd~^cR&;W7E__EFTf@u$@?2E-3c=31) zRL$-b?*i-s`vUKyxV1O%?~xj?(Wu{b+_BHB&jr-l8nn+NnYCf}4`6ZZ41eI?S_;`_ z;x|C^kYB4AWMkl;^)9f>sE_pnvM*SFMS5*A?GJ-L_89kbC>7X8_^*gQwgvH9F?+~= zqnN-J;~z}Bb{O?-9Jw}_^=kkT*k9VGkvw3pxj%#5Uf`En5_gyQW#}dH!)QjZ)%;() zP&OC!3-~qJTh@1hbYN>~AAcBRU}tfE0Hxko;1__1!M+kd3uYPlR}?SUuRj1OnVqJ- zisP7#wtf`wxX;>0k+fi2asLD>W>)}ziKUiZCH|kD;>u5=DP>dfAMu)PSA7w`;(n?R z0$H~6*8dP3vGLmPpcJw1+@oWrs4{#-G5YH2`FRVus%{U z#^gZOCUtKO(!3IvYX`*@V`)P;kp0)XsyHShnoWGV#i0 z0iIW2zI%muR-u?C&w^64t%A>ij%QntIs*b)*(t2^pJW9)P&@l!t875-e8Q5-Ucz%9 z?e0JE%%@3#Jnwmp+mFwBeiLjI)Hx3_%RXV9@dPE<$r8P+bWbeX zDL!G-BF}YFvaQGGIY%eE1a%$(xObj)j+0{>Pdn4G4eUGaEVrEF^tOw|NPy)yO(rtj z`%`-I_hQ$n^Ba=IwzJM|!4-Ad5R@qJtk7}Wh$r9;_8fR-V*+rsM~LSSimEqb*@IL? z(1;w5-5jH!_4ARjp-|Hd>uk!!7erTug2p2a_A7Hg&9G z#~OP+b&ux!OoMy@3c>QauY?Q%O9V}NLzVRA>?|n+KY#8AQe-FQwe#|-um_NbM=Aw!oh0P4BF#_l90>VMJOAY8{8n(-Mh??l8WJ6{|A2I9BfvEVJ)FxqB}vu zPUz;x3xA=K#Tem?SBcKf8Ij=)KP`WHs&cWGa4Ztm0Of2>51}D1RhEvHN|Ki|J4F%R>ZW;{ctoG%!{y0`^ z{c)CB>xa|w!)fX;|F>5wQQz&SldK;CQiHYM7Syf#Y)btF{|7`Q@pr(K-%U{;@o$rA zBkHd?>LTkSftpDBYLa@0`)OEBgdfdPNc?BC{BTnT@z3DZ3#f1Ar-7_r2C2Q;zaXf8 zxPL!JDJuXUi6qQ?#4m;^f0&}~;SVO&38=qz)LrX)0cx)H)sh+k_qni|2mD%=`hfVe zXgoOiuV~i))m!SPX#-Zx1lBuR1(4`)hj5MHa&+2r>q`NS*mCU`lOlGU z`%%~sTLkzcSc2Gb;)kL?$p1jo!-n&J@^;us^~ruDHk|dHAffhK`%QubY&ZAElu7m* z_!}VB*dfHPnN;$N6>01?ez7k-E{XzR+$pW?q?zgN9JR5cg@P8v& z0-xN(@)6ylYyg*wGzSQh_hz^8C-MqlT){^DA-@3jn)QVstv0g#Ai*1(1NVU_gIf*! zUc{=MCVmB&Hjez214|*A2n&s&&6QDeHx#mlK$#gAq#0qxi)Z&3=qlvwBz4H^N)%6~CTG4Bf% zWV8_PC@fVnxk;5uSe{a)dm0ChyH*TlqD4jC=A5J6@-_+7C_M^8m3369GK(#(YjU?J z!?1~DCaeAnF_WAso6@w--CZfqk0Wpok%1XX)QLT=Gr&ZCUPJDVvWC8%P?td}$~wEE zWXN!GslBKuCy!oKl=Fb7D1Yac4$*25u8OFr=QFR07O^@FU{jzn^at3fwd~M~pU=EH z4{?@WTIwL{XmSvsgRgJ8KB>c>QW2*$2QsOwsl5s!d0}#`lt=Dv^b+j6LG+zDQ^z5e ztC;AK4|hQD6}F^|fd`g^Ic*es&Ib>V*GN;>N^0-Li{~@Xio2(&oPXq`aYV0l((0T6 z{LnKRHB#%8N_yxSjrz!S%3z;*Mx*w@P8dt4p3$g#vGav)G8$zk0Zk?~wdeEshPtZ) z1WOp7Pdq8^p1O+{g_G6~X{VIH1^!M*VdrQH)B%ttnrvce95k+ZH0tE+nxI_Tlz~li z3;*DjEi9XNz+Y2OP=6DVX5Ww#v?wg0oJ}T5Hr7e>6$t{vk%ZsHaJIUG-@h!BBf{MD z8s?l_K@@?;XnaQoja8GJ0y|Y^lOMS!4M`gEeBuFecMlt+Fi}b@t0;nC#3;|sF%6=5 zWwWR>$?W-jCgV4z*wO3)0EGn8ys0a$%#aGjw1g`9Y!3 z+ym~d_u!m@?yK72tI}$dTp{bq)(Wkz2+D*&*tJZ!?oQ&@19BwxTfN+SR$W*gI7zfs zy*BsW822MFcYk!sgs;k%j=W2&%V$HYD|WFuML0pgkUq^(9{Jkll;jYI%aS&kb2-a! zikcmcBN17iub~h(6{txBI#xm!8tG7Sn8im?4u=?rp+g1N>q%AI&r2Pl=CT{MnfZ#r zVI-~vL|^1H5M6%NkUSQ(hzm} zAUdIF9$J~D9i^T#ngut=CJ+0CS>(|BgR78o=#<_RIz?_yocn0eR)R&*xD@P;x?&5q zD%zXed&@gUA(SE<)tXEH;E{sT)!AIrk{*>^SRa=cW(h1N79auW&mA4{^WGFwu{YJ@ z;Ep=!{C{xIx^ptA&IFiFNo`U)!^j+{)?X|j7G~#=P;nom2T>gE=^dt`KVd5R6EZVQ zQIyoFa(h^Wyobjfi;$DUI&5+(wQt@Wx$t))xr>hcnt*_2G}C=Y6dgMH;3Qaai7W$5 zGr{GjG<-5rJsF=S5R+Xe8beV;gCQmjaq}sgXn%91C!;%xLb2}Y9d~!x-E|#GN!2Jy zN!9q8`npl029qUKVM~tb6qLPr0 znSY64h$LpiGH)s9vd~_-th6h1SJoH}TNLsMpD>}}5j|UNXjstr6qSTe#25|1*oeqN zd*=oPxe_jtV`u9LmX&u0Nauvyn5;S~eMZ>IBQoa+qD<>VA{le);5b;b1_;{_>dqD+ z8wvpCz{b>}VgpESh6`}qgdK1s5`LkHp?^co&=ehNaabRMXLKKKXbsoI4pDjeA%|0G zafVYbnxTt7cUGhl#<@acXmf=eV4DN9CT8uC=ZFp#s}VU{YgX1L5`=4oZYm8_j}r|sXARIzrNt38T5Dk#j(>5e zlv62nE+P;B00N)^qZmL81Yxk4R0tt(NF5Y_1SK{mC?PBuAb>~`r@?_R5D*9jKmh;% z0s$EaU;qTqFwh~>O#%17b5o*srhtz1YPB-H0N)EM+iroq5MCzHa+DO^nS%S1zeHS9 zlH9leoerK${mI^&9Nvvze{P0w27h)&+fLEuEJvh|5U6Q}Je@utdJMXSGnz_cPxU2z zv;{Yv;rftahwEXp-kE|2D14FAJm#iZ=_&i`Qg;pW(;hvHS{%C%${V${^X>ooG?bLs zO5V_xe;sTgT?R5f{xsSyY=3Mz{*M`!MI7k;onuG^R*RanzTRK}QMSdjEq_$lZ2!2G zu#PoY8oQfZC*DJu7Ex$l6)rw;?HVX{O(p%}zP{V;5sxwL%p~)x>fbN!=3L}%&WX{k z1N)NDgeSg^n)#!F^ zAaOlX4_ANh=vMSdW;#T6gb%zJds*t288>zKs||Riz(~JM*6@#w9c3BY#Vv3z%P7Gf zYc$w?a}2Oz$`5V7%@Q%a%=p`4V3IAv_tN;2&($F}d`GtRHbsvqgnygH)?o+Fd}|}L z6c^d4W^w#7A~hq}#_c*cI!&3MkX8Kn(hFcYerSH+Iz+PUY6)pOaw>cai<+}F)B0>f zciS^rob2@)DN!ERRknGZfrthrCuR1mr%S<0SMk}VnG%W(d>O;vt`cqV)~>A?4m%-t z)A~`6{EI2Q&TuN2v41i^%Rae$qCEu6`KxrRy3PE(O@bqNlWhq72KG=Cs(tO^m|$%g z*|v5xA7lqZ?3E%jPz(tDsx9`|Rkz1EA0baaI&Erb`00hy^+VdjVgLibXl6_UnwDKh zUGd()b-a1~keE-FMKhzNu}ef@5BuxF=q!({Z;uw-7R~&SM1N1S>%xGtadBl|w6nUP zoM9mlg?fKvvQUMzat1FF?1m{Wn%M@Q-dU?8_O`EhBQ=M};2*S&D_P&MnZ_`@NHQI6 z$X1fu$Bn2KLefPu!TkZ$m3F4Pp+alr?cb_bQkvsV#`OBa z>GEn^nDwHWUwE1KCZ$1 z+Wh(MopE$=s45VA+-F22h%@0YnCAJ)UlaCtgt!q_?XKHv`>@wsLA+aPI%JdiZFKRvy& zT5ss+G=DYRWhl$_WX%Sbb<@lw-ZbGKT#@9vZa~^-7f;I>u^Fp)M)bO4FP#=Kj*4?t zYwgUe+i@|dCM|=}l4H<34+8mrHS4C%hsB;<8WpdN)^Xz<#zk~N$dx}QnT&N#^TU$a zVY;&1qbKh{@sr6;rq5wmjR>x*s)znCT3>+f#D7>bQ{t(xa#m_guckeE7SN|4!b;A-rtt{ z4W5cxr{`-2f3`uGPFnBN4)W(&%TIuSv%oa2XDsU2=b}!1EsjR5kMXFrosU}A_5yR% zi+>yR#`x~{=YycM8CEfZEod+WD&xPI-f5-x6h*Cl6VaG&vq5)Yja*Cn04q0h^`k#& z)(+rwXrm+Bo7ynAsk^jILC^NQj(L`r%}ujEHFGjW-f;nbKrKbn=8W1j;<+u(zx+uF zuE$Rt@v|Y9N}N1ugrfuPk-oE_C;BXZz<=7Y{D>O&KHoE1ZAy+AJ~Wuz#c&I_L216D z>bZKT_NS872U<15VccBJ6K5N&9*538Mt>S)@}vXNE%EHpGhGG7$z9NtyaA{I=KF4% z&F{z)hRB3IS@coV9h{vx4k+Wk}+jY^=UmLpMOC3 z++OofWl{o1pXvj41{jK^ogCRC-ZCGBI3{Qw-|k?wY30yc=kn>P+14pCS&Vy%o_sAw zpWKMDvl);*bLXBdR6Ig_a9hW7y@QR{bKC9{8%29il=RS=0jvfnzRh|mlU5j`{#g2S zrG{e1iTccgeOMxA0Ud)$XBIS{yMG&jG^6W@CZF^MDeY_xBjn9O&%8TDCbM?~p*N`I z%5%ek3@)z5($+b}XHYj96ID6f*m=J*Hq$vm5AYuaIj22v9UV0m9|AKcd&4SI2Y)BxA4ZV| zR1>;}l8J6lqP+>(jOGKysjg4h)wJA)gnnSs_}z2zag)7f{2IfL5`FGbPtQ!p@tLWP zLwp)EVR7848Yi+1kkugKyrYJiO)0ycQ++-W)Zt3yjHvgddO!`wahXV-d(8=%7?J*- zUKP|U?hYZofyo)rJ#zDPI)4w)5#d1evU@-!*&Dr#jD%)=cRqK@cxdy7ZeB%fHLlw9 z{hac^JsmYmPLr?oy_wuM@iH@enljn?xmG=n$ooLf6z)dDI{apjwasbu`O993r11vk z>Avv+Qsi9BQ|Ei&Z|uH9%-0|fn`Nz!Xk&ws`dOLvCsfP?JFq$$CV$P1)A8Uq9Xv;- z=DmrY>m!dOJQ=_@|(5`rLJg zq{*hqm=B#oMp|cgj#!NbY7aj^rgxxB~98gB5A;_Mvu zVMYVwqne>+Flmeh&3|Bc#{GsQHR_)V8pXybv)B;ibION3jm`SUu{jUo9722?dqe#M z&Rv^|jT76VohBoN8JfYs9A-D_F@B9!`*J2}K4&^`Sx)qD4^AR5!K0ivXEAmM6~ZG$ zcjf=2T&X)GJhyq23j zxZ3WcviV=m(h>06yDfQB2M^l5mUb4KfXGfutN_PkrmL)B%M<#i4PU3FI=b6ZW83Ps z0GU?V_)4S-Qn0E-bA6e!ZKsZm(E3V@EWM!8AG$;UVMt^D;2(>7BZnz>$=UL6$B*p| zP&}OD!MQiGw0|pRO3%WZ-WW`vw&0*V$Geni(>zR7PWwBuG#${U_fO4YgJd*#Km;)h z2S%c~%{X8Wnv;R!))XAzM%wW?_}=$^uGZ&O=P|w)RKMH5kf+rU{DYzyX zTo~A-FMsF5hn5rCOxD@B`SSTkM5qk69uC!)c~AXvB8>VfLFC`Ont{2lp_+O47t5!Q zKzT51CINWmTnU0@pEzVs4C50HHhm7*@NyRxrg(-S5P-uJ zzW60tD_=HLdTfG_`p-k1U+Q7vQ?~8&IYi;ke1CcQB@i+%I9oKMWZP?k`Ox-q{}4K> zCV9>t_?IDE@Yqjiw^kS!8Pj{4Y9!BWKw0NjVxHw43mW@D{fBD~QQ|st-l@(dibYX1vl$A9=nV-YHl`m zTYn9)^SGwQZ)n}NIpJ;j?}5}YhJ?1Amv}9mmbi@~PHr!A$;tA$0(R(O=QKMfy)B`Vr0lN2}&$Sd+W#4n%Mu0KnJ+<#m=JNKC-b!q3~m2H?S0$KKykL*oq>yoqg z9+|f?hgE#}&Ly`8t(%MC`Dx*jkLrG6o`hddh{3vx;`sskgnD#G!B5+@ZqM zmOF4-wS<&EcE&D4xV~GC+S!=zmt3wFaBHk1MvcFH&l8R`Jlc%7yEZ?OO3m)G%g# zAKhhD{@vxVgWSK_V|cZ+YA9u`gFbs>b?Y^DZI4tp#yS00{f;0QKrcD(v-$z=n(Iu$UY>E(XWoj~gXr0JC$@Fe}Epd*n#fxJj z%JLAHNus)5<0YViY_5r!xqlFE21ZSv?gM$xQpcfxn9Tl-Z3A>P!^cg4=5Oorfq}aX z-vx6ATQ9FYnYT!6J4bS$VG1ju5ByCOEr=J6Gw780hxu+Ae-l)W;=w%EF#oPBMt65k zT;KY#Iw0c#Y2aaAgXXSH&gp?SJOeaus`d8lo}0ooV;;DsmMw|dzJJBLXmNkLIs2F{ z(8k&t{YlJWT-|7If_v^1zq7qUO10cB=uaw@jIKl}T?g3!XC)tpbj~&EIkRUe(>8Ny z8d`X8#E~dw)yWc>Yz#TgHcD$qMW|b>OTY0~!y~keagG+w=ePhu_GT7d)Uv3Eg0pU= zz*2p0y(vMITFbr;hJSl?SJ^F9!-KW?oU?8-vra`bb-IMu!H*4BJ!JkH`CkYvM8iFI zHriIN9QUUm9W}p$%JDECZc|^L=dunh z!FfOWQW8{p^BkaMx~0_3egDf}uM(OMT`h5i(whemSPr3jPQ;*FemIPX4a`fJ4|6+m zX?&LW{2pp)`6^xWiQzJzP-^C&p36~J%eAZpGdOf#W`OacSHOwJU17jYtAnWsJ1wR~ zzADJ>LL%?eu5-F==a+zp(#?BSEHgu;nJ0`~ zR-vVG-qF9D36^}Gfo++7DZTmMd->&Es^^36WmXa9cnp3?=j;{B+}O;O1o(QL^)ZHh-6qwY1JVEX({*$(Yl2EUPdz z$73MO8n_AlxH(71dU;%IiiI+BYqzVHL1gKf_X?JIpi((U>sZ#KN^ssszmx}+ex3S>_u`YW{n>JYAHQ`H*heIx3ktpr&OKx+L@7`pbNZT>Tc!0@bs09;3S2)z>#(Y=pnrAN?F<{Ty-#wj7DHYD;i|2ygkmj= zgzCdmnEuQ7=dov;!LlEL{@aZCdZy_7TK2)){3W8@FO#!inW^m4a)j8kk*$6vPA@XF z{xF==_%Wuu8c!hJ3IxlH21JWfIRMa^LXTI$2r~0cLH^rdxi&!^kvmYqyME<7RFivvXOKf|7M^ z>~=|^VVui+wQ1Qr2Ai$90cF|A6)cPSZSArEhf=;dJ>KP-Av8{`HQQJLq-f{YZQEID zRT<|nU#l*g#A)R_XX9CRa|35EziD?V$$wGGbY7jiTsT3TWvs2Xq7|4~@`oqa;_b|nC4Xj< z!7M<%JqYQ4a7yM#rj}K0`O;^VOIC;NrsjQ1%LD>|W|t#XvpOc$%x!OTdZEiYN7mA2 z1#nScbU&O`o}!yK|1s!oIB)4&idE(2e2$T^tVM>Bb$)!itfyp@&s>>%*(8Em17=Z$ zWM8Er@0={PJfr}sru!#}!B=T)R)5O=;CUCf1xpNLM%kQ~k(cd)u(HmZLzi7#Wci%i z>MhGKAZ3`>#93C47-ceF=vp=pVP!pM!&-8?ljm}N+qx{s#L5A)CDKVeEk7_4AM@&L z50|7~8rhxOsg~mvu(Qu&M=UE5sq&p0{4ML~5oI`E&R*KbXk|KY&0Y3)27hNcx1qKq z;#1CLUX{9BKg31@W{cf@I8P(L^Xsb1q8wHl z17@4fBndawrmvxnhS7E)g8(Yn6*@9`my@wGN){rcR<%|4TVL~ z*fIY3JX@zFeFS!{^VW=IcQuohG7i5IFoKG(;J0q~OJ-2`?J2-%4ncuZp7UNOoGk>SyyIe6L%5c7%y)=x_ z&dlXjL`J)f%LmL(`*+#KTVC$SU@rDNA9Gue<&Zk0ta)9U<+2%LKISUk%N7x=jOWd< zOGg*-Oy;+Jmc@CHS>_bjmWoqGxtOn(mklGZvYp#OF8es*e84PJXUvHS%xT+xTVjEz zb2Y#FER&jpWPd-$sj#d@gUT{LdAqEkG0Nv$*}ZHKft_*Qnr7+lM$W|iqHkH43n|N- z7VT1D!i)O>v!d_Z^6khnc7ZGRdEAC&bsAJQ^NFj=8XBT3=gaA3g9z>XTxKO?w7auM zySgyg18}l22F!|9%FenE+o)~VW6s%q*J-M#lY%`D*?h@l zhl5Kw(L=HW-?rX--SQ>(EM3`)ZB=6(O4{ykPM5n}I7G#| zduEp_XT&;`h{e&%D2lw>m)ow2btnXC9-@;K#(&_b+pwN{gMe&X|GD_nGPej2@wc6) zO&#k{ERW}IH>anwTrfc6$*z{Y(72;DPRf<_JqJcC@4VpTWLIjnMfmD;>_&5`G0R3y zDCg}zx8oq#w)Q#u#bv)59Q?+3n>_h!W8rrm6ngpU7u*=$+AK-fksmVrb28Y=at#oQ z%zrYB`#cf3)%IKh?y{*fxiqZXvy!;a6G)oXaxMkXGV|?&n_yRtp}J78UEVxGYlS2I z%JbQ!WnLK|uSN!XlCxnyb_{v~#Wr@HIGuxVBwj4_4G4TIkTz}L{ zMJ({Wr`Bn-pB|u{ogN+^o|;YV;X5?j3S_Q7D);$uUbFqwfPVj9=HPlb-5-G>V`cWK z$K?_<64L*}$|$aVj$gRPTZTy;w`>^+{*nF+|YK$k_kEVSbGio49dZeRbuv?2))XEg3}%l^=| zN3qBvk9&}-D9~k9cKv^t)D^s0?J>K$ED8sCtD-F_tQw7lt?&O^Qcm1nQ-4z9i*q9i z)!C;W!yP;h9OQD61KtM37&^N>=5R77Y~QC^gInumWtk1iE|2F7h;=!X<+laaT^9a+ z?1~(kJdUD~{fV8`-u`-w$|^g{LariRmI~BXUE%9Pqj>QDODa$BF-R4}qug6{sIE~r zAhkp&dl*d>To0#XdAKOK*?)q^?e<^(5dAbHS5Ub9U%vjoRT6pmKk1L1^#2X{f1bC0 z+$Qq!e=D9xHDHG5R!c}0Bl3dV|3X->v@kS8|Id^{S65g=Sg^FP|64R=%vTESuCPw} ze|Lp7w?h8wx__6e{D0X={}1i1u>SvruCB1o0kDF8)PaG~HAD0&p~Ogcw&=mIbj^7&3}s;yAWW`ah?GmfuP5plhvh0WU|pPFm*Y$G;B%(*N{l zl6Vwdt@5+7va)2YZzW06tDvX}T2w?qQ4yL{q-#>NBRXl=!(2o3xx2#Z@h?Lp2^^f0 z1cC75m3?_0Pg;lsP=Eg4#|ydrf4Y_@z0&bvcw}W|Wg$WT|M7{IB*`bOvcZ-$>h9a5 zRRiUB%f}EbEeP$du!eYec!YLWSVC7RM}%sYj^rqiLGfe%Kjf|GKgzrzTf&4= zhj&5o!xj3|cTt(s|F8PiyDa|>0uU)sV)A+!p??FYsVFWW0{}V4{mDJLF#*_A z>a(Vib)d_WHq3{Pv2;s%geV2$ef+j>Zbz|54s4m?k_@{{;v(iY(UPPE;8tzGO^8_l zO#lq!_`~=^s^%sYfGO33mf`_R(Hv)tGyh7yZY}fW#mJ_h?jhwIf46PVo%9Gt7KVb_ zU&q}^?SD+U8hqRB{!imBQiP_Fya)uy{{xwA5Qx9_mgRHTZP`iXan5G@5Ry^@>?Fw& zAb?{t4bUaj+-iy~9Ha>}#?OjCwaX<$$juFv5Fksm<+-=;8|zFSRS=O0CZgalvnKEDLq9|CiY&4yhDUj1UD36KZ*O*?$<0JJ4l~kTjT4sMJD&M5&>k;(=!6 zm$zrPvn!96lu@+QHY9gDD%l^=>@jMW2n)Ud99uK4~%Uxek$TWkI zzOYgZ_PbW>LGJ$lk5NBz1X-0-1Rj<5fPenLl#-I7VpLLW)kt6)n(Bch)gyy2j-Ui@ zh+_*kDLk;&N;(c? z`~NTll3$v^`_goZd2kIiU`{D&z??@lV1$6+!o-<{=MXDT+U7q;{Lf9z@UMaq9)BE8 zlM&I61USfL(XW%>zsUcWPfTIs|7RFJarOT<@1rbT`?ssem*qbZ`d>m@$qUy~3xXJv zr#flcx%B@sFY`04f8MuVW(G)SWo5O+Hd@K5Ds~gHNRhHU>Eg~V5;6BbjUSnY&|pH4 zfdPR=!sW%+pEUVibauPkW4OmJdw+s+vEQ0@!OZ&w)#6dQ<=9pV=G)c zld9wtzfX{khCc4I+< zetygzpC8j^&deQ`7nfbRfq#rP*$#JE=hwb+CM6jM-DO)8 zW|`z3yDX56GZ;ppG8@I;_Gj)Oo3(wJa#e%RFwy|6jITWnCt<_k3V8X*3)W`v0(!Cgy#J{$6y*SK-Xgy#4w4 zaJ~zH4b)@|6a(z8hbUTk<#y7Nwv3W-03T&zhQ(Iaam)?Z!|8&6|Nqz0rPN(^=L20H z$(W>DceMW>R^{c!j96@=6)ukHx?S0^X&6ScVCyPDo;(wJBjJz$o>5a+F8V%TNI>TmVQuZ+m5)Rr-8>zxZ(qcA{CT^f*lT~)H10xS-_cumu5oWTbz<+3LDI1x@Mp8x9Gy*${S<7~9 zg-4PIWG~&4U;fLL)=t`C;(9n83u)YLL2%G8#?C2OEhQkX@h!>>`7Wt+l}7$V!oxEJ zMix}A|2HD!yDY&#(JDwl5LQf2W?jC}L4nJMnuy&)+VYWv?$G(y+Zb4|N{ZdO)M1s> zC56;h+kgLOYX%{!r6aWSM-(8dS}{zQFHltAAp;17pOyJUiT?l7e4=y$q41;GXqK#O zKXuxE%F0HwbkZs}0%J#c!zM?GnG35ZZ`gFn+EbkLe@+cVB;+Wu;szry$r?%tITRE| z?-CToZzoHaI&H5vPTR|kp%8AUtY%}-oU<`_)PGEKHk{#Lks34@9^|+gf&_>pbaX(_ z5;asu)dp5l;#ffk3mJB&lsHxxs-tRy9n+kF(GfGH3nW+^oxuYLEZ{IS$CN22S^^Ut zBo|<;&=QP>=9t1k2d+i`|8o?ph$5y`TdIs3W@6c8SyR(G;{0Kbvdd5uVPwiOiZC)K z0)GLF=@La4ne&G^%CgMD!}V~wlRo}`DgR*IzV!kVTo0!^>HqTy522HXhlh&auC zC#qEOh(W~oDk#L63WW}is6xy_%d$JzEiJ{p(^*==uwyVt*-Jc}m;c-Cal?|HS=TiS zO#6Dy6hfN3wE=-(ASn8rH>sSVL*sN00u@F27xhC zaxx>tWK~#P-iF~2funa$u8q=U8-I2)b6{S-S{8cYOKb>>A%no@d+!uvPK}7gkCq~I zW+e+bec`<8?n4vIF{69t%jn=-nq`G>X&Y(d>61x^>cE`}OIq&A5B1W0L-|CtXh_#L z39Gcfe#*r7^+5DSP>3@V9683(0;Pm`JPOmN;5*>DBYCAQdsj7I_E!PKv41zF>mtwo z8T`3(X?kD#^OW^RT~e0WdNB9kH{nhEDX}GF;8IjFzvoBp6)xS?n#iG6cYActh-Lh7 z$&UM5MRY(?Z020XPy>r!Y({&yCA8kCJ&Rrr5J#3L)$tY9CfAeb=+J88__kUaBZrGW z4rt&7%&yoo#H9}7;^e}5B7d}g(ij~O9Lbi%_9?j3eqvxw#77^O+vjW$gw0;FM%~dj z>Tk1An~Uw|&UVK42(C&?=$p$fdxsdqF7A(h{9jz-{m8qzTkz3<+V+)4`o{kPfv_(0 z&9N`{U`md+&?qe0W(J3Z#sDXd`E11f!d!S2&C`?QaX+a@1)#(x9Df&xw<$K%|%q*GVqd~#mb1y4}CVKvrdSwIP zeq3)U7I>Ga%_2XS2z9|+(^p!Thq^1b<#MI7N=?TZfNTBfcH9F)lG{X=u-gm!K(in4qriD zrR+NVPmq_`wKP$5oOut$X{~Mh<(kvafO>XAonx};)1U5TakS+>v^9%FK!A&kqF>|>^ztid^YF$$$n@p!Lf(hYrtI?tYUi8G5NxRq?jvaf& z-I6p@N|*SUjbag57xg(lU44oam}z4bx#ceQvZB1#^Fo5WT%AGx2Mz6$(gjDg&TB@U?gMs|0 z?siM^OjJ;}9iHSt-YZ!9{${E}B65L=G12ab#EnFtY735mc`p4@PkUKK25IJ-nFsX& zO84E(gyj@UOC%6G&)MXQTDL$mf1jb)ed*2vV{IO?Z+QV0UcLSg6lm=xzr6SN+wSG( zS%109FE{jXCQc~c)Uuj*A!*(NPADHB=|USDFXf+(S&vd?m=X8CD-VOO#B0jjo81Ry z-B@wnzN#5-D3TH#<@h1RV37<-;Y1cKWOGPuBIr*#mCe}Ijb8$KKz6~Rq^ns8w)TGb z6g#5#*Cl0${Cm53-;UkaK=Pdii#`~@-+#dYuB44vmKOJ4HJN|yyia-VrS%$ZV5St- z$T&GtQo^cWzS10f3Zvg&>k|F6K_WOVQlmCo;X2#_smz) zF+LyBfnMnCxxGK#oW3Jx{ewZ{ruB~ck2~4*hR3qmKD_6i7cn{Gcf1t{0LVZ$zwGkF z543;n%;%L*Y(&5|BSHe)E!`brMpHdQZungubge5t_%>=NeLS?1XEl3hEOEQ(wiYnD zK93OKx1y(?>C^aKH;gkM#>PlkqpA8u4TsPQ#&b388Lc&;4&6awo`~Kr1djrD>|iI1 zS9kOoKkoQ3Ody1{PP;_s1eI(<@1iazZTf$5{491v0h8e}#b{UCom<7^ga<^5ToQSL zFJ&@W|4tgTb-K;*!GYaK$fO+orbYX+?5^u4_pxg85OSu>uEW$W!0TjXytTDlG%Rl` zq#bQFqQMEYvNIiA?T-yVhxqpFi)j;M98%b~dlxPpG}1dp^s_K3;v+W4fL63^Oy_@B z4ah<7?nBeZ^))ml3)1oi)W)p(XcUB zPxDsrY{-;KuojFCY?QIDK-=}HtS4}sbtW6-FC4b4xYk)05p6)%xh3tAxqD6{YxFX0 z!iS&Jm~t|qZC5dCV~?DqF0&1^{F#4ngvJSM@m*?o()GlW!D^72@`tBf5Va&fiuz@Y zjp?o_9{&7iWy~%@P4XVWJ`x;{_UgZ5J~*%4j*fLi^V)8qk>Vn*@nep&USyS*`wQU} z@G;(;FWbcQDCqrxaeWlHvPm?Li{-_^r6p6xMY*$RyUPS}Tuu7^B@|~%IxK(hVC6&% zeMh^U{!T3elhfRW_p)8g1o0#Cxqk(I_lnsz!dE95rPwRD>0#G16AB%(N=up(mL|R4 zY~2lV5ww8UI;?!K3g-vF^=f~@kVq3ATp2bKH&)zH+s%ia4B2L(Dq+NUB0mqgN04)HC>2=# zyD)6FGBhImb77|4cf++ni6>m;%c$GATO)2Y^q{ZId0_lgxW732lN!0Cq&`5Cx9pD@ zpHMu)@v0r#H7FEs)PcV2k0-oLn?mr}IG+f1!~&fMfDir3x%+>1;32ELE}eXF{MOgp z7J?(c1KtG?^}Tu+GwhTmu3%K@4$1cW5>Vjf91`?CRgAm#Ral zA@5Bv$q73kb3=c-K}a!i{m=HVx~5h3(x0uRz+0kte>o!BMDEQiLggZHi0yVGO~43h zTO-2sa2f8!=S+-2aT=EEZ?2A-o zyy6Q*yq(>?z{E6DH3!Tu(}D{U3t4ob9P6K zRy$tZTUhUvHAaSG#qjBlZKays_Meoc@9Q!DA@$iY8~^db(8g#s7I1RitKWE~8)yZ> zxEVI|9K(M)pqm#c$be2WJ5W5qyw6j<)`hI!L}N174KHul47?+aQe``3IZL&a=IwJc z=j!^S$wg@Rbi=x`!fuOAmetqo?f><9Goh6;_q?>R`u_fJD!LjZyyRu?>;SOmj^m$6 zl;wonilL6|7)GkvZL`T(`aJekKNat-Mj65kZLohwmfX^GFyjL4@OyYWcf_~j@Zpii zv2Wd0`YyY;8x4IQG^Q-C=gt!oX&xQM_wNbSeTkfI%qW+3-`s6S*{Osb+F@L|#7_Gs zVD0-(WAl%I=_kp)YSO8yrG# zXy&@P&z#k2gV}{?h36<9OqCIrJJ0l1%Ftf);D~oe9MUopkye93` z-84wj;J^4A_m=Ap8`CFQi9W8fJ>xLYPGYLMU7eZ4+vjQD_vaCGYk0Ta^`x}Q_-UK) zCc1j+x~I1B)0$oGBTn06|EgQQa~yvkg0NIT*o1+Cv|}5&%5KYiT+G_{;V*5(W;eZL zpE!8K+;LYxjr&I7D}}m8WSnX5fw}`b{h3lp{zQFr$n0Z$2#EgH(oT5k1HCi%SeVW8 zyX&P*fgD;kCViP*?eq7(=Vm@gnNv!-5K#QJO)zuTjMx#NcXollwozKtangPt>t8ZhxwSYgJ@#;f#Uq?9R<-Z zbx%bbAkC%H?l*ahsUGy#XR(j?V>6sPP`}u%sNKq|Rba|fG&z({-RHMk=)D#1u4{6S zK2P`>cXsC{IAp55<8VhRds=)K44^?8_tvpI$7yz0a5q9|+oK~rUlM8pW_@J*=x=AIqq)zS6p zd0F<+`aug*>~n?VGwnHcm)fcBi9db7;cWbjzn@G2aw&eh728_cxVC8rq$9D7%v7G! z3_zz8^Ok#e^__~I=)r#s25x%tyMNlwz{xFBaS$HCKh?elUH|kLerrc~GpQ}Y8!xLf z*IcZ!0!~}r?xl9?c;;u!80U8D!ajfGc6dYg|A{hQ_b~U95V)oCwaY!^j8W|y^XAY( zF|UceJ*#4^~6Gs?^`78JN}5?jVOPQ+IsAQVfX$<3Ns8Q zx#h^5y~E&;q+k?w;wiczQp~>%-RU5SY{ADy8-+CW znz5~^z3r>)1JEtP{T`RZwc_zsp1gaxd%+CiuZ@NtB*Ph_nD#ENj?GSzKbA5D6pm1q zyXKTelQ(n+Tfu(`JHqxC1Dzgm`wuN@Kbyl_+ejiJelPhIEHm({Y7WZC@w#7mq{s zZrP9p#Lg!ZoDSSAM>uP+@8e`yd|KKgBL|ixGPS(s2tj|H@-(yQxU0mwFfuVFB3dPF zMB0~Xd|Gwgjga?!ce~~o)hk*49M|t{zr#)r)8k0tLm~?g; zU6&Ik;32lXSLNCUK%sEHgE3Y+v#>WoNRv=H;Z48G3Zma`4cq= zZT8&cRVM>yHel7@z(D!?lIEs(b~GcY3lcD{ zYalw%QCV&%(5*S(4L(iC;V@5c=#V|_TZX^QTGrh!V80gyJe0q1;qnC5icjG6Rx8vc z!*K7U0BlBT^8$V^mR^Rrs63U%R^#mF~x=mx8WQA~7|WBdl>co{_L6=;C|D77#Bpge#D0OWW8I$R(XJ}~A{ z2O%}eeTNk&ZhIq>dR`?|{B}U76E%PCIUE^fcsQ8W;wJGUI6US4I*#MIg|U%HWRMP-sURIPQ@T~F@Th3vzc7FQV^Q#n z(yi9PO_u~^`2Q$8wXXk|gKqyZX5pky9*vDh^F}j`{a62=3b%mLCp|^1lAa<~N$O{9 z@r%+zH6sy%|G)PCz~PJG)_xU|f@xOtja63k&4_0ZKLh%;RuwO?-tfh6tH8tXHA(J9>qzxwcG_4VP=NF?(Az5YK6 zuj~I)(EtAg9^-$Z9VtQox_u`VV~ik^8}R>Mzmr%00}yD1_Gf29G2-L@kMaLFLLFBA zhtm5OBL+u$k{zAK$!eg_;+wXOlTA-EMU$Tz%*|CX%@ixeb*!&GJWzjMrQ3fMvt`;V zN3~_MZ7d&^%QJJmDvxnG{p+i%E8VUv7Sr>N%4JeZPf4ee^8Fc`R!(794fe)0f?$a- zMyj6B%Cj-knr&kl&Y0A?LYJvpzCUBr$_o<;iVLp-XH06{J*nGNz_tBk*i7** z;dfbO@T6GD2OEVhlAE!+btElfjr0_;N>Zhow3@`4J$-_&jShdpffL}d>x5$bv$J6~ zqA`9P2&le_)Q8y{~{r06y3a+$!ihC4Ce8`l=2-oxTTvuM-gK zmD*j>mSC=$GuBHc*Y+A$ZY5WCykqa+1>6Bpyai05@>B6$+do$m^#3uHg{R>2hodej zL2Q}xOw&fw0Y!gInM?Di)-<-T#J1abTX%DFb9;Mx>u@;;{nr!LxSWdrU!mw^saUCH zlqWeObx7S9)ltMI7Q*bX`hX9s7MiT)*-hC_KQR>;}L=6rX~jh*uwT>}mr8Qv1_hopt7MG3WmVcC>@!?tj48m%F@8(d?3GM5 zb54#%9Pv$js|YvRtm+7M_t<@_YjOjyfiaM+R(bg_p3}X#J3!#xJE1?vqAXm?vRA)O zjImo@rQw1)W7d{a@9llxG0GNI?fKl9G0v7%^#b6Z;VQcv5loC>wo*m!K**%qWui*P{$P;pU_|ER2ygKiv8Aed!!`X}SDlu(ti;95-2g=H(>e5` zf+q?=r4x+8w=F^4U#<_>|! z7-lOAdI}P^Tw~I#J_kLuuXLWtqSk+(lr|C+WdtqDaFsPS1Xdga-`WZ<56<~OVrPl< zxW5E7Zd1ssj`~BVyHW4?>b9Uc-BTazX_KoT07^1OyWH>$&KSAYRL&cckLMB;H9k|c zV8D-KytF)bK;Wm4bg<1ywr)yfx$J#clES8xn|ghYtF|QTVKWPIeNyHEm7b3B(dc(CbNK_ce&QuMr8KJ?3Q1T z9UR}7X-lZyDYSmf*-~}-$~gE_`{U<`fW{1cK8RlTX_xbjcxeP~$C%lAYI?(?kuk`Y zRdM+M&r-?K;V{J_XFYvz!8m_XDF5hJ9$dVTs|Qxbn60^7!%d3AWlFZaw0rEol{KDE zI7}|4Pz(6H$EYoekoM+?7xB1G#dbiu$NpQ%citlk*Tq%W!Vm#&jW2b@=_b-fKcB?+ z(SM#KW@#hH`D4shRrC$as*K$&U1Q5PU}ZQ~{lZ!h_1pmD`{L9|R^)$0#+a?SMz>FQ zW2~)J;m@`EG0xVj$n%}lvCCGd=zmiEF=uO)`vuy6jI-rc^Tp>oX4wh_dj$DSt~0h@ zJ~WrfO+fHICf>4&kN&H--q*3L3^65{@&d;HJwsodqgJ8D05sEd`tGVyM{pm<(5<@4VT`+VPV9jlV$CshORDZEwEmdi(slZ3 zX{v3LLA$0-Q5ndd65=PIZ5o{|PyJ9LVX6-s<5P)K64 z+$F}iEvwQFVbYsx-hA*Mro;|on6z>of5_FswW60CHD!NvY;(y)9T$s=%&W8BtTK^q>`#!y?Vj>`jfnvP1BKF!$3qB{C4(U%!I?rkeAjrxO1 zxhT(kbt~4gyP<70XP_L22wTsD*twQzZMbNCjPX{MV=h6irBd)LKb!b;#+)8k(KoYL zS;~RUlp}w1_p9X6M`l`RTqUMIUApagQt8?O)X|X@;QHf%BPb$Qw}A~#ea2w6Y#`#k z{KQlWN0hojTJc=-Mdw(94%V-#Cq;b6*LnQo8&;iMM+^ zn#Ine>rp(%+F!Q9aLhw5nPV2m8LvA)!Bcnm*N=Zr>SN~?ugB^GKj%^=7;d0rjBHIc z-d=Jy#%!$$pO3j4W42yJF5pNRJGMeaM@06GnJrcCJ21a7X3MM2DM!uN*b?gO3WBOk za=i7$ZZSEA*IA0t^|^>UldQ5TIG&7ds$Rqf)CgUia4iem0MKI$xYY%sm5iKa^=+rD=0B4m~GV(jJO|$WKs!C$LQ8vMgw3D zrP`N9zL33rkX*CEEiHS8Q~&akg&u!HC!`|nE2m#m6i**m=pibAY=5#b*Or&SfM9V9 z-KzX3<*d~k2dKWh)%a7JSQf5A*c*vQfVc~wh~+}b9woERxQ^vpB0s+JY`uv)0VJ*i z>~e&w&4!@HFn()Rvik2QjkJ8{1oq3fX0K;|4So24hu%8mWwpO@>W+T5HGhAC#L!wE zN_BO0?uDf043q;98WXkvrchQf^lN{vR*KaJk1^!dRH5OL(%~}I+a4VeE>-RMz?Wm( z)~TokJVfW(g*DzheB&yv{>0Y{ap6gs3dnEv5}iK)MlT zV|8XLjI-g(f6;fz=VDQ2vk=^Jtji4beLpy_#zVMQr0njp8{uG>VlTrCsyPP8HPjvv zy98F;&%h_Dbm~tk*NIBaRksDL{fBMozyLXbl3kaLc$Yy_sCD@$j-`JRRSQ)4{NA>d z*Z#qu8>TOqu$%r>T+RK+VO6f7=%qN;S`nUSx{OrDcs%In{mZzn&+QdDht35Kmgl#2 z7p5Xyd2@%7o}ByyIKEqz20B`NPlnH><63L%PBV0r^Lp;*{*XXN9b&leAGCEhE~xor zm);T;{lDEI=TkFl!0%Bd0siJv`!ER_np?e1(0Ahnm#gCt0 z#;i?rH2pua0HRyuPATmG?Evlo{*Jff>G(PR^>ExI&=HAAwlIHaGmX0OX1*&Yn*y|})8 zeHL7lwPrH?mD7JKVL6aVUm53Y`YKq`p3q7Ifxj&FMb%c-lqENcpHiAp+$+Fe*4F8C zTgP{L*Lm8?%F4=$KPfuVM7IgbS0?R}j-+@*k4NhjS5+fu546Z?#l%&|;#fUPXYH@; zDwU6X1Ud{C@XLdKW3xG}H6;|2WQKYfV5FoK%mp0m4ZVN5ej(J{ZcgX;&9*k?{0H%cX~f z>kU(&FZf{zg|0PK*SbR2+Cta*-MY}>_&gquj}vI|TTt^Kq0NXLDd0DB>?{>djb8*B zpd3N0WxBY+w#4w>H~gX11sMbgDQB%trUp>`4S|1Qh8S>LyM!?wf0l{lXs06*lVD*i z-WV@T;|GXAx9#si#Rhg;!jNGQ5Q<&0DE9Rud6zo>&|&o z*V=!nYn`P$J#}1QO3B6!%I8b9u;|E$s3WNllU@S(ar<+ce$; z<;xVwb3wHB}k4B(tV=iKaB ziq_+dR|bZ`ho^9>Y|#C^UKl`8&NylNZa1#)`zOu-dCfVST>FfelGX;c)=Hc61D$_! z1iggT<8Q(K?S2#cvnc)*`lmoYiuIRZKMA*1j#!w^mM211q zUm(JxRQF{g`XZ6le8eueh)s3^$yP@wT?q?ZLi_%WOQK zD37_?qzjmHl?zR9#PBIxXbn3Ie#fjWQ^6_l`Iv4is^Il4x_?5h;^*10;(UKQI6Aw> z0M@Z)Dep6<`~)6>ceNwzdt>C5sjCgZRJg=SFE2rum({O}pmWIsF)W+}Y+eUQkp#4W zO{u-x9C|0@nAcX-Y4!O8xVnnNMF+=%Td3IE`zGT`bv~az9rNF+(kwt809V)Wh$xG4 z)mnF$=ONd88RRJ_O7FsTYqo#z6@5Gty^F^hBv0CC6^+;W=iBH1M3{ok8*lpvX5d(C z3l;l@uc0yM7AWoViG{xIhZ>^x)N=<8#4oYVc95Z8#U68QO&wPcoP{f^Xt;QI?78KN zwY|_+T*waR6Cljhb-V!NFb3R0r8nXqlq*;J4*zfLw*^)6Mz&M#h)92~g`s9%&DXXi za43153ofPEQ75XvH-t;*FrLx2f(E0D$%euRL};wLwHJ%F;DTPR(2eV?LT@436a5<8 zZ9hlnRGHyhMusiP>XFuho}HLP{YmHksQq8vxX`S|s%SnLgt&H<3qTjgfLo}-BmRbQN#)8F+cOjnBq<9}_Ch!z|&DM2Qu-uNA%A+5w=!`~_t>}LgHOAYz3fh1zVaz+W zwy86I*z!BuTR!Xd#GL3P*p6g%5w)0iE)XaDFEV5<;ntO1L}J$wgumY^4juy zlT7VW%MQq-eTASrto3r$>m7p9-7FHo1e_9Gi99OV6;YD0kZV-4#ymo+o7#)*RBI@ zK{dXhyU$U7YdoA~t{9Q$4#Aa-{kjgJ_p)c-894TDsk(nYf3}Tvwrrixi>=2rTd2bS z_g-T@TUDnQ%0^?IttsXgVCON-7ApNCUu(=~tLpR%c}^VwT?HplIekpHvgniUpRpk1mdZTT$WL{SD)qYCgZ; zJNDmF6%)fB-K>SpJL|TUJ3E zU>l5ix2{6V#|F;l?l`rW@w%j~%us zHZtWKePqk;ArqNNL910AcSY#iINPgF|6b+ovb3X|?t~gDPTc21=7FZ067<%Y;%XD! zkd=Qn=Csu?yO963bADr0UOw@4kjlCX>^j&GSAE6QvKJUa(%md6z<`}@`nM4sPVw&= zvz$}b(-@0P3RX%3nv<5sK1z>qwpLuX$Ir&JTUfg1`YmJMtu4&?<~?KXmR0CKu)c70 zTQ2|&9D}!@x?l8G#-3ZNP)FpUW4)~@)-Qk9uUPCN=gI=U`XtCUJ0eVD5S3`W)Pioj zgurZpMsG%4syG5;84GPeb++LvIR@N<6}mT|a#_;nT<7EvACE4_0HG zt*zkaV(&4{7OL~}z0uguRu$`iveOu6Yf60qn7eSnXizg5tTE$uckRHN#-7qux zh)=8k+lYn(cyO&*E)sXmt{8MRAmigN(Wop|jK78I`kBS6Qe%&;Ddy^dvT}= z`L=v%+Y=6mt7<%-XmJeRiVC-Ye+buH<0HP%*ymOi%MSB^T+r=&18mHdR?~lh&cZXI zItzWLhs!1G+zBO8HT4L-U<^tNFU|D=+QBjZ)?SJ}D_5OB$QazpHus{1`jbxnqJY2Z zHUd39Fgt~#DlS3@D0&HDvAN`>I@d0{dX83f0l?QwYOeVu~msh@X zwV7^^LxGl6y_DWDhhQLVw+GM)Da~ ztM}W83aQn$;dhModsj>EiKII=YVkS8i#)y?Hq%*po+KW z1I9JiJ|91H?75}tTEJ`|t}XiU^%42ivCq~j)DGMENu9VX^nPLr%zHug^T{=Q%hTP0 zE7Wt2ClQ(fR$?_|#7HnO(5|A_FE7iuKSDKt!nMm;^&5U|jX_&LMVC(=d2^x=P69r? z$X^V^j9u1!jib#c3~drCIg@sk4$tPE^Pk6NiiCf8u< z>T~-s;cdv9dycdLpupX_9eyEUaQ0M<6vZbg5E9`W-SSFqw8e9XB< zGoIp2W1d^9f~@&Xa}__$h852ftPlFxoYGmi$_P&Jm}|?F#)fcuxU!6vk4m)2o9hNw zNYH$1_2$$Y`?i=mRzKW~^|wr&!^PIdlv}96+xxF$ep^+i`Q+EzI>|OkFbzxq1~9cs zpjvSb*<}Sd0)T(4>7(=}VHPd8Pz8-fFcha3S;Z^H+3~=e$uT}S_H<+8?XPziGn0Yy zXBKeX-jmIu*Pb)Qd4`)dbeG78@Dfz$DD>}oDdl;LIi z%isS0y;v-Etf7=owi4__ZNf5fm*^xVlKtZVV|<}Jq7rdeH6so`)4zcG1T+tWrzZX4 zFTi{nGx>ijA5f0n*-Ler_RIY7mob?ici`?!Z+O3^;tR9hA}ixD@B?S&be$Z9BCu*F8ev4zkz>C_GSAT z@M9<+w%-E!6?o5p1zk8yeG2Wf)cg}L795;&m$Tt+w3Wz9hsnm5P>LYcm4JX8VYfX_ z+6sTf;){N{|3DqTh7GdSdg+avbtj1@btSE|mzI{6m^9O7>fgY98vO^@UtoR$-;=*R z-G}>hpauegdQec?wwy=11Lt^J_BN{SSX_ImV-(_0SQ31bKr z(n39p4hDlk;T8&q^w9nr>TmX6?6={54gG&K%$MPNn))tSU=5Lu#olzEg!>aZ)_{}tw|@cjt=DSm&VzX|e7$lk{M5WX3VF=ibd#bOWQ z7lY8Kg1l%-k~9W#4G1B`5RB|3Z5tAxU^oa9K@f&P5QqRFKoA5$5ClOG0t7(_5CngO zAi|UaYq$gOn0-sD)9Q7_7`RnSdARh1F|buCczadBF?g#gcs}*!aG9N4K&vyhY;9>A zk?w%&jOz{{H@J+wo?;e^g7Fn!0aTU`}yp!y!$ zwp1-#o|4N&0i#5enxN3iXk#k3&M<$N^<&u*z)QxNzqyf64>CsEVs%?Rs5pjil~N9u zo;U_<)e7ET-CSI5C-Z3^;Cd#yfIwp`XUoNN#BBpEXQMj=HpVzxT_LCFJ7bqERSB*X z@zgWPg*}s8__LfQh?>tPFXtSg{Tg#@i5lC$b~+a|<>l+RlrRqYNaT?)^)`P%%n&hq zv*^_g9ph}Z>RJ6+8Dnhq(j2b#VXikP+XE|O+^trc^U>#y&8<}d3rIc0b#`<_pfi@U zICs;Y1b`8rl_VXePX#`FK=m-kP8`Tz2FJMz_iV6Jas1WR9BV_a{T%#Vxh zeEHOujDT1{3Biv_?iOLZ*~WinhHxg}EUwIu*@NNl{9Zv}G)Bq9wW0Nfu@73dEW09?> zy2G{FW8c;+-R&{6W8c=O*!i@j$L`jsm<2SY$IjNQFe92(W5<@LwH<%#>ak->*4im- zYwWQlE1A{09)2dduxFABf0olGbndELT-;X=3C03jT9t;YE5^XBTFTp_CyaruQo-}7IiJhzu>X#kTdD?3K}yG#EiUp_6nFBcOeH_dT=IXjJa+ivYt zaG%D)mZ{at&%Bha!L?Uradl1oIWv%`3{l-uuQ#CbgXmrnOO^t?GhRn69&@5UHrWD| zY6G;|SYS(w@bdNVHAI@%3NM2qvi#C7;J_!?Si+eZ@vY%{O!H&Rvn2rHclE{qlbUs51F2bp~PmXNc8szk{Y48&ZHpE0^+r5pkz7R&U`-TYb{G2lYsz-;qzm(_(q$DFOLbT&BKj6JqwVEUj5NqA$kT2NItp#2%cbBoX(Ch=W9#iB@$&BbR5(K~m! z!7E3M5<6Eh6`kw$qICa`b+%gZZ8-Zmc5KO7yS#su1wOa%g&6~229gb;;{OW?7y{DX z;@qEiU>euoQa1?e|Att>_8@e}rhUM|$(b?$OUe#vthz;2`3AVpV{ywiJpL{}{Tc_A zCoxJXut()U)QlBFNYvgg4F8bj4FRf0dTWYGMrWGL@M>Hy3YZH+FK|ZEu8})>Mty@B z>u-Oxs;&O49Aj+t(j2ayGd67P3fNv+G*)iqil0yVV6L|#3jp89bxb~8>WX7t5(o_YR~6#JGp>fXKZe*(l{c;0oNJV9l(yU?3Py*Q`(=gVM}X;mEun{j#Y7v z^`OsPyT2;&7Yn*qa$ktNc-{Wu#K_*mZ+TNTUpNC*iD>Myhiue!iqk? zv36)7QYf`A{a|natpfmr1W-%>0O$Y!0B~*o5&-}J09pV508mU&VQgh|bY%bn0M-DY z%1!|QU;qH%$(K(_0Xu&kKryJX!HGcuTMH8?wJ-f($PpbH0Mr;qQUCyW0RRA?dHxas z0001N0000-QbKHHZe(S0LP<>kGBE(x0002c%Y_2~U;yBtUjewmB>?|KK~zDA2?hWF z08&mtUvqSFbz^j2X=HG6Z*X&f%mG44O+#;NY-M9~X>V>&a&LcdWpZ?BWpgmiZ(?cy zAZTDSAOe#gkVYUBAfF%#k{_=i5U*gHARHjKuXvAOu^_zQjv(q_pCCw;AX=4@AbgUI zAa<*g7Lt@8l$79^AVPzbPLh})-r$(6AmpuJiy(r8B81?nAT+5Ut{_yPo2g*3AaJ0v zprjyX;FKV2Ah3U=a$u$)F5tExc#I$@jEx|Eji8Vqh>+ljAcTlus33~CApE%CuOJ$= zAduj-pn)LvAd9t@;G!Tp;DaEXgJ6LmUY(+ypq(HZjH4j%qu{O}sIH)qAdaAbuC5@g zAi7|RAhe+%AYh>&g&+=~oT0#yAdesjk0AI!AjY7}K#zaSlA!+}Skh`B(qR2$pwA%K z&q%@`(g;cdTmuMh1aN)(MR;&;a&*{%OQ^xID@lzS!vR4Cgb0{!h655{AfPZTB!m!X zh>!>jhZ#j>l%zO(_|~Ue<1|~Ym6!6xPGpd`G_B;()i93v-+kZu&8_AJrafnG#l!KO zDp*U_R(OBgw~w7an+;$+`w;T-ONRI&h!+>&1zq_K{q?$3}#O$yRMqr>1Mr|$)j24GcpZ8 zs-SFIw_EgIe{>>O41wP(r*feKlkN?2+H~mWa|VQx2SJta>4kP+zwm(`RJSeHJ&!SC=b963JVuS zPPo2ipRW5tJFGXO0s?T%)@V`p!=xr@^4?F}s<;nji#AQC$qps8&N_qv7&R!hFa4l+ z$^ih~r~nF$s2@-uRyxiY^?k!a7OjPi=lp+7EY$YkhaK!F)eMNq9?pS}_tkeqVQ5F{ zv-6CvORao3x?)5NSQC9n`897;qvSFfyB*SAyRdwld{LeDuxdL6*a7PS;E!G=h}u=am4IvjrEMe&H>cu_neOJ<&zeHjYFQ=VG(-ka&mP?)Cj)N+5WKl|hO zLX~Oyf7#L{>3_3-%1R2B5g0rcfi1DvJ5m8Rm@-lXf+6QsYixEVi7rwV(gR;G8$y|1upfjWV4bWSNdP0H(bY^NFz&^Xb`%`Jg)o zbicL8NYKuIEdHOi>-;}~l23on9*4_H{-4B)R5b?_QWb*>3^DTaw>9~H0(t$U|BdS( zVkAa57u<%ppQl?|^mruCno&+ILqGM|fD^n-er>Sz2L6x5sxun%-=0cIqPLZSG?d2z z5!zlMkYOey|8h16m>r?gnu#YbMJc4FjN&FMc5*v_FW71PEC z{ZB=aZn@H6*DbppJWz08J(~?>TZpfp8S(!qRNXt{G7|}HHGzLj1U9e~OP4nQ^!`in zqpL7(cUzeXwRYYe(c4ax&F zTyQ76u+jx&E{6L5ED4Kevj98=81sK9kcu!;1y-2R+g;%#n^4S}{MR`_m9fWm+W%^f zgt!-S4mM;Qz#->XF~tzJK7K^?Eg;PE%96P&m%EazsdEUK;t)eEUP@wmpr&5xdQ!=|j>L4qS zR|x!rUYUPLXiYCOWR=fjeyCRxd;_^3+ZY6_`q^CPhO3uMMxn z2b^l-8X3h#*Y%FrA~;J7MrEafLZ#>H|6ANw)3KYto1=58x+1W9xTvAYBtoO(o%DeD zzZOGc@aQ`dheKa3$uL+XYH+mj<%})yY`a9Q0kVGq=mF^vyY3jOvc-C`kNE!^9U8X> zmK4x~pz;4%3-#P%P#ByF8iQ9-Jzy>&l}lCU_&AUCw$tVRDgWQ0Jw3sMfSaUP8dm?y zhO>b8e-^`_Q0fOf5`SiHY(Yt7^vcJ78Ah*~Od_=7)R3ATz@@h%&enwMYJc0(19a>n zkuiVrCiK487w%!|g26H+(8E}eAv&N}=qqs&OiKNqHH1XsQ3_ZU9CDD;za3cC}Oy z_MWxqoq~`=lZG@NtQD1Pjr~smgubE`6Dwp}#O@Z?qW1>gBF>_w;RQ7-pW`gn|3rnp z;L+D!!L54*eTAyFv3T9gWZZEoYHE9A7jW=s zvOt6;1f&%TLjU5nAdr7sQqh4$t7Cs~ShT9DT_{*Jv6`QuPxN+HEJ`oU4uG@tzk?GiE*^Ac#gh6`q4 zRcMC&&lmrN#G^8?Tjomi$iQV{v${zwhrg&JsWMNIL?cNm84j}_la}i#ti3j6#oK! z4cY!iqrKnJh2ksiQxC%4H$T^C_7ge2{K8#-HESv} zCvb^Nzz4&B04LDl*$L?0ijn7pxPjzRCworPx$=nIQ5$qke&2Q*g30dt?r=8wENYtI zU6e(>0H}_!VO<(W@3WTt#8r-Rtw(MmyA_ef6H?rF!tEeLx}1zh{jPTdZX))*tFfAp ze(s9h6W}6J(|lpgZU8U9&6C!!pi#?9qRXEA}{C z6as1rG147$!^VlwZ5P{R;=1paIZV_G8*`P{v-k_FTN$qz&}LaH{}Uvqh~g5BLVex- z33YdfnI_UyV>EW%4Yek&@7;>RMD@Qrew(-#O-yjE%OWqJZZBM(r;3|@tgH zMmj!ktR$F+VFf4JzG4La(v6txKjG{qMD=88ejfchxuJsz>}nV5GEuwlI=?2s%`+^) zIkF8jW#0lk>}duW;Cp~YF0g%8#wSjC4=Vs6Z3p|rtVCre-1Kr-ai~Ax;QooTOU*|n znUQ@LYqz5?TFU?M?vT8Hmua%}-}w};N$I=k4&XF1w?q`)0;(IMwZlb`&JNkU`~C1( zNt(;qidT&Z$MjEpyM?eZfzCNbVFzrOXyUu?HaSdm_uc8YiErU%hVOb5{{m|mrOU1N z{-U1k=QDiPb(%fA;oY~rV(&B|$o&(|?m(C)p|i`#?jRciOnP5`J3mIA6kvWy#FO34 zj8K!s6f>W=!ZwH^U4Zh2=;W{{)|uPjiD(g%zTR))aO>?{1|V1TQ0V>%wv&j93Evz% z>bvU(G?St8PQ`3e^sy6_O@bGh<`b*WqAyUp5hXZW&Wy~;;j2`7^MHr5VM#%0-TsMp zw^W6>xoPxw(1r$oCZW$Aip*r`yK_35JTIQjB*U*oE%1l&(vElrBmH~B4k z%$r_=RsV#%JBUsb*wi|jyWR~L6V}(ROJ$<;-*tXX zoEN7}B;(a07Vx(+&@=4FydD1&xG3>05`q;Q)v3M`dc{@2gmn5RwB18|n4nXR(b#o1 z#G3fNcN+?S6W#yr^ljo>bTYxWE{c2sur^|R;>xH#Yx?nmHOy{BdC;V$5kb%vKhYDFu0^-svV1JOAFO|7GO*V~{m;eFZlR3>WwyUy3dWwG=` zHc~C(0)8e2I)Jg6TnJ>ZLiMgNaPy`3SSj2?S`X{)ZT3#iS^QhnTHpon1pLTJmiQ3<; z<7?ttJbfY;ql&nIe;az51vo{INR?$3`1oL>er@Q?KwhrScf=LL7uP?*>?ES{gq&-P ziruk6)#P=4SAv+VzU>C{ljov`8BXO<^b6E~p%yP4N6uKs|AdmLx0rD{0VaiUXu5ym z?`DMAgl`TW!PH8 z+b5d5Q7UV6_-D?QO+yd0{8EPxOtwbN|K0tVLiJC`-HGTt0j8GGyzAYdnXta>dQ>K= z|6S+z#JO17L?%KNVF7=6MQ!mTy~HO-h5Rs`)MVK)%UZa#)gq=ip`QMUzgq}5Cy+U3 z6zqTv6HmPR-8P1acE7v-K5-Xn%|o3r6mGnz;LtZS2?+`L$}PERi*e9yz^M?Tp=1Zu5i}JdEC(4Vv z04=D=8LctQ8C%rN2W&nPF^LFqx0FTLofxO2nGN=hDL(7WnJX=z#L+{=Ec!}r31#qSa)lWilk2<*R!3fGZxs)96mh-N)M2%N{pX5 z%bT~%EF5lC=gFu-TDEe_va(tLIn*M-rMo8FcGqGtN2h1?WI=QC&}YdO`{by&uPV=8 zrR)|^*`imBni9*&^^nPvH8kekFz0H!n@*hk72?HLvY3~}0;rI-y-x{$-709cW;9z< zEL!}JBM9oLE8+|OZVQ;jzknJdH@h=_eB2w5cpX$H!rx3m!cY6x?3sz5LH z<94C=7q9@*{8T6YmNL&S7DTm}nJWZNQ?73HaI zo#`KV+RR@@@U(W5waQ(84);OJWC0Siy~sCZ)tV>1h(dOzXTZ@?Z^=Ml+usGB+$-+- z%dsCR+X6`2Hl980Q5%`*APm~fUp^4@cw{e`^FpcHaOEd-!R$b8!2mr%@E z;K^4ZSw^LcSy?WC0^FAMDIxC59K$-9eu__%{1S%vZFg5WS+Csd&%r*lOco%)?Ty}d zytd66`|^>2o&*|y-Zv8w-xW~T_z(ZncnRdsKfV5wMTBn^X@le?u>i`t74+31Pd>mD ze=GX3_F&M4-xz`@x4X)kyj9@K|G0NjybH)gj*p+qQ{Lz>X?9e-kvZ+bqmmVJ`&H!0 zTZLQx5&I%#vH)=)#fwqIOp_n+^b+!4o$-v*BK2gCaII8-&G}KuEPxopb;`t8of{wz2r(9T|Y zV!PE=kCUxpyr`vfp(S5Ht}VV5wDCxFAcP#1balLcQ^4!X!_pUbZug9ael@0J)@@9l z(U{8S1|EA*9!Tf0+^qa?g9jeyzI}o z@HyX%Dt-uR1Tc-dI!mz^>h68AY@Ds4cJO?E2e4USbIeIR-V^DDhIijUz>|2!a^8Lu z9dE-(0k1C)`nTh%-RfX&V7j=<3dUz?vvW^PH8kF{+{PmCdjdBbq{ZE6Khak)1^`KT z-|w~Kna|hW?d(!V`5ixS?O{K3)27#%v05Mt+t+KSVr-B(r13#B+@>sbTTI2g4y?9+ za~jMP;F_1CPX~;N8Kobe-eDe|9HCv;x05|h^X7d)Y5p;3&bkwr+%K}uXv1lA11PmG z{h)Y41pwsV0jkOsYfTUkMr}0)mH4&QZ)Jr)*W@x=zE08hinpP^HogO>asbrb@vMH& z{egt&{ZHW}#Rjs8@&>bElA5pM_W@^r+&jS}cpMOsAr^`Cd5BB_c?LKJ$_9fv7Tatg zFiBeo%oYNJw1vPR&GQUZJVJALIL7(oM8gilG#8LI!-_{|q9)o@HSNSeuvuI&MXAJ2 zFd5KbV*@!O7d3L@VDC-%lfhS5@d(ZQ7R5x^;fUYh;^GQ(*kKsLpA5dBibrRE=C>%O z!82A!Gm9&xna^!*u!z%^8ORyA`2i~vRt^sf=Oah{qVqg;WFvKGRQyLv$QgvYs3C&V zg6^p!nbCJKT~ilF<*JSkh-3`zf||1 zXDGAn$4rC`S@h`xX}F6TqFIQ4)t9KO!Dmk$+01uH?4ms%h;8eY$=*AB9NAzwo-ogUP$F!k%(fr1 z5GyZFABfF&NV>8HpV@j%(({4X-aFhy%@7-OOc|;icU({w$k6=EIGK-T1le05W-c{D zX?U>BGc+3gqb20=)R9dTO6wU-;s9aq9fo#MLp0}wrSsI0&HMz1k1LNCGX+Pi==XBO zKa%1f<36OUpNGr?142@NA|@Z$k{n~<@)L87GncTqVm@-@Z!TdGZ3aZ*1&G9i0#l$F z(RjkUd13cL!URfeulq5{jjt~I|_no1!r ziNh--Pe|U@vP!l}l=5_Nu*xTl55yE2u6D8;)tgeX?LAWu2r_tzknOvE65I=Vr| zQnEwRg4Diiq9jIt`AUf{Cf6w9Bm%9G0`!gk`sj+!3lTrHMHi?5{vi|8KHOumx5>E zVQ=_?(A=x{M@^USVY2O<)=54a_1<5Mf3FFN&CegB{hQC50~+F&8-y zv5AK%F%a@XN3FF!U>tR$!eGm4sc~EFmkb2Dam8kv`io^<9Gx7VonJT_b(r6{d!&VY zWIXlit_IqF!N8-F!*gT~j>c)rB1uFd8RKM-_f__2nQ3)>kPNb&jPv-k%xtJHEpVDG z6s)C+!y1|nz*r?rRuEFOp{%6Xn%p)Zk+TaD+}MI!RFvdM+)yD%@XWA++189XgJJ^q zaK#qg;FJn~;8)#H%q+CG6Lu6U>i?d-za-%IZ!9){>LUQO&0@9LH!B<0jZVwmvT2Et z6#_~D<)5_`^AZdr(G5lj2e7+j`s)r-g-X)Y z#9fWNQsTFU>sGy1x60;{tEE>T`R9!bgffM)6s!4`sE^SD@g9;jzfL;8UIda}ZyJ?M z_{58U=)Lw^>NIUe_UlVgF{QtjYO%0ihv_ff75#NoXK5=f)%L;gPJLx8- zUo&YXq+cUx`PZ`kko`Ce8meXUzOJlc>Re4aQ{t zlR-Q@{$BnzSG~3=wN)4}=-O^%v2IaWxvE)z)RpRn4U3|3sa@HuR#c3t_H9lpYOAeo z&!Vunf{tBrNJQ@ldkeg93guDc1G>NF&}@Qr(~dE(SgxstD%@KYgSI-S#kwgm{689> zqjMqWzY)jS7WMj_xrlDL+A0mUD%@LDshsB%RE2v!K~;Eys&Jp6D*Wf}+}%1B7q^ao z#YLRA>GWER$=C>@>7Bz`xz;T<`=z)0<3MmlMnp!hSgzx?YUOIHS*%tXx2>i~0k$R9 z;+&o1X_;wt=|~|22r#_-I#NL5@Zn4p=>PNZaDq99hsck_nY;g;LjRBdk2pph)B*@m zq!zj7`d>_wrF-N*{X0C#etI0dKA>NJ6P>wSDyvsFt(D6w#r3bh{%a6?NaR1~`+KDb zU3Q*DdPvw)KCD0s@ba;zd<;H!&^o5sfyD6(W`=}@?$HV+%(w`+d5}%L?D#dOAyW^Ev;>xX^jm`u?>Zx&C`*QjRDK( z1C`=ldcmM#s4BcBB+Rx911rgY26pLy2!Czpf(|J$Zn6?#U@CL@U+ri$rX$Vk?fSit zjrxSM_h@EjR@TgbBl%7IeuYX%G0S7(phHTG;XfHX`w6V>Iz4G(Jv7~6i~6WdOMsGh z)T{uNO@G~V)rZy{*LCg2N@Okd9xw1K{mNufq>$XRq5JLTjft>g_KEF(s7u^24m#ou z^Sw^7+$zABL}rDlaP4)^rT26B__d^E$W|bl{&P9pC@B8PqZkxb)ZkTM&6k`P z*8Me86|*n;=GQ6wy3McG{5s9A&-~iVuM>Z*!LP@^Ci82=UmyP3%dZ{ywfNUueqH$M zE5H8!ddjZ@f9>Sg-d`tw`L*A#`+mLmYrS9N{rc|L-Cx)J+QzTBzs~;p`s=t~zx{gp zYZqo=U0G63N*{!Jj&I&3jhQi`7cN((I7!l{cUQ-~zPT_9>&lXPQu-it{NXVMn%*h? zh?`WP4Opn)gkN9#=pWsqGiVI|2k>hjHoxv!;nx^$!moL>&VLnue!cTwObNe6YOS;Q z>kImV&iQ`<3g_V0#{Vt+8t1e=i1a+mJ2Df5-pr%SZd9;Hn-^prw6Q{W``>c%%l|vpe2VRC=r#> zbLc~skW^8LqY#E7oDDo4j6pjcG&1=EqG`mE5>wJr2qmN>IfPOjmw@d6+8Z-$+{o6* zL8C?&3a%4>TVPsWV*-eoNFfF{2V<>zZSmH^jVwl+bxM`St-!u0Gpg;7odr^=rD-~B z8CK-H@HtyM>uFKef+tI=gcGZI#k9IwRzaz%mLil)P)korB$AX!I7fs)3hJOC*#U^d z5s}f*2ce=5LKuuY8u@db3^_g*dVIo=*D}-Ux*IEhv(yx5XUwFM+{1&cfwauDx`6c1 zyEA}C0Xy>SvUoyr{Gibl5(J2z0R`mY{qWJ_j>nGM(baJY*bbn*F(Yb2M-3A>Qe<`H zz)?rQ05@#Zph3soYX4{d&-f2Ru6liw;TEIKDqZn{ZHk?fyUK`Rje~u~udpr@Tqm}`w3c6EPywi-V`3@7 zP@Dk!62OF47uVLcWUILfO7)z|k}BcE8qo}~oT1OG5?EJORa8^|olWMK8$1Mc(9jem zLdgWRB=l4yM=7D6NH~pX62Y{jl!WwO{vYCh{}BTYk8wu>B|&gFBD!GI0|es8=tGf* z4oMC~LqZ$=YXJJsfBySm;MqayiV1V-LMU_fjkFh^Sm%!he~DjuB)I}AhkYbh0u{6$T)!3rxLp^+*fYY?RpL$O(Z zTro*OX+fh#ZXIkOXXK zD<&tCN@IS&N`M*28965f$E+hq{-pE{!$1{}&^V*Vi6U(wFi2Yn4AM>tEf_fr?i}Ez zUY%6*gbhtjTnu%hL_|gaH_s4@zC2*7-h1|lO`mq&uczQz+Ea@P?^AFs?P=%zdiID- zw^b7x|G%j~AOYMXCf&?5VPHG2)po++1QuNT+93+Nz*I1?4Il-!!M;aTOAdM?IEUehxE-Zy0Ydm(QO$`k8iqVCmDYAT*2J-FWiOS0CDpR zcSjbOdahs-cp2G4%&0G3?sl1f@OOnb+sVZ^jKGZLeky7UyIm34Lri5jhO=-Rxe*HI z2#W5dDpeTB2yffT#W>4Q=k3`%^B~F7ssTmdKI^2UPpbxeHqSiBGSqpilZw*x0BU75 z9=RCmoM@s!!OgQUTnv#+V5>HAMFQ{_xK66Xv(B05Oaejjv}!CahB_yIp3O5YxOo;P z%P@xzY}H1dcHS;A<5O_W?8=t}K0LLkVDc1PGke;3yPiE_ZCX@>X-=@@3a;${_lTj{ zd9`3WZwYXZ*aKj}wXiFPV|!pNDh|-1!s?Wt7zNjiz&&DUc3vN_owr0!iWR_uYhnKr zp~yc^SBo<>mdCb9C_JQpSdMYuBbQ_0mE-Xn_#Xq0PQ3rodrac@AN`Jfd;f9osCUFW z-W_=ycO1J%8^`N$I(3m|CJp=Q%CeGbVp5WiJ|u~Rf_l7cavqXc_OMK!4am(nHlN{89cq{WM+3?iB81*|{R`^!@+N-i{uTE8Z*FGD~NC z3U|V5fj)y=R#y=Fh~&NP{TfQD*;l}g$Y|7S90f6jC^uG(7nk^{;>>B5Fjg*528FH0rtQ*STE2y=mRqypdJP zxmC4VESIdsUa?%C`!-AElC@Uqm-AH_SS`0q-g2>B&E-=0+rYN5aowsiwA44KxoTAl z_ojFHU&k;ZfmdZ<|1;a@xPAqXt)hM%<&)VqQ7=xHm`D0b}~kPKw6L!uN5m+@>X=Mc&%g?vspzB zQAHvz(n=m0;;%<6n|*I;CYnb)O<*Hvt+nnMt4p)u9V*KTL&3Eo#e61~_QSJ*0|=_8 zt0hiSXG$rFDMvYt_z-klfmTL#Vl3(5MID$#EDdD{0@{#tbhSkK?C3BZr)8$qm9*~R zNQ--a4j9>My%nZ{>}(4Km^2LS6 zp#U+##2MipBEw7D39#+tiZ}-KVhdrhWNJr$jUD$Qs|yTd^Y|e9B&BO#dEk|3liWUV zhAfq8cAQ<2mI)5KM*zB9aX7PMi235>LBqDo()X02Zf7OPU=^dtzN6sJ2$6uT0&IgH zX`AibfPs?^6gCPDVm=hHZ72^#n53|<%W{y|(2UzoU(keLF@RlW<;zbME?aqM=9Dyl zV~=6+l08V+PJl?oqrC?np$*EI-6VQ~2@n%(z6B0Ip=>{4p@Ny~uKJq6(j;(Kea%33 z44JY=@FAaB*qZhTKIEF%Ch_(ClCVj9edD5GLm!2Esz+@neHekw0{2qH5+zIFFIYkL zh~#(hFYIN6!(BzC2PQ)!0AZ|9cUOIX&44Q~RNN!@km0#7ls$qk2Mon2EzE=2wU?0`MZX3>@T^aO`?lVQP?IC#*fMHI~yRXyVtbt*wrs+0eP8(5C!q| zRmNUnEM+XDw<|VoTh+#K*{X8XOHpmBa#Sshs@7VAtp-+GrGZse-Kg0u+?+Lko2AOJ zRcUDH+}NsHx)w4PlJ$*kO1a$5Rk?FkwrvgU8#QjrR=vW_S+`zc0*HZ?nQ4WYK$5YL zxN&gS>zkJPHb>=_A<0-sa#}2mE!>=y%dKwNYE-Q>Zd9*VDh;NLg`~xD-Ka3ws&H>s zEn8Jf$EDKH(z%(9Wp8lVZg8!CG^lQLTJDughh^isRb#Ya*=k_pwo14;>l-z0tGq$I zX1CV2>h?;7A!8wN=c-z2b~{Jaa@pjrRv1WMTw-2ZD9FZEu#tIniFt)>A<0-s)j2EN zTve%6R_Cg2TP4>!DZ^|3l zwmGbuHA>FfrmeosRj+MPZrW|s^;(T9o2zEW++cu3wb6ZXtpY@Cxo*`MSgkY)i_1+G z8Oxdkz96PPNwQg_Ze(PC9W^z@B*7^E#t*+S`5T3PBhYW``Hjfmc$DhI+ZdDcJCf(p zjJi!6s)n*LdfA+xC9bM}rbv`XaynuCdhFLo%@J3>PVwsy%qA4Sj+%dc0_@jI5mid) zuLbxu6V9~o&7NBTpNHu|7DB#Ss` z4;_GrbaF^@5Yj~dS@`t^J)}Vk1#JM*pymTKBnUta3277skjBe@n1T+(h!I>6h64yJ zm|%kkDmc`@0W#hu3Q&3(_Ujj&?5NUEma0nAW2DEHh-~hlSRjv?Xv2taQ@N0!D z#4QLAAwl#E0HT*?z>fm*x<2rF{J8VMqlewy4jx^*6JK6zWNI(g*j~73vF3tBT8kBG zEUE+$Gb=k&VMbPeCRGuIgc4KIQV1oaBsqi^F#zBI zgRun?90EXsF<``$>7WZ@1YSCTAc8O!9B$yicW{HZ6lS?1WiW~r1rqoIR)Iq0$rL9~ zhVU)()j^ zL3Tm~7?(7SZN&?;wXn0UGBPu+Ev>FAXOk(F)RcsO6hg_UHwc(qAqcRgz(3IkHB6O7ek#LOuT@An`b2?Kn4WZs;xYG z#O9}+*Xk*__Vv`FV(%%q_Vu*$T0MKj=D`$bS8%$wGN%FDBQ~Ro2~n_}_e%#V*Fd4cahel3=&^*M9n(KnjKTU0B zR2jg`gFy_9!=pKe$&is7p`~h-lZ!I*Q&F3fi!w{qDkC>S9hjJhn97}ZJ@;I}wvW5z zd}Kky-f@V){0lvH9ho%f8z3m`Dw?H#d59SW7g%NPxq^A6^N|G+oBN}kf1$_Fk3bJj zBp@>%{rmv2HF)&%!-EqEhJFMZLdS&1Ip&=j&O)4=`KSg&#fx~p8nZY+DladEGfXq*Y{3iL zNwJ^-kbl_=Qx34>7T+)7@E&BbSchnkxgTs5?i{JnM zaq8W<7~y0eAYD67_d?nkD~s`7vKg4?jt!B!BpR&S5({`kV-RcCgOzfNSP<}SAA!6u zIMQ;rmBK6dtT%X_;E!tB@hlY1xqCrZ(vBaA`Zit&YjmNI)zs&z|9+dAeMLp}$1Aq$ zpCa+&5|QN%9zKsV9FIVMv2eH7e=uC+-&}60EBJF%F)8Wh_#47Zy~~yA7Ai z_wm1Se<(Y4|IIP$zg=!ya_jc;Ts@0Qtr5R)JJ#>P-(>LbkpCv3lSzVW?InRs zee_gc^c=?3c?DPJM6T|430J=(rs=#~<<1++>G-gs#uDS)s;;@~ajwhXy6ZSMP>#9e zI2XYjb=x?1A-}nQ-8gp@7hUf-cYj5O#<{#Y;o`@+O)*=JbFux9TaR-$@qk;6b0>kk za$Wy^yNz!H^^ePsZ*ek+tB-G69>r~9+Oj_*X-ob?`P*{(ORO!!tOwcBYrkU4!WOyc z`ZutUlxn=wLEc<=AX(1oW^gOSR*6-VYlxSPdQ_h+f`Md3h5PPsyax?-bAOzF{6Vtj!;P-`c)qK!^=Zux(foL?ohyeoW(dH` zS-9o;ztI(cxm#tN%8!ROy2ImFHoDgFwgIi+c-^Yl6U4PUf3_2Eru)s49Bwi-C`=EYw;`jd|B2f6N$_B+bx$>DuA#-U@2iA6C;+vQ|p zkD#p@(8*W3zlgt{c*u*8yHhlu-~SSc+X?;>*|w*D)+dycO%-QGQK{RI6=Fn^Z9qI- zNF$f3jI4E&FC9%2rXDnKEvm)y$@dg?Tv3XH-Nrjr@=XPgL{C}yL*7vWERHe`E2L zBd`5`+{(kUa3ei;t*`@lTZG)>Xn^UC_b>6}rUYOf^@ z9a6hr^M|ANDZa6sZ^{YP@3pQtzn+|OPq4c?Jo8wDWb<(2KyRKC{*U}~j_Nkv` z7Zy3;qxvuFntLSlpwe!upX1;=UJrT#_xTC8u42%aXM(f0ptW zwe^v$=iD4pF}zF{dq=r_qsPwZzo>P55xQpO6-DRd`HAiS5_V+Xa^l=^dppAm*W=`W zcE3*ZIheNezL*pY>--G1Hc7Y9~(7_G>Yuj|DOojXreA{30fJwHeNV4R(}8j~H_7@)Ien+Ocgfv@+`dS*Z^`K}>4#oSJzLN$!Go3uXG+Oq@;OsZ9+S=uZQls(d%S_Z<)0|E zQ(X!TXbyXO&F*W?HOrf-app*eu?dz^8a!hkdLcO(Nrsk^^j#8tnQT9kd#B0vH90*d z-M`80VHS8!64yzj?__nJ+&v_J`}5@Tko35g%@<|lG54Yr+0rjc&1d$6S6RYqvYK^n zUX#^6cJ!L`o99l}`pB*zWm8Ch9yuC3Mn{rt_J}fttUhFGlgKi1T-gxyA0X7A5$B$NtJ!@w z8)Z#DUd&dHu4MP_NR}FZb|M7ftt_MG*tkng?niBBcjTVJ`QOgvduP*!=lsK5J9^Jv zX>!wVIHgJ0ys`INJ_#Gox@0{&G_{P%KUT{rW1IENuT`KP$E?F)3fK{bx}DVm0|C9YmyAxWgtv{WO2^)P_1cbIQEkYE@14ozbM*v@aeGRICc& z@m-?!))xRQ#4SnFG%f`!@`R zkzYS_JTzc11e@n4eMoiOSC?I#bn3pEw6PlwQ(m3KMi8*Dpv6xn%ZLwMaL7~hWic0s zw8MCVKu|z11H9({qkTtqxrAcsCVj?i!zk348`+U+lDA9wm?Qdqs-yq z#p11)04&xB8-b2bv+VGur&x8IMO3ri2VNSVb$M22wAQlHp$)B2g=W;EE=r(4L(1!i zT{O)57A%?CZ`r>^xLe3B8*jaNE`zo2|rHV4x-4M3?CZ8KI=$oHSG+6MO(> zQu)V!K78Jz5hp0M7p%#%a|}p5=icq%gZb89+3!+y>OcMo(m&pKH)200AHY)@hzu`= z`nx7y7_D~Rgqjr;xU`%R917fKR9lYb>oMu8b=14ewHpaFm09Set*6~%QAD5By<%vM zwmY6vwdqj>{=*PECEsUMm~~*thP24b>chW(t~ArpSe#iQH}Z)ab+fqf%-*y?`-4e$ zV2^GUBY*vEq*H-R(9VBk?Sh+$DmRj=jo#dax2R1kc-A%7froBp2S`H{`rZ2 zcmidsp8f;3Z(AX|V?&$zD)j~0trA-l9s2CPPGO0r#I6imh!2=$Q|^^}a-7)SZ#%)< zA2k^dO(ZgJh7LG^xBueSw1m^kpVS3+Aw~OgX#o4UPT$|cv0JCbb|u#GFUNHq`z=}2 z2c+dkXDjmOKUn$#(poDgB46z06Vm^G>-JmEtB<&45H#?NGZSTX3RY-E2-!9~rTJ5W zm%Qx~I+EeWNBIA|U?=t8jtL_#X;wlVwjr}^jfS9FcC|VR2WnmQSd@fWH~V6o!nf(J zkd4qoRN+aeJXs)(_5Af_;Y!*tLzjor^+KoC+abGM;4pRTuOukoMGtQ_!e4=H!~1TBNpg@=1jieE7bD z{rMegI=BdN1PUiX>$szT3YpP=N7noau|L7OM{1tv_Bc^VBR8`V2mjByd3fCEgq!rZ z%FW0o((%(VvB|S&i;!F0QNZ`>xpflfMizJ4_@~ugrus%du6zxv=d0=#weus}zRw2U z$WEH-u;4#a-mwN6!SxMpM6~A-3%dttY8{7`x_0H@ryBYms%MvO9d;joLkTvEONG(O zE7GAfE52qlWQ?PSGSj~!h+iQ0*5}c_xs}U%T4m-$y=`;)> zT=r<+0^RJMHdj-zj2CYzPbX4f2eLYnIgpvWlnAVfOx~uLY0}#*YF^8bdj=2E6Lw>&x|tNWaAd( zG_^hI+Ji#xsHcZ8L$}>o&y&yPMTpY{>)!Z$gpq@V{kFjxZx7V>dvCWJaNEo#8~?xI zw-Af3X0IF1dONItU)D)ow_s<}aR98T>fsSgzW_Q=I%Wa*bNU^so`0Xw?n5^3bM0^A z58r>A{PQu-8tQlBPg!i^4WqA$_16Jyd`}Z#BU`Ws#FWuE`t5xHC<*l84wQzTwW%R1 zGwc#f_-W=|5v1`8liY#pV)Np~;abzv?c)lhF2oqjXfyegP3_J@1l$Y+aQ^|AcEG#70sbVQ zt{af00%X^J9579D;4cXKe(rUSOAaRq57lm>&G|F@uS{=-+t2f5?y7AFe3$^_#MmlE z2hbS4LaSFjjwcRu@&UOjHec%c@{oKK5kbG3K-uXxzxw%|a12hT9RBtAh4J5?MF^P5 z-3{+U@jnOXUcP35GwbwJmO{hqnORyI2oo1(Xdrlh_AZ;;Sm>-e-6r=g$;V><2puY> zT5yG{#dW{m2X|<8TWJn1$%Ey5nlH3AgWb>t&X3Fz0Z6u7x@M!{M|3&mmPCOEQNERH zr7FUPSTi!&G!P~(n9xA*tUETjv5+%$dMb;8VfM_K_#`oMR4ADLxfD`s>>E7Z3Lh$Z z)1?)ED*am;n(iKBQyz~z!p^dJ(P&S^Qh=0JK8QQ{nn^sAQyb|@%=wQv3}5*!`h69{ zKfD9<@yQrpR}wZ?F<7|2rTA{HC+^X`3no8c5y&&b-|5oqvsv8Li_{G~nfP$@v*kKK zc%L9U(h69o9K0G+yeSSV~;lgBLn1r8ZD}&K^t9jv89_owZ|gNoYk^|xLo$Q z;WIzOAN9F^7Git$ZAJy8=r_$JpSp%6)xKlO)UL+mTrHj==Ca$%IL&v0ci(q#QPa^P zEe}1#f#g?WdULFNT%zg!&d|0PwK4+lW*Fa6PPcGeM&>~FaK`e0{`iP1FuFf$KbV+* z^&!{XNwEJY)mVNNz=jXB5uvpKeapx4MDyT3BJ$0CP^$$5lCp4(>$Y10E70R0@%nDX zx=o&$6AEObd|H}2ui z?Q!cK-|mouH+S?#eZGtP_woZ?KZ5UnH@H89oBJT{IegvTM0-0#IX zFdnbgQ-1emtxFu`l9O~hg?mmi z%T>LknVfLNbSN@h@M_XFx9DoO&(*-=iyOpZSb$l{3EpsB551#p>~mZe2tT-6Hnwt* zOAB@#6cjdsz4L8h4QFxdo2{{b=o;W6Jfj!2TljxV<-tV(gI>hv!J>VO*IOJ~&|_ui zqLmwWV*$A)Sx&#E?UL!*T0*|M-JjR=Hi*+n4?6VFOEirTJ3D5ZT|w8i*7ThBMZE`Z*$=|D?u+JDj0?zFOAjzuc30tF z0iEIF0rdNKe*-?I;$fWm-ayR*vP@f+MYEl=7R#TO>%{RkzAkZt+c&%p-_3I5Xy3R; zxmFHZx}~+&jomg2)|Yq8_Cx|hsa$1Uep z{F=>H1LhiF1MU}{P8ht$pq%{k?%96xiy^$f_i=dyijRZ)L4FLi|Mlbd<)^hkz-a>l z*_KvLOWV#MpH{tU`8V{bN;lho3VpWrrS>1gJ*xb){ZMcR>;ANVdNcG+HN0!LDD>x4 zd)R&@ykoUjTKg07q%vN$*cQK?mOMLCJ+8cJ=Fx;x)$ca_l+4S@OO1U^dsNrOrbB6u zR{hiTUkV=@ztw{iFZyG`FBPvfeo6mP#gztsrSQ<6J3ZEhrp2&^v@C?R`ojt>cO`!n zVpdg$p^?cv^dD7!mAEP8qi{RxuYrtf__%gxg2Ic^IjDUN-%3}4uC1Pw2;rcM`l7=85Nn;a2@s;GRkY+ddU~QZv_D-BPTik>wP!W_rZitGOm28F^-p!rn(id~ul`K~x6;p4b*}kKx}Pfk5TCX6B#?({ z9X-#^)Xs(tm(#K_>}mM&>i(urca}G6ykePWtC*AivAs3nT#Ik}nSM*$dtuKfuR_mM z_O0Pda+j*?$RBItj5z-UpmgHXjIhqmz--20c-IzxlLvpGRt}-#w!&?X&BMnwKGq9J zWJ{l1yI}31ETdXPA4VBO+(og6_(h#Vwu-#s87mqo8a-2p$setpaJxcp%;&GwqiHlGRBj$b)Gc6h|!H++>Pv_i@fl4O9v&p$3WEdDL^SA1Lc zRJdDz@>ViibXM*p_-p>LJ-Oj({%XrEhMH=$Ja@E2hCAG?%zRyH$yw`|E?lR4kaYs+ zAI~!N{Bj@!y-NfRY+zZGq-#f?ZL)k_Zn0#z)L`MbaIgGtd8OD)WhHJ*JEAePOqHh& z3~Q)?VU61Ncf&i4{p>8=9IaK#8l6$vG1^Uksx7J`R4bVAYFju@ioJRuOl+i*O!XW9 zSM+K9o<8%U>HRzZoE$TkoX@_amek_frRCs)p@qG*ou!4PIr+k3P1`}A67cn^kJmSD z0D(Y$zf5f|;ceSPd;E7`f64t?O^(6ar*0Nn_tabYm&z#ojob`@XvEkbIUd62*@wUS z5JEd!e>F3n{UJ`b;Az&bc<8J#LvB3OM;_!Ev+>8X>YjCwcq4=;roB&(UV?ZB(8X_p z$n?IPQ_7t+=!LVe5-FxMlG=B{U680|A*4(IALEWxU_TN#7++kEC&l;>wurG4Ym06me?!m`kYu=@bZ=2Hj%p0ptO@`ZLRk8v zt${6JmgE`c8qMWP_nl$4Q`)!1c|_9T1ErWXq6J54!gyKXqH$OM4Eq~9z#J|2xX1`h z+KxSW0QqaCnG%cthml_u%3j{e8H=*ka)?~9@?#rk*(uLw1TMl@qG4LhLb?t61xxd5 zf7Z73c6Cx46sub->`}hC2+$M$MwW|SVpE=&26pIs-qPaExJS8q0Q@7KA2t#re0hm~ zX2H$a0v((G2{;?l^Z@LY#xv(;e?D>eOQqV^`(P1TAFvqzliNWq#1g_Cn-1u55Hl+Ei)gWujea2d1MW)7?QsJxZO9ybO?#>!$ef0CYl z=^%yLV~_!87W)eOx?zMlDycZm=tG;n^w$H zhB%2*$}LsO+xw~fnY{Td>t>T(uEBM04oZ$W)&Ryz9+b4Gv4vOPCcnS%_RiDN9)2ZI zjHM0Jmt&ln&oZVWUj`X)56;SG#<09;-HZ*#Z=7;x{q?!fyACd=BiNQ4e^ig0*x<&{ zNi|yN5zsBpMx;F%vDg5KYYk>gT)XhlQ;o@N3a+JZWZGjO@R)T`F|f+HZ*}_R!;B%l zX~irhL=z3(3*BA!?z3rmPpix){>c=RJxcNN)vL>*Om~1o7@E$TH+LXwOvFAvhEs|; z7u&u~4(RaeI~i@!rAK7if5$-ZJnLF9aFx5ys(Q-Dj3K>g#Vkcg6ECH#rOLd$zsO(4 zsI+-?xZE|w-lBu5krNyI7=q+R3q1n5#ovguhmo8^*m^Zh-({@bDAcLOyy(c2rEN^L z$3jFg>!M;{m3!YR`pU+0xB1 z?PDN$n02ifxXRzRO1<)V#%PQw=y9r;^+ca5_nVR8ueqa*0L5u|`BzFrD5Vn33OcfU zpl;Ax%!)xwH{#b6yO#RW9J?6~JM8tV$y_>PkvVS?g9wU1e<*wMM!;U)laIb1#E+6} zE*%ci(pTrjvCe5{6|3MZg9Nnacg_{?lYPb@+%(qEFTq5FOmN5*IKlUL!a6I@wM@T@ zi0wWwUu}$?$JzGA#cVH(piI3x&L>>^OI%Grqijy(A*mdEp^(w;CeX$OzD@Bt7b6X> z@sp=p_I4u6e{xG@#Lq<7lcV;QBZ3R0HYLy5bKEx0G3g;DA29qJn32dcRQ!~xkCYv8 z77}29EWd%UXWlG8D!Dj$))^MZ?4oQtzY`sq^#GQ8FWKW8SxvFPC|4NDg%*dD!~K4j z)A8?xN*}+xs3$Pp$uG}z_Gt6-pS$0#DIpU)cS1+Bf3{Y*%RkirjvGKGx@vfUo=x7yK69J<&+uQP}OP zV7}91fB!HoYTQ^Up7*7}+&c%ZBNy9@VdWoHYCE+*f(JbxsZI6auJ7&O)&`qze%~MB zO}mx+6MO49Z+zlX9lbUf6g@_tYMDK*g{AAwHI7A?H0xT)xXSTv6#GTPjL}+Bio__f zPi=Z&=EDYOEC4#|*8pjZ7A6XIpMEp%!=I^;e|8Ny-U{(uw*uSjAlt8!P!|kQHRX58 zw$C_pDyt@kT7OKC|%h#aEz;ZEy`|;ZR&2`cWs-k4zQ6k&`Pdxngy}wW7IZPWT za4n;EzisId_$TaJu_~EP2HDvO!Ty4YzJUC_m`ov_N!u5@n*?gELc_w@CUWD}05l$M zfAtm)W@fGN8PiAe@Zu^3#80X#I%8ToDR~v>Xm9rPr8X_|(ER(<3;bHB5!~m#LOVZ} zTRXbN zNlV=ig3a&W1kMNW#+cr0#4JM?xs_j6!02oub!iO#m%^83ilfIbrj^mNNFcm%ryX0Y zaFpQo_Oelj7x0Z9wD}C3vExLknn_rSHj&4Gb5ryF%!flGkAWIc!l&HU|RuA$K|JV77H%Qby@uw)Gvs0$1FZ@xSZ2tVKp#(`J64Hl^4xj$vhftm9wg0&r=G%$Z1~(sA=W%7mcfxlTRyD z0iOxZIUPP~P=}cfvX0kjZI!dCk&`ya^p8(7(^MfON5vEQX=a*8G}FQNfrB)hY6KNu zf5J>E7n2EvGMUivlENQge;zu%GzJJ<0Z77+g9g3VE?yUHr9duyP!v(IptAE6o!+g`aNXzlopXU@M+oDnopA0_-t>XqMWurM~2cXe>(gIG&r z<2+5wdPTEV#Wnegf4ySugBb&K>4+bIWe)$BQf0hZ=B&p8&ygq+kK>YF&grl(2wzq? ztJ?J|rgH3<2uLbw%9eVHQm|z718oXYDhfg}f+j6#>iAmDa{fB;xN?(?{n5bmRynH= z5Hk8Rq=YtufPARvD{NWIoMQ}6=_ae3RgLFyd+VGr^2v#Je?TuWf0~{x4I>oHz+eBm zO>Aynj>i+$5c6lZu*~9&JOv^g5t_jGyJ?j?tOH+RL@i=PlCMDK#0oH8Um-6`0S*4n zr^^k*HD3qj3&vELk3-DiA`jfleUU+-;la;6O%XB1=I20MWzZ4g=d}FlFf6^?8=66z6GT95!I^0D@})!-g0j z?x<>7XUDnl9+ele+$Op=M}E)Tv8;fahr1*%op2GmaoYP-jQ$z^xSfoJ!@UBLrf4<#i5jo;Lw(WbIgjT4x+6vhwWW2fw z7%$63@+P*ner?tQSb-)&B2?*Lq=1#`*!_zXu%8aQt7y}$?jdZu@ydj|iZ)%&xssaK z1e*69Q)$i=<1JxUTydvJj3xpbMH*wfE>i>3m@(&^hmDjRIY%~aWEgeIJ8alaGxTi$ zf8jxcpNPC^2(E`KCS4|1I5{_v!+!woM6zBcX0aEE$OTe>H@PBenS`%wUV_Rw?N!6Z ztHYzz`z|?mf&2H@b~~AeMbd3hz4C>6jG^q!pe>?7J3TV>qcd^|qnL8+C*nLBGP`%1 zz+`&20zp&_+#^rg5nL46QLX5s^mOeRuQ-4iwpy>SXTM*<_}%)}hjX=FF-WJ9 zzKso50@#ytQ^mlzXyoAmf6e5UW+Tdu;2LGY%t6pFG#=^zwj9qH--c!5WKX?< zFa+Gq`RWlkT?MSYRTK%<7(4^HBWsh!-->d05GClv9uWDlL_ZjuCJ-p3eK-4oyL*0m z!%13;2!1Wjs{k_HUqK}h0D8tN;5@+29R8I~Qv-vZx0hB3NK@dQvbZp6f3WydR}Q^@ zY#;S_-og>{3*z+kSU}3VO>Hl^s;Ba?C~KkhVp9Yt#IgMb0(cmr9Q@lE{%Sn(4y?im zS@Pz=M64k^ynE>vnh8a}w@7kR*CceX6ai25ChMw$+q+p6N$SyEqwn9CccI2hDMxx5 zXHT!-GbfDWTMLpZHx(>?e|P*b8}s-7At`S?r}1Yrm;vuM^9&wk~@{)pdaS)3XHV(NM#~RZBk7{ z2~H}Te}0-z8am`88cJ@-Fmb4BFfw-iO~yfh6Ljf5u{zRC$J>#YZmRA00@A?qFwV(aglM^r)juivhfJ7 z(wtill(6C=<5E#he;o+KWop72Q2I7tH(eow`F8ynAnjq68u4-p*Df6qL~)UEd6!KI zATGnI(SFwsoX`Aa4pK66CNK;%Gcak?(ooX2kwt4uWt+)1GntclNE(Y}M@1z`QJt<7 zTyb?7MHf7gwe56NvX=bef+Em71t}le0^txL_npUcpf0&wzjHIH9mY(b(At0oW z7yW$#0QgBeWtFq4wT;=WLGbytIU6v@__Xqy`+*e9j}n$}(x&TwNj8CC;448LWge4BS$X9}*)QP+p@zW|!kdXHfJ4?Q6h=LAIf zxOdRzpK>|6CAgvSQ%1OLn&%eHgT}TaKjm@+qH~`=WrS10C4Q_6+Y1|^-=bOLoKMkV zsG9mv6v978@|X?7jFIG>Z;;n&GZhy-HBbt#U2M%J+T|cUeRtBB@s4m+3g;m&( znQ-hve;a?ygkv4nH&F@pIIQ|6szA;`{7``38joxq3h;{qDfD1fWhRE*2dgTRXi@cG zRbj+f)eCH^vKX6fe8l~c&N)lpkZ&qbXLS!@n=}aExGVQdINSLk{A9acEqQdzIc-KJ zz!IMaPPcJkN#k_0xa?*!4@(pT#H63l=99Uke?hBOBWq>BP_?@S*41UWoyi{WJ?M zf0!(FN$MS1<*aI3UjTA9UZPPaL|zETR;rB_)xVcZ2)OCf+sT+r*=fX5+k z1BeTLc^&9v9`>9B^QDpsmZh_^=ddqWe{AdOOfHk#HL~k)Q3e*bO+bf48A#l!n-{3KjIb_I z1`=0n#7v^NjIeXgf8@x}v}ENh_|Bo3@YGcSB(FIw z5kVB!%9N?z*;x~p-8Iru23kGZDd7hL*?~UkJ7KnQvdn&(Ij70Q`k01(rkG~6_0PEU z3hhefJzC|gYFO~nN9c$MIy5Ad1ab~R0iLxPXTjArTX(k2R0~}SCAZ@ne3$JmT{ib} znYsto*?3_jsDJQb_d*D`2iDmLf1)SJ?fHoWmoH{6X0%=IAeyExczLT3GiNdk{avB9 z@}u#y9?1(d`SMwhA;Nh0tVcg7Sz;_;*!6PEtd$)1%P|#LOZ(4y^g9cp=Cd9{tVvUx z+0gNF%xur|)(2D^v94L-{2N-Lnqc3Fj*`B$k9s!2{A0_-d+cVd6V`;(k9nT%kc@iD%@&#jmsmsu|FY{)2 zWWsq%T+bqCJfJ%;K&neegsUTRnCSsb@%%5Vm~Cb=mrU5p^~)Iylq7=8%sI_~D~p=x z2#zdgDO|&RxnauF3tT|#e-{room4SjKwC`t>l+?Z)^cG2DYs54nVJtwCK~{_Ozj1= zLepFtHy$`}6@ff{9~V^fW`NZG2YYK-A2%S->HJdJ#mcZfXd?B zog17E=;EDPUl}!5Vm!JR@we^U#J*;xL}gmIO2 z9L5f+5V~}P5jjQ>h`Sgd{r6m`WT=%f7H!y!7HrHptu{90&4HO$RhM%mk(ybJ_RMz+ zwVBLAzR_o9cklmPS6Nq9Q%_T-rKDwZh{#Du3YTy)-fngooWA#uogvH&Kj>G^XuQj;g@UeQRnUkR8(=+6;dZ@Xf zAMPiMSL*`-@ag$JofH~E2$83gLhmGRV#h=03;+gyPJ*(ke@gjI@+Nk>9^9vsLaVBL z5%bX_l{)jkkb_xBmwH9Em8D^@SJ*r@tuD3_3UWlLQ z;EeME;m5M{fXh;Pvc4oYB4|%m_JQ4t^J7IW%sklyf6g;H+UJ^KzQHk`Dre97q~WQ8 zWt4o^+oPJ0m8a^3xMuNT_fl+KK|$q!*Bac@8r;ypWA{$zC2)f&LS1ynmFSKue04To zUDFk9c2jdD$RN@6TGLN>ca#l60(lhBz8WKV}`IHw=t_=hy0B87dC_9FYYhe^dw`y9XD>4eGsiFaU;5$#c<3Qf*@P zqc>G(pQ{d6!5^zfnyM;a>aun)%9!v}SLCpIq(Nf9ke`#lyg#H6^K%lEWvHepRf4Q} z?U*XT*N%yzlNNQv2;;A+BId=@NrjSnv=*JO9dMl-VCV=er~b1X>wtf3zCg=4Z3QdB#L_?xWsj{C$~$Ed z-aK_5G*6a}+)O4dK=sr}u%0X&uPK-($XY-up%audg!hz_S`I>+q`P%h5OH(JZ$t5d zfC~Q>#ti}jZoUo0i!Lf%e;^~XZ@OSqe}TDYb~OB%mp42P1ohpd9BK?+y<8aQKe|hG z=A8a71eQ)S0-iF^v@$!jzVbU|qxyWmnao?ml6|I>N}wqp@;FQW`F5FQE-I4KG}{xX zUONYkFb92~+8{3&FBq#Xrp#An&cr+dt_eIjRX9H2BVEpKpal>p+PDK=T!J|(f5zeQ zBVEp`b*##Yad^C|%elBrx1tJ%Y37{&aFA=31K`e@gH5IRSXhc0o(AB(u{hCH?YuGH zfzX6#!sY>>`T#y#K%Xnlf90G5{X8Aj<(%$bJnX7EwDLLq0PafWVaG^MCvQ4x>q03- zi;_=9cGyrB1$gK?hL*)_qB_j^e|#<>JrxE0>&E1fn8>(gOrWF7AkyKNAl%(lZ=OCQ ziGha#``td{?n(E2DVn41Niitd7oi?_Pr=BCPHp)Xmc`RdV+8!+&IK4q)?TY}ad7GBYl zQU?Z+$hf=kza@HYcaXOycNsTl?i5nA?k;SA+ygMMw?vQa4)PXd5J`-?3kM7fr|3zk zniTzv%r8fjNbALLWATvJe}T$SeFZB^_oK~puW813y75@tSA#w@m%X2K^8{hb?kg@SNiSgc8JZL*mnX32FQY6cF1?AmvAG-aFY{YwMDN=p3nL1ny#vc>o ztv=dF9WDmr(~ZY&#UIgbg@xaj4Wiv}d>(Xi*ozmVQ9vgufuw68f8+RGQCxirP_0)H ze7+P7UEiX*)1CZC`Kuq@z6Iv2A6^mQr@HE1B_i4hk(^%vnTHfI4&&$Vr@E5v8AReb3~ke2{pjA<4oyAD3!^U^M7sy4VEYpkE8gr| z;XeC8^+Pj<@4)$`e;=8}JxKr+p1}fKI+gIJ9~v=uG!iMgS_y40vgG=z0cW}!)~y4n zM!ndbExqmVOV2?h_gxp@dMBgQV+c`S$^_XLjB)fpCJ{W=kYs-q%p9uTg=>!)@WwyNJkj@7tAsD-rDt2DQ2%f40IysMFN1bU8YT5(&H- z9=+~HV@VIOM(uA8P2H+uM9;u@_+xN?JxeO8Yg;&ZFRzy_G$u>OQ=sLkYBJml01fFM zo;E(qM9G~8Nnf|%#qsGH$kLOlhFva5$Y&Q^bu0|wu4c6N*fU7|Yt3U1t8n2X2qDqI zq*}U^X8ZWW{x9a)& zuNW`xZP|`K_A`A7VO3b(&WM^@N)VSW1m*A)!m4Qe1mqrszb+Zkl@;u}?4j=;M9}M; z%kVZ+X?ts9-0jGtz8?o`NC{%>LeRb!(>vhK5ruZCe`b~kW7BwV%W(9upRE_u>#^m{ zz7=k!D6~HylYatoFR7>eVU@G0H7O%Oortv?+bM)>V*0Tt=PC)|T0@P3i~@Wc&V9Qz zLza#-O>#?c$D^aT(Di1@B{q`nV+f@_4THE(C$xV4z(R;_l;@mY>rzt%TOg%ILun-R z6KfRQf5bA1SFGnkn3H)ljg?a~O)VjxHg9sOmuM{H(UB6+kdabVjyS7_D>n4$E@lmv z+QqM-@~O0skF%&~=*I`?`BMWmp+rw3qvTe4IR1i}$A;YN#N78*<{cy;WXD&w<0}Um zE%_Vjw`a#!w&N=&IWw|pkj0L#d}ha223%ple_QR8Z*7S#e?$EcHyr*30JI&I3m<6) zFCu;XCo5D-md=;4jS=evg*)5fgnzO^`=1dMBbcCfkbn@AG5e#0e-OZE`WK2*gks^Q zFJ)lB;|s=HI230&QSlZI#hh~|+U`jW1q>x?=lV{%Tyy-sU2`{F9s1rqZVDAqfHAzQ zf5=jD6i`E?ZTJJO6OI7N2!;Cnn9MotpsS3TR1($M)r!*XO6gvufPFKWN7Gm+<`9t) zSF)l~A`SU)1-4R@s3}^TK_I0K^c#n~KpD=Mfj8l&vQ9FQLrv(9&-TiPfpe9z8>*Er z5g$8GEknvH%KNeb+e73QG0OZK}Izb_T0r2SB+`oEJuz+s)*~S8> zW<>cqK_Nm!aQ<4r6($jC9|!1#qN?t#tdMlSHQT3R&^FlB^Hx?!Ab|1oFBHdQe@yD5 zgnu6fSo~~b0ZgJWu(-na9nYO7T7#7`mMi5oUF6u!@jd|l`aZ|cfWG#_hTLP~f zGn%mjS}?4Zn$YsSHj{ZYjb$n_dJ=JtRp>0Du?ooz{1!Dq z=oYoWXH;{+rRnGqGwKtPny5tZe@+;ca;gCU03bjRB;yvqP#_oz3S>!?>WN%?6o3yV zJX9DpE+$D~(ole*FaQA<000;SpeO)f5CC8phC>-yJ9b%-N8{4CH#91^9RPR5f4}IP z>aRfmE&4`3#0sJEkHF(+wAZ^u>2F?5|E=I53~fh>t@PFIvEC796B|9we>09{<;Mid z!yRunXa6^~H}H?z*Qx#La_Q>XWIKN=j{Idz)-#s&-FD1Q-K=b-;R-r?+d~kTcpf9S&D1)5cpV|}$Tn5a0? ztT8?wLVBAt}-Lfe1qf18N}+<($y@)`xEM?`QbN94Kj=KotryS)T7874NDky_BW zJoqS&E|a^32lSmqJv5f>9EnFvxRAdZ-yXjq$F3sWfPm=KxJ9e}N5U5LT*37(jw5c+ z^$eEs%9f|}55ze7*NTMY-v}=k`C-N2TDzDR_SbI^c&@;T3s28Se~%4ulr$PT{iSPM zkMd7z(mzPKKjLtNG5m2EZ1ic)c#aG{gZL|nrpv}{Y=asPHqJ}L~Hwt z*u&u?0oCUS@+U_w#NeEIldGWW&IX~KN$1G<(|#Flzl8DI8GNDUt^Cgu;s;Rcu=2@| zdb%Cp`srJqYA*aPf5m^rd)a}NyZr_{uQ~cQM`yio&1!;BOHEWX>FC~(9B1@3a;pCd z%>T{D(v?-`FX^hVnxC}{7Y(17zo5ZSGTFtz)PJd6*d6idvau(a7-%dXRMsf-F;W3K z8sKgrqb~>nuUz1TmG==}yi4o+Rf{j&rg23_UT%yoHx<0Ge`x(Nkr`%{=I3M>xq@3z zR8L)roegR>l zZm=u8U#Xl{pcgsYxvZP7<2?_Dl@rP0d>eN~GtobPSVi??#6IOZ{v{n-YG2mL@mT&FTYee*e{W=fNZPuLzwCs)wy|2%-i_+N zwtRK4cc73js}G6E7K2v5FUmgM-Buw#XvQhJa|f%E-*aS*Z!u4QantVTziQx>o_?g8+tCR@NOmO>qJ$Cofm#z_}|r`8>rUZe>TJo+AKC`7e#*@&8Y|SrjAIZT>2++vr8-uJq?)Et#x83kI9=WE`+@l*3*L}X7z!U1OYY%gTr$fgU;kZ{RaxIK&7JS(I7a#c6CIXJ1J&}hivd@jqe`&vW zjc?=VZvfK^&M=BMgXlt-B_RC70b_3-(YuC>06XjznB| zH8*WepZT8v=6jRfndo1>g>PB;fX!&$OWNTmv=0D{2FKj~cSr2{1Z4gy3W|FCbxdrG2Dq{- zwSSZ*)SlMX{s=rycj|rVL2U$j$~O2f=^s4+|2#sYgH}uUr_xN6^! zo+^^JYovE3cRzBtUTzt$r{R8FDrrJ{U?Ud*embY{SzXGuYwXuIe`WO8#d`@@=zc&^ zzzCmva03#-?FH|$k<;7AwNJt2={EIezdpr(it6NVRKnLJO|Le6>e4y(%Wzh_VrE5V zFqO}On9+ipM#V`JmQxNJWX;9=!Qb#Vft(lWnX{PN_4A9VJ7hGY;^K||d>lr|_Wv&j z|BGn>@fNe?ALc=se*gyB?y_OYWK2^3TZ!If&9sS;?8NN`J88=#d({5mO-WxId;Z+E zbW3aN1qyugj-R9>`y`B?7A#QRHMW&X?aHCfyI2VOe3sU!(Ow_7>4Vl+r2u)18@3b; zBUPetSS#XFV*;O!^X%5R&Bw9oxRxcZ7@f~t`Ey*^87Z(gf8+kMvvONKvcvgVJl>+? z;9`m^&b?`#oTS$C{-)nK)}31Z)_wbt0WMC%+xK~BOUx^jb_DM&x8K=sN*kKM&Z6_83n(M{#7+%ohAF~zf{}~c*+z<;|qGj&-TZR3pW8?w{ zjey^Y?sMydf8L4&eBwGYsz@`4+zBTy?*E$}T={x%4I8Duy)04XdEhP3GcX8>Flo4= zzLoEbXlHNH_|#<`iqb!(v0;{_#PUT>BUb3ahIyT!LVCw8c$n4b_8Q`JhUgPiY_~hh zEr{6#seI;`13vu)bgzCno?}qLd#X^Ha^Mg@(IEnWOGz787~fBKK1zNm5ySK9A%(K)0-!DLC!F%287tQ|l@_F$V_WmAV+;?E}3pDX7qxZe-PMg4xiFEm;U?!D4pfci-)@u-WsxgUZ8N?of_41KST7^ zGgQ6K?5(}gK1V;?$;Q%rCy!CA%o3@1Eg0};f6!@aLOREcsloJnCB{D@*vG0dQw}`D z!DgSKzvsk&J);&711;Sa?UOd}_whqXaa+Dde($cX$f374!vnE|mqIE3W-Gaxtyyi~ zi5TtkPGNn9Cc`kDTsrzJNRgTJW`K-H?eDixsr1HA0rQ6KryzLEK2P4UHZY7vDiw8G zf3)|5Eq&USyoM%z`TXNW(zcf)-DU4h z|8I;LG2B}$Zb6^-l&?!&!wPk--pe}Ae;A0RR{9LO!mYQaOHNatAkDv}v3eB_fH@AP zR}h0+qo3DT;AURx%{sNJ?Hu7=*0!A!`lb-qsmI${><;+f(H;mt*k!Rq9=_NqA2$jo zYULRmV}@MNMetOM28@f49;g08d+&QvxCagR$2x_x_D$8rv)KY8`v`LS#7h3Ze*(L2 z-1$(J>^qGia^)5K&&BtK(yW0D00k;UVi&aV6_}6;v5TDwGwKvNOS*AfnL4|TC9Sbo zOPx+K>f%+`>$tjuXBeaPQ-7DrXq+1*(xi)EQ*81;)s`kskj*`>#G4@_ptDY!ko--}$2+-d0^r2Z{OTTI?+-^kTyV&4xSB{a`o-D%+%^**}T7gJ#w@`0itp0~js z*EEMfJipY+uL^v*sjJEFe{}nuw9}sh-ap9lf)K@E9^$MQeHxk|$b*FXUtaWKTI>Bp zXL{5+%i1$~qOrQ@ToG#j?eUd`wsHG07vcTFfM*KR$5MLi>ZqjF@2!%@#>mTLS}JjR z-F*b4nN7@FOrGgX91806nwsjW=V1oSS6OE$u~Y7o*=#*l{A?Z$f8b*1S^qw*C6X<< z37c2w<3)c7umm1-jtNT+F@fxjTd@vJzOmPgk?B7E3{4Cg#+-)#|E3sid0Om7!0QNS&$h87rBjBx6`?v zA=l%#tMeyoj3#Tfe;Ycx?;j;2UZb09;rt#TbrsQfV%EP39v)LdqLk+~#oj~a%~XrW z|1tY7%54FvJ^o3)N^Z_(!;!`OV`K=wwY{?NR~Pri)maU$MJL|_e&LkM3nA24f26NH0(Pb(GSLBUs~k4C zj`5Sgx?LLYy3V*{JZFGQR(GTYTd8ij45;h65cSpl;6-TkeM3?Ff89S&wB2jZlcvmq zUXkKYy4fUseWk-P|5mx02u^A2dFiU^JXWN=X6Y-H3lPuSAIj*A(b`V>_u%^*ar>v4 z`?}5dR|?$Ze;jRuK020jtepSG{HKl{Z(_XozW4#%`hPjd^*Jf!C(S%Af}$e4ziQR4 z4283|&Pf#KB)djPb|8<~N=f^z+dKJHhX$cYHA%?jF{6CA%UGwOJqmYMBLetX#p%Ia zu^olq;O38-=gH^(N9RkecQ!4L;K5zpQLbm_PpC*yf0vJeTneT0U@FMl?QtM4efQ^L z|4_kaIeTBSxg+l0o*zu*M@GNj=<)vy;KG|HYbzbdf&O%DPjYkgmnP(5M}o#?@5^)! z)=yx)u(!=q7uwTwzmgU>2-Wvq18&rAHaeSWr=UzZ_PE!0>ePGZ_3) z+xZfKeqS`QGV~MR$kDA6v*B2Qw;XOr`Tau{4nNS$lWTSBCnjKj+-nKOOMvJY@zbB) zg4)EG4`xC{BOSV4>mIZlSe=pRJBq8E5RCr4e^9X>PWHG)g!^dB+Z;aehaDP_(8)TW zw8GBkv-I$@jqWw)!DI>78}>21Ha$+Hd=eW7R5!KrP|!RG1+lZM@C=mme7-WWOp|o4 zlkRN@3oB@(j6wfh{jUW~)#`kMeLt6E(~CbkbhLHNBW2x-%CJiS?QY(p^CySC8zr{x zf9n^Rl<0<1sk{fuVhR5SUI94hWmng-760UVy>~pHfiv?}6V)!-S`dOf5KRu)d!e5p zU49TYewwu32Zuk0CRc)PH@Pw%#8I~D4Dr@OzSoI6ee)b=ME0OM2F0=gU3l)#xw(kF z6m|DFdr;ls)?q(3`oM%){lY0%PU%T?e@C3;kU@N=80*YCH0ind3c%WjhQD)tt!zy0 zC)u0$cSg?J#JpN}p^=-myNNFFse{N%r z06&~xJpYXI^SPQ^@#;4Q70ZV~CzMTj-e{SXCZq2Xj($CPi@<@vq%=Dq&E1bWgW_D8 z-jO9PPkaHg6HCe?X_RcNP5KzHs(&Vwn|?g-1hN&BNp~D=elhVm0?mFL_Z24KV^ z@hx#H3v}Pz)!|fPKGryHR+cS9f3DWGj7wixPNj)v^*E4zo~T&OB|LvE#5lpQ$gDU! zOL3Zj_2zn>K@0PXym<}v{f=YjS)jP-1pOYkSatB%*K?e3Y7M?t;;;-`K?w!~af5>hPa|KD| zPXq@%8p_#mi+}9~xJ8pH3;(Y#f>!fB!lMWF%MWutr12D3zWno@M`a$F?^}8vF`qm| z`^_M2Bkevxe849pU6#*Jkn@jE(6^Jj(EGs$bG{PiSvIF31)NH!+>dIrW6b0+@}#3n zS07nfO)t5gWd7kc!8WE}f9{H5Dj2{qI=`FVa#ak|#l6pJ<9uM)>j6pS{#RHy+B2%= z9h-dauUB~;rOsdbd0W~GH;xghnH8-xS}|sB=}`tV7Hmqr^44gzi7Nb{m?FB^F)z~` z8}oB7`2>MKn-$E1=P5yKa!88lidcS2J1yjT%(b-q2)f7lXJImwEG8SiJv-k{^v`KgBepZT0cw zFrKsG8_vg}`?sRQCf6s>j3?{kiOaqTt3N?uJeWEgp<6D}(2)dfo0S`OFx373ySHHe zAs@oD4jzQ|3S+d_N_rk}D>OMg>7dfzmX|kiSVCSak^P~2q6jWP4=qsC6h~+fP0J!XckxnXyv*(8oF{aBMpJ1(Q@1@6w<{pY0!Ek z%E||?vxDB-H0@;|9{V`SLbfMUAE4{n$cLV0J~x^9Vy=#eSf39W_;k_9-82mDWs*Kb zZ8<(Gf6g2u)o2la+fHYc=%2vkV|dx)A)S#B&)}q9E=A967sWdYMd)t@++OVsHRE&b zb#nHP<(HY`??L>`;XvD{_g+76njPY5ZeFR!k7 zaxjw_>21h$x7db@TBLc5dU;lOC2r-uI$HX2G9wLZ%}DA;D@sy_x<7o<`eWtj<;Qe>Zs#Fh}7BPW*L?`@{FYem=(=e#%?g7|@>%f4-;7 z^#2*fA0%)LZSZvT=ou#A8_oNi`}?25cx)ANn4#i99A}ywTmCtTyyhJR<63kz)kHl~ zY`vbL1H#}~rGvp-$cUrv9x=Uifji$wCUSxA0i%7RP`J3Xc+{b-VY)hkP<3r#XPleY z%Uj%>zoIu7K{gotGixLTT{m&+f2w`K>QgFR`GxdWy(d`zzIjcDZP! z)&`i(&Oh|-^NR6xh`*GjBc;9gY{f>$$VA;I(P;MvQJ-Gq_CXh<@sFW_rXk85hCm=A zYF5s~OSPDtS}9{&1{{Vh`G;`!`Q?rn?3Xs?d(1cBEO-UzigbMkowg>Ve{s&3nq$&H zD200?#=F=5+V-__dUq-u`?4Vou;5jkcGT&Z7sehbCQc#t{{8yjAoL>;uHoR=SCM}K z=*)MjoOp=nmqFt_O{peu;e9RCb`{C5im?_PF31PG&&!v=Un8qoWIZCY@^^FHS9N3R zNYR|)4W=MS`qoImCp(-|f0X2$`q|)4Yl}1Kqp~*GGq@B))@m-x^F@5 zcdr)3bh#VZ8tqBt%6g@pA+_iPe@(yx++{fjqNUS=#Q(HtUkjY;ziH{4mmJ;K?c)BNY1 z$G&MBAItlUBWmyd$bl{0so~h&_*u#F$Y6bQZAMDW=-8i`VMPM#%8ZvmQBgI?%FLdp zkG~)PPcpA$SbK-ue-F0&=4Q38A{`v2tLb`?Uwfm->x3D=Rlo8Kl0wxyRp7Cy1V9xz;xYhX(`q&ZlSnt8rgL^+9 z%-1nk(8KtkA#vmkqcpSl?x)|QrtJk_0e;k)@*urWo5YaOq24DuJQ3b$A`kS9cYFE zrMe6JTs75Me`amPbNb*f9oPPI!CgFJG@KP+dAIw=z}9ro-r(6oz|=~ep_Kv{s0WiT zaF!)_MeAbi+8pjP@Ia|0c!L%7Apc z5A;X>yro%)SQB-fY?1C+)!za`+u1pE2K3!vfAVzct;Q z>U!-Z$G+b9;eS!V(T$~cdku(km4t(m1rfb1<-Gn|gRijh|LCv5$L-hAXUnf*^X@-m zuFc3#i9B}=dR$NMO4s#-bF|4%1Jv$Ai7TzA*ZrB`>w37wN5uz4%FHuRIKV5U&lVO>fK2qtWL#U=j1Wsi zKd>`w=zj?ALK)c|Emdgvv1EXLU`h#K^TcHkTSWB`P7|A>Z>5+CEfVdNI$p~9Ex{U* zjjeX}C>t|)4xY?FU9Q63c>Mgywn^70Zs|Elf0E@#=#K8#>Mj<#&nus^)%+6fiyUiW z1{ivDNFhh&ac>K|iKA2HTp@q0I${8?Bce(F0)KaG(KW}l?#p~NzN})={5dU8$z0BB zXmvjatxSLBZ62u=SN7AJ!4u6_-0x2kwhpGloxHI6pF7UbfwObi4@dJ9?jxuz8$&_C zL(uMJG;N!(AM%-X_VY?z{pUy-r}Qgrv%PjI*1?%*2A*^IIqKp0uRpy>5{ao*(qsH> z5P#F_()qU&GpovkqwA`dtXpDE%$>BtB@tlzxf%T*$;U?f&!e5@%)WNoKXZy~iEA>H z0}Puy-05-cE-Mq33ZKV`oxI8FjLfWp_!7KCChvnIe(wdA3uF) zZ+Kb!BTI5_JIOu_m4A^;)(2`qk{i}P9e*X@Ah1!fg!_&?acjy(F3I%9>_SxN@b^J? z$2KIf=m!RFl>U#a4d;Q1pA=Ee|Kb0Si>ptku6m~<)}JF2b$J+CakOGEnBr$a9#!x% z{scvOvYkrd*2uP$r^v7AIA!n{ka3`NeJ7+(UNNz!692~B@Gh84dp@3HCgVcad4I+8 zv}{P3;ZH3Y!+ag|?qdOL`!eOeGwh`?v16Y<1h=|iRr_463Bxpe>kDIv#`FHPc3v=? zF>`%mhIK7BRQN{%`wwn_vbV~=XTxz~>0eAu=B+vCeC)Sj{GYMXJ92jEI;MJylhqLE z{4c|RuGgcO0zd8Pn&uQy3}-C==6`$r=b28s@S|Cj7lOuDXsaqmt}u@)+z`rL%=p+JFCAjL)GY zexdo~8EA5D3+}wo{6SUW;zee-ETZEDNP75McnXrci9E!^ff)DYvy1CrF2_TJn(~?0 zbuAxIHKNRE1f!Atc+FD>Z6C*3s6G|BPPH6Pv(^oNV$}*&@004CJ9M2UW2-w-H}OQ; zrtiso1A>V07Ca7|g65U;m488UB_q4kH`P7RowJ-%hL z!8x+ecZGX0txjd9=<*GeP7^ghiR+jNdhV9X^)=3%AqNMKm$kJP+xYoHPzA=zkTTkT zJUJ1i8a7VFO?}SJExcKRk70#Nx#jGL@f*$y>2BxN{FFd? zPn55zX;?U_A}ys*<&AF%M%@?kO|@@Gx}p0)XEvJu_JY+ZOMewcza!vq(u@*ZU9ir} z?EO1gr=cXXLy7qxL>F|-Df7U1Uai=tc-{K$p~Rbm)`!Hi*_8Qac+CIE=#5*u3SQy= zYy>q&r3GA4Q^QtcrMue*+_p5cl?8tTWTgPME zapQc%{dHxWI^8_k92vsAhp`n0E9mTP3}xg|ga!EkFn`4M9~JF$Q69*G{4Qu{pmz+) zTaQ(uThy}|)fBHUqRz_9@C+sKeHAs(G(25Wv()aIuqi~`W+GtS3$tDjoMRRaT%D63Ic3{2FH3SUNfqS%dbtD?&sXm8lx*}NWylFO_fZ;}Bk0+$pU{$?Y zpF~TcDkmyWORYX{(h{>M>kWvTlOLRjOge`!pr+v()B1%3qm8cd9S@_3Ef5L zctWMfbVpd~{nmFVpBeI(OrE?oIH$q}RgMa+g8}+AeM&_T5M#CKA-aG^-T;5$ewB^`36%<*|*Oj6NW4hY34s~sJHHniKn zWs(Gr1gQjL8@^;Tl$rQ7S)k{&NuR8$8Y8OvWe~oHj{Hn6vMaX0za?Y(^;lm_@Ox!_ z2q)ms8lk@>V+!Eqed`0=UL- zI0(W_`yO~dD6>2j!U-Vy7rX8)BwreR&CKM3GRvER(|>>lPs&)q!>?3&|B2{Lq>03D z0+C*lhRrvbWhI9Q`6sS2mIT$4E(9g{Ph91vTm8e3I@aCY1-yV@K)V&ubpJ|ikLpo2 zfUe267e2lD4>|xuS_GLEaDUg4rAt*adha^ys>plB?Co7U4Zna>D%!gZdwIV~c86QL z?%~%CZDWh#YiS*gvhn@vA{JEbr@At#UAaDSl< zaKT*SR-5=;lZ3t@cv+Q9`;nt|eY}Te5Oy<2ST|GLf7S-I|Egf*oPXL2%;T&zXg8z* z{{}aU-QG3Wl~s=or=r=9yGXT0pKD}0PG{XA#o`wHHKPFI*o<5SI?(znig7Ch&hfP? zE9*26@cAeyn#wJQua>ib*I$=t`e{M(*Cm=f3`O>@OEj@yH-mWKe`kU|N{Z&mik5eS zJYes=U@nLG!PIIQ_J1o=N#XdH9*Nk^ARaoKkR_kxe!*Z(utk<~uGFvU=Y8q`TXwLz zDo&-?obKoY*E`I8c3M_44-318*@+8o>IOiK0Cw)pS|@<3s*aB@m3FG$^{(qivk!A4 zy760~OJ7~(cVOQXeT8;ztp!y))^v)gzNg~dyZ*W=MmQ7oBYzBp2p7mU133tFjZrno z)+>a%rok4n%|Q$KUMUZuLLf&e&*(ZzSsfve9hI6)w#3bE8HpTuD1@i&?0V}7G<&b-a=lN;w&;A&zi!= zHJya1Tyae&MSsNHFKS{7Vxo>zKJOzn3O;i3aUZFbTt4d_<3K@|!W)3+r1274Aj2@l z=eU%>u>o0!Zy#}|W>g=!Pr`fG9I6zh>FuoR+F92eY9=J+H00N^3u*o-N9zSOG!WeV z0{;2!=+iNSk5Pt?MH-5PHxdyOy)_OGZ5VnBX&4d~=6|W(iAW2vr>Dn)MIIX+o!nfU zoQXI%6L4=ONW8VVt*x<@fsvJYARF_b9TU@vfra%e>=xJBvY?f8txlNsJm5hJVgTe6 zp-E_J)YD*r&Jc(XWgkXp!>&|QRNE&g3Q}hnxV$)Iv04}ulf~N(D7lK}w85RR<4YU|HWe z*234;*6OmrmGxNtO2_K2B0ykTQc99~vQi&7I5Jvdnm!0RGAh#fNdOhvS+JjM35Yn0 zNN&+ewrr|O7-)Cgpmclsm!hJdK!e+zM%3QG5r6SVU1d9!44lp-OXeYz@zNngf_oJ- zoPPkm>k$agI%QRgZ{Q`O8)eDe(FNNNDY4NL2oUa#RjwD(i*hSlx&)UHToC0ttKYV)Dj=N{$;>VQ)ap-tr=C2yz!<7Vi^{bTdw@sLGAZ*&YifQ;MymfIP zY=7LkRE@rOt0M9NIso3%Y!(0!g?G zJun^baLHe-7;+yl7Ibd{O^oyW~KI=>vKcBtmUJ)Sv zitL0taJ}kL5JQf8c|3R3f8&=UdCx0!_ z38kW3B4ImU9Nbrp0OE={O1g@$ov)By;(#)obihKx-%`5ch!B|Rgy9&!1p_U^f%X5X zrEiLlLLTW`Nr?dn0fx_V!3GBQ_I0oc^gBTD=;SQ*SKci?9I4*u4~jDJ{8=v83TP_7 zm6RA*tRG-{2gdY2ZOv>U`OfGbsDG?)^au5HQve6J4XZM+1FeCZ^QeHx(N9`*DiU$r z=Rvp=4hj2*{1Uxs)zI8-;I~=#u8-`!;Wm#t?peEcEoQCKP`xGzNu5>>W}hq?8+A7k zIian^`99ZbFIO2ChHGV%1Sh5?ogHC^r;?jy!Pf-!%J%JRnTJOAtfTU#W`8Y!!KnQ#Kp;;3!PoY2CaZ&`_it4z>%$5DeA$QIHgk=YjKfNhC^XjuX+Adhz(BXA&E zk4Wa8V2-;|#7&-k)T5))R*bk>zff{^#s3+bJtg6HLwOIxm9NbsbWtjy2Rx5q_E^cd(4k5ewCcz<+Mnu_~+$dS*l zE|Y4EEj~vtA2%PI^CB#pmevar5%UeLa;)=JpOp z;m~DLebE)4qvWd>QgV_Co|aQCF+OfyVu>58)g*I!U%im!NiSKKpQHTh#l)UuT6<2p zgtz0U<>x4jDy}k7ynjsdC(l03wASU6ON>`9qM;QXsG&VR>(7Ru*)H&IG9wEAR_g7Bpi`qkqq}x+Xh9iZCsDf@+ZT zq)s?s=;(n1BpwY145m#7%~>yX1DMdPAzZYLlzxVw40v*M1`EZ|h33KV&YGG0L7C;e zx;02qBlQ9uDGP%0~*JOK*{U;rOO8j1WU zB7hMfN35=}Tz`0X8=ze7+}l=d1PKiox)OLQV3!@bi19jO!3|a%>l0NF10X4-sZX_u z!v}$N0QxE;ixznx8^Y=l)1FW}TMHpVtpt~?jl|Sj39pGbxkS1fhIJ_rZ`>)?F{-%R zfw!24V=u=JJQm%q9$$+-7=SYhX;`hm%COiB*{-hySAP|Lu7=Y$Dm5n~qNAUw6cv($ ztE`;*NRA{GMzwE?SEZh)Zr`eBTM%d=NW7IW5hpiCXIR5~Xah0vMx7ms6e?ESEq-w@ z=FqW2aq)|TF^7&Fcr5bt_FA}j0V76N2H%W6KOH$3aeNmQe-aUE7)}cb2L%HG|FZgK z#DH<-qJPDnULFg)3M*99ow&})#hHLB@kZs=HbM$*D*+3tj0{Xe6#KE zz%P+{uVb703u#&ub%KwLBE~O~c+aDP;<5As?KFG-O^QPoh56TB438wjqx#Pq~3EFzzk3?@-YAn4fcI`?$|?j zI(Z_CSXOln2AZ?3+OS4V6AP7IK*G z*MRH0D2xg8tMFTA1k|88enegdx-!^DBm9DwmE=EU(Au)|Vg^kAhP)R~IZvwf7}Uml zS8&g(Fm=hyeO5OEn3m0}9d$@UbbAm^UL=IBJXshin)SohV(8uYtdc{xX_mhbC4V!~ zc^rH7tKZOw>vx|ryIlWAYoq$Za7y6c5sw13roBBKEc#2=d<#07guw14H9_Tn`9 zfcqdWSRGsHSCeiOxnlGG)Di^j?TOkLB{ngCQ{tJ)h#m&?xdUoE(_S1NNhC-2p3w1H zMjCh|ksdunTJ+yWOd~)EO&c_j5>cJcAEB;VXN=n9xKlYs)D%t&K|;NR0axU!MG0J8 z6+#+XP~=l5De({qNrN0HMTeX^J5M$%c?^i^grbOP)<>no(u6g(fPeZdu}R&jxl)-* z4!8!*6B%%UEo$s?a|S2zg`pRlGk|fXtT>SYA(Ml2V6jrBj(8CbbIcSr;yf|mmn^%) zk(QYKh=+{W%91jFz)T8X^TFas&`=1A7tt^WIaBt}q$daIz(~+cu|9h@v|<>(TLF80gyMm30W7bDM8DF z$Vu`LP$YR1vThIuMjk{?a(u+2hBqPWPHIZ96GvKNcB!8QaR?}8v6Ur4q<&qz30Zf% zWT|0Ga?69rNjj#f(&b#5fgFtpz4u*WS=Cs27w2Gz)#Ky`fl8E7S=}o$d{tLUo>RF!z39KF!a{r{uGM$i1JDPsr!v zGyDWUbvzlL-)G{}`>gRad=@?l_ukLJy`O{7Ekwd@$r1xsK!KBEnkrq$y*CrQJ1TU& zmo1UbsRsb_(0^SC6V^)u2Ay`KE^SbHp2$(@SL64tJy`hws_O`M-C)`7I|%OkpKF5N zO|lJrZk=q_&MfG_r^r%Gu??%BV)++?b&p+Eh207&)D+&Jm?{f;>}5s9hH;TO5u>gj zxqDfWDXDu5gustU@r!O6HCiksb%%BBv6mH@DodFYF@NeFZa{;@N~Gd3aNkKvYTt_O z;D4BJ<|5W0(tkLDsS^`{^6*l7tSkblAE*lEe;dOZX4G*~jmA?C7s?ymzgg zP*pf&?;6P7wU51P9(&h}d)JD4*EaU94fn1G_pbl;uKD(^VeDP+?Oo&TU8jiKyMEid zW`EneR@=Kq+q*W~yY}GKW#I~?R5t+HyY9(xv(Jd>a!DltapVza4OfF_P$O_>Y~k#p z^${L2yf~Vg5kvq11aRO4AOLUPJn%r4n>KCOuvxQ4jhZxR(rGkkw9c3@lbKnj3>h*2 z001WDm@!*o9B?2^7%*VId}*KoG}?<7Y=0L97&xD~aM`kDfd$NFEn4_xmMmDXT)ARt zX~jy7GpJ;*RHl?sU;zMtGynhtlNI1lAP^9VgQD>)%3?u&6aWq&FvKV#AS(#rNEl!! z3IG5GAOIKufEWP)00@u)N+L1|0MkAy-!;(hJ604AaF%Z2GQPRf&m*-wLO-qjtA86- z(Q}dUtH!ohs|yVycJ7@!5y;R zPuz-kYjJ%sMsblsW*f!Ue!xeKaepGc#7O**<$uhy$h35#^1Iizf%upv&#y?FNrBYo zZ3S&lupiOSJSXJe75&^hJTyfPz8u5I-h63!`d#iD2WeubwfATAD=Cp*+X5p8{7-l`c=Z-P&~jbC-LT;KGGU*ko0qwY6-ND4l57>wE_rmsEj^8vpC)*G`>5RYmso1?+;d_tBR|CjoesZH9VjlY{pB1~&bt)e z__t(Z#}H{fNrm=yV|rQwWpXL{Y(!3OCm%|(Hn#QmlKy{u1QuGwjEIHdCM!Kj=ntfM zG6QlSdL_fbd(SloaOSST2!9`F#u`By)uJ#h(7o+CSpXGQWAZihcDK+6ub?3@4+g-t z2U-xD?qViO9PSwZ(ZF#>*l zkxhH~xo#)K8}#9PC%W12JZk2RlagLeXDWFU%eYv1f9u<5$$uom9h&{zW1=?yIMSc%<^Pzl8J>6^KZ!IByn{odN``OO(eHGsL&e>mKIeh%( zbYO(!YvC&*2d&vR+x1(R*)%Y=uRPvH?6MwQ@69flS+*Cn#-P|-P{s!ADURgck&dbs zBHWKBV}vQT{eNB3>Kx;=^^mUJ%UetF>%A>g9FGR6V18}3Ex-6_*q_$&8>~#q*px)} zX4(3jT#RDDOHpb<3jg?J>~Yu z8V7;vSlyfTe~HP5)s}Da-8mxe$BZk+{R%ue*G9)U&41`ndz(L8f&|Y48G?TjpY61W zqam=~)2h_^QRnP8T{wZoA|y7S8GogDt)IrVm|fR13z|QVb|9thd&son3k-cZl8SAY zS94vb^}ct%d7Ia!GS{71&+mBeF0KL3(Hpg=t(o6WSMRGDIF9VE@Zl+uKO=e|&!f5R z)@D%uMSly|5{s!Z9wjnx|NE3YDy1DsbKYDII%lZ4n+_8TdSqJz>v-G2xotIRwVkSQ zWpa}Bnb!nnBj~`8Cr5j5pHKQ)E}}MmnLLtZBMrHV)sGn^@ejcCy z$6+^2D9Slii2WKb)O|5z=rroAx*6y)8moGR}X4O1p(;K2;@rk=O&B@f}c99&L5D+9yLs#$a7?bL4&>c8I zz9VOZDi4(H0cZHZqj}MGdzPAh=mgwiRbz<$^nPAmk(=}R=O07O!TS|wXp1Ot+}AF0 z#DBl*tiK;Kyk0359gmwQ{5$SF(~$TJ`4ObLhuCc$=%l4w-lnFMh{Hd^M#GHp15#`WZ&~s~3M2?D*4Uhak5aNtQ=aqEuhn4btBy$1|GDw`F)e3}%Uei=p`YHfe77nZT1 z!=CmL{waqx`uT`z$JlMmLaG2;&1IimX$3#ybX9#qxdu_TwYVAeJFofFhO=Owxw7V7 zYQB!R^(W|k05LZb5ow0spdB%ecnEF+4z5wxM$_4UN3UqsCsQunKtUTgw{Wm<>TU?)4W`);!v*^ z30;5rp~x+7KlFE+>klg&`no+~EB!*098PNqu3_rBQ9DI)hqEd6SOc^5vYXqIk=4B; z{?$>kPXOqBYcX_We}B32-nf_lR2TI#n@dIWa0;&PT{xNLe4Y`sO=H$Wu(EOdl%7dke2$zb26e>s3aZGR}nZ{4{2M%Q`2d=I+( ztEM&ReyXI?$rJyeQ2Qcm6s9Hid}Of>>+{*p>jXa^Uv5)BjpsQ3I+xMT_2-*9qXtRF zgZvS->AKRNyd{bq1>EQVwZY!w{P_usk{6N9^1m)C0bkq$;$P^y82xe$oj*FKM0({G zrm|Bo9aw_qJAc2S#KS?wtLt_d>~g(-`{jV)fh5BR{QN0od`z+SCZvB0;D7JQRU~PT zD@Og$wNGA0@?U?wpGXcRNpB}cpF}o`AkA(>R$m_20(o3VVt+r;%QJ}qqx6BHm({ad zidfCz-sZ{?MY@I%kHzVmdwTDPKjGeuTGrPVW^Ixm!+&{f+S>8fzThw#EDb%hhut@vatMPPyX~(`wC_~UzR6FM-R-|`1*Z@ zAA*Y$)AP7AnaVrD`M)H1%^w!x$4tnTBGqIO{}s)oxF7Irg%B`XJS7VHU0?twef|?b`j#{)Enpb_k%bio`0h{e9>}RocWVT z>`Yy!lBVVhwI@Z^2RSB1yT6}jU`Wm%&@l$rjre2OzewG}|B1X);Od4*H=T^XZ%hQ> zI~ZX7KF1S4)9xAjuK@W8sPwzKZlV|eKG{Z{G=KLRbQipw)F8PKzBY&|A`k!ayA7PD z`N}s^Zea2p;PD_&-o(A+A88G<~FBzdeJz`wR~i5bs_U3C-YVu zS;)T1X}g--%y?u zp>!K#07DKa2HM>u!84>xqvKMW$DZl|2zKsZ~qU{|2O0R)Bb;vR>6=5R{qq1+`RDk7*!@_Y zYx$ptKm2BPgP7cCKOLuCKW)DEek{{FXPrdtNQZ1DnqapS$n7P5J2H?w)Nc`J>6#b-o4s5iij5`F|2tas*}~kjH~! zO4idp$esJHIkeyYIqyi49i(oKBfmvvYakkm8ii9`3ua{6=6Rjm0Ry|lwR-XV<8J0K zZS;U+634{ku5Q+P%cl+SAO3BU-^_V`CTPYp54`&};sZw=E;LMc`O4|^$S{B+S+pbE z`=G5v+6*U*;n**CZGXUPA9wz2T;4tCBlWbmt)3NPt~@Gd$v;m!b8~+c>~m@|^YGi~ zdS@{zesrbzeem<~Z;SQ&{8sk!K?dZl9M8LtHnFgomyF6nY;(Z4IwVqX-~c042F`BG zD~h2fX4$`j;u6iGcaN4EQ&( z9FvD1Z^pZL56q2L2cts7Yt@MTpu*OI;+0}Y!ar~N zf3OLrY*r&Ya*O?P>}pW@TZG`rNOLQa%DE9aZ_AAzp~{--H2#J<9)%>xPEEz7gie^w z*qGr9_b-L|Q-53Wy)JfJx;aHJ-}xU;e0`6uLu-2PDaVanh`EgLdJ=@3B7_d1OlOE4 z5_)G-&KK`dt_HJiYndIisei21U0opP9@8^4Nx}N89Gkyg`^lMXSw(NKG$bWD1_f?b z7x~e=i6xfI(Gx)J_0B9jM<{BWapqzZSk!C}J%mGVVSkZ_R!u1lBjw)J+^R-O=ov$u z*&LHamU(-U)-t;3$W2^kEcn*q@{xpZd26sj+EL9Z_hNSWKxQ#9Prflk2x}q59vH>P z?eK+z9!$B$hebkMrT^G;v>r&D!;@KkYq8LO=jp!+x|B`^S>Q_hL}49vaJC0{X+iu# ztdYAUe}AOq-qq_Uh;hxK94O3PtT*%B6?U87Ou5BjYM|E}{sS{X<8B#nwhVrw39;ON zj@`274(KZb%=JR{J}z*j%73sC2p(x03og>k19V1}TP-v!`40oXTi04RczZv@7OY8} z7EVw6U)=3L+E>TiHNJ^3GPmLJH9mc3!yi&@gMYBTHEbPg!FfynVHDTQ7YNQ-x+@Bl ze;naKxw$_Z`LV$K3*3+J*^(lXC(<%(6E~+H>VlZzXviv0B-?P zcLUk`3OzOOGcEwl3%p@l zaDVA-;QCQ5_9wwTllo=__?b#Kp!?LSKmOzXoh^)eD$OS{`DK8Vj{;)jeR#6aq_a1L z$jWmK})3r>Vd8?BHT7MIIX4Lu^D(>$jLdY+5kqdx+Kwa&{jbo&Y z>O7LD{R^wvdq*6Wrp%;|`MEI*xdLo8mu>db3vR}`Gse*m1%6!Vo$0u07klTFpxaXO za{=WCsD6gA)_Ngca`~;}K>7rUN9iYI=H9q+8lOk7su)N1Dgf^gtb%Bo2P$Qew0{ru zOnWj}$Gfj4yPG(vbVH?;Vs5$8jFwjt<`&slR=n0){hzk#GWgqpl`r!jc^$t}Li@WI ztMB4?kj{{|aR}h2i~!1?skPY(*2=F|SOU)%wwU?hdn9Hek}m|Rb>>a8?wjr`l(@UB zy9;w|M9Xd zNWifaWV0w#Fs(jxpVlwRYsP?Frk^;}Tiy;#^c;|<-jG9TkTqA+<~}G9z=hN0Z`C*M zdDfcvXHp#C)(Y8@EEaFEoRzQjAq9CDiWJ(c&to%pYj`sT3TIu3@w zr_*y}&JgdNslJD3;%3W@Eu)EP@YmW%glrw zSvLOR^&Q@%3UfvMLj-!TiL+S}`}8I^MfSgKHX~qE29kh}!rG~GFoHg!WBUdxIi8i; zkFLCZO8(Mm81ykeU@+@#rQ2%VP7|0e-xu{b$n`6Ajz!T}XX7LPFeR1v>&u0T@6YKGy0sG-%F3zd~GM$f}Xe z?v!TD=KTVsuCiIDA%6ppyevNQODr1AQb3aTwNgfi3bSwESRRS}z@X$w8`ET8y~9GvA90WYT`=xjtfe8qVN)9vv5{@NMwNIzX2Dm0 zTK_Z5=(++jcrzdjAOjIk#>Skn)kH0E@2OJo-X{3(QtP0YR6Ij`6{KEx(?Oc0J7}cw z-Ws2T%_N%M`EP!KMlNB(nRDxxE+4zu68HVfy=j>9H--qb=N%|}8<|w$!AJ=W@-VNK z!1}H9Sn_VL*MD+fcT=yA-jo)g7NU|{PTq~dlodK;HNyoAS|JP0bkm6NB6(T1Rkh0V z^+EN=rRt+Mtg%}NaOq6|b?hHaTUEuw$PoG#Z;M^7qndG=$v8OMQ)qe7_I*jYtx&!Lq@GvA2 z2I$NAc@8{fW=D0`X#ZD7I)awA&6L*xO4jL?(=@+DtahUkl$Xp0+d_7u8rVw*RtBrB z6<1H2$hUn)kh)p;VzdsCj#k*Orp+l;zo;p#~2UzuZL2Xi6W=}3N~IvhZ@LI`#L_$%)g*Y@yE-8+E>A`4Kx zJqYLfPrQ#jSG&w^n3@ZGAn6~nkBF%A`MJ8ix`ca5F4v;?#*_@S=TA1~CQ#;T)4?e1 zUw_|}60ba2vK~UI?kI^eb~4(Ns}%0~7Oc;tkXx`VdLg!8ob*Cu!T7pi{sr4!6w=dw zdccdrM%lF`xUMgEzO-7mE~A)yOmG#2+7^{DLlPTnk9{F~T9RHZ2}f5Vx-+C_S2~y%ti7^~eX$kmsc(+rsu6a%gRQiC`d92D|Hhk%ps>WVmtK z;pCbIPs=;8#-p~x;P4ug^ie zp1{lE_+tU2*W+7Ij$1g*`SmHB>wj*|?0-4F*u1<;#feS!lYr!_Rcvpqubm8h4g{M| z`pQk2H_y-R>~(5oagU1+N0v)n^8Y6C2J-G>f8g`>yk3*|krPZCiFX0jo*qFB0j|D1 z0am>HQFyp$kDmAgDjkOpejVj4n+4zKV&3qf_kMW740wrMImtL9eb4)U+J8EBf_s%Y z+;y_f=^bC7AD!?V|Izi;u`WyF_g@R$+c$3ICg)c+wDG|+r*fE98RK^)>HzuT4vf*2 z$N3c(>cRR-lfySY;tU_#@4v83@AV44<)=o_@eq(6WMGH7d&MEV1Gt~Uh7t4}+iNc| zBlbvPHTOkl__5nx(e71n$X5MWTV4}g2*JOZ|5i8%JWIexv2E? zSqfF-vDC2uCl=E(xIBK(z=DDHiSgJaetXjwoHn?bvaHX z$ySgA9dy~aL1LM!Qql|X|$3rOs7HD%V5mfQX`5~HP0E~`zqbkCgC zy=lS*wBQqva97SskAL{jKU#-B^#6Z^Z_K_nmn|NQ10H>EmoDFpkxnxs3;+7}D^6ic zG`nwN@DKQt>5tiX!G9E7-s^B8*86hJ5$%i2-h9NjBlnXd(dtN)6`a`~2|0Y$Es!)l zGO`+KX>ymB&qp}&R3Uq)0PGt{{-V&n(>IsNyZ7qwcb9%Ys+>&HBLC$9+u@I_(PD6L z%_|Xp!sWv^mHYg@+K1rlBfDma2L0@?H4?HXKt7GXnE8_3Fn{p3r%ijKz`Yzm_#G5D z;A8eknp4dlJuTa%uV3fjCO#vcw!gbiLz|zYHJ2U3?bAE9qiXLj#cNwXIEnW)apI@5 zChZ+q@Za38ed$pyTeH{hm!d^#f1!`ZoA7>lH$JbM2aCramN?sO5%9hmV7WJl*kFxt z{jA+>;xl!G zpb7#YBS4u%K~zDA00{;l?9l82V|in2WpiJ4X>(~}X>4h9dC-9Em*WZoC4W=_c$efa zQ~-dSaH7C$RRRKd|F9U)mLF&V*btsTpde3mbZ~WaVkd7ZLjVET=P(O>mO~6f0078B zCzIW?^Fk07L)*0097K7UNTIV{2t}D3w-kY;|pA0{}qyqade% ztFWy?VPk7&a&L8R7QrGW6MwkTF@iV>-cYGSZ)|UJ0_YL&i!J~trQ>qbtvq$ptvrC! ztvpk7a%FC3bZD6E;zn$5VIYjyuiqqeNmpfQXJ~XtPzbS500960fB*mge}DfE0ywfb z+5!Lo000000D#q~5u!9CBS}&i*5CpWk(sG&5@0bb4pcxw0>ca=M1MdCA%=*R7#S(E zO%CG}TP&;E?dlN>MxoAy3WT-VO}q^gU3HKZUjmqZ!)DPC1oZN4cvGN-PI;BwVY#(5 zS%a&G96RNMcSr;S7OhwoYZFtjkxe9yefw>Pb&#tFCZl;x*e&oOnEfc$uw`-o7FXup zbVyr%;ILt#S31_n)qgs^gRde%UNH`EEVyyD4>mySws)s%f7OlMbksbBp|5#KPg;*U z{68Fp=`iH-OEy$i$bb$$T@mn*QRar!3a`~JEU>gQw2|F(*LOiql%B!9IUHczI+bDr-A`MP_D zL2BwWI?Kfgh}Oby#+OZA>y(}o0$|x-L-<74VINz_V0Mcl=Pvxv@5sZhSfil2>wEtq zyp^D|prd+zb*)UE+Zk)6vySS!a+2#t-1tnn$v?rPuEBqCGJ}U2VuPa95u1qRlz?+O zvvgV>z2LN|}5SMl*OhbrTHdQFKFa2P^0d)ibWCcu9001Zg003~avBm=c z0021w00031OjAs0Ze>$+d2D3>Re(PL06;)L0w@3g$U*=>97YO2F7pEbU_?PwL1+Lf zQ(q;|OuHp#;rXm37 z2(UgZi`|01jiH9D1SiBW=52r`ApCV$l!M`JQ+amy4;0#gEz0#o3Q+lT_5f>olCA!(>Gu*eEGF+jVV&@LQuw%S5h z%^WC`6z7S#_(%K&y(qcRWY)1Ml|(k7=1R~VCh>jn@UzKmHpu|TYg~ZJoXVF%${gI^ z6ygu|kg*BY2;#y29l-1Zbswf-cigePDYU#L-_ zo5)P532sfvoR~y5p^DN>zc$sMOg^DWWD`n$CXq&^6cNe{EI$f8CV^PtI5Hws|vc6)Jh(WOefb8`G3F8%Cpn584gt_{(JkDxNkm8&=lB~gu+=%wir$0&M>?qjMTLiwQkExIRH%@9qI5+m3lAtM0D?e$zfe@(Af24?@`|zv zX?;Sd|E>Ig`>(=(5dKF2@gK*P|5L(zIsBI+gu{RTF#n(Y_gyfA`(FqK7I^(fDyjId z^dIU!^1l}mq5opq|30?=Xa2wW{HiM#BmRO9;C}!o zQc`~(x$Npe>SWSfoo<)Q8UZ z7uV(gef96V5!dC#>x}U*|2xN%SR_)2a%3Ofr*PM0YXIL`i?<@wse*iA7sj^E}VT7A=@aK`MY|DPtrd z3DJ77b<_gN737P8BCHlgT+bwu*}N)x8ojz#xc>A94*hQ)M{(k8w$47A&1UI3Thnw+ z(`#yE_{E`S_zj$wTJ|^&Eo#M!wp;Ts+`3V2+aw{mc0D!HIyt%`2w2X{Zpp zMY;8szBK$`MiTtCy`2MGwtk!cx3Is7t$tGzFe57&4HUoM6LH)_ZY7ykM9<{aRhLx| zXY*L()Pfe7;03GPIgQ-L`EMO!dLVy#|6e%&YtSa7Xd}@e=S+^R|6k@ny$Adk;s4zU z=wJK?qh?2|zyklx?D)T-|L^MmJ0bqB;N`ynT}b?o>;6BIqQL(%ar<8a?El@>|4ruq zm&F^NDc>#s9ccQN`Cl|dj+q@O|KD)=FTwwv|4II*`5y<&1ONA({u}w<_}Pt&+-50f6#w;PlsgK#c#}q$0W%`b+(#IF0Q4P(_96|KCmB7 zn4@Q)BBS@WQ5Ceyxn*N2*w|#!K(hmtE4h_*Tq=KwFc{eP`vv=cYXAb{-NLJ46M9VM=+S-$;V*FXb*|OL zZ06W9gkzxoD8IkYyUx*g_3V;zK@L<9+k?1TJBg{V8xWR^RclaXQd^x_mDFT&266^l zGHw!QSBR@aZ-$d8ZzBA_wjVfzHylF4g+fo!$Ya`n8>idrRfeVRW2S%M)9~RU4DG2! z&xXQ}fa4o+U9M?VXL1j;p&t8-UgBNS6+)R^T*)Y}SSy9o0)c2km{Fy3JmrWV)Cg@x zRsD)(N@cYO1UBm{S<-UJ96bE1`e_Y|N_s^gFiTD%=cBrRKV^5UZOMVaD=i$;2%@hg zi2gPDCEZ^5|9(g*9Q%L%`+i)J2!9B_tE`GAai)3%sLICe`x~aKo=xb{NTWDU%kT(; zA_(e`(LJkq@RlPt6DY8BHThaT32}09DX{){4;5mZVsuU!c7U3qO#K8I7#o6_o{+YF zV2!99^j6xyq0YBJmkbQtr1X~et~JO&mMnqVFl6lo0^iY(Usca;_k+WLITaQr>PNlavjOuZN~fJtdq zQ+d2TNb*)LCB=U;dS=5jDr{6tpj)(6k~5QIv=zBYUk*572;~*Dk}FwMRm9gKv8#`| z)B=&OEu>dD{!!Kq<6*Mic#VXbU?>R?kX0E{6hGh_vmM*GYesiL?o=!H~*j;mgm0nfl4a7OOL) zGG*%gZ>%_6nwDW3mzoc+Nz&d?wO76S_%M8<^d_ZAsl^_u?;z#MZhC3ODLc8TAKGxJ z)_vLFr0&>MIc(?XHK#_wflF4e-h;LbeU&z^$!ps*t(tRMr^PaAGhDRdzmqMDL`N>Q zu48|s)F2r?@tql#6Q*71RM-Rzp8;qah7N5@b#d0Vk5C%N8ZOC5Nl zLhz{?zoTt}uRD`V;CqaRMx`T2Y9+>Zv`yF=;+qr(T<GVI6t7zuvBN)As({T%f=-Ejst6nvZ%BY3K|(@ zXk`VwivC|3)Ks z*jC|-A%V^p!tDbb-Q;t)H|A7y=8D;EHqeB;%HJ@wYkiRHG>F+x#FcL%@5FKY7&*I> z6l+;$YH)KuS~w=#Wu_L1vmYby6;BywHKqM%HO7EqQ`a=c)5I-$2;piY2F?8lL)wMq zirnoq+k3v}c*kMu_G4j*m1%#0I5F3mOAu6Vl0FT^v*8U5CtTUr)3OB(Fr!u5<){A# zqv@gUszJ6+U9~kX&zgnD2#uZn*y3vYK5dhttc{Lqg8nNsI&R|X`g0V^B?!6|8c8uR zeD6oI+TnJ(8_^pg>^AX+f)Ur}Loz01gTniTvO`yu0ms0k21*Al_|AXqT3a@IZXvCa zcz0*7%@OVd_*R(x+->M5GVJ@Y`iDF-{8wuM3u> ze(xvbG>OXWTOjvp+dN2g=&ke-B%{!=G zcH^A$UOK)qatUL?sPp=!WwK^+$QVW$vFp#M~L!>&kAB%^<}{xAK;?+ONV-H8^q z%0k1=d~E5~hszmNC3B^wS9ijeG0hXDT$~HV#}PCx@JhM;f*OP>1J~L6O`T>hiWF_` z(*)Y|xTSZ#`_X@J#(=_3-D%9z3=Zs*Ii2|A@mY-)k1h&fHz^pV!Z?{8YH8)eLw2h)BuB!u9{+7snfA)Jt|hXQyh!? zu^-^>QBPR9^Bm=}1YviDI(TA4y&r$s+735$H)?l?v|B|RW~BA; zkcg@_FziCy;nlLx7|J(+JIL5&T$_Cvk%i}>2k@O@Qrv4Rg)@P+l~UjD2I&)T`hHCP z@o%fW66oWWIfXv2)`YF>I&2M@I@2pY*8cV=?zT*mXoo}P_N-NhJH@NV?`B@-PJG3F z%w4l1eZqeX*c4wjI**O&W;*&V>(D2g?bIgl`k#bI=r*>e58lC0lUa7DdIxexRl367 zb%BZy|^^HP=_WFzxv%I zR$PWJ$3iJZW@9kzP#5sty%_A`gJC2;Q2VQ;vSZwW`_Wj&fErHSY0Rg|TVx2~6-^wp z{pf#+6z18+ClO0hxOR4biv*d z*4jW?li(GXW1{g|=YY+U#GflnHWNSZKTLlysKYw?g8??gY`5|a-*ffcA)+K3D(lkj zaDI8xv5^$cd944CUIVNEr3LAsQJ|yNMjlK;Z!6_qw;Sk_u<3US*I)jo&y@f)+A~{h z^=&WJhziwc-E6B;Vn?Gq0nbfzwFjfnI-W z?6mpo2elw6=yicc0Fi8O0R3Tlb|7pM^+GPFduY&p8wQ$*w+~qU1iYh0r9Z5wb8aAJ z8eTp7E^{xvP_NdWn11-bPPi$;{ECF%odRa>`+A!kC9_HBs z_uuVxTO&`}5JuHXUG>CeicWw2T|;P3vEU(TW6XSIs|zRStK%x@?O{ICFBUh2`W#_) z%f(+3Xn8kvvMuV)iGFrm4P8t)1gr&tVkf7P}J`w zpUs;2gZQVsiTz02;aD3?oRCM1Rn}{K)c`!YqP+sjepG5#jc1G0!7zu^|<^v2H+gsMm&|2)lt- z5N3xi%lXDarae%yA0fRq13?VAqP2CwDG^)%5d)Uv<>x89wK0d3Al!CsE`HQu%ePiio?$B4H8_10f!mpBkb-~V;ysI>a`}~Z7q5WA z>^11cRCxJ)ozw;Nod!PqoG%nWbjBJ8*iZoO*G6~wq3JPVF3_u2hWyb-sPe}E!lWvJ zqD;U$)RaD(t#iPenVi$0r!lwXA;xPwfmDY3DTLXD=N0p}qqb+dr_EDq>Ba#wAfp+R zE6K`I{)uJXTl#<5qXKJ;2d_NRVXJdOgt5)RhFs6el?^nbjr}=Ub_K%y9R+mN_*-Nh z9K$Z~Ec`aGqDtdAW&eEYlS*3~KoGd11~&of-sXsA36ZfCgmx2m`Z31$~Awa2;Y3c5$25pJVxr`e)tL4 z3HTpo-`;K06A$}m%l>h`UBBY$qb+NSKCRXXTkJa68jv#6ReY}f_UPSgO_QjPh2^p! z6YP^x;UE%8=6BX3z{kil#lK|j`4Jx2VD8fwXx%Y9>U{U3;fw)=o!Wt%hlam_TL!jL zXotmqq`QCD+1t{&;Ce$dt0pkf=S-ymHd?jkN73(NIo3DR$+>%?!A!Z{<)m!>nXh z=ETLxY|g~DoqH;{1}L$*wzOY1$Ao5u6nHBo z|6YGF?4QUhU#<<6^GzdF@*qg_E)Dz9W`#}Onl#TJAvwwF-Op{Dco1M_hCvGappT#so`cfB-%5&;&%n7!BH#x=eus$kxvMEV z@1R9Md+b5w0P-h(-jo%CH)nVCqX+!08SZ~j-gpuJ`BGu6SXd;*!k3Sn-+j*T>cgRl z}~F4*sfISpxKY~sCDvN7z?I0WOLOZ zC+dKw0cdmuxpKPw7^>ZqoNb~G$1p7zy1>1i{doNbQ=e47TT|xk*P(d2o;g;x1nPg_ z3e)YxvEGmBKpn>DZbUSsZa3-;9`NRIaKtL;IzV+yJYg=>{R&J!h>j+)nicy7 zn-&CVd>cEDYAphUecR6lm-%VGNRH0$h$nsPJDYztpSsuJK)yGv8MJBO`_O+T&mZME zoJv3Q6s+8oLLXl{y#eg}g~1QZ_am88)7@Qp6+rB(gTe$_Y|p>TI7FfJc~-M{aLOeY z==l4D;zbVoq`cPuM2BJ?<{kI1IdLdy1NJ0I9jE#$->&q@i3PiwNgoym1p<}1f7`jbC9KoXy7^5IIm zN6I1^c@riE9Ua&sZT{De=+eZekCY+tk^gyDa z!Q1G|fL-aN$h4@m&d!#8!NrEwT=n3H^RZE}xT=EG z(@%MlE$XfWmO;KDA?AN}30rr*3L)dVMII$U2OC;-H6fyN=G=mSmL%;yh4#uB!C+W1 zw5~5sSuN{SXF+I1LfCcKnapb!N6tIMW4FD6&^H`6`>m}Z`c+mW%H_d>yoww{q}D5> zvcauGSoi|U6iB}&iaiodmopt|i@qop3Dc=EkLj46yqz?CnvQ=ub-T)pFQ0x+x?v&% zey@*!e9C%l7(|C7rl%ZV*%VwM16sj9mf7k_;ujkqoRwtVgR7qoF+0TANlEU$gQbtz z!Gq8o#EC5;?sVq@4YsK6#2-M znNLpMl%B4#ajAa<#2?H`yB`)wo5}-IQICg~#Mar1Yf-F!)|zilepmH4T5)d!Md+r| z@N#L@AN~!mD+YmeT?w|yN}Jqi41IIbt^V%WM&39x2tf5bD&FFqB$hdTHlKyY-s&Ww zL5xm}j?MM8?sKuQg>I-?FWB#^7y~}e%Ru`Pbv{Cu2-tsHVMT4&>wU=$M&ZdpyLXwC z_6A)@>@QMH>0dNQg~$1KV%qb0*B}r3PVG0_;We3^QnhJ3s4058r+??Lk%er~ybg{O zP5A!7pk6&IO9GNKlC;5)0u14=c3Pkaj4_rkJeRt`-NAGl&oe$Q8x(mPdxr+}p+K4j zH&B-Gc>sTkZMrc)JQ$TOG{G*|ntC8KNGJ_HiszH*WQ1yTbMd=m@EH430B=U;z?kr- z-U@LD%o9p&^)pmG2hIoW_7BCWT1_zN+XBv4Q9aEdy)%J|ePe$mWSt!cx^Ecr2^$gV zbo}liC_3XrtlodO@c;R)?|bm_%guZ1Ect!FjgWst6!PE9>DV8$g$9g8xuwcIN{n`1 z&UF2K*x>^>bQneE@Hblzj~ug*J{yRh8$EV^6dY=)tbb1dv|*pxqQ*D;Wh*L9LFQeNGT9O=nT909Oxs33w&Y(8->ez28F+n-l(Yat_G#ATt2!?8O z6h_MCQ}Gs^$uuQ5mTUj!htVIT!~n{IOdeD)Qo1?@Bq6$Lc4h_;2b4v{m^+B8>=334 zE*GjIGo_mp-9YNQ4L$b!{tCm1FI>{B$%lVzIsrVqWQ%OS_Ru3~|LDjG3y9rQjC(lK zsrxAN;I>Qw)B(x?*#S>9JHwOaNihlz#TD9Zy&$yPG9$FxD)V(Swnrs&Mb8*qrVP^Z9?D7B!s~Cjr|3 z(@>nak(F#yydKcV#uM^#^E_k|BGXU5AzP4^gAv$f6yaD4a3Lfg&*RRP`5y(!L7vmj z6pxmFa@3AYCHsU;;A853`V*`;k*t3UKi0OKM)0cQl4Mu$s3J86VL6TiShFy<_tcB#?@Q9UMB%l#)a1tcLj!CG_f9UePX6b)Z8g3Jf z%VsJ|vX>GtmqyCv($(@tt;213q%U>watBMpGA8TAJ$#8|FNfeMt~soD<+b8k(XZ?n z)Ijr+Xulx;M~ApCd_no;s2`68E`@AkSexSb2!Px+ZE;InFBz4V`mjK?8BZ>DjMfc( zq1%+Y45xlGD(NwNEa0Ep2WWqiaUA1iZypQ18vkewG)MH05}|LQ3w8r z)XEYDwbxiPo%sU82Uk%KE!gCs;E?)Zw+6(>Qo#?B?b7Y15w7Bd<0Td2lr{zPEw%Qe zlFd@lj+^D~7-|SE^gD=lvrr;Y2+>@2Ma}af2hcfz=t15Y@vWjBVhz=9i}mJMM0zvU zqKnK$VAM+sDA0dwC|=D)7<&}yP1 z$OeCB!9&Y&r3|m14y{=KqhPdXdVb>dT%ZYpZ=Lqhh*AEdMttrz$Ki1Q|4mIzI2`WH z$;qj4I9!dx;gYbjvT8OpHN81GId4u*4jD2nI{P!TPd|T1CwAWpTzSF!n*3q%Cfqmr zt-#WaQ}b%~JAvn31D?W(#B+B5xDGYXDlr`V2xxB;I}-3sGa`#O0=^sejpBCOGdw4RZmdD)p`Y{qqfgd*;qz2C@Gx05)PS0>%ylgYbf|i}??VQL~Vp7jBPgDDMb^ zG7W@+(d2(;H8w#hj!2x*n3H6{C!e)6oN2eq>~Rq2FMHf%v*PZk2CVcU$NF+qO>JLZf2k5=^*ffI>D zB9TZW5{X2j(WsoIL=2I!m}lmY51|u+hID}_Lq31IGmrTUN@j_x8`v6j7TzDOjs#WnN7a;Y zq^?BmmY}_nink9K`QAjxfV4pByEorBidHpX8^5DF4co?sGWV`NtGm{8{#Tu~#ra=x zR@#aG^~B1W_+L$|tIhvvqo#TOt50=^{a@Wx9?JgJGSvqCU)9w!WdACe%0m9H=IVc# z^IvtUWAJ|!SHUpCwbd`ZKErc`5In9Enp?c5{FJfp{qCRlh@> zehcaDi8-h=lxLL;su>6f5CjEt7@&VJhC@N52r=S_>H!o00}4oRd@3j~I8fj)hy;Md zKmZ^l004jiKp-dpfWg233=9g0a-wW67{K2qe|Hk07j}GB7c_2jCK+9B+~i-bTRKu_ zs+Gi|v0E{J^AWv+$!7NH-IbeQbPx^q$|4uQ4-fN96g=-j8wYVRN7!aFLIQvAyda?A+F`&H8 zUJG*Tl$=$4ElMGOgYXbIg6%Rz)lJse(-4NSqKjuj-QL;e^mhQaHNAIKJE$EEzJ4BlG@=bX9E+~ z_MHup9lGz0#bJnHH;y($=Jm}Xpa(W|q^7t7Z#h+C&@-beud_=d*pk1s)7jW9xC1Fc zpN}RL%0%NPcW2&JgUJK^&Mvp!U4hNy3f@|Q-c;*+%QM3aTS;3^cAI}|-dATKMNv!W zS$kS161_W{=vQa7vlRcNta+9Vnpy}XyT(hJLv3#FvH}Y&PovXds_i5_aYcdOn7cy!1xwEy)99jvH z9t?&mTLS3bVI`Ko&VGM_)t&VMSQs@ev6&8$T_bb6vk7)v)oaCZ&yVdMZfuQ%W!+ZX zAeeCV!qS&ILzUOryWm$3=~=DsqIjfi5FCOgx}ukV;<}GD-WozvUb$19=w|OMjuAR& z-W%)dSTozrWe7ptS!2oay%emger#Q@0mlBHo0#%C+g|T%iB5k+tWOGUZK>CE$ykAc zoj~3CoCjXA9lr8#Jz+}U*`cmO3%#*ihZye0WJ6V3-yR~raKo2V>N_|rPdVoI+JN#p z8-HR2ajK8C?+jwOh4eU1?frGJtIg3Uf-BM9&lSLv+8hM@oOg+Hm)pZRF?t8eu2ye%0w1A@a%J<@emHitN#_8)w;XYW=Q%O#WD! z7DX0!7D5i@hZu~zS}hTe6peGAw%(r83LrHo7cS!7Q78Hlq;c-2gx`M}0;Kb2qPYAE z#8~wX0;l;eWOL*r1Y7@7#7p-zBDni!gxK^7!X*8Hv!8z(1HV1iUB|rY>@L>*l^jT_ z(hDR)h=fep+I6HXFUxI)2Cr>y&$@RP+GxWTd#11hZ_1&LL3}k}`D=d!*WAFLT9X?y(2FoniyeJ98g>XI znw#96an}w^KJ0gP+j@2_Ftb(gYaC*61h4PxX6t=>!_Gjwzfr{S)^^BF>@(sl=~yS_ z#N_x;sxtMgDQBIXU(?h5Rr9~I*3#ym&qHKuKmK>{Yuj4E-vuSA$Pi=(PLKDEe&}IM zreA-~6CMWQruFc>&J*N=gln#wVz69J0){>e$fiI5>|)GN_q)=cysS*Bs zb+%70mWwb>o{aF)zsCE3&F0TV!yvFaz+Ha|JIK)5sUQ2Qv_25#*vt~!0Rp7|k3MM9 zy}E5(Kvrumkiu?MI{_#D^7o7`#E*)bLvVZgr_cSuk1Td)sd z1#pd^8H;;>W^gC^@!12zQ|Ow8{Q>QB=)Otloh_v-44Ky3ScWKE!2{{ea*^7q;fjAy zdnRm8*w}}I+}(t){8DZLR0o!tFt8K$HDW8fpnEgB@g{$hFoemv! z+L#pI+VZbSo4W#8w-bN2HYYht06u?Lz%FmXVBgt8Z-$L+rBX zhPbqm6j9zkrXR|6;r&E>oq#%PM=9{k#ZF*5fvr9oJD?K+H}N{r4u2+<^gD~&Vt0u@ zqbq*vxq6ej<6B=AGi;@OIfqTGbzPo>6tylpXDv`NCfwOan+)-Ae}JR7R3Cp9Qi2Qp zkEgcDwF43-dyQ*1yC5^sTmA9EM4as}9m&dUU1wv=v^sw`Onz?>xtZ(3o9lb=!P~`c z!Y9{inY2b##bF1X_d!tTUC!BPf4=Rsj!qsFOMkX3a2P}$P}86wW%6wR4BsxWRiNgb zZF|TGt;B!Bvv-!rSR5dzaT|X(lzHA+(D#K=)6$#i5ScX$47NKPXm6|fE6(=(+3s~? z(=b@{WJ?RU1a1@206##aQ^7i4=t;+>7- zTe9$GY=zL;W~X0^{L6nvQ9?GtGf2U6Npa@7opALV#}<8-?P~T*Bxx@cX&Sn^?zrcM!V)KtgVGvav;NH`Dd@Iiwgjw58jGb$E ziX^5F4DwK;-1dJ!0qOsvA2hX@tL+PH2{Tu^2XGGZ4(rH2H?#B*dmb-Zbo&~wvA6T@ z8o&~n+8?4Pw&`+`VaEOLH|X{v{Q>?5T(69S!XKisPZM8C5}(uH}Z4O`M7 z#%r_vo(@rNRnLm^o?qL2-q=2|2^a<|dJJDyAS)uW6G?yFSrT_yZ{^%r7kR5abLZFi zR-e!6DqvIVBJ<@Vnk~B>Wo7R$@+t8WK&@>D@!R=To)w1kO(@C^M~k3B?jXXb!l!Ul zY`$h&hFtR@T;adE;>`-C+D@DwoqOi*z78%$ksD5gHSq3PhZIwo4qRMU%Keo+v95Y- z`^lOf7HNMTQ?=XqFn~o5`v)?|7zB?~^gn#{B8H&XEk`5Bs$`7E6|47Slf%^6cnZbn z-n6wbe@$-3c2805CUfj`3FDp=<^)}S;B?szSM<0+IwY_gzZ>YS`q7Z7H5)!1uxa^< zF{IU1_8PH#;BHPJ^2oVzbO;N3AovP%TrpL7G=+b`G;tjb=r@UZ9RPRgT=yHY9!<97 zo9N$K?;0h9B~s5>OtXzuV(XxKcP@{hJl$L?(t67rvze`eU(-K?$jy%#b>s(rR=^oJgu_H~9cjDsF7jfj&oabFy?j~|l zN@T7u8S+22n}G+`2`rhQtXjvjIA$}qxk}Y zDP=$~yA4}JzH1w+tiqpS)$te_`%k9dvmAk9PDlzFxZvUIbWV%p9oBwykW@eFb;2BB z`l8N*%-<+Z6Br11>G#jiuWH@EF+r`s5h6Q?e>y%bYc#Rnr;l{h082$7X?@mwsxg2Jex! zwrR#_18sEYwE{m61GhmP9ve-bXl$Jk|1)&=V}U3Jo0M=!>@}4YD{n|A-fl7Hcb3q; ztr!kYSli1rM0Dt`ixtNq#@#sH5UGE6E1QU8K{|}C({NB261Z3RXB(W$!Q;^mAT-LO zjJb&AQv15yiu5aX?hn$^>%E7;&2wUAnB8#$LvbDVw6wspWCuS;gZC0uR^iG#wgGiZ3s$eA%ff}92x}A+^ z{&cs{3j5}=Sqs3In%@cs1MoS5OA4@`qy$dB%5oo|CAz$y z2@T4H;uH(Ybcl0f^D=_-lhy*wf;$1VLy56O3rDa-B-oJiV+veDkwdT{`aG$M|F}`P ziu42^yfH9O{UQlalh{Ezuf%$2s+?0Q!<_hPXw zyxC!^>-!8>X}z>V!RH-^Zq4cC~SnE0UUF(Tv?*ll8r zSba8EE6gWgZ&NE@esf(1+}BgWK=U&GH^z>rE`{pXH9s3c_q%^Ewp`v0L}Y`3m7l7a z8hE3%^A<_V^qmbc!gAa_8Q+%bZA`t!S}lB4)L^PJ;w{Qc&}^OZ?2k^z=6!csb#2u( zim=XHV#q~Fertu}^e|^f_sejT+O6&5HCe=0##Sc0`<`QNOBhyHcA_Vm>(8dqJ1C`J z&CU>#yEWcGnX-SL9paP+Z8)#0)H^&wS%fjq;JiBB3VUa+zl6(@MX}>J8N_2mr-~0# z2zKK5kE!eL_-j&Z|7_SF>l>IWKX2N5*J|D}X1}S{@vRTb8CGe(oWhgUUN22TMOc+> zVd=Oj+g;R_qNE=qkj^R+fc6Zl2h>*_e#6HxCiXPQ)6##NX^8ywLdX4>Y`+V=RvfqU z+zz7P7>9+u0&X`^tk)$*C^HhtBQ-|Cop7nG*OEtrX!JY#vA!$C4X`8ZszcjgT^|#b zYCz#J0!KcN{n*!xn@ozcw*J>d7QopkP&YV7WR}E+uQ**ysOtT=t?R&|yD^_3mEG#u zP;J+@hDd)t-0VpLZ$G(HC(8XjoNdcz- zv;eaJM7yCC7t1H~o0H^XhWutC)qkeSuJAt#^ACUOKSSjB&{B8C@b|Mx~lvA`cUNUC@Lh=EaC zNezEjBgL_L7y0euWis{mK4}W<(&q53V6(R=vgx^NFm{un*_}z(7`Z3Kl{O1}4r)3HdyKMlQZ9cOn3oKTE_GdMTwqc=ttmTbT&!s&Sq0v5 zluD@_i9qqzvZbs$%Z73Sk31^vlV8%pK;zc>;eb5O={FO-VOA=Jg9BJT8vSX|Kf0b| z5`db8_=GR8A8PE1vS{)=&xI2gqGtv!vvN>(KF3g1I+bE$Y4jzrz80-7r(u{^aJheo zSW)O|vhMy%93A)sHMl^Vzn_9lH02RsLml)9aOATbu8&(u2*l)utml~u{-%Yw4i7%S zAKX5;+`)_+h;ar;juW3H)`673%VoPDO+qb=KI8J7lLL5fxGjqnDR%TnFA}^$g?BuF zs>1y*ZPd8=z4vF+-qXPu`klPc6ytw_IOQ(!HpINeO~q*{%}_j)04&?q6$C*?vLX!8 zP-9GRvjo*nZBUxQu<%&FkgfV0)#emeAH={2{MXpv|+4MK$Cfh)nXv8;hP48 zy{O}=tt@Pk#zPq3a3ByQi6TaoICLHpfWd(S!f8M#7!D4i5d>if5CkJ=AOeJe2oMBe z5QgGF8l@N;4#{3a(={kE%wvBziyScJfkh(T(9=jc=jCwmd(B!0|7WWtW75j`^U}L0 zr+d(UWrERrjrdAd;(<&QUFIC8Uoy0`0vl}NL|;x4w}Z;PnjqLBj(3A~gNlAvb}L2| z?{Is)6SKgOFn>jPvZ0_q61H@|5|)RLSRXhKA<%tgEQwxh&Wpy#K^Gn_A6>y?~t{{iEpXU7Ma%*gxC;Ykx!O$^aO0 z!1ljmuNN}4y{Bb|EpC64X7rV58NvpzWXV0%uuog+3+=;WMsh#f6YF9Ba#{Z;f0XSn z$s3x}yAg)It@_`2>j~IJS)0$6bHJGVfsTgeHf`2D?iH~)=+8z;ex0E$?*+#VovrH9 zrv{p4Kq*xP4fN<7yu~d3_-?VId!lE%*P$^b539jB@fLGj^zDC6c@L3xP3-Loe));C zTh2K;OBTFVqJT`4=(h;z?hvvsQPL2)-9~MQb<}T$JfUnrtEF8)gXMk3S_K_l@)jZH zNW6RfVie0fb2GE9Kb87#q^gqYuzx$o4Q#&#NNqpe7E z9bkk0*(j3Ug^Lx#?MSvm?CI9yP}#OH1-W9o`-wswSbBf_T11z3w!GvS=X8My+57#- zabkIWIBW2aMu)Kk=3SI_dKz8zo?KnWj;(oo6f9~yr_&KnVN$uZxw58WrFa@BRyRIp zwXdkifff2sX?Et^W;q0-zgqLoeN-@yf%DwE-)t?9KfBh{Nr^0-6fuU?VqjwcfVP8)#k|!IYWyV68_A~ z7F(S)&Fm_ab!aOOkzm_A*SH5;Yzxi9k6f?LSWyh@0G#4qF8-q#GFA$i zv3O*{92afOI|sw>B79=DbL3-t)dj@ift$uji1}Ta`%c|JO^2p$b6N)4b;u3$XRC<4 zPQiZ`xFE@f5Uc*@QSp)b+Ikgna}*dS%sLxwz| zY(T4h0L;i3Gj`3QOD;d?yd@Z2j~GVra9Dq*lDVxQ>Pn`7iK5P2dj5hcu^6d3>{uI9 zk1s7S5?v^F`K?9p@E5QX&_9c=-?8BdhyAn3zw$TKt`1q=#J20zGE-en?BeCOp|-$& zogwr-f;2=I@7s+n0PB53_2|A9K3zxtT#J99IX?U;&OQ;}H6Bv1)Cb#?F*paA{NjJO z@ssJNKfr7LVfX%SG6=2zWv%i?0A2bwQBxOTFnKUdMAbhQ^1wy@6NWcN-3PW*b{O0? z7*xvbZ?z(96ir@@=j4eS41Op0nf-!~T^hQ(_13ZsBR)3C3$2 zItJJThY*b8&ynoxaOIR}M!D)BebGT*<&{4LN{MV$H8w>UX+L z!#izh^M*LO6a#J7ct28PzYByF{n$>#Y=6&@(qpd1tu1fjg)g@9(K8XL+n3CNrvk%x ztO=8Oqg$CLJc`}#^jS|U6dGWoWq8FgwBmD4VdbuR-&U_ZR?d(RqbnQv}&12m-BzNwPl&p3{c4}<^CCM+53^{Tk$FT+r9yD+I3BJ^cA8c zIcwZ|tU5M(Y+u?4dmXrk8jC&44pG{dT+80Ud}!D`28Olu@E+##cEe9D%=MYyiS)}6 z7p~?q3u~wMM)xC@-f@>-An-W+a7J6F#Xi(0(k?mT#yH&4IvnQs_1H}=$M~B2u`q>M zKAz_mc%&UP@qa$UD+qdRcHw*FQl!dfTIlxn^$H z8FcGQC~&eLcwT=8h4`91>^L||{77!~k3socVmo=UN5AB4wD~i#f8Mt?uTJJ!`8`TE zbhOF*1SqvH{a^qN1qlGu2T4r;06+!+03hg>9{~UW0QCR>07*?!Wo~3;av)M=b9HQV z0EwV069NEW001B_2mk;D00aR4fB$~~00;mCfIkpwiUWTjnw!v~E&xcu@d89aR6$S# z@1O#R0Q2bsSn(h%0000}Y;SZRF`zP_AT2YXpfn&ZHK3q2H!nC)s3F4Bf+X1)0|0}O zV5X7>65zo&4pZP55-=ltBs?PkVL+b093&W;;qHf>mj#yG2r0*6@f$}|f6>2kH&#c; zg&2F|(u=kn*M}8lsoR8J zYO{vON+?IRlyJ8D3&cjlWAcW!eb5e|l#L9{&3gKg5L1rBylz5#9K&)cap^PDsRAgq zFa2Po&z+nB%86A`Rv?rzaSlolRs(|OOTnapd$mh9@26LPP4wfX;8$sQ)e7Zt$H7f7 zb&G($RMr;hgQV?qNef#PzJ0*t+4Gcq6jg3ZO9wUrw~3{$G+K=yU)krZ1;DHn%LTCn zrvxMkUNDFx;Aot15*B2X0;WS4QVLT^gQ*;6;KDP?K*mn75p?V&f*6lc1Re-<5YM@ji8&3|?z$rAv3etHe9o4^yr3CIg$ z6dk*N!Ha!PFmDJ9Bg`YEp^znc%|sYTC_MJWYzcqjm1X2la8-=p3@k_-Z-lM^Kj zF?VA0oHz;K0qsP4ye48VIOPz-*o0R$;gK}}T7~Wg#h8$>Kx8Hg@tANK#wBJ^JmeBD z9%M^!vImf234=YrRJK=+K0Gkv4Le3Krx`eZ4@}2+cuK@(ptuqqkQqiLJTfx}$VLZ< zokcsq1JK=3Vhxz#Km*x;*ACtQPJ1Om&XRx)U`)cK1dIuZ(nDhW;USSYjYxD4XFzNK zBm=w_8Q|GrddZ*^!SoWZ%wAr{8{Pec2wokqA6|8sJUU7ju<+0^Vkzl3m6UKgy2&Yj z#ALE5cm{a65SxMr%4-hUYYuS%VY<6dbGVNlZ0>a?p zDBs5z$2juhIQ8)2Xn(@N5hLO790rHShEXOC`Qe3m;|(D{#xQS$$pMHLCQKL|fQ(^Y zWf;zhiG+1ox&f0J-7tBPl}H@WQ5d~{D4b4hM4=5(lWrphinZZ+ZFm|c^Acp7i5?ri z!wusavrmm@jh7d14UQ}#D@hki7+0D~8mwq2lrt!dOhzc2dSJukP-vP4m||XgYIs9% z7}fB|dQ3wmf~6tOAg1Bu6K1a`yj);<0(Uc_LH_VcG+?GP&^V)qknxPN1fDa0Mla(T zCm6^x`iCUk39(P<1TW?Uk1U5Fq)g0VG(*gRG{cd|%9y>%c%91Ngy`UrFdxRU39!(q z38u0}R({b;7(=nxY2-1XV??|q#DI)4FNYn-C3t>#N|4<^WK@EPKduC?!jmv7lkmd9 zO9Iyd4;iEZkZ3YsUb;I7&dD%;abrnDHl9Etd75E?lkLJ9-JOI1CM3j)j4~v6Jj{^b zk$H_F6974en1c~=4EGgqv)6|_!b^i4fg@c|qq~E+5y%y;boUNCj3rEF1QV>}(E~Z+ zaKvLL9$pdphc?DMBrhU(qb)Bdg6E?GlNhofAQwXvKpn;KnGY|F*{2MDk9ul}L zhLQ)O7UO}>TDF533$Pu3ynOI>z;%-$oJgNK!gBB$m`Wi?#&T4l zG|^!Ek%WxV;4}gc4SE1(m|{)JycifBnGCNP$WAknWK#w?1D|<+EVQxBW<6AxqQprV zyhPwK;7A%uvSlR<76Vf`gIA6$aO0`B5cH|Lx$fq{i`g150BJQgHBYK%27gFXGf!~l z@%-@b%zw9KwKSQ*`THU4J+-udb!A4yxu|8MRdwAJ0cL-;{kyT`39+v=F6mXzE` z$w?c^dZnIii2d3W=^<_#XxQzL&exJZtCMUjR0;n#QyyZWw7g-_ZY%tq#O4iU zwH1EW#zM6bkf!r>D>(}V@=EnGFXP zmI@!cdk-OjP}W1K@Uhl)nO53$o_f&Ty@z}OeOCBc9}j)<_d}rUNAr?*9nLnyUDrm& z&D!jLf93d9b*?_YzslBKp(svwO_ql~&#-0V?%qj%+}-z^wfi_?wESSkttfBSUKXMBT#_Ivc<^}BfR8Lsx+ZuQ**L{#Ys0s3luAz z7AU8GE;gMO8z)c>&;&~->6ov!QvT8V^`&@`87A5#qC8(KvS{xR<(75)S)}*FUZg`+ z3V)P?Vau+tS4(mIyz`!yC%Ac@|0-YU$1M-%{raj0>*q>6AE}u7>Z2>2?Eh7&rJq=Q zZ8*Kw&zWAGJSzpSwV#J!O>;!lG?9{pW<=_LkfnKkHgr%IE}DO+s*~RAq}4ay@eicd zq;TE*Ec+__m8Kr_nJ1XCzRIflp{pvbbh7@2?&nlZpNQDN$F16OSD5SH+xqag!kOdw z&a9=45HYGAq*vwP?@-Z~B+2zzRYk+;;6!eQcS1S4|2kZ1z2B}U@=@{3Nd}kJb=lX%vKDHgv7eTQSQv2AdrTBi1e@Iha z?Z$|OPv4`+y7s|tM zYMye}ot2^}_UV{9rYoCfg2_^>yLaS&$+|X*SNl=v9p9x(K~WZooQao~m|NCGBHz5) zRd$IYk%P5muj^n&XXc)B3TE?`Z@ICWvtsx%iRi*~N=Hh^sOfd&~n+2CAs8r~MM*cM(L zT}K_>7M_<3q;wD6|k9a1SdEq8_jV9noPjrm*LgO)588fLtW>Ja|;K^ci zSr#W*7A?fFh>1ijJQx-pnUB(cyF#{Pyh7Yz4e|<~foArsnB_2%R=k?Cf&(4EOF+WV zMVA1^gAK9-rXFThlw%d65(t>8IJMzb(Xk{X6|o*s@Tl-+RCu`86f(~^h1la1{&|sL z#>0&+R2yloRcWsFVsqoclTX{*9NsPoL*~R;#{$SL&e7L!nOd z5J<*xZoK3o{i1pMv+VaM)~~Y7mD_&O@9Arn`8E3rNGCT_{Z_6*I*{ zs|?a0yhsb6BOJHm1&b3Pj-WK1)ZgAfoNH6O2mri%rdMZMrM%=iDHptGu}XR9LsC_m z=?&t;d705vgF++s!8as-NJ2D7{K)Hgih7aIym{yStDV@v$Mf%3sXq$*uO~0kTyR24 zl+c8zi7Ds;7#cKahbyE+35{RtAkb&$qvcm^DBDR&{sPVyL210?G%j-@;$H;C{zXu% ziLLI#`Qa}0psG^w|BHv}{QPxPcZQCq|Ch<~B1_<)Nt~x>Ob8Hv$BkUZak!hAC#dC0 zoiy_VxBK9=&az;g*D?Okul2tc+wAy$Ziy`Wc~(`5Tl4cGZFB9tPrtvSv+PYd{;&T1 zREmNQQkyf~W)CUAQ`T|#IUhR5jl4*ogh+k2sRP4BgL=nkv;>E{=|VW%P0j;i$k8sH zVwZX_hOPv09!gbzD&r|HdCF6=aW3N^ZX3A|p3=PJDH(=r8|MWO`DoilA}=C?5+yWV zV&YLi9i}_eLn-aE3)SJ-r5=u{l`h_rC!rSN)|5?0@*+_Y9k>W(v53pv){&PHgw_g zBUHrpZQ?464|<+9OljURG&G}8hj4bD3vaj_clVcn(R7mbK|^yIjW+J<&|5)6Gmb_f z4o7cF&fO5A(JFPCHu6ZkRC173KWrm9w)(rmYW;P*NE;b>$w!p)l5=#1->pOls>y`sB&bK$m;7hq?9 zviw@-HqM!Ny@6i@ty6WahvDnE`2WS`LE!w={T%DAJ2C$6Yi)(VUw!k_X#O%Y-uX~u z*-yuYF8(8+U&!{#3oRHkWwGqHlQ*0(t@2-{6(?@9vp{eC6v)#PC-i|HmEz z9Sms;6{V|~%4l8tP1ej#tI{f7v6w-BHpc(id-C?ol^9MSdWdMVSL-_Sg7>ivKeyO1 zb(tuz3+3R`e$wu;+OjCubXB$B`=i`7SvKxHWd+vee5d&MS2+q*rFX8dyF!ZRyN(UR z={9$Rt?;YVUE$|Yd|TgNZ_^5T=4G>g?&EoX)0r3CLi*JgRT~!V$4RP(0^96=7)x{9 z-v=qK_WPngA78P&L-|^Fg%yj-d>tbiTU99(6?DuBZUCUS&kX0o-n=HQxx`-zHPJ8f8hbu8#|{O5;( z-R_GsGbAkLyy}&U{O_+U{W?Ey*)DwwZOWfDvCW=aC*MXrg(J0Y#+AB%6)H`doH6_2 zi!VCn$Y})_l^BYf`6k;dVcaye@I{y7Y&?yg_aq4>uVZ2tn=