mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-27 02:31:09 +00:00
Dumb walls and slabs now are always exported as parametric solids instead of meshes.
This commit is contained in:
@@ -10,11 +10,14 @@ from bpy.app.handlers import persistent
|
|||||||
def load_post(*args):
|
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, product.generate_box)
|
||||||
|
|
||||||
|
IfcStore.add_element_listener(wall.element_listener)
|
||||||
|
ifcopenshell.api.add_pre_listener("geometry.add_representation", None, wall.ensure_solid)
|
||||||
ifcopenshell.api.add_post_listener("geometry.add_representation", None, wall.generate_axis)
|
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_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("material.edit_layer", None, wall.DumbWallPlaner().regenerate_from_layer)
|
||||||
ifcopenshell.api.add_pre_listener("type.assign_type", None, wall.DumbWallPlaner().regenerate_from_type)
|
ifcopenshell.api.add_pre_listener("type.assign_type", None, wall.DumbWallPlaner().regenerate_from_type)
|
||||||
|
|
||||||
IfcStore.add_element_listener(slab.element_listener)
|
IfcStore.add_element_listener(slab.element_listener)
|
||||||
|
ifcopenshell.api.add_pre_listener("geometry.add_representation", None, slab.ensure_solid)
|
||||||
ifcopenshell.api.add_pre_listener("material.edit_layer", None, slab.DumbSlabPlaner().regenerate_from_layer)
|
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)
|
ifcopenshell.api.add_pre_listener("type.assign_type", None, slab.DumbSlabPlaner().regenerate_from_type)
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ class AddTypeInstance(bpy.types.Operator):
|
|||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
def generate_box(usecase_path, ifc_file, **settings):
|
def generate_box(usecase_path, ifc_file, settings):
|
||||||
box_context = ifcopenshell.util.representation.get_context(ifc_file, "Model", "Box", "MODEL_VIEW")
|
box_context = ifcopenshell.util.representation.get_context(ifc_file, "Model", "Box", "MODEL_VIEW")
|
||||||
if not box_context:
|
if not box_context:
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ def mode_callback(obj, data):
|
|||||||
parametric = ifcopenshell.util.element.get_psets(product).get("EPset_Parametric")
|
parametric = ifcopenshell.util.element.get_psets(product).get("EPset_Parametric")
|
||||||
if not parametric or parametric["Engine"] != "BlenderBIM.DumbSlab":
|
if not parametric or parametric["Engine"] != "BlenderBIM.DumbSlab":
|
||||||
return
|
return
|
||||||
|
IfcStore.edited_objs.add(obj)
|
||||||
modifier = [m for m in obj.modifiers if m.type == "SOLIDIFY"]
|
modifier = [m for m in obj.modifiers if m.type == "SOLIDIFY"]
|
||||||
if modifier:
|
if modifier:
|
||||||
return
|
return
|
||||||
@@ -52,6 +53,11 @@ def mode_callback(obj, data):
|
|||||||
modifier.thickness = depth
|
modifier.thickness = depth
|
||||||
|
|
||||||
|
|
||||||
|
def ensure_solid(usecase_path, ifc_file, settings):
|
||||||
|
# TODO: check if voids are present
|
||||||
|
settings["ifc_representation_class"] = "IfcExtrudedAreaSolid/IfcArbitraryClosedProfileDef"
|
||||||
|
|
||||||
|
|
||||||
class DumbSlabGenerator:
|
class DumbSlabGenerator:
|
||||||
def __init__(self, relating_type):
|
def __init__(self, relating_type):
|
||||||
self.relating_type = relating_type
|
self.relating_type = relating_type
|
||||||
@@ -117,7 +123,7 @@ class DumbSlabGenerator:
|
|||||||
|
|
||||||
|
|
||||||
class DumbSlabPlaner:
|
class DumbSlabPlaner:
|
||||||
def regenerate_from_layer(self, usecase_path, ifc_file, **settings):
|
def regenerate_from_layer(self, usecase_path, ifc_file, settings):
|
||||||
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(ifc_file)
|
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(ifc_file)
|
||||||
layer = settings["layer"]
|
layer = settings["layer"]
|
||||||
thickness = settings["attributes"].get("LayerThickness")
|
thickness = settings["attributes"].get("LayerThickness")
|
||||||
@@ -142,7 +148,7 @@ class DumbSlabPlaner:
|
|||||||
for element in rel.RelatedObjects:
|
for element in rel.RelatedObjects:
|
||||||
self.change_thickness(element, delta_thickness)
|
self.change_thickness(element, delta_thickness)
|
||||||
|
|
||||||
def regenerate_from_type(self, usecase_path, ifc_file, **settings):
|
def regenerate_from_type(self, usecase_path, ifc_file, settings):
|
||||||
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(ifc_file)
|
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(ifc_file)
|
||||||
new_material = ifcopenshell.util.element.get_material(settings["relating_type"])
|
new_material = ifcopenshell.util.element.get_material(settings["relating_type"])
|
||||||
if not new_material.is_a("IfcMaterialLayerSet"):
|
if not new_material.is_a("IfcMaterialLayerSet"):
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import ifcopenshell.util.unit
|
|||||||
import ifcopenshell.util.element
|
import ifcopenshell.util.element
|
||||||
import ifcopenshell.util.representation
|
import ifcopenshell.util.representation
|
||||||
import mathutils.geometry
|
import mathutils.geometry
|
||||||
|
import blenderbim.bim.handler
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from ifcopenshell.api.pset.data import Data as PsetData
|
from ifcopenshell.api.pset.data import Data as PsetData
|
||||||
from ifcopenshell.api.material.data import Data as MaterialData
|
from ifcopenshell.api.material.data import Data as MaterialData
|
||||||
@@ -14,6 +15,27 @@ from math import pi, degrees
|
|||||||
from mathutils import Vector, Matrix
|
from mathutils import Vector, Matrix
|
||||||
|
|
||||||
|
|
||||||
|
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 not parametric or parametric["Engine"] != "BlenderBIM.DumbWall":
|
||||||
|
return
|
||||||
|
IfcStore.edited_objs.add(obj)
|
||||||
|
|
||||||
|
|
||||||
class AddWall(bpy.types.Operator):
|
class AddWall(bpy.types.Operator):
|
||||||
bl_idname = "bim.add_wall"
|
bl_idname = "bim.add_wall"
|
||||||
bl_label = "Add Wall"
|
bl_label = "Add Wall"
|
||||||
@@ -686,7 +708,11 @@ class DumbWallGenerator:
|
|||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
|
||||||
def generate_axis(usecase_path, ifc_file, **settings):
|
def ensure_solid(usecase_path, ifc_file, settings):
|
||||||
|
settings["ifc_representation_class"] = "IfcExtrudedAreaSolid/IfcArbitraryClosedProfileDef"
|
||||||
|
|
||||||
|
|
||||||
|
def generate_axis(usecase_path, ifc_file, settings):
|
||||||
axis_context = ifcopenshell.util.representation.get_context(ifc_file, "Model", "Axis", "GRAPH_VIEW")
|
axis_context = ifcopenshell.util.representation.get_context(ifc_file, "Model", "Axis", "GRAPH_VIEW")
|
||||||
if not axis_context:
|
if not axis_context:
|
||||||
return
|
return
|
||||||
@@ -721,7 +747,7 @@ def generate_axis(usecase_path, ifc_file, **settings):
|
|||||||
bpy.data.meshes.remove(mesh)
|
bpy.data.meshes.remove(mesh)
|
||||||
|
|
||||||
|
|
||||||
def calculate_quantities(usecase_path, ifc_file, **settings):
|
def calculate_quantities(usecase_path, ifc_file, settings):
|
||||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(ifc_file)
|
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(ifc_file)
|
||||||
obj = settings["blender_object"]
|
obj = settings["blender_object"]
|
||||||
product = ifc_file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
product = ifc_file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||||
@@ -763,7 +789,7 @@ def calculate_quantities(usecase_path, ifc_file, **settings):
|
|||||||
|
|
||||||
|
|
||||||
class DumbWallPlaner:
|
class DumbWallPlaner:
|
||||||
def regenerate_from_layer(self, usecase_path, ifc_file, **settings):
|
def regenerate_from_layer(self, usecase_path, ifc_file, settings):
|
||||||
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(ifc_file)
|
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(ifc_file)
|
||||||
layer = settings["layer"]
|
layer = settings["layer"]
|
||||||
thickness = settings["attributes"].get("LayerThickness")
|
thickness = settings["attributes"].get("LayerThickness")
|
||||||
@@ -788,7 +814,7 @@ class DumbWallPlaner:
|
|||||||
for element in rel.RelatedObjects:
|
for element in rel.RelatedObjects:
|
||||||
self.change_thickness(element, delta_thickness)
|
self.change_thickness(element, delta_thickness)
|
||||||
|
|
||||||
def regenerate_from_type(self, usecase_path, ifc_file, **settings):
|
def regenerate_from_type(self, usecase_path, ifc_file, settings):
|
||||||
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(ifc_file)
|
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(ifc_file)
|
||||||
new_material = ifcopenshell.util.element.get_material(settings["relating_type"])
|
new_material = ifcopenshell.util.element.get_material(settings["relating_type"])
|
||||||
if not new_material.is_a("IfcMaterialLayerSet"):
|
if not new_material.is_a("IfcMaterialLayerSet"):
|
||||||
|
|||||||
@@ -15,12 +15,12 @@ def run(usecase_path, ifc_file=None, should_run_listeners=True, **settings):
|
|||||||
|
|
||||||
if should_run_listeners:
|
if should_run_listeners:
|
||||||
for listener in pre_listeners.get(".".join([ifc_key, usecase_path]), []):
|
for listener in pre_listeners.get(".".join([ifc_key, usecase_path]), []):
|
||||||
listener(usecase_path, ifc_file, **settings)
|
listener(usecase_path, ifc_file, settings)
|
||||||
|
|
||||||
if None in registered_ifcs and ifc_key != registered_ifcs[None]:
|
if None in registered_ifcs and ifc_key != registered_ifcs[None]:
|
||||||
global_key = registered_ifcs[None]
|
global_key = registered_ifcs[None]
|
||||||
for listener in pre_listeners.get(".".join([global_key, usecase_path]), []):
|
for listener in pre_listeners.get(".".join([global_key, usecase_path]), []):
|
||||||
listener(usecase_path, ifc_file, **settings)
|
listener(usecase_path, ifc_file, settings)
|
||||||
|
|
||||||
def serialise_entity_instance(entity):
|
def serialise_entity_instance(entity):
|
||||||
return {"cast_type": "entity_instance", "value": entity.id(), "Name": getattr(entity, "Name", None)}
|
return {"cast_type": "entity_instance", "value": entity.id(), "Name": getattr(entity, "Name", None)}
|
||||||
@@ -57,12 +57,12 @@ def run(usecase_path, ifc_file=None, should_run_listeners=True, **settings):
|
|||||||
|
|
||||||
if should_run_listeners:
|
if should_run_listeners:
|
||||||
for listener in post_listeners.get(".".join([ifc_key, usecase_path]), []):
|
for listener in post_listeners.get(".".join([ifc_key, usecase_path]), []):
|
||||||
listener(usecase_path, ifc_file, **settings)
|
listener(usecase_path, ifc_file, settings)
|
||||||
|
|
||||||
if None in registered_ifcs and ifc_key != registered_ifcs[None]:
|
if None in registered_ifcs and ifc_key != registered_ifcs[None]:
|
||||||
global_key = registered_ifcs[None]
|
global_key = registered_ifcs[None]
|
||||||
for listener in post_listeners.get(".".join([global_key, usecase_path]), []):
|
for listener in post_listeners.get(".".join([global_key, usecase_path]), []):
|
||||||
listener(usecase_path, ifc_file, **settings)
|
listener(usecase_path, ifc_file, settings)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class Usecase:
|
|||||||
# IfcExtrudedAreaSolid/IfcRectangleProfileDef
|
# IfcExtrudedAreaSolid/IfcRectangleProfileDef
|
||||||
# IfcExtrudedAreaSolid/IfcCircleProfileDef
|
# IfcExtrudedAreaSolid/IfcCircleProfileDef
|
||||||
# IfcExtrudedAreaSolid/IfcArbitraryClosedProfileDef
|
# IfcExtrudedAreaSolid/IfcArbitraryClosedProfileDef
|
||||||
# IfcExtrudedAreaSolid/IfcArbitraryProfileDef
|
# IfcExtrudedAreaSolid/IfcArbitraryProfileDefWithVoids
|
||||||
"ifc_representation_class": None, # Whether to cast a mesh into a particular class
|
"ifc_representation_class": None, # Whether to cast a mesh into a particular class
|
||||||
}
|
}
|
||||||
self.ifc_vertices = []
|
self.ifc_vertices = []
|
||||||
|
|||||||
Reference in New Issue
Block a user