Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 49 additions & 3 deletions arcade/math.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import math
import random
from typing import Tuple, List, Union
from pyglet.math import Vec2, Vec3
from arcade.types import Point, Vector

_PRECISION = 2
Expand All @@ -11,7 +13,8 @@
"round_fast",
"clamp",
"lerp",
"lerp_vec",
"lerp_2d",
"lerp_3d",
"lerp_angle",
"rand_in_rect",
"rand_in_circle",
Expand All @@ -25,6 +28,7 @@
"rotate_point",
"get_angle_degrees",
"get_angle_radians",
"quaternion_rotation"
]


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


def lerp_vec(v1: Vector, v2: Vector, u: float) -> Vector:
V_2D = Union[Vec2, Tuple[float, float], List[float]]
V_3D = Union[Vec3, Tuple[float, float, float], List[float]]


def lerp_2d(v1: V_2D, v2: V_2D, u: float) -> Tuple[float, float]:
return (
lerp(v1[0], v2[0], u),
lerp(v1[1], v2[1], u)
)


def lerp_3d(v1: V_3D, v2: V_3D, u: float) -> Tuple[float, float, float]:
return (
lerp(v1[0], v2[0], u),
lerp(v1[1], v2[1], u),
lerp(v1[2], v2[2], u)
)


def lerp_angle(start_angle: float, end_angle: float, u: float) -> float:
"""
Linearly interpolate between two angles in degrees,
Expand Down Expand Up @@ -160,7 +176,7 @@ def rand_on_line(pos1: Point, pos2: Point) -> Point:
:return: A random point on the line
"""
u = random.uniform(0.0, 1.0)
return lerp_vec(pos1, pos2, u)
return lerp_2d(pos1, pos2, u)


def rand_angle_360_deg() -> float:
Expand Down Expand Up @@ -354,3 +370,33 @@ def get_angle_radians(x1: float, y1: float, x2: float, y2: float) -> float:
x_diff = x2 - x1
y_diff = y2 - y1
return math.atan2(x_diff, y_diff)


def quaternion_rotation(axis: Tuple[float, float, float],
vector: Tuple[float, float, float],
angle: float) -> Tuple[float, float, float]:
"""
Rotate a 3-dimensional vector of any length clockwise around a 3-dimensional unit length vector.

This method of vector rotation is immune to rotation-lock, however it takes a little more effort
to find the axis of rotation rather than 3 angles of rotation.
Ref: https://danceswithcode.net/engineeringnotes/quaternions/quaternions.html.

:param axis: The unit length vector that will be rotated around
:param vector: The 3-dimensional vector to be rotated
:param angle: The angle in degrees to rotate the vector clock-wise by
:return: A rotated 3-dimension vector with the same length as the argument vector.
"""
_rotation_rads = -math.radians(angle)
p1, p2, p3 = vector
_c2, _s2 = math.cos(_rotation_rads / 2.0), math.sin(_rotation_rads / 2.0)

q0, q1, q2, q3 = _c2, _s2 * axis[0], _s2 * axis[1], _s2 * axis[2]
q0_2, q1_2, q2_2, q3_2 = q0 ** 2, q1 ** 2, q2 ** 2, q3 ** 2
q01, q02, q03, q12, q13, q23 = q0 * q1, q0 * q2, q0 * q3, q1 * q2, q1 * q3, q2 * q3

_x = p1 * (q0_2 + q1_2 - q2_2 - q3_2) + 2.0 * (p2 * (q12 - q03) + p3 * (q02 + q13))
_y = p2 * (q0_2 - q1_2 + q2_2 - q3_2) + 2.0 * (p1 * (q03 + q12) + p3 * (q23 - q01))
_z = p3 * (q0_2 - q1_2 - q2_2 + q3_2) + 2.0 * (p1 * (q13 - q02) + p2 * (q01 + q23))

return _x, _y, _z
4 changes: 2 additions & 2 deletions arcade/paths.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
check_for_collision_with_list,
get_sprites_at_point
)
from arcade.math import get_distance, lerp_vec
from arcade.math import get_distance, lerp_2d
from arcade.types import Point

__all__ = [
Expand Down Expand Up @@ -360,7 +360,7 @@ def has_line_of_sight(observer: Point,
for step in range(steps + 1):
step_distance = step * check_resolution
u = step_distance / distance
midpoint = lerp_vec(observer, target, u)
midpoint = lerp_2d(observer, target, u)
if step_distance > max_distance:
return False
sprite_list = get_sprites_at_point(midpoint, walls)
Expand Down
6 changes: 3 additions & 3 deletions tests/unit/test_math.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ def test_lerp():
assert lerp(2.0, 4.0, 0.75) == approx(3.5)


def test_lerp_vec():
vec = lerp_vec((0.0, 2.0), (8.0, 4.0), 0.25)
def test_lerp_2d():
vec = lerp_2d((0.0, 2.0), (8.0, 4.0), 0.25)
assert vec[0] == approx(2.0)
assert vec[1] == approx(2.5)
vec = lerp_vec((0.0, 2.0), (8.0, 4.0), -0.25)
vec = lerp_2d((0.0, 2.0), (8.0, 4.0), -0.25)
assert vec[0] == approx(-2.0)
assert vec[1] == approx(1.5)

Expand Down