mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-31 17:06:29 +00:00
See #5972. You can now load a hierarchy to visualise the boolean result tree.
This commit is contained in:
@@ -22,19 +22,26 @@ from . import ui, prop, operator
|
|||||||
classes = (
|
classes = (
|
||||||
operator.AddFilling,
|
operator.AddFilling,
|
||||||
operator.AddOpening,
|
operator.AddOpening,
|
||||||
|
operator.BooleansMarkAsManual,
|
||||||
|
operator.DisableEditingBooleans,
|
||||||
|
operator.EnableEditingBooleans,
|
||||||
operator.RemoveFilling,
|
operator.RemoveFilling,
|
||||||
operator.RemoveOpening,
|
operator.RemoveOpening,
|
||||||
operator.SelectDecomposition,
|
operator.SelectDecomposition,
|
||||||
operator.BooleansMarkAsManual,
|
prop.Boolean,
|
||||||
prop.VoidProperties,
|
prop.VoidProperties,
|
||||||
|
prop.BIMBooleanProperties,
|
||||||
ui.BIM_PT_voids,
|
ui.BIM_PT_voids,
|
||||||
ui.BIM_PT_booleans,
|
ui.BIM_PT_booleans,
|
||||||
|
ui.BIM_UL_booleans,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def register():
|
def register():
|
||||||
bpy.types.Scene.VoidProperties = bpy.props.PointerProperty(type=prop.VoidProperties)
|
bpy.types.Scene.VoidProperties = bpy.props.PointerProperty(type=prop.VoidProperties)
|
||||||
|
bpy.types.Scene.BIMBooleanProperties = bpy.props.PointerProperty(type=prop.BIMBooleanProperties)
|
||||||
|
|
||||||
|
|
||||||
def unregister():
|
def unregister():
|
||||||
del bpy.types.Scene.VoidProperties
|
del bpy.types.Scene.VoidProperties
|
||||||
|
del bpy.types.Scene.BIMBooleanProperties
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ class BooleansData:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def booleans(cls):
|
def booleans(cls):
|
||||||
obj = bpy.context.active_object
|
obj = bpy.context.scene.BIMGeometryProperties.representation_obj or bpy.context.active_object
|
||||||
if (
|
if (
|
||||||
not obj.data
|
not obj.data
|
||||||
or not hasattr(obj.data, "BIMMeshProperties")
|
or not hasattr(obj.data, "BIMMeshProperties")
|
||||||
@@ -93,7 +93,7 @@ class BooleansData:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def manual_booleans(cls):
|
def manual_booleans(cls):
|
||||||
obj = bpy.context.active_object
|
obj = bpy.context.scene.BIMGeometryProperties.representation_obj or bpy.context.active_object
|
||||||
if (
|
if (
|
||||||
not obj.data
|
not obj.data
|
||||||
or not hasattr(obj.data, "BIMMeshProperties")
|
or not hasattr(obj.data, "BIMMeshProperties")
|
||||||
|
|||||||
@@ -295,4 +295,50 @@ class BooleansMarkAsManual(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
{"INFO"}, f"{len(booleans)} booleans were marked as {'manual' if self.mark_as_manual else 'automatic'}"
|
{"INFO"}, f"{len(booleans)} booleans were marked as {'manual' if self.mark_as_manual else 'automatic'}"
|
||||||
)
|
)
|
||||||
bonsai.bim.handler.refresh_ui_data()
|
bonsai.bim.handler.refresh_ui_data()
|
||||||
|
|
||||||
|
|
||||||
|
class EnableEditingBooleans(bpy.types.Operator):
|
||||||
|
bl_idname = "bim.enable_editing_booleans"
|
||||||
|
bl_label = "Enable Editing Booleans"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
bl_description = "Manage a hierarchy of boolean operations"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
return bpy.context.scene.BIMGeometryProperties.representation_obj
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
props = context.scene.BIMBooleanProperties
|
||||||
|
rep_obj = bpy.context.scene.BIMGeometryProperties.representation_obj
|
||||||
|
representation = tool.Geometry.get_active_representation(rep_obj)
|
||||||
|
representation = ifcopenshell.util.representation.resolve_representation(representation)
|
||||||
|
props.booleans.clear()
|
||||||
|
|
||||||
|
def load_boolean(item, level=0):
|
||||||
|
new = props.booleans.add()
|
||||||
|
new.name = f"{item.is_a()}/{item.id()}"
|
||||||
|
new.ifc_definition_id = item.id()
|
||||||
|
new.level = level
|
||||||
|
if item.is_a("IfcBooleanResult"):
|
||||||
|
new.name += f"/{item.Operator}"
|
||||||
|
new.operator = item.Operator
|
||||||
|
load_boolean(item.FirstOperand, level + 1)
|
||||||
|
load_boolean(item.SecondOperand, level + 1)
|
||||||
|
|
||||||
|
for item in representation.Items:
|
||||||
|
if item.is_a("IfcBooleanResult"):
|
||||||
|
load_boolean(item)
|
||||||
|
|
||||||
|
props.is_editing = True
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
|
class DisableEditingBooleans(bpy.types.Operator):
|
||||||
|
bl_idname = "bim.disable_editing_booleans"
|
||||||
|
bl_label = "Disable Editing Booleans"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
props = context.scene.BIMBooleanProperties
|
||||||
|
props.is_editing = False
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|||||||
@@ -18,8 +18,21 @@
|
|||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
from bpy.types import PropertyGroup
|
from bpy.types import PropertyGroup
|
||||||
from bpy.props import PointerProperty
|
from bpy.props import PointerProperty, StringProperty, IntProperty, BoolProperty, CollectionProperty
|
||||||
|
|
||||||
|
|
||||||
|
class Boolean(PropertyGroup):
|
||||||
|
name: StringProperty(name="Name")
|
||||||
|
operator: StringProperty(name="Operator")
|
||||||
|
ifc_definition_id: IntProperty(name="IFC Definition ID")
|
||||||
|
level: IntProperty(name="Level")
|
||||||
|
|
||||||
|
|
||||||
class VoidProperties(PropertyGroup):
|
class VoidProperties(PropertyGroup):
|
||||||
desired_opening: PointerProperty(name="Desired Opening To Fill", type=bpy.types.Object)
|
desired_opening: PointerProperty(name="Desired Opening To Fill", type=bpy.types.Object)
|
||||||
|
|
||||||
|
|
||||||
|
class BIMBooleanProperties(PropertyGroup):
|
||||||
|
is_editing: BoolProperty(name="Is Editing", default=False)
|
||||||
|
booleans: CollectionProperty(name="Booleans", type=Boolean)
|
||||||
|
active_boolean_index: IntProperty(name="Active Boolean Index")
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
import bonsai.tool as tool
|
import bonsai.tool as tool
|
||||||
from bpy.types import Panel
|
from bpy.types import Panel, UIList
|
||||||
from bonsai.bim.module.void.data import BooleansData, VoidsData
|
from bonsai.bim.module.void.data import BooleansData, VoidsData
|
||||||
|
|
||||||
|
|
||||||
@@ -110,19 +110,18 @@ class BIM_PT_booleans(Panel):
|
|||||||
if not context.active_object.data:
|
if not context.active_object.data:
|
||||||
return
|
return
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
props = context.active_object.data.BIMMeshProperties
|
props = context.scene.BIMBooleanProperties
|
||||||
|
|
||||||
if context.active_object.data.BIMMeshProperties.ifc_definition_id:
|
if context.active_object.data.BIMMeshProperties.ifc_definition_id:
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
total_booleans = BooleansData.data["total_booleans"]
|
total_booleans = BooleansData.data["total_booleans"]
|
||||||
manual_booleans = BooleansData.data["manual_booleans"]
|
manual_booleans = BooleansData.data["manual_booleans"]
|
||||||
row.label(text=f"{len(total_booleans)} Booleans Found ({len(manual_booleans)} Manual)")
|
row.label(text=f"{len(total_booleans)} Booleans Found ({len(manual_booleans)} Manual)")
|
||||||
|
if props.is_editing:
|
||||||
|
row.operator("bim.disable_editing_booleans", icon="CANCEL", text="")
|
||||||
|
else:
|
||||||
|
row.operator("bim.enable_editing_booleans", icon="IMPORT", text="")
|
||||||
row.operator("bim.add_boolean", text="", icon="ADD")
|
row.operator("bim.add_boolean", text="", icon="ADD")
|
||||||
show_boolean_button = row.row(align=True)
|
|
||||||
show_boolean_button.operator("bim.show_booleans", text="", icon="HIDE_OFF")
|
|
||||||
show_boolean_button.enabled = len(total_booleans) > 0
|
|
||||||
row.operator("bim.hide_booleans", text="", icon="HIDE_ON")
|
|
||||||
|
|
||||||
booleans_are_manual = len(manual_booleans) == len(total_booleans)
|
booleans_are_manual = len(manual_booleans) == len(total_booleans)
|
||||||
op = row.operator(
|
op = row.operator(
|
||||||
"bim.booleans_mark_as_manual", text="", icon="PINNED" if booleans_are_manual else "UNPINNED"
|
"bim.booleans_mark_as_manual", text="", icon="PINNED" if booleans_are_manual else "UNPINNED"
|
||||||
@@ -136,6 +135,26 @@ class BIM_PT_booleans(Panel):
|
|||||||
row.label(text=upsteam_obj.name)
|
row.label(text=upsteam_obj.name)
|
||||||
row.operator("bim.select_entity", text="", icon="RESTRICT_SELECT_OFF").ifc_id = upstream_obj_ifc_id
|
row.operator("bim.select_entity", text="", icon="RESTRICT_SELECT_OFF").ifc_id = upstream_obj_ifc_id
|
||||||
|
|
||||||
|
if not props.is_editing:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.layout.template_list("BIM_UL_booleans", "", props, "booleans", props, "active_boolean_index")
|
||||||
|
|
||||||
|
|
||||||
|
class BIM_UL_booleans(UIList):
|
||||||
|
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
||||||
|
if item:
|
||||||
|
if item.operator == "DIFFERENCE":
|
||||||
|
icon = "SELECT_DIFFERENCE"
|
||||||
|
elif item.operator == "INTERSECTION":
|
||||||
|
icon = "SELECT_INTERSECT"
|
||||||
|
elif item.operator == "UNION":
|
||||||
|
icon = "SELECT_EXTEND"
|
||||||
|
elif "IfcHalfSpaceSolid" in item.name:
|
||||||
|
icon = "NORMALS_FACE"
|
||||||
|
else:
|
||||||
|
icon = "MESH_DATA"
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
row.operator("bim.hide_booleans", text="Hide Boolean")
|
for i in range(0, item.level):
|
||||||
row.operator("bim.remove_booleans", text="Remove Boolean", icon="X")
|
row.label(text="", icon="BLANK1")
|
||||||
|
row.label(text=item.name, icon=icon)
|
||||||
|
|||||||
Reference in New Issue
Block a user