Initial filling

This commit is contained in:
Pascal Serrarens 2025-03-21 09:52:07 +01:00
parent b8f85410b2
commit b60b248f75
7 changed files with 203 additions and 0 deletions

11
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,11 @@
{
"python.testing.unittestArgs": [
"-v",
"-s",
"./test",
"-p",
"*_test.py"
],
"python.testing.pytestEnabled": false,
"python.testing.unittestEnabled": true
}

13
Angle.py Normal file
View File

@ -0,0 +1,13 @@
import math
class Angle:
Rad2Deg = 360 / (math.pi * 2)
Deg2Rad = (math.pi * 2) / 360
@staticmethod
def Normalize(angle):
while angle < -180:
angle += 360
while angle >= 180:
angle -= 360
return angle

52
Direction.py Normal file
View File

@ -0,0 +1,52 @@
import math
from LinearAlgebra.Angle import Angle
class Direction:
def __init__(self, horizontal=0, vertical=0):
self.horizontal: float = Angle.Normalize(horizontal)
self.vertical: float = Angle.Normalize(vertical)
self.Normalize()
@staticmethod
def Degrees(horizontal: float, vertical: float):
direction = Direction (horizontal, vertical)
return direction
def __add__(self, other):
return Direction(self.horizontal + other.x, self.vertical + other.y)
def __neg__(self):
return Direction(self.horizontal + 180, -self.vertical)
def __sub__(self, other):
return Direction(self.horizontal - other.x, self.vertical - other.y)
def __mul__(self, scalar):
return Direction(self.horizontal * scalar, self.vertical * scalar)
def __truediv__(self, scalar):
if scalar != 0:
return Direction(self.horizontal / scalar, self.vertical / scalar)
else:
raise ValueError("Cannot divide by zero")
def Magnitude(self):
return math.sqrt(self.horizontal**2 + self.vertical**2)
def Normalize(self):
if self.vertical > 90 or self.vertical < -90:
self.horizontal += 180
self.verical = 180 - self.verical
def Dot(self, other):
return self.horizontal * other.x + self.vertical * other.y
def __repr__(self):
return f"Direction(x={self.horizontal}, y={self.vertical})"
Direction.forward = Direction(0, 0)
Direction.backward = Direction(-180, 0)
Direction.up = Direction(0, 90)
Direction.down = Direction(0, -90)
Direction.left = Direction(-90, 0)
Direction.right = Direction(90, 0)

44
Quaternion.py Normal file
View File

@ -0,0 +1,44 @@
import math
Deg2Rad = (math.pi * 2) / 360
class Quaternion:
def __init__(self):
self.x = 0
self.y = 0
self.z = 0
self.w = 1
@staticmethod
def Euler(x, y, z):
yaw = x * Deg2Rad
pitch = y * Deg2Rad
roll = z * Deg2Rad
roll_over_2 = roll * 0.5
sin_roll_over_2 = math.sin(roll_over_2)
cos_roll_over_2 = math.cos(roll_over_2)
pitch_over_2 = pitch * 0.5
sin_pitch_over_2 = math.sin(pitch_over_2)
cos_pitch_over_2 = math.cos(pitch_over_2)
yaw_over_2 = yaw * 0.5
sin_yaw_over_2 = math.sin(yaw_over_2)
cos_yaw_over_2 = math.cos(yaw_over_2)
result = Quaternion()
result.w = (cos_yaw_over_2 * cos_pitch_over_2 * cos_roll_over_2 +
sin_yaw_over_2 * sin_pitch_over_2 * sin_roll_over_2)
result.x = (sin_yaw_over_2 * cos_pitch_over_2 * cos_roll_over_2 +
cos_yaw_over_2 * sin_pitch_over_2 * sin_roll_over_2)
result.y = (cos_yaw_over_2 * sin_pitch_over_2 * cos_roll_over_2 -
sin_yaw_over_2 * cos_pitch_over_2 * sin_roll_over_2)
result.z = (cos_yaw_over_2 * cos_pitch_over_2 * sin_roll_over_2 -
sin_yaw_over_2 * sin_pitch_over_2 * cos_roll_over_2)
return result
Quaternion.identity = Quaternion()

41
Spherical.py Normal file
View File

@ -0,0 +1,41 @@
import math
from LinearAlgebra.Direction import Direction
class Spherical:
def __init__(self, distance, direction):
if distance < 0:
self.distance = -distance
self.direction = -direction
else:
self.distance: float = distance
self.direction: Direction = direction
# def __init__(self, distance, horizontal, vertical):
# self.distance = distance
# self.direction = Direction(horizontal, vertical)
def to_cartesian(self):
x = self.distance * math.sin(self.direction.horizontal) * math.cos(self.direction.vertical)
y = self.distance * math.sin(self.direction.horizontal) * math.sin(self.direction.vertical)
z = self.distance * math.cos(self.direction.horizontal)
return x, y, z
def from_cartesian(self, x, y, z):
self.distance = math.sqrt(x**2 + y**2 + z**2)
self.direction.horizontal = math.acos(z / self.distance)
self.direction.vertical = math.atan2(y, x)
def __add__(self, other):
x1, y1, z1 = self.to_cartesian()
x2, y2, z2 = other.to_cartesian()
return Spherical.from_cartesian(x1 + x2, y1 + y2, z1 + z2)
def __sub__(self, other):
x1, y1, z1 = self.to_cartesian()
x2, y2, z2 = other.to_cartesian()
return Spherical.from_cartesian(x1 - x2, y1 - y2, z1 - z2)
def __repr__(self):
return f"Spherical(r={self.distance}, horizontal={self.direction.horizontal}, phi={self.direction.vertical})"
Spherical.zero = Spherical(0, Direction.forward)

28
SwingTwist.py Normal file
View File

@ -0,0 +1,28 @@
from LinearAlgebra.Direction import Direction
from LinearAlgebra.Quaternion import Quaternion
class SwingTwist:
"""A rotation using swing and twist angle components"""
def __init__(self, swing: Direction, twist: float):
if swing.vertical > 90 or swing.vertical < -90:
swing.horizontal += 180
swing.vertical = 180 - swing.vertical
twist += 180
## Swing component of the rotation
self.swing = swing
## The twist component of the rotation
self.twist = twist
@staticmethod
def Degrees(horizontal: float, vertical: float, twist: float):
direction = Direction(horizontal, vertical)
swing_twist = SwingTwist(direction, twist)
return swing_twist
def ToQuaternion(self) -> Quaternion:
"""Convert the SwingTwist rotation to a Quaternion"""
q = Quaternion.Euler(-self.swing.vertical,
self.swing.horizontal,
self.twist)
return q

14
test/Angle_test.py Normal file
View File

@ -0,0 +1,14 @@
import sys
from pathlib import Path
# Add the project root to sys.path
sys.path.append(str(Path(__file__).resolve().parent.parent))
import unittest
class AngleTest(unittest.TestCase):
def test_one(self):
pass
if __name__ == '__main__':
unittest.main()