[FIX] Export: Schnittpunkte zwischen Kreiseln werden erkannt und Weichen entsprechend gezählt und als Teil mit Merkmalen im Export befüllt - nur Kreisel mit gleicher Höhe können einen Schnittpunkt für Weiche bilden - Funktion der Weichenzählung manuell aufrufbar; [FIX] Eckrad nun korrekt angelegt und exportiert

This commit is contained in:
2026-10-14 07:42:08 +02:00
parent 6044c35957
commit 8039251bb8
18 changed files with 1452 additions and 481 deletions
+79
View File
@@ -47,6 +47,7 @@ MIN_PARTNER) - Ergebnis ist die CSV-Spalte "Fehler" in export_csv.py.
Nur von export_csv.py genutzt (EXPORTCSV), nicht von export_sivas.py.
"""
import json
import math
import os
@@ -1091,6 +1092,84 @@ def compute_kreisel_touch_switches(items, tolerance_mm, durchmesser_mm=800.0,
return switches
# Dateiname der von LISP (csv:kreisel-weichen-schreiben, export.lsp) neben
# export_raw.json geschriebenen Kreisel-Beruehrpunkte.
LISP_KREISEL_WEICHEN_DATEI = "kreisel_weichen.json"
def load_lisp_kreisel_weichen(raw_json_path):
"""Liest kreisel_weichen.json aus dem Ordner von raw_json_path.
Die Datei schreibt der LISP-Export (KreiselInsert.lsp kreisel-bp-*):
Kreisel UND Eckraeder, nur gleiche Hoehe, mehrere Punkte je Paar moeglich,
Ueberschneidungen getrennt als "kollisionen". Rueckgabe: dict mit
"beruehrungen"/"kollisionen" oder None, wenn die Datei fehlt/unlesbar ist
(dann rechnet der Aufrufer selbst - compute_kreisel_touch_switches)."""
pfad = os.path.join(os.path.dirname(os.path.abspath(raw_json_path)),
LISP_KREISEL_WEICHEN_DATEI)
if not os.path.exists(pfad):
return None
try:
with open(pfad, encoding="utf-8", errors="replace") as f:
daten = json.load(f)
except (OSError, ValueError):
return None
if not isinstance(daten, dict):
return None
daten.setdefault("beruehrungen", [])
daten.setdefault("kollisionen", [])
return daten
def lisp_touch_switches(lisp_daten, element_box_mm=None, dbg=None):
"""Baut aus den LISP-Beruehrpunkten (load_lisp_kreisel_weichen) dieselben
Switch-dicts wie compute_kreisel_touch_switches - damit laufen
compute_kreisel_umlauf und build_kreisel_weiche_items unveraendert.
Partner-ID = ID-Attribut (= teileid), ohne ID der Handle. Mehrere Punkte
eines Paares bekommen eindeutige Schluessel (WEICHE#a#b, WEICHE#a#b#2, ...).
Die Box wird an achse_rot_grad (Radiale des beruehrenden Rades) ausgerichtet.
Kollisionen werden NICHT zu Weichen, nur ins Debuglog geschrieben."""
if element_box_mm is None:
element_box_mm = load_element_box_mm()
box_l, box_b, box_h = element_box_mm
switches = []
keys = set()
if dbg:
dbg("")
dbg("=== Kreisel-Beruehrpunkte -> ILS-Weichen (aus LISP kreisel_weichen.json) ===")
for b in lisp_daten.get("beruehrungen", []):
id_a = b.get("a") or b.get("a_handle", "")
id_b = b.get("b") or b.get("b_handle", "")
key = f"WEICHE#{id_a}#{id_b}"
n = 1
while key in keys:
n += 1
key = f"WEICHE#{id_a}#{id_b}#{n}"
keys.add(key)
dx, dy, dz = _oriented_box_aabb(math.radians(float(b.get("achse_rot_grad", 0.0))),
box_l, box_b, box_h)
sw = {
"key": key,
"x": float(b.get("x", 0.0)), "y": float(b.get("y", 0.0)), "z": float(b.get("z", 0.0)),
"dx": dx, "dy": dy, "dz": dz,
"nachbarn": [id_a, id_b],
"achse_von": b.get("achse_von", "") or id_a,
"beruehrung": b.get("art", ""),
}
switches.append(sw)
if dbg:
dbg(f" {id_a} <-> {id_b}: {sw['beruehrung']} ({b.get('detail', '')}) "
f"bei ({sw['x']:.0f}, {sw['y']:.0f}, {sw['z']:.0f})")
if dbg:
for k in lisp_daten.get("kollisionen", []):
dbg(f" KOLLISION {k.get('a', '')} <-> {k.get('b', '')}: {k.get('art', '')} "
f"({k.get('detail', '')}) bei ({float(k.get('x', 0)):.0f}, "
f"{float(k.get('y', 0)):.0f})")
dbg(f"Erzeugte ILS-Weichen: {len(switches)}")
return switches
# ---------------------------------------------------------------------------
# Kreisel <-> Strecken-Enden: verfeinerte Kollisionsbox fuer compute_neighbor_
# ids (die "Nachbarn"-Spalte einer GF/VF-Strecke soll nur an ihrem echten AS-/