mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 09:21:46 +00:00
Support duplicating potential openings and potential/existing booleans
This commit is contained in:
@@ -983,7 +983,9 @@ class OverrideDuplicateMove(bpy.types.Operator):
|
||||
OverrideDuplicateMove.duplicate_item(self, obj)
|
||||
continue
|
||||
|
||||
linked_non_ifc_object = linked and not element
|
||||
tracked_opening_type = tool.Model.get_tracked_opening_type(obj)
|
||||
is_tracked_opening = bool(tracked_opening_type)
|
||||
keep_data_linked = linked and not element and not is_tracked_opening
|
||||
|
||||
# Prior to duplicating, sync the object placement to make decomposition recreation more stable.
|
||||
if tool.Ifc.is_moved(obj):
|
||||
@@ -1000,11 +1002,17 @@ class OverrideDuplicateMove(bpy.types.Operator):
|
||||
if tool.Ifc.is_edited(obj, ignore_scale=True):
|
||||
tool.Ifc.edit(new_obj)
|
||||
|
||||
if obj.data and not linked_non_ifc_object:
|
||||
if obj.data and not keep_data_linked:
|
||||
# assure root.copy_class won't replace the previous mesh globally
|
||||
temp_data = obj.data.copy()
|
||||
new_obj.data = temp_data
|
||||
|
||||
# Unlink from previous boolean element
|
||||
# and keep object tracked for decorations.
|
||||
if is_tracked_opening:
|
||||
new_obj.data.BIMMeshProperties.ifc_boolean_id = 0
|
||||
tool.Root.add_tracked_opening(new_obj, tracked_opening_type)
|
||||
|
||||
if obj == context.active_object:
|
||||
self.new_active_obj = new_obj
|
||||
for collection in obj.users_collection:
|
||||
@@ -1012,7 +1020,7 @@ class OverrideDuplicateMove(bpy.types.Operator):
|
||||
obj.select_set(False)
|
||||
new_obj.select_set(True)
|
||||
|
||||
if linked_non_ifc_object:
|
||||
if not element:
|
||||
continue
|
||||
|
||||
# clear object's collection so it will be able to have it's own
|
||||
|
||||
@@ -489,7 +489,7 @@ class AddPotentialOpening(Operator, AddObjectHelper):
|
||||
obj.matrix_world = new_matrix
|
||||
|
||||
tool.Model.purge_scene_openings()
|
||||
tool.Root.add_tracked_opening(obj)
|
||||
tool.Root.add_tracked_opening(obj, "OPENING")
|
||||
|
||||
DecorationsHandler.install(context)
|
||||
return {"FINISHED"}
|
||||
@@ -513,7 +513,7 @@ class AddPotentialHalfSpaceSolid(Operator, AddObjectHelper):
|
||||
obj.name = "HalfSpaceSolid"
|
||||
|
||||
tool.Model.purge_scene_openings()
|
||||
tool.Root.add_tracked_opening(obj)
|
||||
tool.Root.add_tracked_opening(obj, "BOOLEAN")
|
||||
|
||||
DecorationsHandler.install(context)
|
||||
return {"FINISHED"}
|
||||
@@ -663,7 +663,7 @@ class ShowBooleans(Operator, tool.Ifc.Operator, AddObjectHelper):
|
||||
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)
|
||||
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)
|
||||
@@ -849,7 +849,7 @@ class ShowOpenings(Operator, tool.Ifc.Operator):
|
||||
self.on_new_opening_obj(opening)
|
||||
|
||||
def on_new_opening_obj(self, opening_obj: bpy.types.Object) -> None:
|
||||
tool.Root.add_tracked_opening(opening_obj)
|
||||
tool.Root.add_tracked_opening(opening_obj, "OPENING")
|
||||
opening_obj.display_type = "WIRE"
|
||||
|
||||
|
||||
|
||||
@@ -51,8 +51,6 @@ def copy_class(
|
||||
geometry.rename_object(data, geometry.get_representation_name(ifc.get_entity(data)))
|
||||
root.assign_body_styles(new, obj)
|
||||
collector.assign(obj)
|
||||
if root.is_element_a(new, "IfcOpeningElement"):
|
||||
root.add_tracked_opening(obj)
|
||||
return new
|
||||
|
||||
|
||||
|
||||
@@ -2014,6 +2014,14 @@ class Model(bonsai.core.tool.Model):
|
||||
def get_booleaned_obj(cls, boolean_obj: bpy.types.Object) -> bpy.types.Object:
|
||||
return boolean_obj.data.BIMMeshProperties.obj
|
||||
|
||||
@classmethod
|
||||
def get_tracked_opening_type(cls, obj: bpy.types.Object) -> Union[Literal["OPENING", "BOOLEAN"], None]:
|
||||
"""Get tracked opening type, return `None` if object is not a tracked opening."""
|
||||
for opening in bpy.context.scene.BIMModelProperties.openings:
|
||||
if opening.obj == obj:
|
||||
return opening.name
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def bm_sort_out_geom(
|
||||
cls, geom_data: list[Union[bmesh.types.BMVert, bmesh.types.BMEdge, bmesh.types.BMFace]]
|
||||
|
||||
@@ -26,17 +26,18 @@ import bonsai.core.tool
|
||||
import bonsai.core.aggregate
|
||||
import bonsai.core.geometry
|
||||
import bonsai.tool as tool
|
||||
from typing import Union, Optional, Any
|
||||
from typing import Union, Optional, Any, Literal
|
||||
from bonsai.bim.module.spatial.decorator import GridDecorator
|
||||
from bonsai.bim.module.geometry.decorator import ItemDecorator
|
||||
|
||||
|
||||
class Root(bonsai.core.tool.Root):
|
||||
@classmethod
|
||||
def add_tracked_opening(cls, obj: bpy.types.Object) -> None:
|
||||
def add_tracked_opening(cls, obj: bpy.types.Object, opening_type: Literal["OPENING", "BOOLEAN"]) -> None:
|
||||
"""Add tracked opening or boolean object."""
|
||||
new = bpy.context.scene.BIMModelProperties.openings.add()
|
||||
new.obj = obj
|
||||
new.name = opening_type
|
||||
|
||||
@classmethod
|
||||
def assign_body_styles(cls, element: ifcopenshell.entity_instance, obj: bpy.types.Object) -> None:
|
||||
|
||||
@@ -33,9 +33,10 @@ class TestImplementsTool(NewFile):
|
||||
class TestAddTrackedOpening(NewFile):
|
||||
def test_run(self):
|
||||
obj = bpy.data.objects.new("Object", None)
|
||||
subject.add_tracked_opening(obj)
|
||||
subject.add_tracked_opening(obj, "OPENING")
|
||||
props = bpy.context.scene.BIMModelProperties
|
||||
assert props.openings[0].obj == obj
|
||||
assert props.openings[0].name == "OPENING"
|
||||
|
||||
|
||||
class TestCopyRepresentation(NewFile):
|
||||
|
||||
Reference in New Issue
Block a user