export_csv: VF_n/GF_n-Einzelelemente zu Foerdereinheit/Gefaelleeinheit gruppieren

Die Einzelteil-Proxy-Zeilen (Boegen, Streckenelemente, Umlenk-/Motorstation)
aus der letzten Session sind fuer den Normalfall zu granular. Standardmaessig
(*csv-export-alle-elemente* = nil) fasst csv:unitmark-aktualisieren sie jetzt
zu je einer "Foerdereinheit"/"Gefaelleeinheit"-Zeile pro zusammenhaengendem
VF-/GF-Abschnitt einer Kette zusammen, mit einem persistenten Rechteck-Marker
(ZZ_UNIT_MARKER, analog ZZ_ASES_MARKER) auf der Bounding-Box-Vereinigung
aller enthaltenen Elemente. Der bisherige Rohdaten-Export bleibt ueber
(csv:export-alle-elemente-an) weiterhin verfuegbar.

Einheiten-Grenzen kommen rein export-seitig aus der sepliste (SEP/AS/ES in
echter Bau-Reihenfolge) plus dem bereits vorhandenen SSG_SEP_TYP je
Separator - eine bauzeitige Markierung in vf_linienzug.lsp/vf_standard.lsp/
vf_etage.lsp waere deutlich invasiver gewesen (3 unabhaengige Baupfade ohne
gemeinsamen Einstiegspunkt). csv:sepliste-partition (Lauflaengen-Kodierung
ueber die typisierte sepliste) und csv:element-unit-zuordnung (Zuordnung der
gesammelten Elemente per Kettenrichtungs-Projektion statt der nachweislich
unzuverlaessigen csv:nested-welt-records-Listenreihenfolge) sind reine,
dateifrei getestete Funktionen.

