From afeeaeb9843388828891718a8d450650f622ff44 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Mon, 3 Apr 2023 17:19:40 +0500 Subject: [PATCH] Fixed some validation errors for doors and windows #2925 Fixed the ones caused by using 3d curves as inner/outer curves in profiles. --- .../api/geometry/add_door_representation.py | 9 ++++- .../api/geometry/add_window_representation.py | 35 ++++++++++++------- .../ifcopenshell/util/shape_builder.py | 25 ++++++++++--- 3 files changed, 51 insertions(+), 18 deletions(-) diff --git a/src/ifcopenshell-python/ifcopenshell/api/geometry/add_door_representation.py b/src/ifcopenshell-python/ifcopenshell/api/geometry/add_door_representation.py index 051166426b..8da182abe9 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/geometry/add_door_representation.py +++ b/src/ifcopenshell-python/ifcopenshell/api/geometry/add_door_representation.py @@ -61,8 +61,15 @@ def create_ifc_door_lining( V(th_side, 0.0, 0.0), ] + points = [p.xz for p in points] door_lining = builder.polyline(points, closed=True) - door_lining = builder.extrude(door_lining, size.y, extrusion_vector=V(0, 1, 0)) + door_lining = builder.extrude( + door_lining, + size.y, + position_x_axis=V(1, 0, 0), + position_z_axis=V(0, -1, 0), + extrusion_vector=V(0, 0, -1), + ) builder.translate(door_lining, position) return door_lining diff --git a/src/ifcopenshell-python/ifcopenshell/api/geometry/add_window_representation.py b/src/ifcopenshell-python/ifcopenshell/api/geometry/add_window_representation.py index 030428149c..2dcf6daec2 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/geometry/add_window_representation.py +++ b/src/ifcopenshell-python/ifcopenshell/api/geometry/add_window_representation.py @@ -30,15 +30,15 @@ import collections # - order of rows is from top of the window to bottom DEFAULT_PANEL_SCHEMAS = { - "SINGLE_PANEL": [[0]], - "DOUBLE_PANEL_HORIZONTAL": [[0], [1]], - "DOUBLE_PANEL_VERTICAL": [[0, 1]], - "TRIPLE_PANEL_BOTTOM": [[0, 1], [2, 2]], - "TRIPLE_PANEL_TOP": [[0, 0], [1, 2]], - "TRIPLE_PANEL_LEFT": [[0, 1], [0, 2]], - "TRIPLE_PANEL_RIGHT": [[0, 1], [2, 1]], - "TRIPLE_PANEL_HORIZONTAL": [[0], [1], [2]], - "TRIPLE_PANEL_VERTICAL": [[0, 1, 2]], + "SINGLE_PANEL": [[0]], + "DOUBLE_PANEL_HORIZONTAL": [[0], [1]], + "DOUBLE_PANEL_VERTICAL": [[0, 1]], + "TRIPLE_PANEL_BOTTOM": [[0, 1], [2, 2]], + "TRIPLE_PANEL_TOP": [[0, 0], [1, 2]], + "TRIPLE_PANEL_LEFT": [[0, 1], [0, 2]], + "TRIPLE_PANEL_RIGHT": [[0, 1], [2, 1]], + "TRIPLE_PANEL_HORIZONTAL": [[0], [1], [2]], + "TRIPLE_PANEL_VERTICAL": [[0, 1, 2]], } @@ -54,13 +54,20 @@ def create_ifc_window_frame_simple(builder, size: Vector, thickness: list, posit th_left, th_up, th_right, th_bottom = thickness - panel_rect = builder.rectangle(size=size * V(1, 0, 1)) + panel_rect = builder.rectangle(size=size.xz) inner_rect_size = size - V(th_left + th_right, 0, th_bottom + th_up) - inner_rect = builder.rectangle(size=inner_rect_size * V(1, 0, 1), position=V(th_left, 0, th_bottom)) + inner_rect = builder.rectangle(size=inner_rect_size.xz, position=V(th_left, th_bottom)) panel_profile = builder.profile(panel_rect, inner_curves=inner_rect) - panel_extruded = builder.extrude(panel_profile, size.y, extrusion_vector=V(0, 1, 0), position=position) + panel_extruded = builder.extrude( + panel_profile, + size.y, + position_x_axis=V(1, 0, 0), + position_z_axis=V(0, -1, 0), + extrusion_vector=V(0, 0, -1), + position=position, + ) return panel_extruded @@ -133,7 +140,9 @@ def create_ifc_window( glass = builder.extrude( glass_rect, glass_thickness, - extrusion_vector=V(0, 1, 0), + position_x_axis=V(1, 0, 0), + position_z_axis=V(0, -1, 0), + extrusion_vector=V(0, 0, -1), position=glass_position, ) diff --git a/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py b/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py index de244c1aa6..d0d8126e8f 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py +++ b/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py @@ -55,7 +55,6 @@ class ShapeBuilder: return ifc_curve def get_rectangle_coords(self, size: Vector = Vector((1.0, 1.0)).freeze(), position: Vector = None): - dimensions = len(size) if not position: @@ -184,9 +183,28 @@ class ShapeBuilder: # because of that you can't create bool edges of outer_curve this way # < returns IfcArbitraryClosedProfileDef or IfcArbitraryProfileDefWithVoids + + if outer_curve.Dim != 2: + # TODO: replace with exception + print( + f"WARNING. Outer curve for IfcArbitraryClosedProfileDef/IfcIfcArbitraryProfileDefWithVoid should be 2D to be valid, currently it has {outer_curve.Dim} dimensions.\n" + "Ref: https://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcArbitraryClosedProfileDef.htm#8.15.3.1.4-Formal-propositions" + ) + import traceback + traceback.print_stack() + if inner_curves: if not isinstance(inner_curves, collections.abc.Iterable): inner_curves = [inner_curves] + # TODO: replace with exception + if any(curve.Dim != 2 for curve in inner_curves): + print( + "WARNING. InnerCurve for IfcIfcArbitraryProfileDefWithVoid sould be 2D to be valid, " + "currently on one of the inner curves is using different amount of dimensions.\n" + "Ref: https://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcArbitraryClosedProfileDef.htm#8.15.3.1.4-Formal-propositions" + ) + import traceback + traceback.print_stack() profile = self.file.createIfcArbitraryProfileDefWithVoids( ProfileName=name, ProfileType=profile_type, OuterCurve=outer_curve, InnerCurves=inner_curves @@ -241,7 +259,6 @@ class ShapeBuilder: def rotate_2d_point( self, point_2d: Vector, angle=90, pivot_point: Vector = Vector((0.0, 0.0)).freeze(), counter_clockwise=False ): - # > angle - in degrees # < rotated Vector @@ -407,9 +424,9 @@ class ShapeBuilder: if hasattr(c.SweptArea, "InnerCurves"): for inner_curve in c.SweptArea.InnerCurves: - self.translate(inner_curve, base_position) + self.translate(inner_curve, base_position.to_2d()) self.mirror(inner_curve, mirror_axes, mirror_point, placement_matrix=placement_matrix) - self.translate(inner_curve, -new_position) + self.translate(inner_curve, -new_position.to_2d()) # extrusion converted to world space base_extruded_direction = Vector(c.ExtrudedDirection.DirectionRatios)