Files
gta6/tools/extract/tests/test_heights.py
T
knsoandClaude Sonnet 5 6de4b81942 feat(extract): Gebäudepolygone, Höhen aus Wahrzeichen und Vierteln, Palmenpunkte
buildings.py regularisiert Gebäude-Maskenpolygone (gebaeude/spekulativ) zu
Rechtecken, wenn sie ihr gedrehtes Hüllrechteck zu mindestens 85 % ausfüllen,
sonst zu vereinfachten Grundrissen; zu kleine oder entartete Polygone liefern
None. heights.py weist Gebäuden eine Höhe zu (Wahrzeichen-Treffer schlägt
Viertel-Bereich, deterministisch geseedet) und platziert Palmenpunkte entlang
strandnaher Mittellinien: der Versatz vom Fahrbahnrand wird von innen nach
außen gesucht (PALM_VERGE), bis eine Position sowohl PALM_KERB von der
Fahrbahn als auch PALM_CLEARANCE von Gebäuden einhält; findet sich keine,
entfällt die Palme. Start bei halber PALM_SPACING verhindert doppelte Palmen
an Kreuzungen, wo Task 4 Mittellinien pro Ast trennt.

pyproject.toml ergänzt einen gezielten filterwarnings-Eintrag: Shapelys
oriented_envelope (minimum_rotated_rectangle) meldet für bereits achsen-
parallele/rechtwinklige Polygone eine RuntimeWarning aus GEOS (Winkelterm
wird 0/0), obwohl das Ergebnis nachweislich korrekt bleibt – u.a. löst der
Briefs eigener L-Shape-Test das aus. Nur dieser eine Text+Kategorie-
kombinierte Fall wird gefiltert, jede andere Warnung bleibt sichtbar.

Auf dem echten Mosaik: 2141 Gebäudepolygone (258 spekulativ, 211 von
regularize verworfen), Höhen 6.0-15.0 m (nur "district", da data/skyline.json
und data/districts.json erst in Task 6 kommen), 2433 Palmenpunkte. Straßen-
und Mittellinienzahlen (475 Stücke/40 Brücken, 2323 Linien/Median 27 m)
decken sich exakt mit den in Task 4 unabhängig ermittelten Referenzwerten.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-12 15:43:10 +02:00

55 lines
2.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from shapely.geometry import Polygon
from leonida.heights import DISTRICT_RANGES, assign_heights
SQUARE = Polygon([(0, 0), (20, 0), (20, 20), (0, 20)])
FAR = Polygon([(500, 500), (520, 500), (520, 520), (500, 520)])
def test_landmark_height_wins():
res = assign_heights([SQUARE], landmarks=[{"xyz": [10, 10, 0], "height": 180.0}],
districts=[], seed=1)
assert res[0]["height"] == 180.0
assert res[0]["source"] == "skyline"
def test_district_range_is_used_without_landmark():
res = assign_heights([SQUARE], landmarks=[],
districts=[{"name": "Downtown", "x": 5, "y": 5}], seed=1)
lo, hi = DISTRICT_RANGES["Downtown"]
assert lo <= res[0]["height"] <= hi
assert res[0]["source"] == "district"
def test_same_seed_gives_same_height():
args = dict(landmarks=[], districts=[{"name": "Downtown", "x": 5, "y": 5}], seed=42)
assert assign_heights([SQUARE], **args)[0]["height"] == assign_heights([SQUARE], **args)[0]["height"]
def test_unknown_district_falls_back_to_default():
res = assign_heights([FAR], landmarks=[], districts=[], seed=3)
lo, hi = DISTRICT_RANGES["default"]
assert lo <= res[0]["height"] <= hi
from shapely.geometry import LineString, Point
from leonida.heights import PALM_KERB, palm_points
def test_no_palm_stands_on_the_carriageway():
"""Der Versatz muss vom Fahrbahnrand her gedacht werden, nicht von einem festen Wert.
Am echten Mosaik hat die Fahrbahn an den Mittellinienpunkten p50 5,4 m, p90 11,7 m
und p95 14,0 m Halbbreite. Ein fester Versatz von 4 m setzt 60 % der Palmen auf die
Fahrbahn, einer von 11 m immer noch 12,5 % – und auf der Hälfte der Straßen stünde
die Palme dann im Nachbargebäude.
"""
road = Polygon([(0, -9), (200, -9), (200, 9), (0, 9)]) # 18 m breite Fahrbahn
line = LineString([(0, 0), (200, 0)])
sand = Polygon([(0, 20), (200, 20), (200, 40), (0, 40)])
pts = palm_points([sand], [], [line], [], [road], seed=1)
assert pts
assert all(road.distance(Point(x, y)) >= PALM_KERB for x, y in pts)
def test_palms_do_not_pile_up_where_centerlines_meet():
"""Mittellinien sind an Kreuzungen getrennt (Task 4). Ein Start bei Position 0 setzt
auf zwei gegenüberliegenden Ästen zwei Palmen in genau denselben Punkt."""
sand = Polygon([(-80, 20), (80, 20), (80, 40), (-80, 40)])
arms = [LineString([(0, 0), (60, 0)]), LineString([(0, 0), (-60, 0)])]
pts = palm_points([sand], [], arms, [], [], seed=1)
assert pts
assert len(set(pts)) == len(pts)