Aggregate data types

This commit is contained in:
Thomas Krijnen
2026-01-14 13:59:07 +01:00
parent ffcc02fb99
commit 9147938c36
3 changed files with 14 additions and 12 deletions
@@ -60,9 +60,9 @@ def remove_representation(
elif subelement.is_a("IfcProfileDef") and subelement.ProfileName: elif subelement.is_a("IfcProfileDef") and subelement.ProfileName:
named_profiles.add(subelement) named_profiles.add(subelement)
do_not_delete = file.by_type("IfcGeometricRepresentationContext") do_not_delete = set(file.by_type("IfcGeometricRepresentationContext"))
if should_keep_named_profiles: if should_keep_named_profiles:
do_not_delete += named_profiles do_not_delete |= named_profiles
# Order matters - layer assignments may reference representation directly. # Order matters - layer assignments may reference representation directly.
also_consider = list(presentation_layer_assignments_reps) also_consider = list(presentation_layer_assignments_reps)
@@ -73,7 +73,7 @@ def remove_representation(
file, file,
representation, representation,
also_consider=also_consider, also_consider=also_consider,
do_not_delete=set(do_not_delete), do_not_delete=do_not_delete,
) )
for texture in textures: for texture in textures:
@@ -16,6 +16,7 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>. # along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
from collections import deque
import ifcopenshell import ifcopenshell
import ifcopenshell.ifcopenshell_wrapper as W import ifcopenshell.ifcopenshell_wrapper as W
import ifcopenshell.api.geometry import ifcopenshell.api.geometry
@@ -302,7 +303,7 @@ class Usecase:
self.whitelisted_inverse_attributes = { self.whitelisted_inverse_attributes = {
"IfcMaterial": ["HasExternalReferences", "HasProperties", "HasRepresentation"] "IfcMaterial": ["HasExternalReferences", "HasProperties", "HasRepresentation"]
} }
self.existing_contexts = self.file.by_type("IfcGeometricRepresentationContext") self.existing_contexts = list(self.file.by_type("IfcGeometricRepresentationContext"))
element = self.add_element(self.settings["element"]) element = self.add_element(self.settings["element"])
if element.HasRepresentation: if element.HasRepresentation:
self.reuse_existing_contexts() self.reuse_existing_contexts()
@@ -329,7 +330,7 @@ class Usecase:
"IfcProductDefinitionShape": ["HasShapeAspects"], "IfcProductDefinitionShape": ["HasShapeAspects"],
"IfcRepresentationMap": ["HasShapeAspects"], "IfcRepresentationMap": ["HasShapeAspects"],
} }
self.existing_contexts = self.file.by_type("IfcGeometricRepresentationContext") self.existing_contexts = list(self.file.by_type("IfcGeometricRepresentationContext"))
element = self.add_element(self.settings["element"]) element = self.add_element(self.settings["element"])
self.reuse_existing_contexts() self.reuse_existing_contexts()
return element return element
@@ -348,7 +349,7 @@ class Usecase:
"IfcProductDefinitionShape": ["HasShapeAspects"], "IfcProductDefinitionShape": ["HasShapeAspects"],
"IfcRepresentationMap": ["HasShapeAspects"], "IfcRepresentationMap": ["HasShapeAspects"],
} }
self.existing_contexts = self.file.by_type("IfcGeometricRepresentationContext") self.existing_contexts = list(self.file.by_type("IfcGeometricRepresentationContext"))
element = self.add_element(self.settings["element"]) element = self.add_element(self.settings["element"])
self.reuse_existing_contexts() self.reuse_existing_contexts()
@@ -390,9 +391,9 @@ class Usecase:
new = self.file_add(element) new = self.file_add(element)
self.added_elements[element.id()] = new self.added_elements[element.id()] = new
self.check_inverses(element) self.check_inverses(element)
subelement_queue = self.settings["library"].traverse(element, max_levels=1)[1:] subelement_queue = deque(self.settings["library"].traverse(element, max_levels=1)[1:])
while subelement_queue: while subelement_queue:
subelement = subelement_queue.pop(0) subelement = subelement_queue.popleft()
existing_element = self.get_existing_element(subelement) existing_element = self.get_existing_element(subelement)
if existing_element: if existing_element:
self.added_elements[subelement.id()] = existing_element self.added_elements[subelement.id()] = existing_element
@@ -22,7 +22,7 @@ import ifcopenshell.util.element
import ifcopenshell.util.representation import ifcopenshell.util.representation
from typing import Any, Callable, Optional, Union, Literal, overload from typing import Any, Callable, Optional, Union, Literal, overload
from collections.abc import Generator, Sequence from collections.abc import Generator, Sequence
from collections import namedtuple from collections import deque, namedtuple
MATERIAL_TYPE = Literal[ MATERIAL_TYPE = Literal[
@@ -958,7 +958,7 @@ def get_elements_by_profile(profile: ifcopenshell.entity_instance) -> set[ifcope
:return: The elements using the profile. :return: The elements using the profile.
""" """
ifc_file = profile.file ifc_file = profile.file
queue = ifc_file.get_inverse(profile) queue = list(ifc_file.get_inverse(profile))
processed: set[ifcopenshell.entity_instance] = set() processed: set[ifcopenshell.entity_instance] = set()
representations: set[ifcopenshell.entity_instance] = set() representations: set[ifcopenshell.entity_instance] = set()
while queue: while queue:
@@ -1661,14 +1661,14 @@ def remove_deep2(
subgraph = list(ifc_file.traverse(element, breadth_first=True)) subgraph = list(ifc_file.traverse(element, breadth_first=True))
subgraph.extend(also_consider) subgraph.extend(also_consider)
subgraph_set = set(subgraph) subgraph_set = set(subgraph)
subelement_queue = [element] subelement_queue = deque([element])
# Cache already processed entities to avoid traversing them multiple time. # Cache already processed entities to avoid traversing them multiple time.
# E.g. lots of IFCINDEXEDPOLYCURVES may reference the same IFCCARTESIANPOINTLIST2D. # E.g. lots of IFCINDEXEDPOLYCURVES may reference the same IFCCARTESIANPOINTLIST2D.
processed_ids: set[int] = set() processed_ids: set[int] = set()
while subelement_queue: while subelement_queue:
subelement = subelement_queue.pop(0) subelement = subelement_queue.popleft()
subelement_id = subelement.id() subelement_id = subelement.id()
if ( if (
subelement_id subelement_id
@@ -1703,6 +1703,7 @@ def remove_deep2(
# We delete elements from subgraph in reverse order to allow batching to work # We delete elements from subgraph in reverse order to allow batching to work
for subelement in filter(lambda e: e in to_delete, subgraph[::-1]): for subelement in filter(lambda e: e in to_delete, subgraph[::-1]):
to_delete.remove(subelement)
ifc_file.remove(subelement) ifc_file.remove(subelement)
# ifc_file.unbatch() # ifc_file.unbatch()