Korrigiert nebenbei eine falsche Annahme: L_VF_m/L_GF_m zaehlen pro Segment,
nicht pro Einheit - die tatsaechliche Einheiten-Anzahl kommt nur aus der
sepliste-Typfolge.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Michael Stangl
2026-09-24 23:46:41 +02:00
co-authored by Claude Sonnet 5
parent f751a90076
commit e7643bf181
6 changed files with 943 additions and 47 deletions
+81
View File
@@ -410,6 +410,87 @@
(csv:element-teileart "Vario_Motorstation_500mm_rechts"))
(tu-eq "csv:element-teileart/unbekannt" nil
(csv:element-teileart "AS_Element_90_links"))
;; --- csv:sepliste-partition: sepliste in Foerdereinheit-/Gefaelleeinheit-
;; Spannen aufteilen (Lauflaengen-Kodierung ueber den effektiven Typ) -----
;; Reine Rechenfunktion auf (typ lfdnr strecke-typ welt-pt)-Tupeln, hier
;; ohne Zeichnung testbar (welt-pt wird von der Partitionierung selbst
;; nicht gebraucht, darum ueberall nil).
;; HundM05 VF_1-Beispiel (echt verifiziert): AS, SEP2=VF, SEP3=GF, SEP4=GF,
;; SEP5=VF, ES -> 3 Einheiten VF,GF,VF. SEP3+SEP4 bracketen GEMEINSAM eine
;; einzige Gefaelleeinheit (nicht zwei separate).
(setq _sep-hundm05
'(("AS" 1 nil nil) ("SEP" 2 "VF" nil) ("SEP" 3 "GF" nil)
("SEP" 4 "GF" nil) ("SEP" 5 "VF" nil) ("ES" 6 nil nil)))
(tu-eq "csv:sepliste-partition/hundm05"
'(("VF" (1 2)) ("GF" (3 4)) ("VF" (5 6)))
(csv:sepliste-partition _sep-hundm05))
;; Minimalfall: nur AS-SEP(VF)-ES, kein Typwechsel -> 1 Foerdereinheit ueber
;; die ganze Kette.
(setq _sep-minimal '(("AS" 1 nil nil) ("SEP" 2 "VF" nil) ("ES" 3 nil nil)))
(tu-eq "csv:sepliste-partition/minimal"
'(("VF" (1 2 3)))
(csv:sepliste-partition _sep-minimal))
;; Einzel-GF-Fall: die Gefaelleeinheit wird nur von EINEM SEP (nicht zwei)
;; UND dem nachfolgenden ES bracketiert.
(setq _sep-einzel-gf
'(("AS" 1 nil nil) ("SEP" 2 "VF" nil) ("SEP" 3 "GF" nil) ("ES" 4 nil nil)))
(tu-eq "csv:sepliste-partition/einzel-gf"
'(("VF" (1 2)) ("GF" (3 4)))
(csv:sepliste-partition _sep-einzel-gf))
;; 3+ gleichtypige SEP-Eintraege hintereinander muessen weiterhin EINE
;; Einheit ergeben (nicht mehrere) - Lauflaengen-Regel, kein Sonderfall.
(setq _sep-dreifach-gf
'(("AS" 1 nil nil) ("SEP" 2 "VF" nil) ("SEP" 3 "GF" nil)
("SEP" 4 "GF" nil) ("SEP" 5 "GF" nil) ("SEP" 6 "VF" nil) ("ES" 7 nil nil)))
(tu-eq "csv:sepliste-partition/dreifach-gf"
'(("VF" (1 2)) ("GF" (3 4 5)) ("VF" (6 7)))
(csv:sepliste-partition _sep-dreifach-gf))
;; Kette beginnend mit GF (AS erbt den Typ des ersten SEP-Eintrags, hier GF
;; statt des sonstigen Default "VF").
(setq _sep-startet-gf
'(("AS" 1 nil nil) ("SEP" 2 "GF" nil) ("ES" 3 nil nil)))
(tu-eq "csv:sepliste-partition/startet-gf"
'(("GF" (1 2 3)))
(csv:sepliste-partition _sep-startet-gf))
;; --- csv:dot2: 2D-Skalarprodukt ---
(tu-eqf "csv:dot2/achsen" 0.0 (csv:dot2 '(1.0 0.0) '(0.0 1.0)))
(tu-eqf "csv:dot2/parallel" 6.0 (csv:dot2 '(2.0 0.0) '(3.0 0.0)))
;; --- csv:element-unit-zuordnung: Elemente per Kettenrichtungs-Projektion
;; den Einheiten-Spannen zuordnen und INNERHALB jeder Spanne nach der
;; Projektion sortieren -----------------------------------------------
;; Gerade Kette AS(0,0) -SEP2(VF, 10,0)- SEP3(GF, 20,0) -ES(30,0)- entlang
;; der X-Achse. unit-spans: VF=[1,2], GF=[2,3] (SEP2 gehoert zu beiden
;; Spannen als Grenzmarker, siehe csv:sepliste-partition).
(setq _sep-proj
'(("AS" 1 nil (0.0 0.0 0.0)) ("SEP" 2 "VF" (10.0 0.0 0.0))
("SEP" 3 "GF" (20.0 0.0 0.0)) ("ES" 4 nil (30.0 0.0 0.0))))
(setq _spans-proj (csv:sepliste-partition _sep-proj))
(tu-eq "csv:sepliste-partition/proj-spans" '(("VF" (1 2)) ("GF" (3 4))) _spans-proj)
;; Zwei Elemente: eines bei x=5 (klar in der VF-Spanne [0,10]), eines bei
;; x=17 (in der Luecke zwischen den Spannen-Grenzpunkten [10,20], aber
;; naeher an der GF-Grenze 20 als an der VF-Grenze 10 - eindeutig GF, kein
;; Gleichstand wie bei x=15 in der Luecken-Mitte).
(setq _elem-vf (list 'PROXY1 'WRAPPER "STRECKENELEMENT" '(5.0 0.0 0.0)))
(setq _elem-gf (list 'PROXY2 'WRAPPER "STRECKENELEMENT" '(17.0 0.0 0.0)))
(setq _zuord (csv:element-unit-zuordnung _spans-proj _sep-proj (list _elem-vf _elem-gf)))
(tu-eq "csv:element-unit-zuordnung/vf-treffer" (list _elem-vf) (nth 0 _zuord))
(tu-eq "csv:element-unit-zuordnung/gf-treffer" (list _elem-gf) (nth 1 _zuord))
;; Sortierung innerhalb einer Spanne: zwei Elemente in der VF-Spanne,
;; absichtlich in "falscher" Reihenfolge uebergeben - das Ergebnis muss
;; nach x sortiert sein (frueheres x zuerst).
(setq _elem-a (list 'PROXY_A 'WRAPPER "BOGEN" '(8.0 0.0 0.0)))
(setq _elem-b (list 'PROXY_B 'WRAPPER "BOGEN" '(2.0 0.0 0.0)))
(setq _zuord2 (csv:element-unit-zuordnung _spans-proj _sep-proj (list _elem-a _elem-b)))
(tu-eq "csv:element-unit-zuordnung/sortiert" (list _elem-b _elem-a) (nth 0 _zuord2))
)