docs: fünf Befunde des Vorabscans im Plan berichtigt
Signatur von road_graph, eine wirkungslose Hilfsfunktion, eine Zusicherung die der Vereinfachung widerspricht, ein doppelter Aufruf und ein sorted() über Wörterbücher ohne Schlüssel. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
b24714adf4
commit
a86a4c9601
1 file changed
+13
-14
@@ -388,12 +388,9 @@ def _junction_clusters(pixels: nx.Graph, shape) -> tuple[np.ndarray, list[tuple[
|
||||
for k in range(1, count + 1):
|
||||
rows, cols = np.nonzero(junction & (labelled == k))
|
||||
points.append(to_world([(rows.mean(), cols.mean())])[0])
|
||||
return labelled * junction_reach(labelled, junction), points
|
||||
|
||||
|
||||
def junction_reach(labelled: np.ndarray, junction: np.ndarray) -> np.ndarray:
|
||||
"""Alle gewachsenen Pixel gehören zum Knoten, nicht nur die ursprünglichen."""
|
||||
return labelled > 0
|
||||
# labelled traegt die Knotennummer auf jedem *gewachsenen* Pixel. Genau das braucht _attach():
|
||||
# Das Ende einer Kette liegt neben einem gewachsenen Pixel, nicht neben einem Kreuzungspixel.
|
||||
return labelled, points
|
||||
|
||||
|
||||
def _chain(sub: nx.Graph) -> list[tuple[int, int]]:
|
||||
@@ -420,7 +417,7 @@ def _attach(graph: Graph, pixels: nx.Graph, clusters: np.ndarray, pixel) -> int:
|
||||
Ausführen: `cd tools/extract && PYTHONUTF8=1 uv run pytest tests/test_roads_graph.py -q`
|
||||
Erwartet: 5 bestanden.
|
||||
|
||||
Bleibt etwas rot, ist der wahrscheinlichste Grund `_junction_clusters`: `clusters` muss für **jedes** gewachsene Pixel die Knotennummer tragen, damit `_attach` das Ende einer Kette einem Knoten zuordnen kann. Die Rückgabe `labelled * junction_reach(...)` ist genau dafür da — `labelled` allein ist außerhalb der gewachsenen Bereiche 0, und das ist gewollt.
|
||||
Bleibt etwas rot, ist der wahrscheinlichste Grund `_junction_clusters`: `clusters` muss für **jedes** gewachsene Pixel die Knotennummer tragen, damit `_attach` das Ende einer Kette einem Knoten zuordnen kann. `ndi.label` auf der gewachsenen Maske leistet genau das; außerhalb der gewachsenen Bereiche steht 0, und das ist gewollt.
|
||||
|
||||
- [ ] **Schritt 6: Volle Suite und Commit**
|
||||
|
||||
@@ -457,7 +454,9 @@ dort ein.
|
||||
- `CLASS_WIDTH = {"gasse": 6.0, "wohnstrasse": 12.0, "hauptstrasse": 18.0, "boulevard": 24.0}`
|
||||
- `clean(graph: Graph) -> Graph`
|
||||
- `measure_widths(graph: Graph, distance: np.ndarray) -> Graph` (setzt `width` und `klass` je Kante)
|
||||
- `road_graph(labels: np.ndarray) -> Graph` — der Aufruf für die Pipeline: Skelett, Graph, säubern, messen
|
||||
- `road_graph(labels: np.ndarray, distance: np.ndarray) -> Graph` — der Aufruf für die Pipeline:
|
||||
Skelett, Graph, säubern, Breite und Klasse. Die Distanztransformation kommt von außen, weil
|
||||
`run.py` sie auch für die Palmen braucht.
|
||||
|
||||
- [ ] **Schritt 1: Den fehlschlagenden Test schreiben**
|
||||
|
||||
@@ -508,7 +507,9 @@ def test_knoten_mit_nur_zwei_kanten_verschwindet():
|
||||
Edge(1, 2, gerade(punkt(50, 0), punkt(100, 0)))])
|
||||
out = clean(graph)
|
||||
assert len(out.edges) == 1
|
||||
assert out.edges[0].points == [punkt(0, 0), punkt(50, 0), punkt(100, 0)]
|
||||
# clean() vereinfacht mit 1,0 m, und der Zwischenpunkt liegt genau auf der Verbindungslinie -
|
||||
# Douglas-Peucker wirft ihn weg. Geprüft wird das Verketten, nicht die Zahl der Stützpunkte.
|
||||
assert out.edges[0].points == [punkt(0, 0), punkt(100, 0)]
|
||||
|
||||
|
||||
def test_breite_ignoriert_die_kreuzungsenden():
|
||||
@@ -1193,8 +1194,8 @@ def _sidewalk(carriage, corridor):
|
||||
|
||||
def _kerb_lines(graph: Graph, carriage, bridges) -> list[LineString]:
|
||||
"""Die Fahrbahnkante, ohne die Stücke an Gassen und auf Brücken."""
|
||||
ohne = [ribbon(graph, k).buffer(0.2) for k, edge in enumerate(graph.edges)
|
||||
if not SECTION[edge.klass].kerb and ribbon(graph, k) is not None]
|
||||
ohne = [band.buffer(0.2) for k, edge in enumerate(graph.edges)
|
||||
if not SECTION[edge.klass].kerb and (band := ribbon(graph, k)) is not None]
|
||||
ohne += [b.buffer(0.2) for b in bridges]
|
||||
rand = carriage.boundary
|
||||
if ohne:
|
||||
@@ -1690,7 +1691,7 @@ def chunk_payload(i, j, *, land, surfaces, carriageway, curb, sidewalk, markings
|
||||
"carriageway": sorted(({"poly": _rings(p, i, j), "klasse": k} for p, k in carriageway),
|
||||
key=lambda c: (c["poly"], c["klasse"])),
|
||||
"curb": sorted(_line(l, i, j) for l in curb),
|
||||
"sidewalk": sorted({"poly": _rings(p, i, j)} for p in sidewalk),
|
||||
"sidewalk": sorted(({"poly": _rings(p, i, j)} for p in sidewalk), key=lambda s: s["poly"]),
|
||||
"markings": sorted(({"poly": _rings(p, i, j), "art": a} for p, a in markings),
|
||||
key=lambda m: (m["poly"], m["art"])),
|
||||
"lots": sorted(({"poly": _rings(p, i, j)} for p in lots), key=lambda l: l["poly"]),
|
||||
@@ -1706,8 +1707,6 @@ def chunk_payload(i, j, *, land, surfaces, carriageway, curb, sidewalk, markings
|
||||
}
|
||||
```
|
||||
|
||||
`sorted({"poly": ...} for ...)` ohne `key` schlägt bei Wörterbüchern fehl — bei `sidewalk` deshalb `key=lambda s: s["poly"]` ergänzen, wie bei `lots`.
|
||||
|
||||
`write_debug_png` liest `payload["roads"]`; dort auf `payload["carriageway"]` umstellen, Farbe unverändert.
|
||||
|
||||
- [ ] **Schritt 4: Test laufen lassen**
|
||||
|
||||
Reference in new issue
Block a user