mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 17:31:45 +00:00
fixed bug in mep transitions
it wasn't taking into account that offset can be too big to sustain the angle
This commit is contained in:
@@ -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):
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user