[ADD] AS/ES-Koordinatensysteme als K1/K2 exportieren + Kollision/Schleuselemente daran ausrichten

Export (Lisp/export.lsp):
- Neue csv:vfgf-k-kos-strings leitet fuer VF_n/GF_n-Wrapper K1 (AS/KS_EIN) und
  K2 (ES/KS_AUS) aus den verschachtelten AS_Element/ES_Element ab (via
  ssg-collect-nested-inserts) und schreibt sie wie K1-K4 als Positions-String.
  Bisher waren die K-Spalten fuer Strecken leer.

Kollisionspruefung Kreisel<->GF/VF (lib/export_neighbors.py):
- compute_neighbor_ids testet Strecken (GF/VF UND "ILS 2.0 Strecke - Modul")
  nicht mehr ueber die grosse Wrapper-Box, sondern ueber je eine kleine feste
  Box an der AS- (K1) und ES-Position (K2). Fallback auf Wrapper-Box, wenn
  K1/K2 fehlen (Altbestand).

Schleuselement-Positionen (lib/export_neighbors.py):
- compute_strecke_kreisel_schleus setzt Aus-/Einschleuselement ans AS/ES-KOS,
  um eine halbe Box entlang der Foerderachse nach aussen versetzt (AS: davor,
  ES: dahinter) - realistischer als der bisherige Kreiselrand-Punkt.

Keine Magic Numbers (cfg/export.cfg [Boundingbox]):
- element_box_laenge/breite/hoehe_mm (250/100/30) ersetzen die WEICHE_BOX_*-
  Konstanten; gelesen von load_element_box_mm und an alle Rechenfunktionen
  durchgereicht (WEICHE_BOX_* nur noch dokumentierter Fallback).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-04 14:00:52 +02:00
parent 29b7bf1a10
commit c88be420be
4 changed files with 254 additions and 40 deletions
+12 -5
View File
@@ -11,7 +11,8 @@ Nach der Kollisions-/Nachbarschaftserkennung wird ausserdem an jedem
Beruehrpunkt zweier Kreisel eine "ILS Weiche"-Zeile angehaengt (siehe
build_kreisel_weiche_items / export_neighbors.compute_kreisel_touch_switches):
Anzahl 1, Position = Beruehrkoordinaten, Nachbarn = die beiden Kreisel-IDs,
K1-K4/Insertpoint leer, Boundingbox = statische Default-Box (WEICHE_BOX_*),
K1-K4/Insertpoint leer, Boundingbox = feste Element-Box (element_box_mm,
cfg/export.cfg [Boundingbox]),
mit der Laengsseite senkrecht zur Achse des beruehrenden Kreisels; die TeileId
zaehlt aus der hoechsten bereits vergebenen numerischen ID hoch.
@@ -113,6 +114,7 @@ from export_neighbors import (
load_omniflo_cell_size_mm,
load_omniflo_ks_tolerance_mm,
load_kreisel_durchmesser_mm,
load_element_box_mm,
load_collision_debug_target,
compute_neighbor_ids,
compute_neighbor_errors,
@@ -131,6 +133,7 @@ NEIGHBOR_TOLERANCE_MM = load_neighbor_tolerance_mm()
NEIGHBOR_OMNIFLO_CELL_SIZE_MM = load_omniflo_cell_size_mm()
NEIGHBOR_OMNIFLO_KS_TOLERANCE_MM = load_omniflo_ks_tolerance_mm()
KREISEL_DURCHMESSER_MM = load_kreisel_durchmesser_mm()
ELEMENT_BOX_MM = load_element_box_mm()
NEIGHBOR_DEBUG_TARGET = load_collision_debug_target()
@@ -460,12 +463,14 @@ def build_kreisel_weiche_items(items, planquadrat_cfg, start_elem_nr, dbg=None):
(max_numeric_teileid), 4-stellig aufgefuellt wie die Kreisel-IDs. Anzahl
ist wie bei allen Zeilen 1; Nachbarn = die beiden Kreisel-IDs; K1-K4 und
Insertpoint bleiben leer; Position = Beruehrkoordinaten; Boundingbox = die
statische, an der Kreiselachse ausgerichtete Default-Box (WEICHE_BOX_*).
feste, an der Kreiselachse ausgerichtete Element-Box (element_box_mm,
cfg/export.cfg [Boundingbox]).
Rueckgabe: fortgeschriebene Elementnummer (start_elem_nr + Anzahl Weichen).
"""
switches = compute_kreisel_touch_switches(
items, NEIGHBOR_TOLERANCE_MM, durchmesser_mm=KREISEL_DURCHMESSER_MM, dbg=dbg)
items, NEIGHBOR_TOLERANCE_MM, durchmesser_mm=KREISEL_DURCHMESSER_MM,
element_box_mm=ELEMENT_BOX_MM, dbg=dbg)
naechste_id = max_numeric_teileid(items)
elem_nr = start_elem_nr
@@ -512,7 +517,8 @@ def build_strecke_schleus_items(items, planquadrat_cfg, start_elem_nr, dbg=None)
Rueckgabe: fortgeschriebene Elementnummer.
"""
schleus, warnings = compute_strecke_kreisel_schleus(
items, durchmesser_mm=KREISEL_DURCHMESSER_MM, dbg=dbg)
items, durchmesser_mm=KREISEL_DURCHMESSER_MM,
element_box_mm=ELEMENT_BOX_MM, dbg=dbg)
# Warnungen (>2 Kreisel-BBox-Beruehrungen je Strecke) auf die Strecken-Zeile
# schreiben (Spalte "Warnungen") und in die Konsole ausgeben.
@@ -815,7 +821,8 @@ def process_blocks(blocks, lookup, dbg=None):
neighbor_ids = compute_neighbor_ids(
items, NEIGHBOR_TOLERANCE_MM, NEIGHBOR_OMNIFLO_CELL_SIZE_MM,
kreisel_durchmesser_mm=KREISEL_DURCHMESSER_MM,
omniflo_ks_tolerance_mm=NEIGHBOR_OMNIFLO_KS_TOLERANCE_MM, dbg=dbg)
omniflo_ks_tolerance_mm=NEIGHBOR_OMNIFLO_KS_TOLERANCE_MM,
element_box_mm=ELEMENT_BOX_MM, dbg=dbg)
neighbor_errors = compute_neighbor_errors(items, neighbor_ids)
for item, nachbarn, fehler in zip(items, neighbor_ids, neighbor_errors):
item["nachbarn"] = nachbarn