Skip to content

Commit bd19fea

Browse files
authored
Updating arcade.math (#2040)
* Updating arcade.math changed lerp_vec to lerp_2d created lerp_3d, and quaternion_rotation methods. Also updated any methods which used lerp_vec * remove example from arcade.math.quaternion_rotation
1 parent 5f154b1 commit bd19fea

File tree

3 files changed

+54
-8
lines changed

3 files changed

+54
-8
lines changed

arcade/math.py

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import math
44
import random
5+
from typing import Tuple, List, Union
6+
from pyglet.math import Vec2, Vec3
57
from arcade.types import Point, Vector
68

79
_PRECISION = 2
@@ -11,7 +13,8 @@
1113
"round_fast",
1214
"clamp",
1315
"lerp",
14-
"lerp_vec",
16+
"lerp_2d",
17+
"lerp_3d",
1518
"lerp_angle",
1619
"rand_in_rect",
1720
"rand_in_circle",
@@ -25,6 +28,7 @@
2528
"rotate_point",
2629
"get_angle_degrees",
2730
"get_angle_radians",
31+
"quaternion_rotation"
2832
]
2933

3034

@@ -64,13 +68,25 @@ def lerp(v1: float, v2: float, u: float) -> float:
6468
return v1 + ((v2 - v1) * u)
6569

6670

67-
def lerp_vec(v1: Vector, v2: Vector, u: float) -> Vector:
71+
V_2D = Union[Vec2, Tuple[float, float], List[float]]
72+
V_3D = Union[Vec3, Tuple[float, float, float], List[float]]
73+
74+
75+
def lerp_2d(v1: V_2D, v2: V_2D, u: float) -> Tuple[float, float]:
6876
return (
6977
lerp(v1[0], v2[0], u),
7078
lerp(v1[1], v2[1], u)
7179
)
7280

7381

82+
def lerp_3d(v1: V_3D, v2: V_3D, u: float) -> Tuple[float, float, float]:
83+
return (
84+
lerp(v1[0], v2[0], u),
85+
lerp(v1[1], v2[1], u),
86+
lerp(v1[2], v2[2], u)
87+
)
88+
89+
7490
def lerp_angle(start_angle: float, end_angle: float, u: float) -> float:
7591
"""
7692
Linearly interpolate between two angles in degrees,
@@ -160,7 +176,7 @@ def rand_on_line(pos1: Point, pos2: Point) -> Point:
160176
:return: A random point on the line
161177
"""
162178
u = random.uniform(0.0, 1.0)
163-
return lerp_vec(pos1, pos2, u)
179+
return lerp_2d(pos1, pos2, u)
164180

165181

166182
def rand_angle_360_deg() -> float:
@@ -354,3 +370,33 @@ def get_angle_radians(x1: float, y1: float, x2: float, y2: float) -> float:
354370
x_diff = x2 - x1
355371
y_diff = y2 - y1
356372
return math.atan2(x_diff, y_diff)
373+
374+
375+
def quaternion_rotation(axis: Tuple[float, float, float],
376+
vector: Tuple[float, float, float],
377+
angle: float) -> Tuple[float, float, float]:
378+
"""
379+
Rotate a 3-dimensional vector of any length clockwise around a 3-dimensional unit length vector.
380+
381+
This method of vector rotation is immune to rotation-lock, however it takes a little more effort
382+
to find the axis of rotation rather than 3 angles of rotation.
383+
Ref: https://danceswithcode.net/engineeringnotes/quaternions/quaternions.html.
384+
385+
:param axis: The unit length vector that will be rotated around
386+
:param vector: The 3-dimensional vector to be rotated
387+
:param angle: The angle in degrees to rotate the vector clock-wise by
388+
:return: A rotated 3-dimension vector with the same length as the argument vector.
389+
"""
390+
_rotation_rads = -math.radians(angle)
391+
p1, p2, p3 = vector
392+
_c2, _s2 = math.cos(_rotation_rads / 2.0), math.sin(_rotation_rads / 2.0)
393+
394+
q0, q1, q2, q3 = _c2, _s2 * axis[0], _s2 * axis[1], _s2 * axis[2]
395+
q0_2, q1_2, q2_2, q3_2 = q0 ** 2, q1 ** 2, q2 ** 2, q3 ** 2
396+
q01, q02, q03, q12, q13, q23 = q0 * q1, q0 * q2, q0 * q3, q1 * q2, q1 * q3, q2 * q3
397+
398+
_x = p1 * (q0_2 + q1_2 - q2_2 - q3_2) + 2.0 * (p2 * (q12 - q03) + p3 * (q02 + q13))
399+
_y = p2 * (q0_2 - q1_2 + q2_2 - q3_2) + 2.0 * (p1 * (q03 + q12) + p3 * (q23 - q01))
400+
_z = p3 * (q0_2 - q1_2 - q2_2 + q3_2) + 2.0 * (p1 * (q13 - q02) + p2 * (q01 + q23))
401+
402+
return _x, _y, _z

arcade/paths.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
check_for_collision_with_list,
2020
get_sprites_at_point
2121
)
22-
from arcade.math import get_distance, lerp_vec
22+
from arcade.math import get_distance, lerp_2d
2323
from arcade.types import Point
2424

2525
__all__ = [
@@ -360,7 +360,7 @@ def has_line_of_sight(observer: Point,
360360
for step in range(steps + 1):
361361
step_distance = step * check_resolution
362362
u = step_distance / distance
363-
midpoint = lerp_vec(observer, target, u)
363+
midpoint = lerp_2d(observer, target, u)
364364
if step_distance > max_distance:
365365
return False
366366
sprite_list = get_sprites_at_point(midpoint, walls)

tests/unit/test_math.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ def test_lerp():
1515
assert lerp(2.0, 4.0, 0.75) == approx(3.5)
1616

1717

18-
def test_lerp_vec():
19-
vec = lerp_vec((0.0, 2.0), (8.0, 4.0), 0.25)
18+
def test_lerp_2d():
19+
vec = lerp_2d((0.0, 2.0), (8.0, 4.0), 0.25)
2020
assert vec[0] == approx(2.0)
2121
assert vec[1] == approx(2.5)
22-
vec = lerp_vec((0.0, 2.0), (8.0, 4.0), -0.25)
22+
vec = lerp_2d((0.0, 2.0), (8.0, 4.0), -0.25)
2323
assert vec[0] == approx(-2.0)
2424
assert vec[1] == approx(1.5)
2525

0 commit comments

Comments
 (0)