mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-06 07:51:47 +00:00
Fix bug where switching geometry may not correctly share representations
This commit is contained in:
@@ -295,35 +295,22 @@ class SwitchRepresentation(bpy.types.Operator, tool.Ifc.Operator):
|
||||
return False
|
||||
|
||||
def _execute(self, context):
|
||||
target_representation = tool.Ifc.get().by_id(self.ifc_definition_id)
|
||||
target = target_representation.ContextOfItems
|
||||
is_subcontext = target.is_a("IfcGeometricRepresentationSubContext")
|
||||
for obj in set(context.selected_objects + [context.active_object]):
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
if not element:
|
||||
continue
|
||||
if not obj.mode == "OBJECT":
|
||||
continue
|
||||
if obj == context.active_object:
|
||||
representation = target_representation
|
||||
else:
|
||||
if is_subcontext:
|
||||
representation = ifcopenshell.util.representation.get_representation(
|
||||
element, target.ContextType, target.ContextIdentifier, target.TargetView
|
||||
)
|
||||
else:
|
||||
representation = ifcopenshell.util.representation.get_representation(element, target.ContextType)
|
||||
if not representation:
|
||||
continue
|
||||
core.switch_representation(
|
||||
tool.Ifc,
|
||||
tool.Geometry,
|
||||
obj=obj,
|
||||
representation=representation,
|
||||
should_reload=self.should_reload,
|
||||
is_global=self.should_switch_all_meshes,
|
||||
should_sync_changes_first=True,
|
||||
)
|
||||
context = tool.Ifc.get().by_id(self.ifc_definition_id).ContextOfItems
|
||||
for obj in tool.Blender.get_selected_objects():
|
||||
if (
|
||||
(element := tool.Ifc.get_entity(obj))
|
||||
and obj.mode == "OBJECT"
|
||||
and (representation := ifcopenshell.util.representation.get_representation(element, context))
|
||||
):
|
||||
core.switch_representation(
|
||||
tool.Ifc,
|
||||
tool.Geometry,
|
||||
obj=obj,
|
||||
representation=representation,
|
||||
should_reload=self.should_reload,
|
||||
is_global=self.should_switch_all_meshes,
|
||||
should_sync_changes_first=True,
|
||||
)
|
||||
|
||||
|
||||
class RemoveRepresentation(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
@@ -121,44 +121,10 @@ def switch_representation(
|
||||
if not geometry.does_representation_id_exist(representation_id):
|
||||
return
|
||||
|
||||
entity = ifc.get_entity(obj)
|
||||
assert entity
|
||||
current_obj_data = geometry.get_object_data(obj)
|
||||
|
||||
if not current_obj_data and geometry.is_text_literal(representation):
|
||||
if not geometry.get_object_data(obj) and geometry.is_text_literal(representation):
|
||||
return
|
||||
|
||||
use_immediate_repr = geometry.should_use_immediate_representation(entity, apply_openings)
|
||||
if use_immediate_repr:
|
||||
# if it has openings make sure to switch to element's mapped representation
|
||||
representation = geometry.unresolve_type_representation(representation, entity)
|
||||
else:
|
||||
# doesn't resolve mapped representations in case if it's going to have openings
|
||||
# otherwise we would also add openings to the type and other occurences mesh data
|
||||
representation = geometry.resolve_mapped_representation(representation)
|
||||
|
||||
old_repr_data = geometry.get_representation_data(representation)
|
||||
if should_reload or not old_repr_data:
|
||||
new_repr_data = geometry.import_representation(obj, representation, apply_openings=apply_openings)
|
||||
geometry.rename_object(new_repr_data, geometry.get_representation_name(representation))
|
||||
geometry.link(representation, new_repr_data)
|
||||
else:
|
||||
new_repr_data = old_repr_data
|
||||
|
||||
geometry.change_object_data(obj, new_repr_data, is_global=is_global and not use_immediate_repr)
|
||||
geometry.record_object_materials(obj)
|
||||
|
||||
# we assume that all the occurences and the type have the same representation context active
|
||||
# so geometry.delete_data cannot remove the data that's still used by some other object
|
||||
if should_reload and old_repr_data:
|
||||
# if current object was using some temporary mesh (like during profile edit mode) instead of `old_repr_data`
|
||||
# then `change_object_data` won't switch the mesh for all the occurences and we need to do it explicitly
|
||||
if current_obj_data != old_repr_data and geometry.has_data_users(old_repr_data):
|
||||
geometry.replace_object_data_globally(old_repr_data, new_repr_data)
|
||||
geometry.delete_data(old_repr_data)
|
||||
|
||||
geometry.clear_modifiers(obj)
|
||||
geometry.clear_cache(entity)
|
||||
geometry.reimport_element_representations(obj, representation, apply_openings=apply_openings)
|
||||
|
||||
|
||||
def get_representation_ifc_parameters(
|
||||
|
||||
@@ -603,65 +603,108 @@ class Geometry(bonsai.core.tool.Geometry):
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def import_representation(
|
||||
def reimport_element_representations(
|
||||
cls, obj: bpy.types.Object, representation: ifcopenshell.entity_instance, apply_openings: bool = True
|
||||
) -> Union[bpy.types.Mesh, bpy.types.Curve]:
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
assert element
|
||||
|
||||
elements = set()
|
||||
element_types = set()
|
||||
representation = ifcopenshell.util.representation.resolve_representation(representation)
|
||||
context = representation.ContextOfItems
|
||||
for mapped_element in ifcopenshell.util.element.get_elements_by_representation(tool.Ifc.get(), representation):
|
||||
if mapped_element.is_a("IfcTypeProduct"):
|
||||
element_types.add(mapped_element)
|
||||
else:
|
||||
elements.add(mapped_element)
|
||||
if element_type := ifcopenshell.util.element.get_type(mapped_element):
|
||||
element_types.add(element_type)
|
||||
|
||||
logger = logging.getLogger("ImportIFC")
|
||||
ifc_import_settings = bonsai.bim.import_ifc.IfcImportSettings.factory(bpy.context, None, logger)
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
assert element # Type checker.
|
||||
settings = ifcopenshell.geom.settings()
|
||||
settings.set("weld-vertices", True)
|
||||
settings.set("apply-default-materials", False)
|
||||
settings.set("layerset-first", True)
|
||||
settings.set("keep-bounding-boxes", True)
|
||||
context = representation.ContextOfItems
|
||||
settings.set("dimensionality", ifcopenshell.ifcopenshell_wrapper.CURVES_SURFACES_AND_SOLIDS)
|
||||
|
||||
ifc_importer = bonsai.bim.import_ifc.IfcImporter(ifc_import_settings)
|
||||
ifc_importer.file = tool.Ifc.get()
|
||||
|
||||
# create_shape doesn't support point cloud representations.
|
||||
if representation.RepresentationType in ("PointCloud", "Point"):
|
||||
mesh = tool.Loader.create_point_cloud_mesh(representation)
|
||||
if mesh is None:
|
||||
raise Exception(f"Failed to process point cloud representation: {representation}.")
|
||||
return mesh
|
||||
# TODO support fallbacks like for point clouds
|
||||
|
||||
if element.is_a("IfcTypeProduct"):
|
||||
# You may only specify a single representation when creating shapes for types
|
||||
try:
|
||||
shape = ifcopenshell.geom.create_shape(settings, representation)
|
||||
except:
|
||||
settings.set("dimensionality", ifcopenshell.ifcopenshell_wrapper.CURVES_SURFACES_AND_SOLIDS)
|
||||
shape = ifcopenshell.geom.create_shape(settings, representation)
|
||||
else:
|
||||
if not apply_openings:
|
||||
settings.set("disable-opening-subtractions", True)
|
||||
settings.set("context-ids", [context.id()])
|
||||
if not apply_openings:
|
||||
settings.set("disable-opening-subtractions", True)
|
||||
|
||||
if context.ContextIdentifier == "Body" and context.TargetView == "MODEL_VIEW":
|
||||
try:
|
||||
shape = ifcopenshell.geom.create_shape(settings, element, representation)
|
||||
except:
|
||||
settings.set("dimensionality", ifcopenshell.ifcopenshell_wrapper.CURVES_SURFACES_AND_SOLIDS)
|
||||
shape = ifcopenshell.geom.create_shape(settings, element, representation)
|
||||
else:
|
||||
settings.set("dimensionality", ifcopenshell.ifcopenshell_wrapper.CURVES_SURFACES_AND_SOLIDS)
|
||||
shape = ifcopenshell.geom.create_shape(settings, element, representation)
|
||||
shape = None
|
||||
iterator = ifcopenshell.geom.iterator(settings, tool.Ifc.get(), multiprocessing.cpu_count(), include=elements)
|
||||
meshes = {}
|
||||
if iterator.initialize():
|
||||
while True:
|
||||
shape = iterator.get()
|
||||
element = tool.Ifc.get().by_id(shape.id)
|
||||
if obj := tool.Ifc.get_object(element):
|
||||
mesh_name = tool.Loader.get_mesh_name_from_shape(shape.geometry)
|
||||
mesh = meshes.get(mesh_name)
|
||||
if mesh is None:
|
||||
# Duplicate code
|
||||
representation = tool.Ifc.get().by_id(int(shape.geometry.id.split("-")[0]))
|
||||
if element.is_a("IfcAnnotation") and element.ObjectType == "DRAWING":
|
||||
mesh = tool.Loader.create_camera(element, representation, shape)
|
||||
if element.is_a("IfcAnnotation") and ifc_importer.is_curve_annotation(element):
|
||||
mesh = ifc_importer.create_curve(element, shape)
|
||||
elif shape:
|
||||
mesh = ifc_importer.create_mesh(element, shape)
|
||||
ifc_importer.material_creator.load_existing_materials()
|
||||
shape_has_openings = cls.does_shape_has_openings(shape)
|
||||
ifc_importer.material_creator.create(element, obj, mesh, shape_has_openings)
|
||||
mesh.BIMMeshProperties.has_openings_applied = apply_openings
|
||||
if not shape_has_openings:
|
||||
tool.Loader.load_indexed_colour_map(representation, mesh)
|
||||
tool.Loader.link_mesh(shape, mesh)
|
||||
meshes[mesh_name] = mesh
|
||||
|
||||
if element.is_a("IfcAnnotation") and element.ObjectType == "DRAWING":
|
||||
mesh = tool.Loader.create_camera(element, representation, shape)
|
||||
if element.is_a("IfcAnnotation") and ifc_importer.is_curve_annotation(element):
|
||||
mesh = ifc_importer.create_curve(element, shape)
|
||||
elif shape:
|
||||
mesh = ifc_importer.create_mesh(element, shape)
|
||||
ifc_importer.material_creator.load_existing_materials()
|
||||
shape_has_openings = cls.does_shape_has_openings(shape)
|
||||
ifc_importer.material_creator.create(element, obj, mesh, shape_has_openings)
|
||||
mesh.BIMMeshProperties.has_openings_applied = apply_openings
|
||||
if not shape_has_openings:
|
||||
tool.Loader.load_indexed_colour_map(representation, mesh)
|
||||
old_mesh = obj.data
|
||||
cls.change_object_data(obj, mesh, is_global=False)
|
||||
cls.record_object_materials(obj)
|
||||
if not cls.has_data_users(old_mesh):
|
||||
cls.delete_data(old_mesh)
|
||||
cls.clear_modifiers(obj)
|
||||
cls.clear_cache(element)
|
||||
|
||||
return mesh
|
||||
if not iterator.next():
|
||||
break
|
||||
|
||||
for element in element_types:
|
||||
if obj := tool.Ifc.get_object(element):
|
||||
if representation := ifcopenshell.util.representation.get_representation(element, context):
|
||||
geometry = ifcopenshell.geom.create_shape(settings, representation)
|
||||
mesh_name = tool.Loader.get_mesh_name_from_shape(geometry)
|
||||
mesh = meshes.get(mesh_name)
|
||||
if mesh is None:
|
||||
# Duplicate code
|
||||
representation = tool.Ifc.get().by_id(int(geometry.id.split("-")[0]))
|
||||
if geometry:
|
||||
mesh = ifc_importer.create_mesh(element, geometry)
|
||||
ifc_importer.material_creator.load_existing_materials()
|
||||
shape_has_openings = False
|
||||
ifc_importer.material_creator.create(element, obj, mesh, shape_has_openings)
|
||||
mesh.BIMMeshProperties.has_openings_applied = apply_openings
|
||||
if not shape_has_openings:
|
||||
tool.Loader.load_indexed_colour_map(representation, mesh)
|
||||
tool.Loader.link_mesh(geometry, mesh)
|
||||
meshes[mesh_name] = mesh
|
||||
|
||||
old_mesh = obj.data
|
||||
cls.change_object_data(obj, mesh, is_global=False)
|
||||
cls.record_object_materials(obj)
|
||||
if not cls.has_data_users(old_mesh):
|
||||
cls.delete_data(old_mesh)
|
||||
cls.clear_modifiers(obj)
|
||||
cls.clear_cache(element)
|
||||
|
||||
@classmethod
|
||||
def does_shape_has_openings(
|
||||
|
||||
Reference in New Issue
Block a user