Add new opening functions to BIM tool workspace UI

This commit is contained in:
Dion Moult
2022-10-03 20:49:44 +11:00
parent 49cd966d43
commit 8c25349b49
6 changed files with 116 additions and 83 deletions
@@ -162,41 +162,66 @@ class AddElementOpening(bpy.types.Operator):
return obj
def add_object(self, context):
props = context.scene.BIMModelProperties
bm = bmesh.new()
bmesh.ops.create_cube(bm, size=self.size)
bm.verts.ensure_lookup_table()
bm.edges.ensure_lookup_table()
bm.faces.ensure_lookup_table()
mesh = bpy.data.meshes.new(name="Dumb Opening")
bm.to_mesh(mesh)
bm.free()
obj = object_data_add(context, mesh, operator=self)
obj.name = "Opening"
has_deleted_opening = True
while has_deleted_opening:
has_deleted_opening = False
for i, opening in enumerate(props.openings):
if not opening.obj:
props.openings.remove(i)
has_deleted_opening = True
new = props.openings.add()
new.obj = obj
DecorationsHandler.install(context)
class AddPotentialOpening(Operator, AddObjectHelper):
bl_idname = "bim.add_potential_opening"
bl_label = "Add Potential Opening"
bl_options = {"REGISTER", "UNDO"}
size: FloatProperty(name="Size", default=0.5)
x: FloatProperty(name="X", default=0.5)
y: FloatProperty(name="Y", default=0.5)
z: FloatProperty(name="Z", default=0.5)
def draw_settings(context, layout, tool):
row = self.layout.row()
row.prop(data=self, property="x", label="Size X")
row = self.layout.row()
row.prop(data=self, property="y")
row = self.layout.row()
row.prop(data=self, property="z")
def execute(self, context):
add_object(self, context)
props = context.scene.BIMModelProperties
new_matrix = None
if context.selected_objects and context.active_object:
new_matrix = context.active_object.matrix_world.copy()
new_matrix.col[3] = context.scene.cursor.location.to_4d().to_4d()
x = self.x / 2
y = self.y / 2
z = self.z / 2
verts = [
Vector((-x, -y, -z)),
Vector((-x, -y, z)),
Vector((-x, y, -z)),
Vector((-x, y, z)),
Vector((x, -y, -z)),
Vector((x, -y, z)),
Vector((x, y, -z)),
Vector((x, y, z)),
]
edges = []
faces = [
[0, 1, 3, 2],
[2, 3, 7, 6],
[6, 7, 5, 4],
[4, 5, 1, 0],
[2, 6, 4, 0],
[7, 3, 1, 5],
]
mesh = bpy.data.meshes.new(name="Opening")
mesh.from_pydata(verts, edges, faces)
obj = object_data_add(context, mesh, operator=self)
obj.name = "Opening"
if new_matrix:
obj.matrix_world = new_matrix
tool.Model.clear_scene_openings()
new = props.openings.add()
new.obj = obj
DecorationsHandler.install(context)
return {"FINISHED"}
@@ -218,13 +243,7 @@ class AddPotentialHalfSpaceSolid(Operator, AddObjectHelper):
obj = object_data_add(context, mesh, operator=self)
obj.name = "HalfSpaceSolid"
has_deleted_opening = True
while has_deleted_opening:
has_deleted_opening = False
for i, opening in enumerate(props.openings):
if not opening.obj:
props.openings.remove(i)
has_deleted_opening = True
tool.Model.clear_scene_openings()
new = props.openings.add()
new.obj = obj
@@ -263,13 +282,7 @@ class AddBoolean(Operator, tool.Ifc.Operator):
matrix=obj1.matrix_world.inverted() @ obj2.matrix_world,
)
has_deleted_opening = True
while has_deleted_opening:
has_deleted_opening = False
for i, opening in enumerate(props.openings):
if not opening.obj:
props.openings.remove(i)
has_deleted_opening = True
tool.Model.clear_scene_openings()
blenderbim.core.geometry.switch_representation(
tool.Geometry,
@@ -334,13 +347,7 @@ class ShowBooleans(Operator, tool.Ifc.Operator, AddObjectHelper):
obj = object_data_add(bpy.context, mesh, operator=self)
obj.name = "HalfSpaceSolid"
has_deleted_opening = True
while has_deleted_opening:
has_deleted_opening = False
for i, opening in enumerate(props.openings):
if not opening.obj:
props.openings.remove(i)
has_deleted_opening = True
tool.Model.clear_scene_openings()
new = props.openings.add()
new.obj = obj
@@ -425,6 +432,7 @@ class HideOpenings(Operator, tool.Ifc.Operator):
def _execute(self, context):
props = bpy.context.scene.BIMModelProperties
to_delete = set()
for obj in context.selected_objects:
element = tool.Ifc.get_entity(obj)
if not element:
@@ -433,8 +441,11 @@ class HideOpenings(Operator, tool.Ifc.Operator):
for opening in openings:
opening_obj = tool.Ifc.get_object(opening)
if opening_obj:
tool.Ifc.unlink(element=opening, obj=opening_obj)
bpy.data.objects.remove(opening_obj)
to_delete.add(opening_obj)
for opening_obj in to_delete:
tool.Ifc.unlink(element=opening, obj=opening_obj)
bpy.data.objects.remove(opening_obj)
tool.Model.clear_scene_openings()
return {"FINISHED"}
@@ -200,3 +200,6 @@ class BIMModelProperties(PropertyGroup):
)
length: bpy.props.FloatProperty(default=42.0)
openings: bpy.props.CollectionProperty(type=ObjProperty)
x: bpy.props.FloatProperty(name="X", default=0.5)
y: bpy.props.FloatProperty(name="Y", default=0.5)
z: bpy.props.FloatProperty(name="Z", default=0.5)
@@ -18,10 +18,10 @@
import os
import bpy
import blenderbim.tool as tool
import blenderbim.bim.module.type.prop as type_prop
from blenderbim.bim.helper import prop_with_search, close_operator_panel
from bpy.types import WorkSpaceTool
from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.module.model.data import AuthoringData
from blenderbim.bim.module.model import prop
@@ -56,13 +56,13 @@ class BimTool(WorkSpaceTool):
("bim.hotkey", {"type": "O", "value": "PRESS", "alt": True}, {"properties": [("hotkey", "A_O")]}),
)
def draw_settings(context, layout, tool):
def draw_settings(context, layout, something):
props = context.scene.BIMModelProperties
is_tool_header = context.region.type == "TOOL_HEADER"
is_sidebar = context.region.type == "UI"
row = layout.row(align=True)
if not IfcStore.get_file():
if not tool.Ifc.get():
row.label(text="No IFC Project", icon="ERROR")
return
@@ -232,9 +232,9 @@ class BimTool(WorkSpaceTool):
row.label(text="", icon="EVENT_SHIFT")
row.label(text="", icon="EVENT_O")
if len(context.selected_objects) == 2:
row.operator("bim.add_opening", text="Void")
row.operator("bim.add_opening", text="Apply Void")
else:
row.operator("bim.add_potential_opening", text="Void")
row.operator("bim.add_potential_opening", text="Add Void")
if AuthoringData.data["is_voidable_element"]:
if AuthoringData.data["has_visible_openings"]:
row.operator("bim.edit_openings", icon="CHECKMARK", text="")
@@ -265,7 +265,7 @@ class BimTool(WorkSpaceTool):
row.label(text="Decomposition", icon="EVENT_D")
class Hotkey(bpy.types.Operator):
class Hotkey(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.hotkey"
bl_label = "Hotkey"
bl_options = {"REGISTER", "UNDO"}
@@ -273,10 +273,7 @@ class Hotkey(bpy.types.Operator):
@classmethod
def poll(cls, context):
return IfcStore.get_file()
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
return tool.Ifc.get()
def _execute(self, context):
self.props = context.scene.BIMModelProperties
@@ -288,6 +285,16 @@ class Hotkey(bpy.types.Operator):
getattr(self, f"hotkey_{self.hotkey}")()
return {"FINISHED"}
def draw(self, context):
props = context.scene.BIMModelProperties
if self.hotkey == "S_O":
row = self.layout.row()
row.prop(props, "x")
row = self.layout.row()
row.prop(props, "y")
row = self.layout.row()
row.prop(props, "z")
def hotkey_S_A(self):
bpy.ops.bim.add_constr_type_instance()
@@ -366,10 +373,16 @@ class Hotkey(bpy.types.Operator):
bpy.ops.bim.extend_profile(join_type="V")
def hotkey_S_O(self):
bpy.ops.bim.add_element_opening(voided_building_element="", filling_building_element="")
if len(bpy.context.selected_objects) == 2:
bpy.ops.bim.add_opening()
else:
bpy.ops.bim.add_potential_opening(x=self.props.x, y=self.props.y, z=self.props.z)
def hotkey_A_D(self):
bpy.ops.bim.toggle_decomposition_parenting()
def hotkey_A_O(self):
bpy.ops.bim.toggle_opening_visibility()
if AuthoringData.data["has_visible_openings"]:
bpy.ops.bim.hide_openings()
else:
bpy.ops.bim.show_openings()
@@ -24,7 +24,6 @@ classes = (
operator.RemoveOpening,
operator.AddFilling,
operator.RemoveFilling,
operator.ToggleOpeningVisibility,
operator.ToggleDecompositionParenting,
prop.VoidProperties,
ui.BIM_PT_voids,
@@ -37,9 +37,7 @@ class AddOpening(bpy.types.Operator, tool.Ifc.Operator):
obj1, obj2 = context.selected_objects
element1 = tool.Ifc.get_entity(obj1)
element2 = tool.Ifc.get_entity(obj2)
if element1 and element2:
return {"FINISHED"}
if not element1 and not element2:
if type(element1) == type(element2):
return {"FINISHED"}
if element2 and not element1:
obj1, obj2 = obj2, obj1
@@ -50,6 +48,13 @@ class AddOpening(bpy.types.Operator, tool.Ifc.Operator):
return {"FINISHED"}
if not obj1.data or not hasattr(obj1.data, "BIMMeshProperties"):
return {"FINISHED"}
has_visible_openings = False
for opening in [r.RelatedOpeningElement for r in element1.HasOpenings]:
if tool.Ifc.get_object(opening):
has_visible_openings = True
break
body_context = ifcopenshell.util.representation.get_context(IfcStore.get_file(), "Model", "Body")
element2 = blenderbim.core.root.assign_class(
tool.Ifc,
@@ -73,8 +78,11 @@ class AddOpening(bpy.types.Operator, tool.Ifc.Operator):
should_sync_changes_first=False,
)
Data.load(tool.Ifc.get(), element1.id())
tool.Ifc.unlink(obj=obj2)
bpy.data.objects.remove(obj2)
if not has_visible_openings:
tool.Ifc.unlink(obj=obj2)
bpy.data.objects.remove(obj2)
context.view_layer.objects.active = obj1
return {"FINISHED"}
@@ -177,18 +185,6 @@ class RemoveFilling(bpy.types.Operator):
return {"FINISHED"}
class ToggleOpeningVisibility(bpy.types.Operator):
bl_idname = "bim.toggle_opening_visibility"
bl_label = "Toggle Opening Visibility"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
for project in [c for c in context.view_layer.layer_collection.children if "IfcProject" in c.name]:
for collection in [c for c in project.children if "IfcOpeningElements" in c.name]:
collection.hide_viewport = not collection.hide_viewport
return {"FINISHED"}
class ToggleDecompositionParenting(bpy.types.Operator):
bl_idname = "bim.toggle_decomposition_parenting"
bl_label = "Toggle Decomposition Parenting"
+12 -1
View File
@@ -51,7 +51,7 @@ class Model(blenderbim.core.tool.Model):
@classmethod
def load_openings(cls, element, openings):
if not openings:
return
return []
obj = tool.Ifc.get_object(element)
ifc_import_settings = import_ifc.IfcImportSettings.factory()
ifc_importer = import_ifc.IfcImporter(ifc_import_settings)
@@ -69,3 +69,14 @@ class Model(blenderbim.core.tool.Model):
opening_obj.matrix_parent_inverse = obj.matrix_world.inverted()
ifc_importer.place_objects_in_collections()
return ifc_importer.added_data.values()
@classmethod
def clear_scene_openings(cls):
props = bpy.context.scene.BIMModelProperties
has_deleted_opening = True
while has_deleted_opening:
has_deleted_opening = False
for i, opening in enumerate(props.openings):
if not opening.obj:
props.openings.remove(i)
has_deleted_opening = True