mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-17 19:09:07 +00:00
66 lines
2.3 KiB
Python
66 lines
2.3 KiB
Python
import ifcopenshell
|
|
import ifcopenshell.util.element
|
|
from toposort import toposort_flatten as toposort
|
|
|
|
|
|
|
|
class Patcher:
|
|
def __init__(self, src, file, logger, args=None):
|
|
self.src = src
|
|
self.file = file
|
|
self.logger = logger
|
|
self.args = args
|
|
self.optimized_file = ifcopenshell.file(schema=self.file.schema)
|
|
|
|
|
|
def patch(self):
|
|
def generate_instances_and_references():
|
|
"""
|
|
Generator which yields an entity id and
|
|
the set of all of its references contained in its attributes.
|
|
"""
|
|
for inst in self.file:
|
|
yield inst.id(), set(i.id() for i in self.file.traverse(inst)[1:] if i.id())
|
|
|
|
instance_mapping = {}
|
|
|
|
|
|
def map_value(v):
|
|
"""
|
|
Recursive function which replicates an entity instance, with
|
|
its attributes, mapping references to already registered
|
|
instances. Indeed, because of the toposort we know that
|
|
forward attribute value instances are mapped before the instances
|
|
that reference them.
|
|
"""
|
|
if isinstance(v, (list, tuple)):
|
|
# lists are recursively traversed
|
|
return type(v)(map(map_value, v))
|
|
elif isinstance(v, ifcopenshell.entity_instance):
|
|
if v.id() == 0:
|
|
# express simple types are not part of the toposort and just copied
|
|
return self.optimized_file.create_entity(v.is_a(), v[0])
|
|
|
|
|
|
return instance_mapping[v]
|
|
else:
|
|
# a plain python value can just be returned
|
|
return v
|
|
|
|
info_to_id = {}
|
|
|
|
for id in toposort(dict(generate_instances_and_references())):
|
|
inst = self.file[id]
|
|
info = inst.get_info(include_identifier=False, recursive=True, return_type=frozenset)
|
|
if info in info_to_id:
|
|
mapped = instance_mapping[inst] = instance_mapping[self.file[info_to_id[info]]]
|
|
|
|
else:
|
|
info_to_id[info] = id
|
|
instance_mapping[inst] = self.optimized_file.create_entity(
|
|
inst.is_a(),
|
|
*map(map_value, inst)
|
|
)
|
|
|
|
self.file = self.optimized_file
|
|
|