mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 09:21:46 +00:00
shape_builder tests - remove mathutils dependency #5192
This commit is contained in:
@@ -20,13 +20,15 @@ import pytest
|
||||
import test.bootstrap
|
||||
import ifcopenshell.api
|
||||
import numpy as np
|
||||
from ifcopenshell.util.shape_builder import ShapeBuilder, V, is_x, np_rotation_matrix
|
||||
from math import degrees, radians, tan
|
||||
from mathutils import Vector, Matrix
|
||||
from ifcopenshell.util.shape_builder import ShapeBuilder, is_x, np_rotation_matrix, np_to_3d, np_angle, V
|
||||
from math import degrees, radians
|
||||
from typing import Any, Union
|
||||
|
||||
|
||||
class TestNumpyRotationMatrix(test.bootstrap.IFC4):
|
||||
def test_run(self):
|
||||
from mathutils import Matrix, Vector
|
||||
|
||||
# 2D.
|
||||
assert np.allclose(Matrix.Rotation(radians(45), 2), np_rotation_matrix(radians(45), 2))
|
||||
assert np.allclose(Matrix.Rotation(radians(45), 2, "Z"), np_rotation_matrix(radians(45), 2, "Z"))
|
||||
@@ -68,12 +70,12 @@ class TestCreatePolyline(test.bootstrap.IFC4):
|
||||
builder = ShapeBuilder(self.file)
|
||||
|
||||
# rectangle
|
||||
points = Vector((0, 0)), Vector((1, 0)), Vector((1, 1)), Vector((0, 1))
|
||||
position = Vector((2, 0))
|
||||
points = V([(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0)])
|
||||
position = (2.0, 0.0)
|
||||
polyline = builder.polyline(points, closed=True, position_offset=position)
|
||||
|
||||
points = [p + position for p in points]
|
||||
assert np.allclose(np.array(points), np.array(polyline.Points.CoordList))
|
||||
points += position
|
||||
assert np.allclose(points, polyline.Points.CoordList)
|
||||
# use 1 line index if there are no arcs
|
||||
assert len(polyline.Segments) == 1
|
||||
segment = polyline.Segments[0]
|
||||
@@ -83,13 +85,13 @@ class TestCreatePolyline(test.bootstrap.IFC4):
|
||||
def test_polyline_with_arc(self):
|
||||
builder = ShapeBuilder(self.file)
|
||||
|
||||
points = Vector((1, 0)), Vector((0.707, 0.707)), Vector((0, 1)), Vector((0, 2))
|
||||
position = Vector((2, 0))
|
||||
points = V([(1, 0), (0.707, 0.707), (0, 1), (0, 2)])
|
||||
position = (2, 0)
|
||||
arc_points = (1,)
|
||||
# 4=IfcIndexedPolyCurve(#3,(IfcArcIndex((1,2,3)),IfcLineIndex((3,4,1))),$)
|
||||
# 4=IfcIndexedPolyCurve(# 3,(IfcArcIndex((1,2,3)),IfcLineIndex((3,4,1))),$)
|
||||
polyline = builder.polyline(points, closed=False, position_offset=position, arc_points=arc_points)
|
||||
points = [p + position for p in points]
|
||||
assert np.allclose(np.array(points), np.array(polyline.Points.CoordList))
|
||||
points += position
|
||||
assert np.allclose(points, polyline.Points.CoordList)
|
||||
assert len(polyline.Segments) == 2
|
||||
|
||||
segment = polyline.Segments[0]
|
||||
@@ -103,13 +105,13 @@ class TestCreatePolyline(test.bootstrap.IFC4):
|
||||
def test_closed_polyline_ending_with_arc(self):
|
||||
builder = ShapeBuilder(self.file)
|
||||
|
||||
points = Vector((0, 0)), Vector((1, 0)), Vector((0.5, 0.5))
|
||||
position = Vector((2, 0))
|
||||
points = V([(0, 0), (1, 0), (0.5, 0.5)])
|
||||
position = (2, 0)
|
||||
arc_points = (2,)
|
||||
# 4=IfcIndexedPolyCurve(#3,(IfcLineIndex((1,2)),IfcArcIndex((2,3,1))),$)
|
||||
polyline = builder.polyline(points, closed=True, position_offset=position, arc_points=arc_points)
|
||||
points = [p + position for p in points]
|
||||
assert np.allclose(np.array(points), np.array(polyline.Points.CoordList))
|
||||
points += position
|
||||
assert np.allclose(points, polyline.Points.CoordList)
|
||||
assert len(polyline.Segments) == 2
|
||||
|
||||
segment = polyline.Segments[0]
|
||||
@@ -122,12 +124,16 @@ class TestCreatePolyline(test.bootstrap.IFC4):
|
||||
|
||||
|
||||
class TestCalculateTransitions(test.bootstrap.IFC4):
|
||||
def calculate_and_test(self, params, length):
|
||||
def calculate_and_test(self, params: dict[str, Any], length: Union[float, None]):
|
||||
np_X, np_Y = 0, 1
|
||||
np_XY = slice(2)
|
||||
np_YX = [1, 0]
|
||||
|
||||
end_profile = params["end_profile"]
|
||||
start_half_dim = params["start_half_dim"]
|
||||
end_half_dim = params["end_half_dim"]
|
||||
offset = params["offset"]
|
||||
offset = offset if not end_profile else offset.yx
|
||||
start_half_dim: np.ndarray = params["start_half_dim"]
|
||||
end_half_dim: np.ndarray = params["end_half_dim"]
|
||||
offset: np.ndarray = params["offset"]
|
||||
offset = offset if not end_profile else offset[np_YX]
|
||||
angle = params["angle"]
|
||||
|
||||
calculated_length = self.builder.mep_transition_calculate(**params)
|
||||
@@ -135,47 +141,50 @@ class TestCalculateTransitions(test.bootstrap.IFC4):
|
||||
assert calculated_length is None
|
||||
return
|
||||
|
||||
assert is_x(calculated_length, length)
|
||||
assert calculated_length is not None and 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
|
||||
diff = start_half_dim.xy - end_half_dim.xy
|
||||
same_dimension = is_x(diff.x if not end_profile else diff.y, 0)
|
||||
diff = np.subtract(start_half_dim[np_XY], end_half_dim[np_XY])
|
||||
same_dimension = is_x(diff[np_X] if not end_profile else diff[np_Y], 0)
|
||||
if not same_dimension:
|
||||
confirmation_method = "A"
|
||||
else:
|
||||
confirmation_method = "B" if is_x(offset.x, 0) else "C"
|
||||
confirmation_method = "B" if is_x(offset[np_X], 0) else "C"
|
||||
|
||||
if confirmation_method == "A":
|
||||
A = (end_half_dim if end_profile else start_half_dim) * V(1, 0, 0)
|
||||
end_profile_offset = offset.to_3d() + V(0, 0, length)
|
||||
D = (start_half_dim if end_profile else end_half_dim) * V(1, 0, 0)
|
||||
A = (end_half_dim if end_profile else start_half_dim) * (1, 0, 0)
|
||||
end_profile_offset = np_to_3d(offset, length)
|
||||
D = (start_half_dim if end_profile else end_half_dim) * (1, 0, 0)
|
||||
B, C = -A, -D
|
||||
C += end_profile_offset
|
||||
D += end_profile_offset
|
||||
tested_angle = degrees((A - D).angle(B - C))
|
||||
tested_angle = degrees(np_angle(A - D, B - C))
|
||||
assert is_x(tested_angle, angle)
|
||||
|
||||
elif confirmation_method == "B":
|
||||
O = V(0, 0, 0)
|
||||
A = V(-start_half_dim.x, 0, length) + offset.to_3d()
|
||||
B = A * V(-1, 1, 1)
|
||||
tested_angle = degrees((A - O).angle(B - O))
|
||||
O = np.zeros(3)
|
||||
A = (-start_half_dim[np_X], 0, length) + np_to_3d(offset)
|
||||
B = A * (-1, 1, 1)
|
||||
tested_angle = degrees(np_angle(A - O, B - O))
|
||||
assert is_x(tested_angle, angle)
|
||||
|
||||
elif confirmation_method == "C":
|
||||
A = V(-start_half_dim.x, 0, 0)
|
||||
H = A + V(0, 0, length)
|
||||
H.y += offset.y
|
||||
A = V(-start_half_dim[np_X], 0, 0)
|
||||
H = A + (0, 0, length)
|
||||
H[np_Y] += offset[np_Y]
|
||||
D = H.copy()
|
||||
D.x += offset.x
|
||||
tested_angle = degrees((H - A).angle(D - A))
|
||||
D[np_X] += offset[np_X]
|
||||
tested_angle = degrees(np_angle(H - A, D - A))
|
||||
assert is_x(tested_angle, angle)
|
||||
|
||||
angle = self.builder.mep_transition_calculate(**params | {"angle": None, "length": calculated_length})
|
||||
assert is_x(angle, angle)
|
||||
calculated_angle = self.builder.mep_transition_calculate(
|
||||
**params | {"angle": None, "length": calculated_length}
|
||||
)
|
||||
assert calculated_angle is not None
|
||||
assert is_x(calculated_angle, angle)
|
||||
|
||||
def test_mep_transition_same_dims_no_offset(self):
|
||||
self.builder = ShapeBuilder(self.file)
|
||||
@@ -257,5 +266,5 @@ class TestCalculateTransitions(test.bootstrap.IFC4):
|
||||
self.calculate_and_test(params, None)
|
||||
|
||||
# method C
|
||||
params["offset"].x = 10
|
||||
params["offset"][0] = 10.0
|
||||
self.calculate_and_test(params, None)
|
||||
|
||||
Reference in New Issue
Block a user