Files
allwpilib/wpimath/src/test/python/geometry/test_pose2d.py
2026-01-02 09:10:02 -08:00

150 lines
5.4 KiB
Python

import pytest
import math
from wpimath import Pose2d, Rotation2d, Translation2d, Transform2d
from wpimath.units import feetToMeters
def test_rotate_by():
x = 1
y = 2
initial = Pose2d(x, y, math.radians(45))
rotation = Rotation2d(math.radians(5))
rotated = initial.rotateBy(rotation)
# Translation is rotated by CCW rotation matrix
c = rotation.cos()
s = rotation.sin()
assert rotated.x == pytest.approx(c * x - s * y)
assert rotated.y == pytest.approx(s * x + c * y)
assert rotated.rotation().degrees() == pytest.approx(
initial.rotation().degrees() + rotation.degrees()
)
def test_transform_by():
initial = Pose2d(x=1, y=2, rotation=Rotation2d.fromDegrees(45))
transform = Transform2d(Translation2d(x=5, y=0), Rotation2d.fromDegrees(5))
transformed = initial + transform
assert transformed.x == pytest.approx(1.0 + 5.0 / math.sqrt(2.0))
assert transformed.y == pytest.approx(2.0 + 5.0 / math.sqrt(2.0))
assert transformed.rotation().degrees() == pytest.approx(50.0)
def test_relative_to():
initial = Pose2d(x=0, y=0, rotation=Rotation2d.fromDegrees(45))
final = Pose2d(x=5, y=5, rotation=Rotation2d.fromDegrees(45.0))
final_relative_to_initial = final.relativeTo(initial)
assert final_relative_to_initial.x == pytest.approx(5.0 * math.sqrt(2.0), abs=1e-9)
assert final_relative_to_initial.y == pytest.approx(0.0, abs=1e-9)
assert final_relative_to_initial.rotation().degrees() == pytest.approx(
0.0, abs=1e-9
)
def test_rotate_around():
initial = Pose2d(x=5, y=0, rotation=Rotation2d.fromDegrees(0))
point = Translation2d(x=0, y=0)
rotated = initial.rotateAround(point, Rotation2d.fromDegrees(180))
assert rotated.x == pytest.approx(-5.0, abs=1e-9)
assert rotated.y == pytest.approx(0.0, abs=1e-9)
assert rotated.rotation().degrees() == pytest.approx(180.0, abs=1e-9)
def test_equality():
a = Pose2d(x=0, y=5, rotation=Rotation2d.fromDegrees(43))
b = Pose2d(x=0, y=5, rotation=Rotation2d.fromDegrees(43))
assert a == b
def test_inequality():
a = Pose2d(x=0, y=5, rotation=Rotation2d.fromDegrees(43))
b = Pose2d(x=0, y=feetToMeters(5), rotation=Rotation2d.fromDegrees(43))
assert a != b
def test_minus():
initial = Pose2d(x=0, y=0, rotation=Rotation2d.fromDegrees(45))
final = Pose2d(x=5, y=5, rotation=Rotation2d.fromDegrees(45))
transform = final - initial
assert transform.x == pytest.approx(5.0 * math.sqrt(2.0), abs=1e-9)
assert transform.y == pytest.approx(0.0, abs=1e-9)
assert transform.rotation().degrees() == pytest.approx(0.0, abs=1e-9)
def test_nearest():
origin = Pose2d(x=0, y=0, rotation=Rotation2d.fromDegrees(0))
pose1 = Pose2d(
Translation2d(distance=1.0, angle=Rotation2d.fromDegrees((45))),
Rotation2d.fromDegrees(0),
)
pose2 = Pose2d(
Translation2d(distance=2.0, angle=Rotation2d.fromDegrees((90))),
Rotation2d.fromDegrees(0),
)
pose3 = Pose2d(
Translation2d(distance=3.0, angle=Rotation2d.fromDegrees((135))),
Rotation2d.fromDegrees(0),
)
pose4 = Pose2d(
Translation2d(distance=4.0, angle=Rotation2d.fromDegrees((180))),
Rotation2d.fromDegrees(0),
)
pose5 = Pose2d(
Translation2d(distance=5.0, angle=Rotation2d.fromDegrees((270))),
Rotation2d.fromDegrees(0),
)
assert origin.nearest([pose5, pose3, pose4]).x == pytest.approx(pose3.x)
assert origin.nearest([pose5, pose3, pose4]).y == pytest.approx(pose3.y)
assert origin.nearest([pose1, pose2, pose3]).x == pytest.approx(pose1.x)
assert origin.nearest([pose1, pose2, pose3]).y == pytest.approx(pose1.y)
assert origin.nearest([pose4, pose2, pose3]).x == pytest.approx(pose2.x)
assert origin.nearest([pose4, pose2, pose3]).y == pytest.approx(pose2.y)
# Rotation component sort (when distance is the same)
# Use the same translation because using different angles at the same
# distance can cause rounding error.
translation = Translation2d(distance=1.0, angle=Rotation2d.fromDegrees(0))
pose_a = Pose2d(translation, Rotation2d.fromDegrees(0))
pose_b = Pose2d(translation, Rotation2d.fromDegrees(30))
pose_c = Pose2d(translation, Rotation2d.fromDegrees(120))
pose_d = Pose2d(translation, Rotation2d.fromDegrees(90))
pose_e = Pose2d(translation, Rotation2d.fromDegrees(-180))
assert Pose2d(x=0, y=0, rotation=Rotation2d.fromDegrees(360)).nearest(
[pose_a, pose_b, pose_d]
).rotation().degrees() == pytest.approx(pose_a.rotation().degrees())
assert Pose2d(x=0, y=0, rotation=Rotation2d.fromDegrees(-335)).nearest(
[pose_b, pose_c, pose_d]
).rotation().degrees() == pytest.approx(pose_b.rotation().degrees())
assert Pose2d(x=0, y=0, rotation=Rotation2d.fromDegrees(-120)).nearest(
[pose_b, pose_c, pose_d]
).rotation().degrees() == pytest.approx(pose_c.rotation().degrees())
assert Pose2d(x=0, y=0, rotation=Rotation2d.fromDegrees(85)).nearest(
[pose_a, pose_c, pose_d]
).rotation().degrees() == pytest.approx(pose_d.rotation().degrees())
assert Pose2d(x=0, y=0, rotation=Rotation2d.fromDegrees(170)).nearest(
[pose_a, pose_d, pose_e]
).rotation().degrees() == pytest.approx(pose_e.rotation().degrees())
def test_to_matrix():
before = Pose2d(x=1, y=2, rotation=Rotation2d.fromDegrees(20))
after = Pose2d.fromMatrix(before.toMatrix())
assert before == after