From d64d7cf27a88fd595fc7a06ceeb90f4dbeda1958 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Mon, 31 May 2021 17:43:42 +1000 Subject: [PATCH] Dumb slabs now roundtrip the Blender solidify modifier --- src/blenderbim/blenderbim/bim/ifc.py | 7 ++++ .../blenderbim/bim/module/model/handler.py | 4 ++ .../blenderbim/bim/module/model/slab.py | 41 +++++++++++++++++++ .../blenderbim/bim/module/model/wall.py | 23 +++++++---- 4 files changed, 66 insertions(+), 9 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/ifc.py b/src/blenderbim/blenderbim/bim/ifc.py index 457c70bada..363d1fe437 100644 --- a/src/blenderbim/blenderbim/bim/ifc.py +++ b/src/blenderbim/blenderbim/bim/ifc.py @@ -14,6 +14,7 @@ class IfcStore: pset_template_file = None library_path = "" library_file = None + element_listeners = set() @staticmethod def purge(): @@ -60,6 +61,10 @@ class IfcStore: return return obj + @staticmethod + def add_element_listener(callback): + IfcStore.element_listeners.add(callback) + @staticmethod def link_element(element, obj): IfcStore.id_map[element.id()] = obj @@ -68,6 +73,8 @@ class IfcStore: obj.BIMObjectProperties.ifc_definition_id = element.id() blenderbim.bim.handler.subscribe_to(obj, "mode", blenderbim.bim.handler.mode_callback) blenderbim.bim.handler.subscribe_to(obj, "name", blenderbim.bim.handler.name_callback) + for listener in IfcStore.element_listeners: + listener(element, obj) @staticmethod def unlink_element(element=None, obj=None): diff --git a/src/blenderbim/blenderbim/bim/module/model/handler.py b/src/blenderbim/blenderbim/bim/module/model/handler.py index b50aa35bf4..f5cedd2186 100644 --- a/src/blenderbim/blenderbim/bim/module/model/handler.py +++ b/src/blenderbim/blenderbim/bim/module/model/handler.py @@ -2,15 +2,19 @@ import bpy import ifcopenshell import ifcopenshell.api from blenderbim.bim.module.model import product, wall, slab +from blenderbim.bim.ifc import IfcStore from bpy.app.handlers import persistent @persistent def load_post(*args): ifcopenshell.api.add_post_listener("geometry.add_representation", None, product.generate_box) + ifcopenshell.api.add_post_listener("geometry.add_representation", None, wall.generate_axis) ifcopenshell.api.add_post_listener("geometry.add_representation", None, wall.calculate_quantities) ifcopenshell.api.add_pre_listener("material.edit_layer", None, wall.DumbWallPlaner().regenerate_from_layer) ifcopenshell.api.add_pre_listener("type.assign_type", None, wall.DumbWallPlaner().regenerate_from_type) + + IfcStore.add_element_listener(slab.element_listener) ifcopenshell.api.add_pre_listener("material.edit_layer", None, slab.DumbSlabPlaner().regenerate_from_layer) ifcopenshell.api.add_pre_listener("type.assign_type", None, slab.DumbSlabPlaner().regenerate_from_type) diff --git a/src/blenderbim/blenderbim/bim/module/model/slab.py b/src/blenderbim/blenderbim/bim/module/model/slab.py index 2f70250af4..949b61ff4a 100644 --- a/src/blenderbim/blenderbim/bim/module/model/slab.py +++ b/src/blenderbim/blenderbim/bim/module/model/slab.py @@ -5,12 +5,53 @@ import ifcopenshell import ifcopenshell.util.type import ifcopenshell.util.unit import mathutils.geometry +import blenderbim.bim.handler from blenderbim.bim.ifc import IfcStore from math import pi, degrees from mathutils import Vector, Matrix from ifcopenshell.api.material.data import Data as MaterialData +def element_listener(element, obj): + blenderbim.bim.handler.subscribe_to(obj, "mode", mode_callback) + + +def mode_callback(obj, data): + for obj in bpy.context.selected_objects + [bpy.context.active_object]: + if ( + obj.mode != "EDIT" + or not obj.data + or not isinstance(obj.data, (bpy.types.Mesh, bpy.types.Curve, bpy.types.TextCurve)) + or not obj.BIMObjectProperties.ifc_definition_id + or not bpy.context.scene.BIMProjectProperties.is_authoring + ): + return + product = IfcStore.get_file().by_id(obj.BIMObjectProperties.ifc_definition_id) + parametric = ifcopenshell.util.element.get_psets(product).get("EPset_Parametric") + if parametric and parametric["Engine"] != "BlenderBIM.DumbSlab": + return + modifier = [m for m in obj.modifiers if m.type == "SOLIDIFY"] + if modifier: + return + depth = obj.dimensions.z + bm = bmesh.from_edit_mesh(obj.data) + bmesh.ops.dissolve_limit(bm, angle_limit=pi / 180 * 1, verts=bm.verts, edges=bm.edges) + bm.faces.ensure_lookup_table() + non_bottom_faces = [] + for face in bm.faces: + if face.normal.z > -0.9: + non_bottom_faces.append(face) + else: + face.normal_flip() + bmesh.ops.delete(bm, geom=non_bottom_faces, context="FACES") + bmesh.update_edit_mesh(obj.data) + bm.free() + modifier = obj.modifiers.new("Slab Depth", "SOLIDIFY") + modifier.use_even_offset = True + modifier.offset = 1 + modifier.thickness = depth + + class DumbSlabGenerator: def __init__(self, relating_type): self.relating_type = relating_type diff --git a/src/blenderbim/blenderbim/bim/module/model/wall.py b/src/blenderbim/blenderbim/bim/module/model/wall.py index a14b333970..0c6ec6b426 100644 --- a/src/blenderbim/blenderbim/bim/module/model/wall.py +++ b/src/blenderbim/blenderbim/bim/module/model/wall.py @@ -686,7 +686,6 @@ class DumbWallGenerator: return obj - def generate_axis(usecase_path, ifc_file, **settings): axis_context = ifcopenshell.util.representation.get_context(ifc_file, "Model", "Axis", "GRAPH_VIEW") if not axis_context: @@ -747,13 +746,19 @@ def calculate_quantities(usecase_path, ifc_file, **settings): net_volume = gross_volume bm.free() - ifcopenshell.api.run("pset.edit_qto", ifc_file, should_run_listeners=False, qto=qto, properties={ - "Length": round(length, 2), - "Width": round(width, 2), - "Height": round(height, 2), - "GrossVolume": round(gross_volume, 2), - "NetVolume": round(net_volume, 2) - }) + ifcopenshell.api.run( + "pset.edit_qto", + ifc_file, + should_run_listeners=False, + qto=qto, + properties={ + "Length": round(length, 2), + "Width": round(width, 2), + "Height": round(height, 2), + "GrossVolume": round(gross_volume, 2), + "NetVolume": round(net_volume, 2), + }, + ) PsetData.load(ifc_file, obj.BIMObjectProperties.ifc_definition_id) @@ -835,7 +840,7 @@ class DumbWallPlaner: break if not slide_vector: continue - slide_vector *= (slide_magnitude / abs(slide_vector.y)) + slide_vector *= slide_magnitude / abs(slide_vector.y) vert.co += slide_vector # An end face is a quad that is on one end of the wall or the other. It must