Initial Vibe coded project
This commit is contained in:
commit
0891cf12a5
21 files changed
+2830
No files matched your search
@@ -0,0 +1,89 @@
|
||||
import math
|
||||
import random
|
||||
|
||||
import pytest
|
||||
|
||||
from flight_map.curves import Cubic, interpolate
|
||||
|
||||
|
||||
def test_spline_interpolates_samples_with_continuous_tangent() -> None:
|
||||
points = [(0.0, 0.0), (1.0, 2.0), (5.0, 3.0), (6.0, -1.0)]
|
||||
curves = interpolate(points)
|
||||
assert len(curves) == len(points) - 1
|
||||
for index, curve in enumerate(curves):
|
||||
assert curve.point(0) == pytest.approx(points[index])
|
||||
assert curve.point(1) == pytest.approx(points[index + 1])
|
||||
for first, second in zip(curves, curves[1:], strict=False):
|
||||
incoming = (first.end[0] - first.control2[0], first.end[1] - first.control2[1])
|
||||
outgoing = (second.control1[0] - second.start[0], second.control1[1] - second.start[1])
|
||||
cross = incoming[0] * outgoing[1] - incoming[1] * outgoing[0]
|
||||
dot = incoming[0] * outgoing[0] + incoming[1] * outgoing[1]
|
||||
assert abs(cross) < 1e-10 and dot > 0
|
||||
# A non-collinear path must actually curve, not just encode straight lines as cubics.
|
||||
assert curves[0].point(0.5) != pytest.approx((0.5, 1.0))
|
||||
|
||||
|
||||
def test_two_points_remain_a_straight_path_and_duplicates_are_finite() -> None:
|
||||
curve = interpolate([(0, 0), (9, 6)])[0]
|
||||
assert curve.point(0.5) == pytest.approx((4.5, 3))
|
||||
for segment in interpolate([(0, 0), (0, 0), (1, 2), (1, 2), (3, 0)]):
|
||||
assert all(math.isfinite(coordinate) for p in segment.points for coordinate in p)
|
||||
assert interpolate([]) == []
|
||||
assert interpolate([(0, 0)]) == []
|
||||
|
||||
|
||||
def test_curve_portion_preserves_original_shape() -> None:
|
||||
curve = Cubic((-2, 0), (1, 5), (3, -5), (6, 0))
|
||||
portion = curve.portion(0.2, 0.8)
|
||||
for fraction in (0, 0.1, 0.5, 0.8, 1):
|
||||
assert portion.point(fraction) == pytest.approx(curve.point(0.2 + fraction * 0.6))
|
||||
with pytest.raises(ValueError):
|
||||
curve.portion(0.8, 0.2)
|
||||
|
||||
|
||||
def test_curve_can_enter_bounds_when_both_endpoints_are_outside() -> None:
|
||||
curve = Cubic((-2, 0), (-1, 3), (1, 3), (2, 0))
|
||||
rectangle = (-1.0, 1.0, 1.0, 3.0)
|
||||
portions = curve.clipped(rectangle)
|
||||
assert len(portions) == 1
|
||||
assert portions[0].start[0] == pytest.approx(-1)
|
||||
assert portions[0].end[0] == pytest.approx(1)
|
||||
assert portions[0].point(0.5)[1] > 2
|
||||
|
||||
|
||||
def test_clipping_handles_multiple_entries_tangency_and_boundary_lines() -> None:
|
||||
curve = Cubic((-2, 0), (4, 0), (-4, 0), (2, 0))
|
||||
rectangle = (-0.1, -1.0, 0.1, 1.0)
|
||||
assert len(curve.inside_intervals(rectangle)) == 3
|
||||
boundary = Cubic((-2, 0), (-1, 0), (1, 0), (2, 0))
|
||||
assert len(boundary.clipped((-1, 0, 1, 1))) == 1
|
||||
# Only touches the lower edge; it has no visible interval inside the rectangle.
|
||||
tangent = Cubic((0, -3), (1, 1), (2, 1), (3, -3))
|
||||
assert tangent.clipped((-1, 0, 4, 4)) == []
|
||||
|
||||
|
||||
def test_random_clipping_matches_dense_curve_membership() -> None:
|
||||
randomizer = random.Random(42)
|
||||
rectangle = (-1.0, -1.0, 1.0, 1.0)
|
||||
for _ in range(100):
|
||||
points = [(randomizer.uniform(-3, 3), randomizer.uniform(-3, 3)) for _ in range(4)]
|
||||
curve = Cubic(*points)
|
||||
intervals = curve.inside_intervals(rectangle)
|
||||
for index in range(201):
|
||||
t = index / 200
|
||||
x, y = curve.point(t)
|
||||
inside = -1 <= x <= 1 and -1 <= y <= 1
|
||||
selected = any(first - 1e-10 <= t <= last + 1e-10 for first, last in intervals)
|
||||
assert selected == inside
|
||||
for portion in curve.clipped(rectangle):
|
||||
for index in range(51):
|
||||
x, y = portion.point(index / 50)
|
||||
assert -1 - 1e-8 <= x <= 1 + 1e-8 and -1 - 1e-8 <= y <= 1 + 1e-8
|
||||
|
||||
|
||||
def test_transformation_preserves_bezier_shape() -> None:
|
||||
curve = Cubic((0, 0), (1, 2), (2, -1), (3, 0))
|
||||
transformed = curve.transform([2, 0, 0, -2, 10, 20])
|
||||
for t in (0, 0.1, 0.6, 1):
|
||||
x, y = curve.point(t)
|
||||
assert transformed.point(t) == pytest.approx((2 * x + 10, -2 * y + 20))
|
||||
Reference in new issue
Block a user