64 lines
3.5 KiB
Python
64 lines
3.5 KiB
Python
from shapely.geometry import Polygon
|
|
from leonida.emit import chunk_payload, split_by_chunk, split_by_chunk_all
|
|
|
|
BIG = Polygon([(-1000, 2500), (-700, 2500), (-700, 2200), (-1000, 2200)]) # Chunk (0,0) und Nachbarn
|
|
|
|
def test_polygon_is_clipped_into_its_chunks():
|
|
parts = split_by_chunk(BIG)
|
|
assert set(parts) >= {(0, 0), (1, 0), (0, 1), (1, 1)}
|
|
assert abs(sum(p.area for p in parts.values()) - BIG.area) < 1.0
|
|
|
|
def test_coordinates_are_chunk_local_three_js():
|
|
# chunk_payload() nimmt (wie in run.py) bereits chunk-geschnittene Geometrie entgegen;
|
|
# BIG selbst überspannt vier Chunks (siehe Test oben), darum hier zuerst zuschneiden.
|
|
clipped = split_by_chunk(BIG)[(0, 0)]
|
|
payload = chunk_payload(0, 0, land=[clipped], surfaces=[], roads=[], centerlines=[], buildings=[], palms=[])
|
|
ring = payload["land"][0][0] # Ruling 34: [0] ist jetzt der Aussenring
|
|
assert payload["origin"] == [-1000, -2500] # three-z = -Y
|
|
assert min(x for x, _ in ring) >= -0.01
|
|
assert max(x for x, _ in ring) <= 250.01
|
|
|
|
def test_payload_matches_schema():
|
|
payload = chunk_payload(2, 3, land=[], surfaces=[], roads=[], centerlines=[], buildings=[], palms=[])
|
|
assert set(payload) == {"chunk", "origin", "land", "surfaces", "roads", "centerlines", "buildings", "palms", "paths"}
|
|
assert payload["chunk"] == [2, 3]
|
|
|
|
def test_paths_are_chunk_local_rings_like_roads():
|
|
path = Polygon([(-990, 2490), (-980, 2490), (-980, 2480), (-990, 2480)])
|
|
payload = chunk_payload(0, 0, land=[], surfaces=[], roads=[], centerlines=[], buildings=[], palms=[], paths=[path])
|
|
(entry,) = payload["paths"]
|
|
assert set(entry) == {"poly"}
|
|
ring = entry["poly"][0]
|
|
assert (min(x for x, _ in ring), max(x for x, _ in ring)) == (10, 20)
|
|
assert (min(z for _, z in ring), max(z for _, z in ring)) == (10, 20)
|
|
|
|
def test_polygon_holes_survive_into_the_payload():
|
|
"""Ein von Strassen umschlossener Block darf nicht zu Asphalt werden. An echten Daten
|
|
gehen sonst 449.876 m2 Strassenloch und 208.657 m2 Stadtloch verloren."""
|
|
outer = Polygon([(-1000, 2250), (-800, 2250), (-800, 2450), (-1000, 2450)],
|
|
[[(-950, 2300), (-870, 2300), (-870, 2400), (-950, 2400)]])
|
|
payload = chunk_payload(0, 0, land=[outer], surfaces=[], roads=[], centerlines=[],
|
|
buildings=[], palms=[])
|
|
assert len(payload["land"]) == 1
|
|
rings = payload["land"][0]
|
|
assert len(rings) == 2 # Aussenring und Loch
|
|
exterior, hole = rings
|
|
# Das Loch liegt innerhalb des Aussenrings, nicht daneben.
|
|
assert min(x for x, _ in exterior) < min(x for x, _ in hole)
|
|
assert max(x for x, _ in exterior) > max(x for x, _ in hole)
|
|
assert all(0 <= x <= 250 and 0 <= z <= 250 for x, z in hole)
|
|
|
|
def test_split_by_chunk_all_yields_polygons_for_a_multi_part_intersection():
|
|
"""split_by_chunk_all() ist die Variante, die run.py tatsaechlich benutzt (nicht
|
|
split_by_chunk), und hat einen MultiPolygon-Zweig, den kein anderer Test trifft: ein
|
|
Polygon, dessen Schnitt mit der Chunk-Zelle in mehrere Teile zerfaellt. Hier eine
|
|
Klammerform (Steg ausserhalb der Zelle, zwei Zinken, die je einmal hineinreichen)."""
|
|
staple = Polygon([
|
|
(-1100, 2495), (-850, 2495), (-850, 2470), (-1010, 2470),
|
|
(-1010, 2280), (-850, 2280), (-850, 2255), (-1010, 2255),
|
|
(-1100, 2255),
|
|
])
|
|
parts = list(split_by_chunk_all([staple], 0, 0))
|
|
assert len(parts) == 2
|
|
assert all(p.geom_type == "Polygon" for p in parts)
|