From 35734f4b670e9f8e9824dc0332ba88dc713f9843 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sat, 18 Jan 2025 18:35:13 +1100 Subject: [PATCH] Guess representation type from items based on where rule Previously we never implemented this in a very strict way so it was prone to mistakes. --- .../ifcopenshell/util/representation.py | 143 +++++++++++++++++- .../ifcopenshell/util/shape_builder.py | 14 +- 2 files changed, 143 insertions(+), 14 deletions(-) diff --git a/src/ifcopenshell-python/ifcopenshell/util/representation.py b/src/ifcopenshell-python/ifcopenshell/util/representation.py index 573c3692e0..b4606cff29 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/representation.py +++ b/src/ifcopenshell-python/ifcopenshell/util/representation.py @@ -20,7 +20,7 @@ import numpy as np import numpy.typing as npt import ifcopenshell import ifcopenshell.util.placement -from typing import Optional, Union, TypedDict, Literal, Iterator +from typing import Optional, Union, TypedDict, Literal, Iterator, Iterable CONTEXT_TYPE = Literal["Model", "Plan", "NotDefined"] @@ -144,6 +144,147 @@ def get_representation( return r +def guess_type(items: Iterable[ifcopenshell.entity_instance]) -> str | None: + """Guesses the appropriate RepresentationType attribute based on a list of items + + :param items: A list of IfcRepresentationItem, typically in an IfcShapeRepresentation + :return: The appropriate RepresentationType value, or None if no valid value + """ + if all([True if i.is_a("IfcMappedItem") else False for i in items]): + return "MappedRepresentation" + elif all([True if i.is_a("IfcPoint") or i.is_a("IfcCartesianPointList") else False for i in items]): + return "Point" + elif all([True if i.is_a("IfcCartesianPointList3d") else False for i in items]): + return "PointCloud" + elif all([True if i.is_a("IfcCurve") and i.Dim == 2 else False for i in items]): + return "Curve2D" + elif all([True if i.is_a("IfcCurve") and i.Dim == 3 else False for i in items]): + return "Curve3D" + elif all([True if i.is_a("IfcCurve") else False for i in items]): + return "Curve" + elif all([True if i.is_a("IfcSegment") else False for i in items]): + return "Segment" + elif all([True if i.is_a("IfcSurface") and i.Dim == 2 else False for i in items]): + return "Surface2D" + elif all([True if i.is_a("IfcSurface") and i.Dim == 3 else False for i in items]): + return "Surface3D" + elif all([True if i.is_a("IfcSurface") else False for i in items]): + return "Surface" + elif all([True if i.is_a("IfcSectionedSurface") else False for i in items]): + return "SectionedSurface" + elif all([True if i.is_a("IfcAnnotationFillArea") else False for i in items]): + return "FillArea" + elif all([True if i.is_a("IfcTextLiteral") else False for i in items]): + return "Text" + elif all([True if i.is_a("IfcBSplineSurface") else False for i in items]): + return "AdvancedSurface" + elif all( + [ + ( + True + if i.is_a("IfcGeometricSet") or i.is_a("IfcPoint") or i.is_a("IfcCurve") or i.is_a("IfcSurface") + else False + ) + for i in items + ] + ): + return "GeometricSet" + elif all( + [ + ( + True + if i.is_a("IfcGeometricCurveSet") + or (i.is_a("IfcGeometricSet") and all([e.is_a("IfcSurface") for e in i.Elements])) + or i.is_a("IfcPoint") + or i.is_a("IfcCurve") + else False + ) + for i in items + ] + ): + return "GeometricCurveSet" + elif all( + [ + ( + True + if i.is_a("IfcPoint") + or i.is_a("IfcCurve") + or i.is_a("IfcGeometricCurveSet") + or i.is_a("IfcAnnotationFillArea") + or i.is_a("IfcTextLiteral") + else False + ) + for i in items + ] + ): + return "Annotation2D" + elif all([True if i.is_a("IfcTessellatedItem") else False for i in items]): + return "Tessellation" + elif all( + [ + ( + True + if i.is_a("IfcTessellatedItem") + or i.is_a("IfcShellBasedSurfaceModel") + or i.is_a("IfcFaceBasedSurfaceModel") + else False + ) + for i in items + ] + ): + return "SurfaceModel" + elif all([True if i.is_a("IfcSolidModel") else False for i in items]): + return "SolidModel" + elif all( + [True if i.is_a() == "IfcExtrudedAreaSolid" or i.is_a() == "IfcRevolvedAreaSolid" else False for i in items] + ): + return "SweptSolid" + elif all( + [ + ( + True + if i.is_a("IfcTessellatedItem") + or i.is_a("IfcShellBasedSurfaceModel") + or i.is_a("IfcFaceBasedSurfaceModel") + or i.is_a("IfcSolidModel") + else False + ) + for i in items + ] + ): + return "SurfaceOrSolidModel" + elif all( + [ + ( + True + if i.is_a("IfcSweptAreaSolid") or i.is_a("IfcSweptDiskSolid") or i.is_a("IfcSectionedSolidHorizontal") + else False + ) + for i in items + ] + ): + return "AdvancedSweptSolid" + elif all([True if i.is_a("IfcCsgSolid") or i.is_a("IfcBooleanClippingResult") else False for i in items]): + return "Clipping" + elif all( + [ + True if i.is_a("IfcBooleanResult") or i.is_a("IfcCsgPrimitive3d") or i.is_a("IfcCsgSolid") else False + for i in items + ] + ): + return "CSG" + elif all([True if i.is_a("IfcFacetedBrep") else False for i in items]): + return "Brep" + elif all([True if i.is_a("IfcManifoldSolidBrep") else False for i in items]): + return "AdvancedBrep" + elif all([True if i.is_a("IfcBoundingBox") else False for i in items]): + return "BoundingBox" + elif all([True if i.is_a("IfcSectionedSpine") else False for i in items]): + return "SectionedSpine" + elif all([True if i.is_a("IfcLightSource") else False for i in items]): + return "LightSource" + + def resolve_representation(representation: ifcopenshell.entity_instance) -> ifcopenshell.entity_instance: """Resolve possibly mapped representation. diff --git a/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py b/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py index de4dce0714..02295462d7 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py +++ b/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py @@ -987,20 +987,8 @@ class ShapeBuilder: if not isinstance(items, collections.abc.Iterable): items = [items] - item_types = set([i.is_a() for i in items]) if not representation_type: - if "IfcSweptDiskSolid" in item_types: - representation_type = "AdvancedSweptSolid" - elif "IfcExtrudedAreaSolid" in item_types: - representation_type = "SweptSolid" - elif "IfcCsgSolid" in item_types: - representation_type = "CSG" - elif items[0].is_a("IfcTessellatedItem"): - representation_type = "Tessellation" - elif items[0].is_a("IfcCurve") and items[0].Dim == 3: - representation_type = "Curve3D" - else: - representation_type = "Curve2D" + representation_type = ifcopenshell.util.representation.guess_type(items) representation = self.file.createIfcShapeRepresentation( ContextOfItems=context,