57 lines
1.9 KiB
Python
57 lines
1.9 KiB
Python
"""Tests der Broadphase (Sweep-and-Prune)."""
|
|
|
|
import random
|
|
|
|
from sandbox.physics import Body, Vector2
|
|
from sandbox.physics.broadphase import find_candidate_pairs
|
|
from tests.helpers import material
|
|
|
|
|
|
def _random_scene(seed: int, count: int) -> list[Body]:
|
|
rng = random.Random(seed)
|
|
bodies = []
|
|
for _ in range(count):
|
|
position = Vector2(rng.uniform(0, 400), rng.uniform(0, 300))
|
|
if rng.random() < 0.5:
|
|
bodies.append(Body.circle(position, rng.uniform(5, 30), material()))
|
|
else:
|
|
bodies.append(Body.box(position, rng.uniform(5, 30), rng.uniform(5, 30), material()))
|
|
return bodies
|
|
|
|
|
|
def _overlap(a: Body, b: Body) -> bool:
|
|
a_min_x, a_min_y, a_max_x, a_max_y = a.bounds()
|
|
b_min_x, b_min_y, b_max_x, b_max_y = b.bounds()
|
|
return a_min_x <= b_max_x and b_min_x <= a_max_x and a_min_y <= b_max_y and b_min_y <= a_max_y
|
|
|
|
|
|
def test_matches_brute_force_on_random_scenes() -> None:
|
|
for seed in range(5):
|
|
bodies = _random_scene(seed, 60)
|
|
expected = {
|
|
(min(a.id, b.id), max(a.id, b.id))
|
|
for i, a in enumerate(bodies)
|
|
for b in bodies[i + 1 :]
|
|
if _overlap(a, b)
|
|
}
|
|
found = [(a.id, b.id) for a, b in find_candidate_pairs(bodies)]
|
|
assert len(found) == len(set(found)), "kein Paar doppelt"
|
|
assert set(found) == expected
|
|
|
|
|
|
def test_pairs_are_ordered_by_id() -> None:
|
|
bodies = _random_scene(7, 40)
|
|
for a, b in find_candidate_pairs(bodies):
|
|
assert a.id < b.id
|
|
|
|
|
|
def test_pairs_of_sleeping_bodies_are_skipped() -> None:
|
|
a = Body.circle(Vector2(0, 0), 10, material())
|
|
b = Body.circle(Vector2(15, 0), 10, material())
|
|
c = Body.circle(Vector2(30, 0), 10, material())
|
|
a.put_to_sleep()
|
|
b.put_to_sleep()
|
|
pairs = {(x.id, y.id) for x, y in find_candidate_pairs([a, b, c])}
|
|
assert (a.id, b.id) not in pairs # beide schlafen
|
|
assert (b.id, c.id) in pairs # schlafend + wach wird geprüft
|