mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-09 13:52:23 +00:00
Fix #2968. Deletions are no longer postponed. Should fix or reveal a lot of sync errors.
This commit is contained in:
@@ -45,7 +45,6 @@ class IfcExporter:
|
|||||||
self.set_header()
|
self.set_header()
|
||||||
IfcStore.update_cache()
|
IfcStore.update_cache()
|
||||||
if bpy.context.scene.BIMProjectProperties.is_authoring:
|
if bpy.context.scene.BIMProjectProperties.is_authoring:
|
||||||
self.sync_deletions()
|
|
||||||
self.sync_all_objects()
|
self.sync_all_objects()
|
||||||
self.sync_edited_objects()
|
self.sync_edited_objects()
|
||||||
extension = self.ifc_export_settings.output_file.split(".")[-1].lower()
|
extension = self.ifc_export_settings.output_file.split(".")[-1].lower()
|
||||||
@@ -87,19 +86,6 @@ class IfcExporter:
|
|||||||
self.get_application_name(), self.get_application_version()
|
self.get_application_name(), self.get_application_version()
|
||||||
)
|
)
|
||||||
|
|
||||||
def sync_deletions(self):
|
|
||||||
results = []
|
|
||||||
for ifc_definition_id in IfcStore.deleted_ids:
|
|
||||||
try:
|
|
||||||
product = self.file.by_id(ifc_definition_id)
|
|
||||||
if hasattr(product, "GlobalId"):
|
|
||||||
results.append(product.GlobalId)
|
|
||||||
except:
|
|
||||||
continue
|
|
||||||
ifcopenshell.api.run("root.remove_product", self.file, **{"product": product})
|
|
||||||
IfcStore.deleted_ids.clear()
|
|
||||||
return results
|
|
||||||
|
|
||||||
def sync_all_objects(self):
|
def sync_all_objects(self):
|
||||||
results = []
|
results = []
|
||||||
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(self.file)
|
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(self.file)
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ class IfcStore:
|
|||||||
cache_path = None
|
cache_path = None
|
||||||
id_map = {}
|
id_map = {}
|
||||||
guid_map = {}
|
guid_map = {}
|
||||||
deleted_ids = set()
|
|
||||||
edited_objs = set()
|
edited_objs = set()
|
||||||
pset_template_path = ""
|
pset_template_path = ""
|
||||||
pset_template_file = None
|
pset_template_file = None
|
||||||
@@ -63,7 +62,6 @@ class IfcStore:
|
|||||||
IfcStore.cache_path = None
|
IfcStore.cache_path = None
|
||||||
IfcStore.id_map = {}
|
IfcStore.id_map = {}
|
||||||
IfcStore.guid_map = {}
|
IfcStore.guid_map = {}
|
||||||
IfcStore.deleted_ids = set()
|
|
||||||
IfcStore.edited_objs = set()
|
IfcStore.edited_objs = set()
|
||||||
IfcStore.pset_template_path = ""
|
IfcStore.pset_template_path = ""
|
||||||
IfcStore.pset_template_file = None
|
IfcStore.pset_template_file = None
|
||||||
@@ -278,23 +276,6 @@ class IfcStore:
|
|||||||
data = {"id": element.id(), "obj": obj.name}
|
data = {"id": element.id(), "obj": obj.name}
|
||||||
IfcStore.commit_link_element(data)
|
IfcStore.commit_link_element(data)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def delete_element(element):
|
|
||||||
IfcStore.deleted_ids.add(element.id())
|
|
||||||
if IfcStore.history:
|
|
||||||
data = {"id": element.id()}
|
|
||||||
IfcStore.history[-1]["operations"].append(
|
|
||||||
{"rollback": IfcStore.rollback_delete_element, "commit": IfcStore.commit_delete_element, "data": data}
|
|
||||||
)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def rollback_delete_element(data):
|
|
||||||
IfcStore.deleted_ids.remove(data["id"])
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def commit_delete_element(data):
|
|
||||||
IfcStore.deleted_ids.add(data["id"])
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def link_element(element, obj):
|
def link_element(element, obj):
|
||||||
existing_obj = IfcStore.id_map.get(element.id(), None)
|
existing_obj = IfcStore.id_map.get(element.id(), None)
|
||||||
|
|||||||
@@ -250,6 +250,20 @@ class UpdateRepresentation(bpy.types.Operator, Operator):
|
|||||||
|
|
||||||
obj.data.BIMMeshProperties.ifc_definition_id = int(new_representation.id())
|
obj.data.BIMMeshProperties.ifc_definition_id = int(new_representation.id())
|
||||||
obj.data.name = f"{old_representation.ContextOfItems.id()}/{new_representation.id()}"
|
obj.data.name = f"{old_representation.ContextOfItems.id()}/{new_representation.id()}"
|
||||||
|
|
||||||
|
# TODO: In simple scenarios, a type has a ShapeRepresentation of ID
|
||||||
|
# 123. This is then mapped through mapped representations by
|
||||||
|
# occurrences, with no cartesian transformation. In this case, the mesh
|
||||||
|
# data is 100% shared and therefore all have the same mesh name
|
||||||
|
# referencing ID 123. (i.e. the local origins are shared). However, in
|
||||||
|
# complex scenarios, occurrences may have their own cartesian
|
||||||
|
# transformation (via MappingTarget). This will mean that occurrences
|
||||||
|
# will not share the same mesh data and will instead reference a
|
||||||
|
# different ShapeRepresentation ID. In this scenario, we have to
|
||||||
|
# propagate the obj.data back to the type itself and all sibling
|
||||||
|
# occurrences and accommodate their individual cartesian
|
||||||
|
# transformations.
|
||||||
|
|
||||||
core.remove_representation(tool.Ifc, tool.Geometry, obj=obj, representation=old_representation)
|
core.remove_representation(tool.Ifc, tool.Geometry, obj=obj, representation=old_representation)
|
||||||
if obj.data.BIMMeshProperties.ifc_parameters:
|
if obj.data.BIMMeshProperties.ifc_parameters:
|
||||||
core.get_representation_ifc_parameters(tool.Geometry, obj=obj)
|
core.get_representation_ifc_parameters(tool.Geometry, obj=obj)
|
||||||
@@ -352,7 +366,6 @@ class OverrideDeleteTrait:
|
|||||||
return
|
return
|
||||||
if element.is_a("IfcAnnotation") and element.ObjectType == "DRAWING":
|
if element.is_a("IfcAnnotation") and element.ObjectType == "DRAWING":
|
||||||
return blenderbim.core.drawing.remove_drawing(tool.Ifc, tool.Drawing, drawing=element)
|
return blenderbim.core.drawing.remove_drawing(tool.Ifc, tool.Drawing, drawing=element)
|
||||||
IfcStore.delete_element(element)
|
|
||||||
if obj.users_collection and obj.users_collection[0].name == obj.name:
|
if obj.users_collection and obj.users_collection[0].name == obj.name:
|
||||||
parent = ifcopenshell.util.element.get_aggregate(element)
|
parent = ifcopenshell.util.element.get_aggregate(element)
|
||||||
if not parent:
|
if not parent:
|
||||||
@@ -379,6 +392,7 @@ class OverrideDeleteTrait:
|
|||||||
self.delete_opening_element(rel.RelatedOpeningElement)
|
self.delete_opening_element(rel.RelatedOpeningElement)
|
||||||
for port in ifcopenshell.util.system.get_ports(element):
|
for port in ifcopenshell.util.system.get_ports(element):
|
||||||
self.remove_port(port)
|
self.remove_port(port)
|
||||||
|
ifcopenshell.api.run("root.remove_product", tool.Ifc.get(), product=element)
|
||||||
|
|
||||||
def delete_opening_element(self, element):
|
def delete_opening_element(self, element):
|
||||||
bpy.ops.bim.remove_opening(opening_id=element.id())
|
bpy.ops.bim.remove_opening(opening_id=element.id())
|
||||||
@@ -661,7 +675,7 @@ class OverrideJoin(bpy.types.Operator, Operator):
|
|||||||
continue
|
continue
|
||||||
element = tool.Ifc.get_entity(obj)
|
element = tool.Ifc.get_entity(obj)
|
||||||
if element:
|
if element:
|
||||||
tool.Ifc.delete(element)
|
ifcopenshell.api.run("root.remove_product", tool.Ifc.get(), product=element)
|
||||||
bpy.ops.object.join()
|
bpy.ops.object.join()
|
||||||
bpy.ops.bim.update_representation(obj=self.target.name, ifc_representation_class="")
|
bpy.ops.bim.update_representation(obj=self.target.name, ifc_representation_class="")
|
||||||
elif representation.RepresentationType == "SweptSolid":
|
elif representation.RepresentationType == "SweptSolid":
|
||||||
@@ -699,7 +713,7 @@ class OverrideJoin(bpy.types.Operator, Operator):
|
|||||||
tool.Ifc.get().createIfcDirection([float(n) for n in position[:, 0][:3]]),
|
tool.Ifc.get().createIfcDirection([float(n) for n in position[:, 0][:3]]),
|
||||||
)
|
)
|
||||||
items.append(copied_item)
|
items.append(copied_item)
|
||||||
tool.Ifc.delete(element)
|
ifcopenshell.api.run("root.remove_product", tool.Ifc.get(), product=element)
|
||||||
representation.Items = items
|
representation.Items = items
|
||||||
bpy.ops.object.join()
|
bpy.ops.object.join()
|
||||||
core.switch_representation(
|
core.switch_representation(
|
||||||
@@ -719,7 +733,7 @@ class OverrideJoin(bpy.types.Operator, Operator):
|
|||||||
continue
|
continue
|
||||||
element = tool.Ifc.get_entity(obj)
|
element = tool.Ifc.get_entity(obj)
|
||||||
if element:
|
if element:
|
||||||
tool.Ifc.delete(element)
|
ifcopenshell.api.run("root.remove_product", tool.Ifc.get(), product=element)
|
||||||
bpy.ops.object.join()
|
bpy.ops.object.join()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -347,11 +347,9 @@ def sync_references(ifc, collector, drawing_tool, drawing=None):
|
|||||||
should_create_annotation = False
|
should_create_annotation = False
|
||||||
|
|
||||||
if annotation:
|
if annotation:
|
||||||
if ifc.is_deleted(annotation):
|
if reference_obj and (ifc.is_moved(reference_obj) or ifc.is_edited(reference_obj)):
|
||||||
should_delete_existing_annotation = True
|
should_delete_existing_annotation = True
|
||||||
elif reference_obj and (ifc.is_moved(reference_obj) or ifc.is_edited(reference_obj)):
|
elif not reference_obj:
|
||||||
should_delete_existing_annotation = True
|
|
||||||
elif not reference_obj and ifc.is_deleted(reference_element):
|
|
||||||
should_delete_existing_annotation = True
|
should_delete_existing_annotation = True
|
||||||
|
|
||||||
if reference_obj and (should_delete_existing_annotation or not annotation):
|
if reference_obj and (should_delete_existing_annotation or not annotation):
|
||||||
|
|||||||
@@ -376,13 +376,11 @@ class Ifc:
|
|||||||
def get_object(cls, entity): pass
|
def get_object(cls, entity): pass
|
||||||
def get_path(cls): pass
|
def get_path(cls): pass
|
||||||
def get_schema(cls): pass
|
def get_schema(cls): pass
|
||||||
def is_deleted(cls, element): pass
|
|
||||||
def is_edited(cls, obj): pass
|
def is_edited(cls, obj): pass
|
||||||
def is_moved(cls, obj): pass
|
def is_moved(cls, obj): pass
|
||||||
def link(cls, element, obj): pass
|
def link(cls, element, obj): pass
|
||||||
def schema(cls): pass
|
def schema(cls): pass
|
||||||
def edit(cls, obj): pass
|
def edit(cls, obj): pass
|
||||||
def delete(cls, element): pass
|
|
||||||
def resolve_uri(cls, uri): pass
|
def resolve_uri(cls, uri): pass
|
||||||
def run(cls, command, **kwargs): pass
|
def run(cls, command, **kwargs): pass
|
||||||
def set(cls, ifc): pass
|
def set(cls, ifc): pass
|
||||||
|
|||||||
@@ -149,7 +149,7 @@ class Drawing(blenderbim.core.tool.Drawing):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def delete_drawing_elements(cls, elements):
|
def delete_drawing_elements(cls, elements):
|
||||||
for element in elements:
|
for element in elements:
|
||||||
tool.Ifc.delete(element)
|
ifcopenshell.api.run("root.remove_product", tool.Ifc.get(), product=element)
|
||||||
obj = tool.Ifc.get_object(element)
|
obj = tool.Ifc.get_object(element)
|
||||||
if obj:
|
if obj:
|
||||||
obj_data = obj.data
|
obj_data = obj.data
|
||||||
|
|||||||
@@ -51,10 +51,6 @@ class Ifc(blenderbim.core.tool.Ifc):
|
|||||||
checksum = obj.BIMMaterialProperties.shading_checksum
|
checksum = obj.BIMMaterialProperties.shading_checksum
|
||||||
return checksum != repr(np.array(obj.diffuse_color).tobytes())
|
return checksum != repr(np.array(obj.diffuse_color).tobytes())
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def is_deleted(cls, element):
|
|
||||||
return element.id() in IfcStore.deleted_ids
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def is_edited(cls, obj):
|
def is_edited(cls, obj):
|
||||||
return list(obj.scale) != [1.0, 1.0, 1.0] or obj in IfcStore.edited_objs
|
return list(obj.scale) != [1.0, 1.0, 1.0] or obj in IfcStore.edited_objs
|
||||||
@@ -100,10 +96,6 @@ class Ifc(blenderbim.core.tool.Ifc):
|
|||||||
def edit(cls, obj):
|
def edit(cls, obj):
|
||||||
IfcStore.edited_objs.add(obj)
|
IfcStore.edited_objs.add(obj)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def delete(cls, element):
|
|
||||||
IfcStore.delete_element(element)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def resolve_uri(cls, uri):
|
def resolve_uri(cls, uri):
|
||||||
if os.path.isabs(uri):
|
if os.path.isabs(uri):
|
||||||
|
|||||||
@@ -61,6 +61,8 @@ class TestCreateCamera(NewFile):
|
|||||||
class TestCreateSvgSheet(NewFile):
|
class TestCreateSvgSheet(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
ifc = ifcopenshell.file()
|
ifc = ifcopenshell.file()
|
||||||
|
ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcProject")
|
||||||
|
tool.Ifc.set(ifc)
|
||||||
document = ifc.createIfcDocumentInformation(
|
document = ifc.createIfcDocumentInformation(
|
||||||
Identification="X",
|
Identification="X",
|
||||||
Name="FOOBAR",
|
Name="FOOBAR",
|
||||||
@@ -87,12 +89,16 @@ class TestDeleteDrawingElements(NewFile):
|
|||||||
collection = bpy.data.collections.new("Collection")
|
collection = bpy.data.collections.new("Collection")
|
||||||
bpy.context.scene.collection.children.link(collection)
|
bpy.context.scene.collection.children.link(collection)
|
||||||
collection.objects.link(obj)
|
collection.objects.link(obj)
|
||||||
element = ifc.createIfcAnnotation()
|
element = ifc.createIfcAnnotation(GlobalId=ifcopenshell.guid.new())
|
||||||
tool.Ifc.link(element, obj)
|
tool.Ifc.link(element, obj)
|
||||||
|
|
||||||
element_id = element.id()
|
element_id = element.id()
|
||||||
subject.delete_drawing_elements([element])
|
subject.delete_drawing_elements([element])
|
||||||
assert element_id in IfcStore.deleted_ids
|
try:
|
||||||
|
ifc.by_id(element_id)
|
||||||
|
assert False
|
||||||
|
except:
|
||||||
|
pass
|
||||||
assert not bpy.data.objects.get("Object")
|
assert not bpy.data.objects.get("Object")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user