export: jeden Wert nur an einer Stelle setzen (ZUORDNUNG, sepliste-IDs, Typen, K1/K2)

- ZUORDNUNG: ssg-id-check-all laeuft jetzt ZUERST, danach sind die
  Wrapper-IDs endgueltig - Separator-Kopien, AS/ES- und Einheiten-Marker
  bekommen ZUORDNUNG direkt beim Erzeugen. Entfallen:
  csv:sep-proxies-zuordnung-setzen, csv:asmark-ids-setzen,
  csv:unitmark-ids-setzen. zuordnung_fix/*cs-sep-fix-by-handle* bleibt
  (count_sep_scan rechnet eigenstaendige Sensoren bewusst neu).
- sepliste-IDs: Zuordnung ueber die KS-Kettenfolge je Typ
  (csv:sepliste-kette-paare) statt ueber die teils gespiegelten
  sepliste-Koordinaten (csv:sepliste-paare, csv:sepliste-ids-setzen
  entfallen). Die Kette wird je Lauf einmal berechnet (csv:kette-von);
  die ID liest csv:block-to-json erst beim Schreiben. Behebt vertauschte
  TrackIds/Nachbarn in HundM05 VF_1 (0031/0029).
- Element-Klassifizierung: eine Tabelle csv:element-familien (cfg-Muster)
  fuer Suche und Klassifizierung; csv:proxy-typ entfaellt.
- Einheiten-Marker: K1/K2 nur noch in *csv-baustein-by-handle*
  (csv:geometrie-merken), K1/K2-Attribute und
  csv:unitmark-k-kos-strings entfallen.

Geprueft: HundM05-Export alt/neu headless verglichen - einzige Abweichung
ist die korrigierte Reihenfolge in VF_1. LISP-Unit-Tests 303/303.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Samer Ayadi
2026-09-28 12:10:16 +02:00
co-authored by Claude Opus 5.5
parent e67f7cc1aa
commit 1e6b152d72
10 changed files with 416 additions and 642 deletions
+4 -5
View File
@@ -423,12 +423,11 @@ Sammelt INSERT-Blöcke aus der Zeichnung und exportiert sie als JSON oder ruft P
| `c:EXPORTSIVAS` | Alle Blöcke als JSON sammeln und `export_sivas.py` aufrufen (Sivas-CSV) |
| `c:EXPORTCSV` | Alle Blöcke als JSON sammeln und `export_csv.py` aufrufen (einfache Item-Liste, inkl. Omniflo Bogen/Weiche/Gerade und abschließender "Omniflo Sum"-Zeile) |
| `csv:collect-export-blocks` | Alle INSERT-Blöcke der Zeichnung als JSON-Array sammeln |
| `csv:run-export py-skript json-datei output-csv` | Python-Skript mit gesammelten Daten aufrufen; legt vorher fuer in VF_n/GF_n/KREISEL_n **verpackte** Separator_SP_2D/_3D-Sub-INSERTs (Sensor-Symbol; siehe `ssg-collect-nested-inserts` in `ssg_core.lsp` - NICHT der interne Staustrecke_Separator_SP-Trennsteg) je eine echte, temporaere Kopie **an derselben Stelle** an (`csv:sep-proxies-erzeugen`, Position/Drehung/Skalierung ueber alle Verschachtelungsebenen hinweg identisch zum Vorbild - kein kosmetischer Versatz mehr, der die geometrische Sensor-Zuordnung verfaelschen wuerde), damit sie ganz normal ueber `ssg-id-check-all`/`csv:collect-export-blocks` erfasst werden, und entfernt sie danach wieder (`csv:sep-proxies-loeschen`). Die verpackten **AS-/ES-Schleuselemente** derselben Kette bekommen stattdessen einen DAUERHAFTEN Marker (`csv:asmark-aktualisieren`, siehe unten); beide Wege teilen sich die Platzierungsrechnung (`csv:nested-welt-records` + `csv:block-einfuegen-welt`). Reihenfolge ist wesentlich: **erst alle** Kopien aus allen Wrappern erzeugen, **dann** `ssg-id-check-all` (vergibt IDs oberhalb des globalen Maximums), **dann** `csv:sep-proxies-zuordnung-setzen` und `csv:sepliste-ids-setzen` |
| `csv:sep-proxies-zuordnung-setzen proxy-liste` | ZUORDNUNG jeder Separator-Kopie auf die **ID ihres Wrapper-Blocks** setzen (ein in VF_n mit ID 0010 verpackter Separator erhaelt ZUORDNUNG 0010) und die Zuordnung ueber `*cs-sep-fix-by-handle*` fuer `cs-zuordnung-lauf` festnageln - fuer verpackte Separatoren ist der Carrier bekannt und wird nicht per Boundingbox geraten. Muss NACH `ssg-id-check-all` laufen, da ein frisch gebauter Wrapper vorher noch keine ID hat |
| `csv:run-export py-skript json-datei output-csv` | Python-Skript mit gesammelten Daten aufrufen; legt vorher fuer in VF_n/GF_n/KREISEL_n **verpackte** Separator_SP_2D/_3D-Sub-INSERTs (Sensor-Symbol; siehe `ssg-collect-nested-inserts` in `ssg_core.lsp` - NICHT der interne Staustrecke_Separator_SP-Trennsteg) je eine echte, temporaere Kopie **an derselben Stelle** an (`csv:sep-proxies-erzeugen`, Position/Drehung/Skalierung ueber alle Verschachtelungsebenen hinweg identisch zum Vorbild - kein kosmetischer Versatz mehr, der die geometrische Sensor-Zuordnung verfaelschen wuerde), damit sie ganz normal ueber `ssg-id-check-all`/`csv:collect-export-blocks` erfasst werden, und entfernt sie danach wieder (`csv:sep-proxies-loeschen`). Die verpackten **AS-/ES-Schleuselemente** derselben Kette bekommen stattdessen einen DAUERHAFTEN Marker (`csv:asmark-aktualisieren`, siehe unten); beide Wege teilen sich die Platzierungsrechnung (`csv:nested-welt-records` + `csv:block-einfuegen-welt`). Reihenfolge ist wesentlich: **erst** `ssg-id-check-all` (Wrapper-IDs endgueltig), **dann** die Kopien/Marker (ZUORDNUNG direkt beim Erzeugen), **dann** `csv:ketten-verarbeiten` (IDs in Kettenfolge, Separator-Typ, sepliste-Stellvertreter), **dann** ein zweites `ssg-id-check-all` (Restnummerierung) |
| `csv:asmark-aktualisieren` | AS-/ES-Kettenenden sichtbar machen: setzt an jedes verpackte `AS_Element*`/`ES_Element*` einer VF_n/GF_n-Kette ein kleines Rechteck (Block `ZZ_ASES_MARKER`, Groesse aus `cfg/export.cfg` `[Marker]`, Layer aus `cfg/layer.cfg` `ases_marker`), das nach dem Export **stehen bleibt**. Unsichtbare Attribute ID/ZUORDNUNG/TYP/LFDNR/ELEMENT/ARTINR; die `ID` fuellt `ssg-id-check-all` und der naechste Export **uebernimmt sie**, ein AS/ES behaelt seine TeileId also ueber Laeufe hinweg. Baut bei jedem Export alle Marker neu auf (Wiederfinden ueber ZUORDNUNG+TYP+LFDNR) und entfernt verwaiste |
| `csv:asmark-ids-setzen marker-liste` | Nach `ssg-id-check-all`: ZUORDNUNG (Wrapper-ID) am Marker nachtragen und seine ID am `sepliste`-Eintrag vermerken |
| `csv:sepliste-ids-setzen proxy-liste` | ID jeder Kopie (Separator UND AS/ES, beide Listen zusammen) an ihren `sepliste`-Eintrag des Wrappers haengen; Ergebnis in `*csv-sepliste-id-by-handle*` (Key = Wrapper-Handle), von `csv:block-to-json` als Feld `id` je Eintrag geschrieben. Muss NACH `ssg-id-check-all` laufen |
| `csv:sepliste-paare eintraege proxies` | Zuordnung `sepliste`-Eintrag -> Kopie: nur innerhalb desselben Typmarkers (`AS`/`ES`/`SEP`) und **exklusiv** (kuerzester Abstand zuerst, danach sind Eintrag und Kopie verbraucht). Damit verschiebt EIN fehlerhafter Koordinatenwert in der `sepliste` keine anderen Zuordnungen. Reine Rechenfunktion, getestet in `tests/test_unit.lsp` |
| `csv:ketten-verarbeiten sep-proxies element-proxies asmarks` | Je VF_n/GF_n aus DERSELBEN KS-geordneten Kette (`csv:kette-von`, einmal je Lauf berechnet): Einheiten-Proxies (`group_vf_gf`), IDs in Kettenfolge, Separator-Typ VF/GF (`csv:kette-sep-typen` -> `*cs-sep-typ-by-handle*`) und der Stellvertreter jedes `sepliste`-Eintrags (`*csv-sepliste-id-by-handle*`, Key = Wrapper-Handle; `csv:block-to-json` liest dessen ID beim Schreiben als Feld `id`) |
| `csv:sepliste-kette-paare eintraege typen` | Zuordnung `sepliste`-Eintrag -> Kettenbaustein ueber die **Reihenfolge je Typ** (k-tes `AS`/`SEP`/`ES` der sepliste = k-tes der KS-Kette), ohne die (teils gespiegelten) sepliste-Koordinaten. Reine Rechenfunktion, getestet in `tests/test_unit.lsp` |
| `csv:element-familien` | EINZIGE Tabelle Familie -> Blockmuster (`pattern_nested_*` aus `cfg/export.cfg`) fuer Suche (`csv:pattern-nested-element`) UND Klassifizierung (`csv:element-teileart`, darauf aufbauend `csv:kette-typ`) |
| `csv:read-attribs ename` | Attribute eines INSERT als JSON-Objekt lesen |
| `c:OMNI_UPDATE_ATTRIBS` | HOEHE/DREHUNG aller Omniflo-Elemente aus der Zeichnung aktualisieren |
+325 -529
View File
File diff suppressed because it is too large Load Diff
+48 -47
View File
@@ -43,7 +43,14 @@ Datei: `Lisp/export.lsp`. `c:EXPORTCSV` ruft `csv:run-export` mit
`include-bbox=T` auf (im Unterschied zu `c:EXPORTSIVAS`, das keine
Bounding-Boxen braucht).
1. **`csv:sep-proxies-erzeugen`** — Separator_SP-Symbole, die beim
Jeder Wert wird dabei genau EINMAL gesetzt; die Reihenfolge sorgt dafuer,
dass er beim Setzen schon feststeht (`csv:export-vorbereiten`):
1. **`ssg-id-check-all`** — ZUERST, noch bevor ein Stellvertreter existiert:
vergibt fehlende IDs und korrigiert Duplikate. Danach ist die ID jedes
Wrappers (`VF_n`/`GF_n`/`KREISEL_n`) endgueltig, die folgenden Schritte
koennen `ZUORDNUNG` direkt beim Erzeugen setzen.
2. **`csv:sep-proxies-erzeugen`** — Separator_SP-Symbole, die beim
Zusammenbau von `KREISEL_n`/`ECKRAD_n`/`VF_n`/`GF_n` in die
Compound-Blockdefinition verpackt wurden, sind fuer `(ssget "X" ...)`
unsichtbar. Diese Funktion fuegt fuer jeden Fund eine ECHTE, temporaere
@@ -51,32 +58,30 @@ Bounding-Boxen braucht).
durchlaeuft danach ID-Vergabe und Export ganz normal ueber den freien-
Separator-Pfad (Blockname-Muster `Separator_SP*` trifft zu) und bekommt
dadurch eine echte `vla-getboundingbox`-Box, die das verpackte Original nie
haben koennte. Rueckgabe: Liste von Records
`(proxy-ename wrapper-ename typ (x y z))`.
1b. **`csv:asmark-aktualisieren`** — die AS-/ES-Enden derselben Kette
haben koennte. Dabei bekommt die Kopie `ZUORDNUNG = Wrapper-ID` (bekannt,
nicht geraten) und wird in `*cs-sep-fix-by-handle*` als "bekannt"
vermerkt: `count_sep_scan.lsp` und `export_csv.py` (Feld `zuordnung_fix`)
berechnen die Zuordnung EIGENSTAENDIGER Sensoren bei jedem Lauf
geometrisch neu und nehmen verpackte Separatoren damit davon aus.
Rueckgabe: Liste von Records `(proxy-ename wrapper-ename "SEP" (x y z)
trennsteg-ent)`.
2b. **`csv:asmark-aktualisieren`** — die AS-/ES-Enden derselben Kette
(`AS_Element*`/`ES_Element*`, Muster `pattern_schleuselement`) bekommen
KEINE Kopie des Elements, sondern einen eigenen (ebenfalls temporaeren) Marker — siehe eigener
Abschnitt "Der AS/ES-Marker" unten. Beide Wege teilen sich die
Platzierungsrechnung (`csv:nested-welt-records` liefert die Weltlage jedes
verpackten Fundes, `csv:block-einfuegen-welt` setzt ein Objekt dorthin).
2. **`ssg-id-check-all`** — vergibt fehlende IDs (inkl. der frisch erzeugten
Proxies) und korrigiert Duplikate. Muss NACH den Proxies laufen, sonst
wuerden diese Kopien numerisch nie erfasst. `ssg-id-collect-blocks`
(`ssg_id.lsp`) erfasst dafuer auch `AS_Element*`/`ES_Element*`.
3. **`csv:sep-proxies-zuordnung-setzen`** — jetzt steht die ID jedes Wrappers
fest: die Proxy-Kopie bekommt `ZUORDNUNG = Wrapper-ID` fest zugewiesen
(nicht geraten) und wird zusaetzlich in `*cs-sep-fix-by-handle*` vermerkt,
damit `count_sep_scan.lsp` diesen Wert spaeter nicht per Geometrie
ueberschreibt. Nur fuer die Separator-Kopien — AS/ES sind keine Sensoren.
3b. **`csv:asmark-ids-setzen` + `csv:sepliste-ids-setzen`** — ebenfalls erst
jetzt moeglich: jedes Bauteil wird seinem `sepliste`-Eintrag zugeordnet und
seine ID unter `*csv-sepliste-id-by-handle*` (Key = Wrapper-Handle)
abgelegt; `csv:block-to-json` schreibt sie als Feld `id` in den Eintrag.
AS/ES laufen ueber die Marker (die ihre ID schon kennen, die Zuordnung
steht im Marker-Attribut `LFDNR`), SEP ueber die temporaeren Kopien und
`csv:sepliste-paare` — siehe eigener Abschnitt unten. `csv:asmark-ids-setzen`
traegt zusaetzlich die `ZUORDNUNG` (Wrapper-ID) am Marker nach; ohne sie
faende der naechste Export den Marker nicht wieder.
KEINE Kopie des Elements, sondern einen eigenen (ebenfalls temporaeren)
Marker, mit `ZUORDNUNG` direkt beim Erzeugen — siehe eigener Abschnitt
"Der AS/ES-Marker" unten.
2c. **`csv:element-proxies-erzeugen`** — nur Modus `all_elements`: Kopien der
uebrigen Kettenbausteine (Boegen, Streckenelemente, Umlenk-/Motorstation).
3. **`csv:ketten-verarbeiten`** — je `VF_n`/`GF_n` die KS-geordnete Kette
(`csv:kette-von`, einmal je Lauf berechnet) auswerten: Einheiten-Proxies
(Modus `group_vf_gf`), IDs in Kettenfolge, Separator-Typ VF/GF
(`csv:kette-sep-typen`) und die Stellvertreter der `sepliste`-Eintraege
(`csv:sepliste-kette-paare`, siehe eigener Abschnitt unten). Alles aus
DERSELBEN Kette - Einheiten-BB, Separator-Typ und TrackIds passen damit
zusammen.
3b. **`ssg-id-check-all`** (zweiter Lauf) — Restnummerierung (z.B. Kreisel-
Separator ohne Kette) und Duplikat-Korrektur unter den neuen
Stellvertretern; danach `csv:res-ids-schreiben` (reservierte IDs).
4. **`omni:update-all-attribs`** — Hoehe/Drehung aller Omniflo-Elemente vor
dem Export aktualisieren.
5. **`count_sep_scan.lsp::cs-zuordnung-lauf`** (nur bei Bedarf, siehe
@@ -229,8 +234,9 @@ zu zaehlen.
### Das Feld `id` je sepliste-Eintrag
Seit `csv:sepliste-ids-setzen` traegt JEDER Eintrag zusaetzlich die `id` des
realen Bauteils, das ihn in der Zeichnung vertritt:
JEDER Eintrag traegt zusaetzlich die `id` des realen Bauteils, das ihn in der
Zeichnung vertritt (zugeordnet in `csv:ketten-verarbeiten`, die ID selbst
liest `csv:block-to-json` erst beim Schreiben vom Stellvertreter):
```json
{"typ": "AS", "lfdnr": 1, "x": 5070.1, "y": 1199.2, "id": "0031"}
@@ -286,26 +292,21 @@ jeder, der keinem Kettenende mehr entspricht.
Im Export ist der Marker eine eigene Zeile (`pattern_ases_marker` in
`cfg/export.cfg`) und liefert die `id` des AS-/ES-Eintrags in der `sepliste`.
**Zuordnung Eintrag -> Kopie (`csv:sepliste-paare`).** Verglichen wird nur
innerhalb desselben Typmarkers (`AS`/`ES`/`SEP`) und EXKLUSIV: alle Paare
eines Typs werden nach Abstand sortiert, das kuerzeste zuerst genommen, danach
sind Eintrag UND Kopie verbraucht. Zwei Gruende gegen das naheliegende "je
Eintrag die naechste Kopie":
**Zuordnung Eintrag -> Bauteil (`csv:sepliste-kette-paare`).** Ueber die
REIHENFOLGE je Typ: das k-te `AS`/`SEP`/`ES` der sepliste (nach `lfdnr`) ist
das k-te `AS`/`SEP`/`ES` der KS-geordneten Kette (`csv:kette-von`). Die
sepliste entsteht beim Bau per `entnext`-Wanderung in Baureihenfolge, und
gebaut wird in Foerderrichtung - dieselbe Folge, die die KS-Kette
rekonstruiert. Die x/y-Koordinaten der sepliste werden dafuer NICHT benutzt.
- waehlen zwei Eintraege dieselbe Kopie, bleibt eine Kopie ohne Eintrag und
ein Eintrag ohne ID (genau dieses Muster verursacht in Python die
Separatoren ohne `Nachbarn`/`TrackIds`);
- EIN fehlerhafter Koordinatenwert in der sepliste (bekannter Fall: gespiegeltes
`x` bei `lfdnr=2`) verschiebt so keine anderen Zuordnungen mehr — alle
uebrigen Eintraege finden ihre Kopie ueber den kurzen Abstand zuerst, der
fehlerhafte bekommt den Rest zugeteilt. Liegt dieser Rest weiter als
`csv:sepliste-abstand-warnung-mm` (500 mm) entfernt, meldet der Export das
(`exp-sepliste-abstand`), ohne die Zuordnung zu verwerfen.
Die Sortierung ist eine strikte Totalordnung (Abstand, dann `lfdnr`, dann
Index) — `vl-sort` wirft Elemente weg, die unter der Vergleichsfunktion gleich
sind, zwei Paare mit identischem Abstand wuerden sonst zu einem verschmelzen.
Getestet in `tests/test_unit.lsp` (`csv:sepliste-paare/*`, zeichnungsfrei).
Frueher lief die Zuordnung ueber den kuerzesten Abstand zwischen sepliste-
Koordinate und Kopie (`csv:sepliste-paare`). Die sepliste-Koordinaten sind
aber teils gespiegelt (bekannter Fall: `x` bei `lfdnr=2`) - das vertauschte
real zwei Separatoren von HundM05 `VF_1` in TrackIds und Nachbarn. Passen
sepliste und Kette in der Anzahl nicht zusammen, meldet der Export das
(`exp-sepliste-ohne-proxy`); die ueberzaehligen Eintraege bleiben ohne `id`.
Getestet in `tests/test_unit.lsp` (`csv:sepliste-kette-paare/*`,
zeichnungsfrei).
## Phase 2 (Python): `lib/export_csv.py::process_blocks`
-4
View File
@@ -704,17 +704,13 @@
"exp-sep-zuordnung": "\n[%1] verpackte Separator-Kopie(n): ZUORDNUNG aus der ID des Wrapper-Blocks gesetzt.",
"exp-sep-zuordnung-ohne-id": "\n[%1] verpackte Separator-Kopie(n) ohne Wrapper-ID - ZUORDNUNG wird geometrisch bestimmt.",
"exp-sepliste-ids": "\n[EXPORT] %1 sepliste-Eintrag/Eintraege mit der ID des zugehoerigen Bauteils versehen.",
"exp-sepliste-ohne-id": "\n[EXPORT] %1 sepliste-Eintrag/Eintraege ohne ID - die Kopie hat kein gefuelltes ID-Attribut.",
"exp-sepliste-ohne-proxy": "\n[EXPORT] WARNUNG: Block '%1': %2 sepliste-Eintrag/Eintraege ohne passende Kopie - diese Eintraege bleiben im Export ohne ID.",
"exp-sepliste-abstand": "\n[EXPORT] WARNUNG: Block '%1': %2-Eintrag lfdnr=%3 liegt %4 mm von seinem Bauteil entfernt - sepliste-Koordinate pruefen (Zuordnung bleibt gueltig).",
"exp-asmark-blockdef": "\n[EXPORT] Blockdefinition '%1' fuer die AS/ES-Marker angelegt.",
"exp-asmark-blockdef-fehler": "\n[EXPORT] WARNUNG: Blockdefinition '%1' konnte nicht angelegt werden - es werden keine AS/ES-Marker gesetzt.",
"exp-asmark-bilanz": "\n[EXPORT] AS/ES-Marker: %1 neu, %2 mit bisheriger ID uebernommen, %3 verwaiste entfernt.",
"exp-asmark-ids": "\n[EXPORT] %1 AS/ES-Marker mit ihrer ID am sepliste-Eintrag vermerkt.",
"exp-unitmark-blockdef": "\n[EXPORT] Blockdefinition '%1' fuer die Einheiten-Proxies angelegt.",
"exp-unitmark-blockdef-fehler": "\n[EXPORT] WARNUNG: Blockdefinition '%1' konnte nicht angelegt werden - es werden keine Foerder-/Gefaelleeinheiten exportiert.",
"exp-unitmark-bilanz": "\n[EXPORT] Foerder-/Gefaelleeinheiten: %1 Proxy(s) erzeugt, %2 alte entfernt.",
"exp-unitmark-ids": "\n[EXPORT] %1 Einheiten-Proxy(s) mit ID versehen.",
"exp-kette-luecke": "\n[EXPORT] WARNUNG: Kette '%1' reisst ab (kein K1 auf dem letzten K2) - %2 Baustein(e) als eigene Teilkette weitergefuehrt, Einheitengrenzen dort pruefen.",
"exp-hilfskopien-behalten": "\n[EXPORT] csv_leave_proxies=1: %1 %2 bleiben in der Zeichnung (Abschalten: (dbg-schalter-off \"csv_leave_proxies\"))",
"exp-art-separator": "Separator-Kopie(n)",
-4
View File
@@ -704,17 +704,13 @@
"exp-sep-zuordnung": "\n[%1] packed separator copy/copies: ZUORDNUNG set from the wrapper block ID.",
"exp-sep-zuordnung-ohne-id": "\n[%1] packed separator copy/copies without a wrapper ID - ZUORDNUNG determined geometrically.",
"exp-sepliste-ids": "\n[EXPORT] %1 sepliste entry/entries tagged with the ID of the matching part.",
"exp-sepliste-ohne-id": "\n[EXPORT] %1 sepliste entry/entries without an ID - the copy has no ID attribute value.",
"exp-sepliste-ohne-proxy": "\n[EXPORT] WARNING: block '%1': %2 sepliste entry/entries without a matching copy - those entries stay without an ID in the export.",
"exp-sepliste-abstand": "\n[EXPORT] WARNING: block '%1': %2 entry lfdnr=%3 is %4 mm away from its part - check the sepliste coordinate (the mapping stays valid).",
"exp-asmark-blockdef": "\n[EXPORT] Block definition '%1' for the AS/ES markers created.",
"exp-asmark-blockdef-fehler": "\n[EXPORT] WARNING: block definition '%1' could not be created - no AS/ES markers are placed.",
"exp-asmark-bilanz": "\n[EXPORT] AS/ES markers: %1 new, %2 kept with their previous ID, %3 orphaned ones removed.",
"exp-asmark-ids": "\n[EXPORT] %1 AS/ES marker ID(s) recorded at their sepliste entry.",
"exp-unitmark-blockdef": "\n[EXPORT] Block definition '%1' for the unit proxies created.",
"exp-unitmark-blockdef-fehler": "\n[EXPORT] WARNING: block definition '%1' could not be created - no conveyor/gravity units are exported.",
"exp-unitmark-bilanz": "\n[EXPORT] Conveyor/gravity units: %1 proxy(s) created, %2 old ones removed.",
"exp-unitmark-ids": "\n[EXPORT] %1 unit proxy(s) given an ID.",
"exp-kette-luecke": "\n[EXPORT] WARNING: chain '%1' is broken (no K1 at the last K2) - %2 element(s) continued as a separate sub-chain, check the unit boundaries there.",
"exp-hilfskopien-behalten": "\n[EXPORT] csv_leave_proxies=1: %1 %2 remain in the drawing (switch off: (dbg-schalter-off \"csv_leave_proxies\"))",
"exp-art-separator": "separator copy(ies)",
+2 -2
View File
@@ -597,8 +597,8 @@ def map_sepliste_kette_items(items, sep_kette, dbg=None):
Separator_SP-Kopie (csv:sep-proxies-erzeugen, export.lsp). Beide Wege
wuerden sonst dieselben physischen Bauteile DOPPELT zaehlen.
Zuordnung: EXAKTER ID-Abgleich. Seit csv:sepliste-ids-setzen/
csv:asmark-ids-setzen (Lisp/export.lsp) traegt praktisch jeder sepliste-
Zuordnung: EXAKTER ID-Abgleich. Seit csv:ketten-verarbeiten
(Lisp/export.lsp, Zuordnung ueber die KS-Kette) traegt praktisch jeder sepliste-
Eintrag bereits die TeileId des ihn vertretenden Items als Feld "id" -
das Item mit GENAU dieser teileid IST der gesuchte Partner. Kein Rate-/
Naeheverfahren mehr noetig, keine der frueheren Ambiguitaeten (ein
+1 -1
View File
@@ -1175,7 +1175,7 @@ def compute_sep_kette(items, dbg=None):
compute_kreisel_umlauf). "id" ist die TeileId des Bauteils, das diesen
Eintrag in der Zeichnung vertritt (AS/ES ueber den
ZZ_ASES_MARKER, SEP ueber die beim Export ausgepackte temporaere
Separator_SP-Kopie - siehe csv:sepliste-ids-setzen, Lisp/export.lsp) -
Separator_SP-Kopie - siehe csv:ketten-verarbeiten, Lisp/export.lsp) -
leerer String, wenn (noch) keine ID zugewiesen wurde (Altbestand).
Kein x/y mehr: die sepliste-XDATA traegt seit 2026-09-25 keine
+1 -1
View File
@@ -221,7 +221,7 @@ class TestSeplisteNachbarnAufgeloest:
vertreten (AS/ES ueber den ZZ_ASES_MARKER, SEP ueber den freien-
Separator-Pfad in process_blocks) - jeder sepliste-Eintrag traegt
bereits die TeileId seines Items als Feld "id" (siehe
csv:asmark-ids-setzen/csv:sepliste-ids-setzen, Lisp/export.lsp)."""
csv:ketten-verarbeiten, Lisp/export.lsp)."""
k = _kreisel("0001", 0.0, 0.0, 0.0, abstand=1000.0)
strecke = {
"teileart": "ILS 2.0 Gefaellestrecke",
+2 -2
View File
@@ -5,8 +5,8 @@ test_export_separatorliste.py - "TrackIds"-Spalte einer Strecke (VF_n/GF_n).
Laeuft komplett ohne BricsCAD (reine Python-Logik, siehe lib/export_csv.py).
Eine Strecke (VF_n/GF_n) traegt in ihrer "sepliste"-XDATA je AS-/SEP-/ES-
Eintrag x/y sowie (seit csv:asmark-ids-setzen/csv:sepliste-ids-setzen,
Lisp/export.lsp) ein Feld "id" - die TeileId des Bauteils, das diesen
Eintrag x/y sowie (seit csv:ketten-verarbeiten, Lisp/export.lsp) ein
Feld "id" - die TeileId des Bauteils, das diesen
Eintrag in der Zeichnung vertritt (AS/ES ueber den
ZZ_ASES_MARKER, SEP ueber die beim Export ausgepackte temporaere
Separator_SP-Kopie). write_separatorliste_merkmale() soll daraus, ueber die
+33 -47
View File
@@ -311,15 +311,6 @@
;; ------------------------------------------------------------
;; TESTS: export.lsp - CSV/KOS-Kodierung
;; ------------------------------------------------------------
;; Hilfsfunktion der csv:sepliste-paare-Tests: nur (lfdnr index) vergleichen,
;; nicht den Fliesskomma-Abstand. Bewusst auf Top-Level (nicht im Testblock):
;; per defun IN einem Testblock definierte Funktionen sind in BricsCAD im
;; laufenden Durchlauf nicht zuverlaessig gebunden (siehe Ladearchitektur oben).
(defun tu-paare (e p)
(mapcar (function (lambda (x) (list (nth 0 x) (nth 1 x))))
(csv:sepliste-paare e p))
)
(defun tu-tests-export ()
(princ "\n[export]")
@@ -344,40 +335,27 @@
;; json-escape: Anfuehrungszeichen maskieren
(tu-eq "csv:json-escape/quote" "a\\\"b" (csv:json-escape "a\"b"))
;; --- csv:sepliste-paare: sepliste-Eintrag <-> ausgepackte Kopie ---------
;; Reine Rechenfunktion (Eintraege + Kopien rein, (lfdnr index abstand)
;; raus) - hier ohne Zeichnung testbar. Im Export liefert
;; csv:sepliste-ids-setzen die Kopien in Erzeugungsreihenfolge; nur der
;; Index zaehlt, darum vergleichen die Tests (lfdnr index) statt der
;; Fliesskomma-Abstaende.
(tu-eq "csv:sepliste-paare/leer" nil (csv:sepliste-paare nil nil))
;; Gerade Kette AS -> SEP -> SEP -> ES; Kopien bewusst in anderer
;; Reihenfolge als die sepliste (die Erzeugungsreihenfolge der Kopien folgt
;; der Blockdefinition, nicht der Bauabfolge).
(setq _e '(("AS" 1 0.0 0.0) ("SEP" 2 1000.0 0.0) ("SEP" 3 2000.0 0.0) ("ES" 4 3000.0 0.0)))
(setq _p '(("SEP" 2000.0 0.0) ("AS" 0.0 0.0) ("ES" 3000.0 0.0) ("SEP" 1000.0 0.0)))
(tu-eq "csv:sepliste-paare/kette" '((1 1) (2 3) (3 0) (4 2)) (tu-paare _e _p))
;; EIN fehlerhafter Koordinatenwert (bekannter Fehlerfall: gespiegeltes x
;; bei lfdnr=2) darf die uebrigen Zuordnungen nicht verschieben - die
;; exklusive Vergabe teilt dem fehlerhaften Eintrag den Rest zu.
(setq _e '(("SEP" 1 1000.0 0.0) ("SEP" 2 -1000.0 -5000.0) ("SEP" 3 3000.0 0.0)))
(setq _p '(("SEP" 1000.0 0.0) ("SEP" 2000.0 0.0) ("SEP" 3000.0 0.0)))
(tu-eq "csv:sepliste-paare/gespiegelte-koordinate" '((1 0) (2 1) (3 2)) (tu-paare _e _p))
;; Gleiche Abstaende duerfen kein Paar verschlucken: vl-sort wirft
;; Elemente weg, die unter der Vergleichsfunktion gleich sind - deshalb
;; sortiert csv:sepliste-paare nach (Abstand, lfdnr, Index).
(setq _e '(("SEP" 1 0.0 0.0) ("SEP" 2 0.0 0.0)))
(setq _p '(("SEP" 0.0 0.0) ("SEP" 0.0 0.0)))
(tu-eq "csv:sepliste-paare/gleiche-abstaende" '((1 0) (2 1)) (tu-paare _e _p))
;; Typ trennt: eine AS-Kopie wird nie einem SEP-Eintrag zugeteilt, der
;; SEP-Eintrag bleibt ohne Partner (und im Export ohne ID).
(setq _e '(("AS" 1 0.0 0.0) ("SEP" 2 10.0 0.0)))
(setq _p '(("AS" 5.0 0.0)))
(tu-eq "csv:sepliste-paare/typ-trennt" '((1 0)) (tu-paare _e _p))
;; --- csv:sepliste-kette-paare: sepliste-Eintrag <-> Kettenbaustein -------
;; Zuordnung ueber die Reihenfolge je Typ (k-tes AS/SEP/ES der sepliste =
;; k-tes der geordneten Kette), Rueckgabe ((lfdnr . index) ...).
(tu-nil "csv:sepliste-kette-paare/leer" (csv:sepliste-kette-paare nil nil))
;; HundM05-artige Kette: Koordinaten spielen keine Rolle (auch gespiegelte
;; x-Werte aendern nichts), Bausteine ohne sepliste-Typ werden uebersprungen.
(setq _e '(("AS" 1 0.0 0.0) ("SEP" 2 -9999.0 0.0) ("SEP" 3 2000.0 0.0) ("ES" 4 3000.0 0.0)))
(tu-eq "csv:sepliste-kette-paare/kette"
'((1 . 0) (2 . 2) (3 . 5) (4 . 7))
(csv:sepliste-kette-paare _e
'("AS" "STRECKENELEMENT" "SEP" "UMLENKSTATION" "MOTORSTATION" "SEP" "BOGEN" "ES")))
;; lfdnr-Reihenfolge zaehlt, nicht die Reihenfolge der Eintraege in der Liste.
(setq _e '(("SEP" 3 0.0 0.0) ("AS" 1 0.0 0.0) ("SEP" 2 0.0 0.0)))
(tu-eq "csv:sepliste-kette-paare/unsortiert"
'((1 . 0) (2 . 1) (3 . 2))
(csv:sepliste-kette-paare _e '("AS" "SEP" "SEP")))
;; Mehr Eintraege als Bausteine: die ueberzaehligen bleiben ohne Partner.
(setq _e '(("AS" 1 0.0 0.0) ("SEP" 2 0.0 0.0) ("SEP" 3 0.0 0.0)))
(tu-eq "csv:sepliste-kette-paare/fehlender-baustein"
'((1 . 0) (2 . 2))
(csv:sepliste-kette-paare _e '("AS" "BOGEN" "SEP" "ES")))
;; --- csv:asmark-finden: bisherigen AS/ES-Marker im Bestand wiederfinden ---
;; Schluessel ist (Wrapper-ID, Typ, lfdnr) - alle drei muessen passen, sonst
@@ -415,10 +393,18 @@
(vl-symbol-name (car b)))))))
(setq *csv-res-sammlung* _rs)
;; csv:proxy-typ: Typmarker aus dem Blocknamen (Grundlage der Zuordnung).
(tu-eq "csv:proxy-typ/as" "AS" (csv:proxy-typ "AS_Element_90_links_3D"))
(tu-eq "csv:proxy-typ/es" "ES" (csv:proxy-typ "ES_Element_30_rechts_2D"))
(tu-eq "csv:proxy-typ/sep" "SEP" (csv:proxy-typ "Separator_SP_3D"))
;; csv:pattern-nested-element: Suchmuster = alle Familienmuster aus
;; csv:element-familien - jede Familie ist also auch klassifizierbar.
(tu-eq "csv:pattern-nested-element/aus-familien"
(ssg-join (mapcar 'cdr (csv:element-familien)) ",")
(csv:pattern-nested-element))
(tu-true "csv:element-familien/jedes-muster-klassifiziert"
(not (vl-some (function (lambda (f)
(not (equal (car f) (csv:element-teileart
(vl-string-subst "X" "*"
(substr (cdr f) 1 (cond ((vl-string-search "," (cdr f)))
((strlen (cdr f)))))))))))
(csv:element-familien))))
;; csv:element-teileart: TeileArt-Familie eines ausgepackten VF_n/GF_n-
;; Bausteins aus dem Blocknamen (Boegen/Streckenelement/Umlenk-/Motor-