Simple support for API listeners for parametric IFC authoring - editing any parameter can now trigger events from a "parametric engine" which synchronises other related geometry and attributes in the IFC dataset. Implement auto box generation as a first demo.

This commit is contained in:
Dion Moult
2021-05-19 14:45:36 +10:00
parent 851ab07192
commit b650c045f5
6 changed files with 106 additions and 42 deletions
@@ -10,6 +10,7 @@ if bpy is not None:
modules = {
"project": None,
"parametric": None,
"search": None,
"bcf": None,
"root": None,
@@ -14,14 +14,6 @@ from ifcopenshell.api.void.data import Data as VoidData
from mathutils import Vector
def get_context_id(context_type, context_identifier, target_view):
for context in ContextData.contexts.values():
if context["ContextType"] == context_type:
for i, subcontext in context["HasSubContexts"].items():
if subcontext["ContextIdentifier"] == context_identifier and subcontext["TargetView"] == target_view:
return i
class EditObjectPlacement(bpy.types.Operator):
bl_idname = "bim.edit_object_placement"
bl_label = "Edit Object Placement"
@@ -107,23 +99,6 @@ class AddRepresentation(bpy.types.Operator):
print("Failed to write shape representation")
return {"FINISHED"}
# TODO: Migrate to parametric engine system
box_context_id = get_context_id("Model", "Box", "MODEL_VIEW")
old_box = ifcopenshell.util.representation.get_representation(product, "Model", "Box", "MODEL_VIEW")
if (
box_context_id
and context_of_items.ContextType == "Model"
and context_of_items.ContextIdentifier
and context_of_items.ContextIdentifier == "Body"
):
if old_box:
bpy.ops.bim.remove_representation(representation_id=old_box.id(), obj=obj.name)
representation_data["context"] = self.file.by_id(box_context_id)
new_box = ifcopenshell.api.run("geometry.add_representation", self.file, **representation_data)
ifcopenshell.api.run(
"geometry.assign_representation", self.file, **{"product": product, "representation": new_box}
)
[
bpy.ops.bim.add_style(material=s.material.name)
for s in obj.material_slots
@@ -326,20 +301,6 @@ class UpdateRepresentation(bpy.types.Operator):
new_representation = ifcopenshell.api.run("geometry.add_representation", self.file, **representation_data)
box_context_id = get_context_id("Model", "Box", "MODEL_VIEW")
old_box = ifcopenshell.util.representation.get_representation(product, "Model", "Box", "MODEL_VIEW")
if (
box_context_id
and old_box
and context_of_items.ContextType == "Model"
and context_of_items.ContextIdentifier
and context_of_items.ContextIdentifier == "Body"
):
representation_data["context"] = self.file.by_id(box_context_id)
new_box = ifcopenshell.api.run("geometry.add_representation", self.file, **representation_data)
for inverse in self.file.get_inverse(old_box):
ifcopenshell.util.element.replace_attribute(inverse, old_box, new_box)
ifcopenshell.api.run(
"geometry.assign_styles",
self.file,
@@ -0,0 +1,15 @@
import bpy
from . import ui, operator
classes = (
operator.ActivateParametricEngine,
ui.BIM_PT_parametric,
)
def register():
pass
def unregister():
pass
@@ -0,0 +1,38 @@
import bpy
import ifcopenshell
import ifcopenshell.api
import ifcopenshell.util.representation
from blenderbim.bim.ifc import IfcStore
def generate_box(usecase_path, ifc_file, **settings):
box_context = ifcopenshell.util.representation.get_context(ifc_file, "Model", "Box", "MODEL_VIEW")
if not box_context:
return
obj = settings["blender_object"]
product = ifc_file.by_id(obj.BIMObjectProperties.ifc_definition_id)
old_box = ifcopenshell.util.representation.get_representation(product, "Model", "Box", "MODEL_VIEW")
if settings["context"].ContextType == "Model" and getattr(settings["context"], "ContextIdentifier") == "Body":
if old_box:
bpy.ops.bim.remove_representation(representation_id=old_box.id(), obj=obj.name)
new_settings = settings.copy()
new_settings["context"] = box_context
new_box = ifcopenshell.api.run(
"geometry.add_representation", ifc_file, should_run_listeners=False, **new_settings
)
ifcopenshell.api.run(
"geometry.assign_representation",
ifc_file,
should_run_listeners=False,
**{"product": product, "representation": new_box}
)
class ActivateParametricEngine(bpy.types.Operator):
bl_idname = "bim.activate_parametric_engine"
bl_label = "Activate Parametric Engine"
def execute(self, context):
ifcopenshell.api.add_post_listener("geometry.add_representation", IfcStore.get_file(), generate_box)
return {"FINISHED"}
@@ -0,0 +1,22 @@
from bpy.types import Panel
from blenderbim.bim.ifc import IfcStore
from ifcopenshell.api.type.data import Data
class BIM_PT_parametric(Panel):
bl_label = "IFC Parametric Engines"
bl_idname = "BIM_PT_parametric"
bl_options = {"DEFAULT_CLOSED"}
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
@classmethod
def poll(cls, context):
return IfcStore.get_file()
def draw(self, context):
#props = context.active_object.BIMTypeProperties
row = self.layout.row(align=True)
#row.prop(props, "relating_type_class", text="")
row.operator("bim.activate_parametric_engine", icon="PLUGIN")