From 1a142ad5eb714cbb99696093342ffc2570689e07 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Wed, 23 Aug 2023 15:06:05 +0500 Subject: [PATCH] fixed bug in mep transitions it wasn't taking into account that offset can be too big to sustain the angle --- .../ifcopenshell/util/shape_builder.py | 37 ++++++++++++++----- .../test/util/test_shape_builder.py | 32 +++++++++++++++- 2 files changed, 57 insertions(+), 12 deletions(-) diff --git a/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py b/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py index b21fbc4389..d0667cad9a 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py +++ b/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py @@ -1106,13 +1106,16 @@ class ShapeBuilder: def check_transition(end_profile=False): length = self.mep_transition_calculate(**calculation_arguments, angle=angle, end_profile=end_profile) + if length is None: + return + other_side_angle = self.mep_transition_calculate( **calculation_arguments, length=length, end_profile=not end_profile ) # NOTE: for now we just hardcode the good value for that case - same_dimensions = is_x(diff.length, 0) - if same_dimensions and is_x(offset.y if not end_profile else offset.x, 0): + same_dimension = is_x(diff.y if not end_profile else diff.x, 0) + if same_dimension and is_x(offset.y if not end_profile else offset.x, 0): requested_angle = 90 else: requested_angle = angle @@ -1142,17 +1145,24 @@ class ShapeBuilder: if end_profile: diff, offset = diff.yx, offset.yx - same_dimensions = is_x(diff.length, 0) - + same_dimension = is_x(diff.x, 0) a = diff.x + offset.x b = diff.x - offset.x if length is None: - if not same_dimensions: - if diff.x == 0: - return 0 - + if not same_dimension: t = tan(radians(angle)) - h = (a + b + sqrt(a**2 + 4 * a * b * t**2 + 2 * a * b + b**2)) / (2 * t) + h0 = a**2 + 4 * a * b * t**2 + 2 * a * b + b**2 + # TODO: we might need to specify the exact failing cases in the future + if h0 < 0: + print( + f"B. Coulndn't calculate transition length for angle = {angle}, offset = {offset}, diff = {diff}" + ) + return None + + h = (a + b + sqrt(h0)) / (2 * t) + if h < abs(offset.y) or is_x(h, offset.y): + print(f"B. angle = {angle} requires h = {h} which is not possible with y offset = {offset.y}") + return None length = sqrt(h**2 - offset.y**2) if verbose: @@ -1168,6 +1178,9 @@ class ShapeBuilder: if is_x(offset.x, 0): angle = 90 # NOTE: for now we just hardcode the good value for that case h = start_half_dim.x / tan(radians(angle / 2)) + if h < abs(offset.y) or is_x(h, offset.y): + print(f"B. angle = {angle} requires h = {h} which is not possible with y offset = {offset.y}") + return None length = sqrt(h**2 - offset.y**2) if verbose: @@ -1178,6 +1191,9 @@ class ShapeBuilder: print(f"B. length = {length}, requested angle = {angle}, tested angle = {tested_angle}") else: h = offset.x / tan(radians(angle)) + if h < abs(offset.y) or is_x(h, offset.y): + print(f"C. angle = {angle} requires h = {h} which is not possible with y offset = {offset.y}") + return None length = sqrt(h**2 - offset.y**2) if verbose: @@ -1192,13 +1208,14 @@ class ShapeBuilder: return length elif angle is None: - if not same_dimensions: + if not same_dimension: if length == 0: return 0 h = sqrt(length**2 + offset.y**2) t = -h * (a + b) / (a * b - h**2) angle = degrees(atan(t)) + else: h = sqrt(length**2 + offset.y**2) if is_x(offset.x, 0): diff --git a/src/ifcopenshell-python/test/util/test_shape_builder.py b/src/ifcopenshell-python/test/util/test_shape_builder.py index 23b2d92f90..c3b1b29fc5 100644 --- a/src/ifcopenshell-python/test/util/test_shape_builder.py +++ b/src/ifcopenshell-python/test/util/test_shape_builder.py @@ -34,14 +34,19 @@ class TestCalculateTransitions(test.bootstrap.IFC4): angle = params["angle"] calculated_length = self.builder.mep_transition_calculate(**params) + if length is None: + assert calculated_length is None + return + assert is_x(calculated_length, length) # angle confirmation methods: # A - between two profiles of different dimensions # B - between two profiles of same dimensions, no offset by x # C - between two profiles of same dimensions, has offset by x - same_dimensions = is_x((start_half_dim.xy - end_half_dim.xy).length, 0) - if not same_dimensions: + diff = start_half_dim.xy - end_half_dim.xy + same_dimension = is_x(diff.x if not end_profile else diff.y, 0) + if not same_dimension: confirmation_method = "A" else: confirmation_method = "B" if is_x(offset.x, 0) else "C" @@ -134,3 +139,26 @@ class TestCalculateTransitions(test.bootstrap.IFC4): "verbose": True, } self.calculate_and_test(params, 165.83124) + + def test_mep_transition_y_offset_too_big(self): + self.builder = ShapeBuilder(self.file) + + # method A + params = { + "start_half_dim": V(100, 50, 0), + "end_half_dim": V(50, 100, 0), + # offset.y > h - 190 > 186.6 + "offset": V(0, 190), + "end_profile": False, + "angle": 30, + "verbose": True, + } + self.calculate_and_test(params, None) + + # method B + params["end_half_dim"] = V(100, 100, 0) + self.calculate_and_test(params, None) + + # method C + params["offset"].x = 10 + self.calculate_and_test(params, None)