mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-24 15:07:38 +00:00
Add new opening functions to BIM tool workspace UI
This commit is contained in:
@@ -162,41 +162,66 @@ class AddElementOpening(bpy.types.Operator):
|
|||||||
return obj
|
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):
|
class AddPotentialOpening(Operator, AddObjectHelper):
|
||||||
bl_idname = "bim.add_potential_opening"
|
bl_idname = "bim.add_potential_opening"
|
||||||
bl_label = "Add Potential Opening"
|
bl_label = "Add Potential Opening"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
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):
|
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"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
@@ -218,13 +243,7 @@ class AddPotentialHalfSpaceSolid(Operator, AddObjectHelper):
|
|||||||
obj = object_data_add(context, mesh, operator=self)
|
obj = object_data_add(context, mesh, operator=self)
|
||||||
obj.name = "HalfSpaceSolid"
|
obj.name = "HalfSpaceSolid"
|
||||||
|
|
||||||
has_deleted_opening = True
|
tool.Model.clear_scene_openings()
|
||||||
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 = props.openings.add()
|
||||||
new.obj = obj
|
new.obj = obj
|
||||||
@@ -263,13 +282,7 @@ class AddBoolean(Operator, tool.Ifc.Operator):
|
|||||||
matrix=obj1.matrix_world.inverted() @ obj2.matrix_world,
|
matrix=obj1.matrix_world.inverted() @ obj2.matrix_world,
|
||||||
)
|
)
|
||||||
|
|
||||||
has_deleted_opening = True
|
tool.Model.clear_scene_openings()
|
||||||
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
|
|
||||||
|
|
||||||
blenderbim.core.geometry.switch_representation(
|
blenderbim.core.geometry.switch_representation(
|
||||||
tool.Geometry,
|
tool.Geometry,
|
||||||
@@ -334,13 +347,7 @@ class ShowBooleans(Operator, tool.Ifc.Operator, AddObjectHelper):
|
|||||||
obj = object_data_add(bpy.context, mesh, operator=self)
|
obj = object_data_add(bpy.context, mesh, operator=self)
|
||||||
obj.name = "HalfSpaceSolid"
|
obj.name = "HalfSpaceSolid"
|
||||||
|
|
||||||
has_deleted_opening = True
|
tool.Model.clear_scene_openings()
|
||||||
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 = props.openings.add()
|
||||||
new.obj = obj
|
new.obj = obj
|
||||||
@@ -425,6 +432,7 @@ class HideOpenings(Operator, tool.Ifc.Operator):
|
|||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
props = bpy.context.scene.BIMModelProperties
|
props = bpy.context.scene.BIMModelProperties
|
||||||
|
to_delete = set()
|
||||||
for obj in context.selected_objects:
|
for obj in context.selected_objects:
|
||||||
element = tool.Ifc.get_entity(obj)
|
element = tool.Ifc.get_entity(obj)
|
||||||
if not element:
|
if not element:
|
||||||
@@ -433,8 +441,11 @@ class HideOpenings(Operator, tool.Ifc.Operator):
|
|||||||
for opening in openings:
|
for opening in openings:
|
||||||
opening_obj = tool.Ifc.get_object(opening)
|
opening_obj = tool.Ifc.get_object(opening)
|
||||||
if opening_obj:
|
if opening_obj:
|
||||||
tool.Ifc.unlink(element=opening, obj=opening_obj)
|
to_delete.add(opening_obj)
|
||||||
bpy.data.objects.remove(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"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -200,3 +200,6 @@ class BIMModelProperties(PropertyGroup):
|
|||||||
)
|
)
|
||||||
length: bpy.props.FloatProperty(default=42.0)
|
length: bpy.props.FloatProperty(default=42.0)
|
||||||
openings: bpy.props.CollectionProperty(type=ObjProperty)
|
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 os
|
||||||
import bpy
|
import bpy
|
||||||
|
import blenderbim.tool as tool
|
||||||
import blenderbim.bim.module.type.prop as type_prop
|
import blenderbim.bim.module.type.prop as type_prop
|
||||||
from blenderbim.bim.helper import prop_with_search, close_operator_panel
|
from blenderbim.bim.helper import prop_with_search, close_operator_panel
|
||||||
from bpy.types import WorkSpaceTool
|
from bpy.types import WorkSpaceTool
|
||||||
from blenderbim.bim.ifc import IfcStore
|
|
||||||
from blenderbim.bim.module.model.data import AuthoringData
|
from blenderbim.bim.module.model.data import AuthoringData
|
||||||
from blenderbim.bim.module.model import prop
|
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")]}),
|
("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
|
props = context.scene.BIMModelProperties
|
||||||
is_tool_header = context.region.type == "TOOL_HEADER"
|
is_tool_header = context.region.type == "TOOL_HEADER"
|
||||||
is_sidebar = context.region.type == "UI"
|
is_sidebar = context.region.type == "UI"
|
||||||
|
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
if not IfcStore.get_file():
|
if not tool.Ifc.get():
|
||||||
row.label(text="No IFC Project", icon="ERROR")
|
row.label(text="No IFC Project", icon="ERROR")
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -232,9 +232,9 @@ class BimTool(WorkSpaceTool):
|
|||||||
row.label(text="", icon="EVENT_SHIFT")
|
row.label(text="", icon="EVENT_SHIFT")
|
||||||
row.label(text="", icon="EVENT_O")
|
row.label(text="", icon="EVENT_O")
|
||||||
if len(context.selected_objects) == 2:
|
if len(context.selected_objects) == 2:
|
||||||
row.operator("bim.add_opening", text="Void")
|
row.operator("bim.add_opening", text="Apply Void")
|
||||||
else:
|
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["is_voidable_element"]:
|
||||||
if AuthoringData.data["has_visible_openings"]:
|
if AuthoringData.data["has_visible_openings"]:
|
||||||
row.operator("bim.edit_openings", icon="CHECKMARK", text="")
|
row.operator("bim.edit_openings", icon="CHECKMARK", text="")
|
||||||
@@ -265,7 +265,7 @@ class BimTool(WorkSpaceTool):
|
|||||||
row.label(text="Decomposition", icon="EVENT_D")
|
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_idname = "bim.hotkey"
|
||||||
bl_label = "Hotkey"
|
bl_label = "Hotkey"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
@@ -273,10 +273,7 @@ class Hotkey(bpy.types.Operator):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
return IfcStore.get_file()
|
return tool.Ifc.get()
|
||||||
|
|
||||||
def execute(self, context):
|
|
||||||
return IfcStore.execute_ifc_operator(self, context)
|
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
self.props = context.scene.BIMModelProperties
|
self.props = context.scene.BIMModelProperties
|
||||||
@@ -288,6 +285,16 @@ class Hotkey(bpy.types.Operator):
|
|||||||
getattr(self, f"hotkey_{self.hotkey}")()
|
getattr(self, f"hotkey_{self.hotkey}")()
|
||||||
return {"FINISHED"}
|
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):
|
def hotkey_S_A(self):
|
||||||
bpy.ops.bim.add_constr_type_instance()
|
bpy.ops.bim.add_constr_type_instance()
|
||||||
|
|
||||||
@@ -366,10 +373,16 @@ class Hotkey(bpy.types.Operator):
|
|||||||
bpy.ops.bim.extend_profile(join_type="V")
|
bpy.ops.bim.extend_profile(join_type="V")
|
||||||
|
|
||||||
def hotkey_S_O(self):
|
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):
|
def hotkey_A_D(self):
|
||||||
bpy.ops.bim.toggle_decomposition_parenting()
|
bpy.ops.bim.toggle_decomposition_parenting()
|
||||||
|
|
||||||
def hotkey_A_O(self):
|
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.RemoveOpening,
|
||||||
operator.AddFilling,
|
operator.AddFilling,
|
||||||
operator.RemoveFilling,
|
operator.RemoveFilling,
|
||||||
operator.ToggleOpeningVisibility,
|
|
||||||
operator.ToggleDecompositionParenting,
|
operator.ToggleDecompositionParenting,
|
||||||
prop.VoidProperties,
|
prop.VoidProperties,
|
||||||
ui.BIM_PT_voids,
|
ui.BIM_PT_voids,
|
||||||
|
|||||||
@@ -37,9 +37,7 @@ class AddOpening(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
obj1, obj2 = context.selected_objects
|
obj1, obj2 = context.selected_objects
|
||||||
element1 = tool.Ifc.get_entity(obj1)
|
element1 = tool.Ifc.get_entity(obj1)
|
||||||
element2 = tool.Ifc.get_entity(obj2)
|
element2 = tool.Ifc.get_entity(obj2)
|
||||||
if element1 and element2:
|
if type(element1) == type(element2):
|
||||||
return {"FINISHED"}
|
|
||||||
if not element1 and not element2:
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
if element2 and not element1:
|
if element2 and not element1:
|
||||||
obj1, obj2 = obj2, obj1
|
obj1, obj2 = obj2, obj1
|
||||||
@@ -50,6 +48,13 @@ class AddOpening(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
if not obj1.data or not hasattr(obj1.data, "BIMMeshProperties"):
|
if not obj1.data or not hasattr(obj1.data, "BIMMeshProperties"):
|
||||||
return {"FINISHED"}
|
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")
|
body_context = ifcopenshell.util.representation.get_context(IfcStore.get_file(), "Model", "Body")
|
||||||
element2 = blenderbim.core.root.assign_class(
|
element2 = blenderbim.core.root.assign_class(
|
||||||
tool.Ifc,
|
tool.Ifc,
|
||||||
@@ -73,8 +78,11 @@ class AddOpening(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
should_sync_changes_first=False,
|
should_sync_changes_first=False,
|
||||||
)
|
)
|
||||||
Data.load(tool.Ifc.get(), element1.id())
|
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
|
context.view_layer.objects.active = obj1
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
@@ -177,18 +185,6 @@ class RemoveFilling(bpy.types.Operator):
|
|||||||
return {"FINISHED"}
|
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):
|
class ToggleDecompositionParenting(bpy.types.Operator):
|
||||||
bl_idname = "bim.toggle_decomposition_parenting"
|
bl_idname = "bim.toggle_decomposition_parenting"
|
||||||
bl_label = "Toggle Decomposition Parenting"
|
bl_label = "Toggle Decomposition Parenting"
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ class Model(blenderbim.core.tool.Model):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def load_openings(cls, element, openings):
|
def load_openings(cls, element, openings):
|
||||||
if not openings:
|
if not openings:
|
||||||
return
|
return []
|
||||||
obj = tool.Ifc.get_object(element)
|
obj = tool.Ifc.get_object(element)
|
||||||
ifc_import_settings = import_ifc.IfcImportSettings.factory()
|
ifc_import_settings = import_ifc.IfcImportSettings.factory()
|
||||||
ifc_importer = import_ifc.IfcImporter(ifc_import_settings)
|
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()
|
opening_obj.matrix_parent_inverse = obj.matrix_world.inverted()
|
||||||
ifc_importer.place_objects_in_collections()
|
ifc_importer.place_objects_in_collections()
|
||||||
return ifc_importer.added_data.values()
|
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
|
||||||
|
|||||||
Reference in New Issue
Block a user