mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-24 07:16:53 +00:00
Fix #5972. Purge old non-item-based boolean code
This commit is contained in:
@@ -83,14 +83,11 @@ classes = (
|
|||||||
opening.EditOpenings,
|
opening.EditOpenings,
|
||||||
opening.FlipFill,
|
opening.FlipFill,
|
||||||
opening.HideAllOpenings,
|
opening.HideAllOpenings,
|
||||||
opening.HideBooleans,
|
|
||||||
opening.HideOpenings,
|
opening.HideOpenings,
|
||||||
opening.PurgeUnusedOpenings,
|
opening.PurgeUnusedOpenings,
|
||||||
opening.RecalculateFill,
|
opening.RecalculateFill,
|
||||||
opening.RemoveBoolean,
|
opening.RemoveBoolean,
|
||||||
opening.RemoveBooleans,
|
|
||||||
opening.SelectBoolean,
|
opening.SelectBoolean,
|
||||||
opening.ShowBooleans,
|
|
||||||
opening.ShowOpenings,
|
opening.ShowOpenings,
|
||||||
opening.UpdateOpeningsFocus,
|
opening.UpdateOpeningsFocus,
|
||||||
profile.ChangeCardinalPoint,
|
profile.ChangeCardinalPoint,
|
||||||
|
|||||||
@@ -558,260 +558,6 @@ class AddBoolean(Operator, tool.Ifc.Operator):
|
|||||||
tool.Root.reload_item_decorator()
|
tool.Root.reload_item_decorator()
|
||||||
|
|
||||||
|
|
||||||
class ShowBooleans(Operator, tool.Ifc.Operator, AddObjectHelper):
|
|
||||||
bl_idname = "bim.show_booleans"
|
|
||||||
bl_label = "Show Booleans"
|
|
||||||
bl_description = "Show booleans for the selected objects.\nCan be used to reset booleans positions"
|
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def poll(cls, context):
|
|
||||||
obj = context.active_object
|
|
||||||
return (
|
|
||||||
obj is not None
|
|
||||||
and obj.data
|
|
||||||
and hasattr(obj.data, "BIMMeshProperties")
|
|
||||||
and obj.data.BIMMeshProperties.ifc_definition_id
|
|
||||||
)
|
|
||||||
|
|
||||||
def _execute(self, context):
|
|
||||||
selected_objects = tool.Blender.get_selected_objects()
|
|
||||||
boolean_objs = []
|
|
||||||
for obj in selected_objects:
|
|
||||||
if not isinstance(mesh := obj.data, bpy.types.Mesh) or not mesh.BIMMeshProperties.ifc_definition_id:
|
|
||||||
continue
|
|
||||||
boolean_objs.extend(self.show_booleans(obj))
|
|
||||||
|
|
||||||
if boolean_objs:
|
|
||||||
DecorationsHandler.install(context)
|
|
||||||
tool.Blender.set_objects_selection(context, boolean_objs[0], boolean_objs)
|
|
||||||
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
def show_booleans(self, obj: bpy.types.Object) -> list[bpy.types.Object]:
|
|
||||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
|
||||||
representation = tool.Ifc.get().by_id(obj.data.BIMMeshProperties.ifc_definition_id)
|
|
||||||
booleans: list[ifcopenshell.entity_instance] = []
|
|
||||||
for item in representation.Items:
|
|
||||||
booleans.extend(self.get_booleans(item))
|
|
||||||
|
|
||||||
props = bpy.context.scene.BIMModelProperties
|
|
||||||
tool.Model.purge_scene_openings()
|
|
||||||
|
|
||||||
existing_booleans = {
|
|
||||||
boolean_obj.data.BIMMeshProperties.ifc_boolean_id: boolean_obj
|
|
||||||
for opening in props.openings
|
|
||||||
if (boolean_obj := opening.obj).data.BIMMeshProperties.obj == obj
|
|
||||||
}
|
|
||||||
objects_to_remove = set()
|
|
||||||
|
|
||||||
booleans_objs: list[bpy.types.Object] = []
|
|
||||||
for boolean in booleans:
|
|
||||||
boolean_obj = None
|
|
||||||
|
|
||||||
if boolean.is_a() == "IfcHalfSpaceSolid":
|
|
||||||
surface = boolean.BaseSurface
|
|
||||||
if surface.is_a("IfcPlane"):
|
|
||||||
boolean_obj = self.create_half_space_solid()
|
|
||||||
position = surface.Position
|
|
||||||
position = Matrix(ifcopenshell.util.placement.get_axis2placement(position).tolist())
|
|
||||||
position.translation *= unit_scale
|
|
||||||
boolean_obj.matrix_world = obj.matrix_world @ position
|
|
||||||
else:
|
|
||||||
self.report(
|
|
||||||
{"INFO"},
|
|
||||||
f"Showing boolean using non-IfcPlane IfcSurface ({surface.is_a()}) is not supported.",
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
settings = ifcopenshell.geom.settings()
|
|
||||||
logger = logging.getLogger("ImportIFC")
|
|
||||||
ifc_import_settings = import_ifc.IfcImportSettings.factory(bpy.context, IfcStore.path, logger)
|
|
||||||
shape = ifcopenshell.geom.create_shape(settings, boolean)
|
|
||||||
if shape:
|
|
||||||
ifc_importer = import_ifc.IfcImporter(ifc_import_settings)
|
|
||||||
ifc_importer.file = tool.Ifc.get()
|
|
||||||
mesh = ifc_importer.create_mesh(boolean, shape)
|
|
||||||
else:
|
|
||||||
mesh = None
|
|
||||||
boolean_obj = object_data_add(bpy.context, mesh, operator=self)
|
|
||||||
boolean_obj.name = "BooleanMesh"
|
|
||||||
boolean_obj.matrix_world = obj.matrix_world
|
|
||||||
|
|
||||||
if boolean_obj:
|
|
||||||
boolean_id = boolean.id()
|
|
||||||
if boolean_id in existing_booleans:
|
|
||||||
# Remove existing boolean as it will be reloaded.
|
|
||||||
objects_to_remove.add(existing_booleans[boolean_id])
|
|
||||||
boolean_obj.data.BIMMeshProperties.ifc_boolean_id = boolean_id
|
|
||||||
boolean_obj.data.BIMMeshProperties.obj = obj
|
|
||||||
tool.Root.add_tracked_opening(boolean_obj, "BOOLEAN")
|
|
||||||
booleans_objs.append(boolean_obj)
|
|
||||||
|
|
||||||
tool.Blender.remove_data_blocks(objects_to_remove, remove_unused_data=True)
|
|
||||||
return booleans_objs
|
|
||||||
|
|
||||||
def get_booleans(self, item: ifcopenshell.entity_instance) -> list[ifcopenshell.entity_instance]:
|
|
||||||
results = []
|
|
||||||
if item.is_a("IfcBooleanResult"):
|
|
||||||
results.extend(self.get_booleans(item.FirstOperand))
|
|
||||||
results.append(item.SecondOperand)
|
|
||||||
return results
|
|
||||||
|
|
||||||
def create_half_space_solid(self) -> bpy.types.Object:
|
|
||||||
bm = bmesh.new()
|
|
||||||
bmesh.ops.create_grid(bm, size=0.5)
|
|
||||||
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(bpy.context, mesh, operator=self)
|
|
||||||
obj.name = "HalfSpaceSolid"
|
|
||||||
return obj
|
|
||||||
|
|
||||||
|
|
||||||
class HideBooleans(Operator, tool.Ifc.Operator):
|
|
||||||
bl_idname = "bim.hide_booleans"
|
|
||||||
bl_label = "Hide Booleans"
|
|
||||||
bl_description = (
|
|
||||||
"Hide boolean objects and apply their changed transforms.\n"
|
|
||||||
"If boolean object is selected, hide it, otherwise hide all boolean objects"
|
|
||||||
)
|
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
|
||||||
|
|
||||||
def _execute(self, context):
|
|
||||||
ifc_file = tool.Ifc.get()
|
|
||||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(ifc_file)
|
|
||||||
builder = ifcopenshell.util.shape_builder.ShapeBuilder(ifc_file)
|
|
||||||
|
|
||||||
set_active_obj, set_selected_objs = None, None
|
|
||||||
boolean_objs: list[bpy.types.Object]
|
|
||||||
selected_objects = tool.Blender.get_selected_objects()
|
|
||||||
selected_booleans_objs = [
|
|
||||||
obj for obj in selected_objects if tool.Model.get_tracked_opening_type(obj) == "BOOLEAN"
|
|
||||||
]
|
|
||||||
|
|
||||||
# Hide currently selected booleans, otherwise hide all booleans.
|
|
||||||
if selected_booleans_objs:
|
|
||||||
boolean_objs = selected_booleans_objs
|
|
||||||
if (active_object := context.active_object) in selected_booleans_objs:
|
|
||||||
active_obj_source = active_object
|
|
||||||
else:
|
|
||||||
active_obj_source = selected_booleans_objs[0]
|
|
||||||
set_active_obj = tool.Model.get_booleaned_obj(active_obj_source)
|
|
||||||
assert set_active_obj
|
|
||||||
set_selected_objs = [
|
|
||||||
bool_obj for obj in selected_booleans_objs if (bool_obj := tool.Model.get_booleaned_obj(obj))
|
|
||||||
]
|
|
||||||
else:
|
|
||||||
props = bpy.context.scene.BIMModelProperties
|
|
||||||
boolean_objs = [obj for o in props.openings if (obj := o.obj) and o.name == "BOOLEAN"]
|
|
||||||
|
|
||||||
objects_to_remove: set[bpy.types.Object] = set()
|
|
||||||
booleans_to_add: dict[bpy.types.Object, list[bpy.types.Object]] = defaultdict(list)
|
|
||||||
|
|
||||||
for obj in boolean_objs:
|
|
||||||
main_obj = tool.Model.get_booleaned_obj(obj)
|
|
||||||
if not main_obj:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Update boolean transform.
|
|
||||||
if main_obj:
|
|
||||||
ifc_boolean_id = obj.data.BIMMeshProperties.ifc_boolean_id
|
|
||||||
boolean = tool.Ifc.get_entity_by_id(ifc_boolean_id)
|
|
||||||
|
|
||||||
if boolean is None:
|
|
||||||
booleans_to_add[main_obj].append(obj)
|
|
||||||
continue
|
|
||||||
|
|
||||||
if boolean.is_a("IfcHalfSpaceSolid"):
|
|
||||||
surface = boolean.BaseSurface
|
|
||||||
|
|
||||||
# Only IfcPlane is supported currently.
|
|
||||||
position = surface.Position
|
|
||||||
m = Matrix(ifcopenshell.util.placement.get_axis2placement(position).tolist())
|
|
||||||
m.translation *= unit_scale
|
|
||||||
|
|
||||||
# Only update if transform was changed.
|
|
||||||
if not np.allclose(m, obj.matrix_world):
|
|
||||||
new_m = main_obj.matrix_world.inverted() @ obj.matrix_world
|
|
||||||
new_m.normalize()
|
|
||||||
new_m.translation /= unit_scale
|
|
||||||
new_m = np.array(new_m)
|
|
||||||
ifcopenshell.util.element.remove_deep2(ifc_file, position)
|
|
||||||
surface.Position = builder.create_axis2_placement_3d_from_matrix(new_m)
|
|
||||||
tool.Geometry.reload_representation(main_obj)
|
|
||||||
|
|
||||||
objects_to_remove.add(obj)
|
|
||||||
|
|
||||||
tool.Blender.remove_data_blocks(objects_to_remove, remove_unused_data=True)
|
|
||||||
tool.Model.purge_scene_openings()
|
|
||||||
|
|
||||||
if booleans_to_add:
|
|
||||||
for obj, boolean_objs in booleans_to_add.items():
|
|
||||||
with context.temp_override(selected_objects=boolean_objs + [obj]):
|
|
||||||
bpy.ops.bim.add_boolean()
|
|
||||||
|
|
||||||
if set_active_obj and set_selected_objs is not None:
|
|
||||||
tool.Blender.set_objects_selection(context, set_active_obj, set_selected_objs)
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
|
|
||||||
class RemoveBooleans(Operator, tool.Ifc.Operator, AddObjectHelper):
|
|
||||||
bl_idname = "bim.remove_booleans"
|
|
||||||
bl_label = "Remove Booleans"
|
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
|
||||||
|
|
||||||
def _execute(self, context):
|
|
||||||
upstream_obj = None
|
|
||||||
bbim_boolean_updates = {}
|
|
||||||
objects_to_remove = set()
|
|
||||||
for obj in context.selected_objects:
|
|
||||||
if (
|
|
||||||
not obj.data
|
|
||||||
or not hasattr(obj.data, "BIMMeshProperties")
|
|
||||||
or not obj.data.BIMMeshProperties.ifc_boolean_id
|
|
||||||
):
|
|
||||||
continue
|
|
||||||
try:
|
|
||||||
item = tool.Ifc.get().by_id(obj.data.BIMMeshProperties.ifc_boolean_id)
|
|
||||||
except:
|
|
||||||
continue
|
|
||||||
|
|
||||||
boolean_id = None
|
|
||||||
for inverse in tool.Ifc.get().get_inverse(item):
|
|
||||||
if inverse.is_a("IfcBooleanResult"):
|
|
||||||
boolean_id = inverse.id()
|
|
||||||
break
|
|
||||||
ifcopenshell.api.run("geometry.remove_boolean", tool.Ifc.get(), item=item)
|
|
||||||
|
|
||||||
if obj.data.BIMMeshProperties.obj:
|
|
||||||
upstream_obj = obj.data.BIMMeshProperties.obj
|
|
||||||
element = tool.Ifc.get_entity(upstream_obj)
|
|
||||||
bbim_boolean_updates.setdefault(element, []).append(boolean_id)
|
|
||||||
body = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
|
|
||||||
if body:
|
|
||||||
bonsai.core.geometry.switch_representation(
|
|
||||||
tool.Ifc,
|
|
||||||
tool.Geometry,
|
|
||||||
obj=upstream_obj,
|
|
||||||
representation=body,
|
|
||||||
should_reload=True,
|
|
||||||
is_global=True,
|
|
||||||
should_sync_changes_first=False,
|
|
||||||
)
|
|
||||||
objects_to_remove.add(obj)
|
|
||||||
|
|
||||||
tool.Blender.remove_data_blocks(objects_to_remove, remove_unused_data=True)
|
|
||||||
|
|
||||||
for element, boolean_ids in bbim_boolean_updates.items():
|
|
||||||
tool.Model.unmark_manual_booleans(element, boolean_ids)
|
|
||||||
|
|
||||||
tool.Blender.set_active_object(upstream_obj)
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
|
|
||||||
class ShowOpenings(Operator, tool.Ifc.Operator):
|
class ShowOpenings(Operator, tool.Ifc.Operator):
|
||||||
bl_idname = "bim.show_openings"
|
bl_idname = "bim.show_openings"
|
||||||
bl_label = "Show"
|
bl_label = "Show"
|
||||||
|
|||||||
@@ -162,13 +162,6 @@ class BIM_PT_booleans(Panel):
|
|||||||
)
|
)
|
||||||
op.mark_as_manual = not booleans_are_manual
|
op.mark_as_manual = not booleans_are_manual
|
||||||
|
|
||||||
elif upsteam_obj := obj.data.BIMMeshProperties.obj:
|
|
||||||
upstream_obj_ifc_id = upsteam_obj.BIMObjectProperties.ifc_definition_id
|
|
||||||
|
|
||||||
row = layout.row(align=True)
|
|
||||||
row.label(text=upsteam_obj.name)
|
|
||||||
row.operator("bim.select_entity", text="", icon="RESTRICT_SELECT_OFF").ifc_id = upstream_obj_ifc_id
|
|
||||||
|
|
||||||
if not props.is_editing:
|
if not props.is_editing:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user