From ced6326bfdc07d8682e858431f931a1ad538a899 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Thu, 29 Jun 2023 18:33:53 +0500 Subject: [PATCH] ShapeBuilder to use IfcPolyline of IfcIndexedPolyCurve to support ifc2x3 needed it to add suport for window/door modifiers in ifc2x3 in the next commit --- .../ifcopenshell/util/shape_builder.py | 87 ++++++++++++------- 1 file changed, 57 insertions(+), 30 deletions(-) diff --git a/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py b/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py index 27eb25a2e7..daf8f06018 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py +++ b/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py @@ -38,8 +38,11 @@ class ShapeBuilder: def polyline(self, points, closed=False, position_offset=None, arc_points=[]): # > points - list of points formatted like ( (x0, y0), (x1, y1) ) # < IfcIndexedPolyCurve - segments = [] + if arc_points and self.file.schema == "IFC2X3": + raise Exception("Arcs are not supported for IFC2X3.") + + segments = [] cur_i = 0 while cur_i < len(points) - 1: cur_i_ifc = cur_i + 1 @@ -55,30 +58,34 @@ class ShapeBuilder: if position_offset: points = [Vector(p) + position_offset for p in points] - dimensions = len(points[0]) - if dimensions == 2: - ifc_points = self.file.createIfcCartesianPointList2D(points) - elif dimensions == 3: - ifc_points = self.file.createIfcCartesianPointList3D(points) + if self.file.schema == "IFC2X3": + points = [self.file.createIfcCartesianPoint(p) for p in points] + ifc_curve = self.file.createIfcPolyline(Points=points) + else: + dimensions = len(points[0]) + if dimensions == 2: + ifc_points = self.file.createIfcCartesianPointList2D(points) + elif dimensions == 3: + ifc_points = self.file.createIfcCartesianPointList3D(points) - ifc_segments = [] - # because IfcLineIndex support 2+ points - # we merge neighbor line segments into one - current_line_segment = [] - last_segment = len(segments) - 1 - for seg_i, segment in enumerate(segments): - if len(segment) == 2: - current_line_segment += segment + ifc_segments = [] + # because IfcLineIndex support 2+ points + # we merge neighbor line segments into one + current_line_segment = [] + last_segment = len(segments) - 1 + for seg_i, segment in enumerate(segments): + if len(segment) == 2: + current_line_segment += segment - if current_line_segment and (len(segment) == 3 or seg_i == last_segment): - ifc_segments.append(self.file.createIfcLineIndex(current_line_segment)) - current_line_segment = [] + if current_line_segment and (len(segment) == 3 or seg_i == last_segment): + ifc_segments.append(self.file.createIfcLineIndex(current_line_segment)) + current_line_segment = [] - if len(segment) == 3: - ifc_segments.append(self.file.createIfcArcIndex(segment)) + if len(segment) == 3: + ifc_segments.append(self.file.createIfcArcIndex(segment)) - # NOTE: IfcIndexPolyCurve support only consequtive segments - ifc_curve = self.file.createIfcIndexedPolyCurve(Points=ifc_points, Segments=ifc_segments) + # NOTE: IfcIndexPolyCurve support only consequtive segments + ifc_curve = self.file.createIfcIndexedPolyCurve(Points=ifc_points, Segments=ifc_segments) return ifc_curve def get_rectangle_coords(self, size: Vector = Vector((1.0, 1.0)).freeze(), position: Vector = None): @@ -251,9 +258,10 @@ class ShapeBuilder: if create_copy: c = ifcopenshell.util.element.copy_deep(self.file, c) - if c.is_a("IfcIndexedPolyCurve"): - coords = [Vector(co) + translation for co in c.Points.CoordList] - c.Points.CoordList = coords + if c.is_a() in ("IfcIndexedPolyCurve", "IfcPolyline"): + coords = self.get_polyline_coords(c) + coords = [Vector(co) + translation for co in coords] + self.set_polyline_coords(c, coords) elif c.is_a("IfcCircle") or c.is_a("IfcExtrudedAreaSolid") or c.is_a("IfcEllipse"): base_position = Vector(c.Position.Location.Coordinates) @@ -312,11 +320,12 @@ class ShapeBuilder: if create_copy: c = ifcopenshell.util.element.copy_deep(self.file, c) - if c.is_a("IfcIndexedPolyCurve"): + if c.is_a() in ("IfcIndexedPolyCurve", "IfcPolyline"): + original_coords = self.get_polyline_coords(c) coords = [ - self.rotate_2d_point(Vector(co), angle, pivot_point, counter_clockwise) for co in c.Points.CoordList + self.rotate_2d_point(Vector(co), angle, pivot_point, counter_clockwise) for co in original_coords ] - c.Points.CoordList = coords + self.set_polyline_coords(c, coords) elif c.is_a("IfcCircle"): base_position = Vector(c.Position.Location.Coordinates) @@ -408,10 +417,11 @@ class ShapeBuilder: else curve_or_item_el ) - if c.is_a("IfcIndexedPolyCurve"): + if c.is_a() in ("IfcIndexedPolyCurve", "IfcPolyline"): + original_coords = self.get_polyline_coords(c) inverted_placement_matrix = placement_matrix.inverted() if placement_matrix else None coords = [] - for co in c.Points.CoordList: + for co in original_coords: co_base = Vector(co) if placement_matrix: # TODO: add support for Z-axis too @@ -424,7 +434,7 @@ class ShapeBuilder: coords.append(co) - c.Points.CoordList = coords + self.set_polyline_coords(c, coords) elif c.is_a("IfcCircle") or c.is_a("IfcEllipse"): base_position = Vector(c.Position.Location.Coordinates) @@ -594,3 +604,20 @@ class ShapeBuilder: kwargs["position_x_axis"].rotate(rot) kwargs["position_z_axis"].rotate(rot) return kwargs + + def get_polyline_coords(self, polyline): + """polyline should be either `IfcIndexedPolyCurve` or `IfcPolyline`""" + coords = None + if polyline.is_a("IfcIndexedPolyCurve"): + coords = polyline.Points.CoordList + elif polyline.is_a("IfcPolyline"): + coords = [p.Coordinates for p in polyline.Points] + return coords + + def set_polyline_coords(self, polyline, coords): + """polyline should be either `IfcIndexedPolyCurve` or `IfcPolyline`""" + if polyline.is_a("IfcIndexedPolyCurve"): + polyline.Points.CoordList = coords + elif polyline.is_a("IfcPolyline"): + for i, co in enumerate(coords): + polyline.Points[i].Coordinates = co