From 9fc0baf1755c7647a2ca4603ebbc18c325c32986 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Mon, 18 Apr 2022 10:27:06 +1000 Subject: [PATCH] #1153 Add support for IfcAnnotationFillArea representation --- .../api/geometry/add_representation.py | 47 ++++++++++++++++--- .../ifcopenshell/util/element.py | 4 +- .../test/util/test_element.py | 5 ++ 3 files changed, 48 insertions(+), 8 deletions(-) diff --git a/src/ifcopenshell-python/ifcopenshell/api/geometry/add_representation.py b/src/ifcopenshell-python/ifcopenshell/api/geometry/add_representation.py index 9bac3ba502..99fa4d658e 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/geometry/add_representation.py +++ b/src/ifcopenshell-python/ifcopenshell/api/geometry/add_representation.py @@ -149,9 +149,7 @@ class Usecase: shape_representation.Items = items return shape_representation elif self.settings["context"].ContextIdentifier == "Annotation": - shape_representation = self.create_geometric_curve_set_representation(is_2d=True) - shape_representation.RepresentationType = "Annotation2D" - return shape_representation + return self.create_annotation2d_representation() elif self.settings["context"].ContextIdentifier == "Axis": return self.create_curve2d_representation() elif self.settings["context"].ContextIdentifier == "Body": @@ -172,9 +170,7 @@ class Usecase: elif self.settings["context"].ContextIdentifier == "SurveyPoints": pass else: - shape_representation = self.create_geometric_curve_set_representation(is_2d=True) - shape_representation.RepresentationType = "Annotation2D" - return shape_representation + return self.create_annotation2d_representation() def create_lighting_representation(self): return self.file.createIfcShapeRepresentation( @@ -293,6 +289,33 @@ class Usecase: self.create_curves(is_2d=True), ) + def create_annotation_fill_areas(self): + items = [] + if self.file.schema != "IFC2X3": + points = self.create_cartesian_point_list_from_vertices(self.settings["geometry"].vertices, is_2d=True) + for polygon in self.settings["geometry"].polygons: + if self.file.schema == "IFC2X3": + curve = self.create_curve_from_polygon_ifc2x3(polygon, is_2d=True) + else: + curve = self.create_curve_from_polygon(points, polygon, is_2d=True) + items.append(self.file.createIfcAnnotationFillArea(OuterBoundary=curve)) + return items + + def create_curve_from_polygon(self, points, polygon, is_2d=False): + indices = list(polygon.vertices) + indices.append(indices[0]) + edge_loop = [self.file.createIfcLineIndex((v1 + 1, v2 + 1)) for v1, v2 in zip(indices, indices[1:])] + return self.file.createIfcIndexedPolyCurve(points, edge_loop) + + def create_curve_from_polygon_ifc2x3(self, polygon, is_2d=False): + indices = list(polygon.vertices) + indices.append(indices[0]) + points = [ + self.create_cartesian_point(v.co.x, v.co.y, v.co.z if not is_2d else None) + for v in self.settings["geometry"].vertices + ] + return self.file.createIfcPolyline([points[i] for i in indices]) + def create_curves(self, is_2d=False): if isinstance(self.settings["geometry"], bpy.types.Mesh): if self.file.schema == "IFC2X3": @@ -600,6 +623,18 @@ class Usecase: return (co / self.settings["unit_scale"]) + self.settings["coordinate_offset"] return co / self.settings["unit_scale"] + def create_annotation2d_representation(self): + if isinstance(self.settings["geometry"], bpy.types.Mesh) and len(self.settings["geometry"].polygons): + items = self.create_annotation_fill_areas() + else: + items = [self.file.createIfcGeometricCurveSet(self.create_curves(is_2d=True))] + return self.file.createIfcShapeRepresentation( + self.settings["context"], + self.settings["context"].ContextIdentifier, + "Annotation2D", + items, + ) + def create_geometric_curve_set_representation(self, is_2d=False): geometric_curve_set = self.file.createIfcGeometricCurveSet(self.create_curves(is_2d=is_2d)) return self.file.createIfcShapeRepresentation( diff --git a/src/ifcopenshell-python/ifcopenshell/util/element.py b/src/ifcopenshell-python/ifcopenshell/util/element.py index caa618d373..a3813e5d85 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/element.py +++ b/src/ifcopenshell-python/ifcopenshell/util/element.py @@ -89,12 +89,12 @@ def get_predefined_type(element): element_type = get_type(element) if element_type: predefined_type = getattr(element_type, "PredefinedType", None) - if predefined_type == "USERDEFINED": + if predefined_type == "USERDEFINED" or not predefined_type: predefined_type = getattr(element_type, "ElementType", None) if predefined_type and predefined_type != "NOTDEFINED": return predefined_type predefined_type = getattr(element, "PredefinedType", None) - if predefined_type == "USERDEFINED": + if predefined_type == "USERDEFINED" or not predefined_type: predefined_type = getattr(element, "ObjectType", None) return predefined_type diff --git a/src/ifcopenshell-python/test/util/test_element.py b/src/ifcopenshell-python/test/util/test_element.py index 8a14e6993f..e2b9c72a80 100644 --- a/src/ifcopenshell-python/test/util/test_element.py +++ b/src/ifcopenshell-python/test/util/test_element.py @@ -148,6 +148,11 @@ class TestGetPredefinedTypeIFC4(test.bootstrap.IFC4): element.ObjectType = "FOOBAR" assert subject.get_predefined_type(element) == "FOOBAR" + def test_getting_an_element_type_without_a_predefined_type_attribute(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcAnnotation") + element.ObjectType = "FOOBAR" + assert subject.get_predefined_type(element) == "FOOBAR" + def test_getting_an_inherited_predefined_type(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType")