feat: Sivas-Merkmale 4427-4432 (AS-/ES-Element) im Export befuellen
Die Streckenbloecke GF_N und VF_N tragen Winkel und Seite ihres AS-/ES-
Elements bereits als Attribute des gemeinsamen Schemas (WINKEL_AS/SEITE_AS/
WINKEL_ES/SEITE_ES, *strecke-attr-front* in ssg_core.lsp). Diese Information
landet jetzt auch im details-JSON des Sivas-Exports.
Zuordnung (Sivas-Hierarchie: 4431/4432 schalten Winkel und Seite frei):
4431/4432 AS-/ES-Element vorhanden Ja/Nein
4427/4429 Winkel "30 °"/"90 °"
4428/4430 Seite links/rechts
Die Zuordnung steht vollstaendig in cfg/sivas.cfg - mit denselben sechs
Zeilen in [gefaellestrecke] und [variofoerderer], jeweils direkt hinter 2950,
was auch die Reihenfolge im details-JSON bestimmt.
Ob ein Element vorhanden ist, entscheidet ausschliesslich WINKEL_AS/WINKEL_ES:
das Schema laesst den Winkel leer, wenn keines gewaehlt wurde, waehrend
SEITE_AS/SEITE_ES mit "rechts" immer einen Vorgabewert tragen. Ohne Element
bleiben Winkel UND Seite leer, damit in Sivas keine Seite unter einem
"Nein"-Knoten haengt.
Weitere Punkte:
- sivas_mapping: neuer Dekorator @braucht_attribs. Ein so markierter
Transform wird als fn(wert, attribs) statt fn(wert) aufgerufen und sieht
damit die uebrigen Attribute des Blocks - noetig, weil die Seite vom
Winkel abhaengt. Ohne diese Klammer muessten bedingte Merkmale wieder als
Python-Code aus der Config herauswandern.
- Die Winkel-Schreibweise der Sivas-Auswahlliste ("30 °" mit Leerzeichen vor
dem Gradzeichen) steht als Tabelle [as_es_winkel_anzeige] in sivas.cfg,
Bauart wie [geruest_typ_anzeige] - weicht Sivas davon ab, ist das die
einzige Stelle zum Nachziehen.
- gefaellestrecke_signature beruecksichtigt AS/ES: zwei sonst baugleiche
Gefaellestrecken mit AS links bzw. rechts bleiben getrennte Zeilen, sonst
zeigte die gemeinsame Zeile nur die Seite des ersten Blocks.
- Altbestand ohne diese Attribute meldet "Nein" statt abzubrechen.
- Merkmalsstamm_in_Sivas.xlsx auf den aktuellen Sivas-Stand gebracht
(enthaelt neben 4427-4432 auch 4002, 7010-7013 und Klartext-Korrekturen;
4339/4383 heissen jetzt eindeutig "... Gefaellestrecke"/"... Variofoerderer").
- 12 neue Tests in tests/test_export_sivas_as_es.py, ohne BricsCAD lauffaehig.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Binary file not shown.
+51
-4
@@ -28,19 +28,45 @@
|
|||||||
# (TRANSFORMS-Dict), die den ermittelten Rohwert
|
# (TRANSFORMS-Dict), die den ermittelten Rohwert
|
||||||
# (Attribut- oder Default-Wert) in die Sivas-Anzeige
|
# (Attribut- oder Default-Wert) in die Sivas-Anzeige
|
||||||
# umwandelt (z.B. "0"/"1" -> "Ja"/"Nein"). Bekannte Namen:
|
# umwandelt (z.B. "0"/"1" -> "Ja"/"Nein"). Bekannte Namen:
|
||||||
# ja_nein, geruest_typ_anzeige. Ein unbekannter Name
|
# ja_nein, geruest_typ_anzeige, mm_zu_m, as_es_vorhanden,
|
||||||
|
# as_es_winkel, as_seite, es_seite. Ein unbekannter Name
|
||||||
# bricht NICHT ab, der Rohwert wird unveraendert
|
# bricht NICHT ab, der Rohwert wird unveraendert
|
||||||
# uebernommen (siehe sivas_mapping.anwenden).
|
# uebernommen (siehe sivas_mapping.anwenden).
|
||||||
|
# Soll ein Merkmal ohne eigenes Attribut nur per Transform
|
||||||
|
# entstehen, braucht die Zeile trotzdem den ":" vor dem
|
||||||
|
# "|" ("WINKEL_AS : | as_es_vorhanden") - sonst gilt der
|
||||||
|
# Transform-Name als Fallback-Attributname.
|
||||||
|
# Transforms, die mit @braucht_attribs markiert sind
|
||||||
|
# (as_seite/es_seite), sehen zusaetzlich alle uebrigen
|
||||||
|
# Attribute des Blocks - noetig, wenn ein Merkmal von
|
||||||
|
# einem ZWEITEN Attribut abhaengt (Seite nur, wenn der
|
||||||
|
# zugehoerige Winkel ueberhaupt ein Element ausweist).
|
||||||
#
|
#
|
||||||
# Abschnittsnamen entsprechen den bisherigen build_*_details-Funktionen in
|
# Abschnittsnamen entsprechen den bisherigen build_*_details-Funktionen in
|
||||||
# export_sivas.py: [gefaellestrecke], [kreisel], [eckrad], [geruest]. Die
|
# export_sivas.py: [gefaellestrecke], [kreisel], [eckrad], [geruest]. Die
|
||||||
# geruest-typ-Anzeige-Tabelle (ASCII-Attributwert -> Sivas-Klartext mit
|
# Anzeige-Tabellen (ASCII-Attributwert -> Sivas-Klartext/Optionswert:
|
||||||
# Umlauten) UND SEPARATOR_BEARBEITUNG_ANZEIGE bleiben eigene, kleine
|
# [geruest_typ_anzeige], [as_es_winkel_anzeige]) UND
|
||||||
# Abschnitte weiter unten.
|
# SEPARATOR_BEARBEITUNG_ANZEIGE bleiben eigene, kleine Abschnitte weiter
|
||||||
|
# unten.
|
||||||
|
#
|
||||||
|
# [gefaellestrecke] und [variofoerderer] fuehren die AS-/ES-Merkmale
|
||||||
|
# (4427-4432) absichtlich DOPPELT: GF_N- und VF_N-Bloecke tragen dieselben
|
||||||
|
# Attribute des gemeinsamen Strecken-Schemas, und jeder Abschnitt soll fuer
|
||||||
|
# sich lesbar bleiben. Aenderungen dort bitte in beiden nachziehen (der Test
|
||||||
|
# tests/test_export_sivas_as_es.py::test_zuordnung_steht_in_der_config wacht
|
||||||
|
# darueber).
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
||||||
[gefaellestrecke]
|
[gefaellestrecke]
|
||||||
2950= MONTAGEHOEHE_m : 0
|
2950= MONTAGEHOEHE_m : 0
|
||||||
|
# AS-/ES-Element, Reihenfolge wie die Sivas-Hierarchie (identisch in
|
||||||
|
# [variofoerderer]): 4431/4432 Ja/Nein schalten Winkel und Seite frei.
|
||||||
|
4431= WINKEL_AS : | as_es_vorhanden
|
||||||
|
4427= WINKEL_AS : | as_es_winkel
|
||||||
|
4428= SEITE_AS : | as_seite
|
||||||
|
4432= WINKEL_ES : | as_es_vorhanden
|
||||||
|
4429= WINKEL_ES : | as_es_winkel
|
||||||
|
4430= SEITE_ES : | es_seite
|
||||||
4384= : Gefällestrecke
|
4384= : Gefällestrecke
|
||||||
4318= L_GF_m
|
4318= L_GF_m
|
||||||
4391= GF_WINKEL
|
4391= GF_WINKEL
|
||||||
@@ -85,6 +111,14 @@ Farbe= FARBE
|
|||||||
# Die Gefaelle-/Vario-Segmentpaare (4312-4392, 4353/4354/4386) haengen an der
|
# Die Gefaelle-/Vario-Segmentpaare (4312-4392, 4353/4354/4386) haengen an der
|
||||||
# Listenlaenge von L_GF_m/L_VF_m und bleiben Code.
|
# Listenlaenge von L_GF_m/L_VF_m und bleiben Code.
|
||||||
2950= MONTAGEHOEHE_m : 0
|
2950= MONTAGEHOEHE_m : 0
|
||||||
|
# AS-/ES-Element, Reihenfolge wie die Sivas-Hierarchie (identisch in
|
||||||
|
# [gefaellestrecke]): 4431/4432 Ja/Nein schalten Winkel und Seite frei.
|
||||||
|
4431= WINKEL_AS : | as_es_vorhanden
|
||||||
|
4427= WINKEL_AS : | as_es_winkel
|
||||||
|
4428= SEITE_AS : | as_seite
|
||||||
|
4432= WINKEL_ES : | as_es_vorhanden
|
||||||
|
4429= WINKEL_ES : | as_es_winkel
|
||||||
|
4430= SEITE_ES : | es_seite
|
||||||
4329= GF_Bogen_L_90 : 0
|
4329= GF_Bogen_L_90 : 0
|
||||||
4330= GF_Bogen_L_60 : 0
|
4330= GF_Bogen_L_60 : 0
|
||||||
4331= GF_Bogen_L_30 : 0
|
4331= GF_Bogen_L_30 : 0
|
||||||
@@ -103,6 +137,19 @@ Farbe= FARBE
|
|||||||
3992= GERUEST_EINZELMODUL : 0 | ja_nein
|
3992= GERUEST_EINZELMODUL : 0 | ja_nein
|
||||||
3993= GERUEST_TYP : Schoenenberger Geruest | geruest_typ_anzeige
|
3993= GERUEST_TYP : Schoenenberger Geruest | geruest_typ_anzeige
|
||||||
|
|
||||||
|
[as_es_winkel_anzeige]
|
||||||
|
# Attributwert WINKEL_AS/WINKEL_ES -> Optionswert der Sivas-Auswahlliste zu
|
||||||
|
# Merkmal 4427/4429. Im Merkmalstamm heissen die Optionen "30 °"/"90 °" (mit
|
||||||
|
# Leerzeichen vor dem Gradzeichen) - das Attribut in der Zeichnung bleibt die
|
||||||
|
# nackte Zahl. Gleiche Bauart wie [geruest_typ_anzeige]: steht ein Winkel
|
||||||
|
# hier NICHT drin, wird er unveraendert uebernommen.
|
||||||
|
#
|
||||||
|
# >>> Falls Sivas den Import mit "30 °" ablehnt, ist DIESE Tabelle die
|
||||||
|
# >>> einzige Stelle zum Nachziehen (z.B. auf "30°" ohne Leerzeichen oder
|
||||||
|
# >>> auf die nackte Zahl) - der Code bleibt unberuehrt.
|
||||||
|
30= 30 °
|
||||||
|
90= 90 °
|
||||||
|
|
||||||
[geruest_typ_anzeige]
|
[geruest_typ_anzeige]
|
||||||
# ASCII-Attributwert (GERUEST_TYP) -> Sivas-Klartext mit Umlauten/Sonder-
|
# ASCII-Attributwert (GERUEST_TYP) -> Sivas-Klartext mit Umlauten/Sonder-
|
||||||
# zeichen (Attribute selbst bleiben ASCII, siehe CLAUDE.md-Konvention).
|
# zeichen (Attribute selbst bleiben ASCII, siehe CLAUDE.md-Konvention).
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ der Wahrheit ist der Code in `lib/export_sivas.py` - diese Datei ist ein
|
|||||||
Backup/Nachschlagewerk, bei Aenderungen am Code bitte hier nachziehen.
|
Backup/Nachschlagewerk, bei Aenderungen am Code bitte hier nachziehen.
|
||||||
|
|
||||||
Stand: abgeglichen mit `lib/export_sivas.py` nach der Umstellung von
|
Stand: abgeglichen mit `lib/export_sivas.py` nach der Umstellung von
|
||||||
beschreibenden JSON-Keys auf reine Merkmalnummern (Sept. 2026).
|
beschreibenden JSON-Keys auf reine Merkmalnummern (Sept. 2026), ergaenzt um
|
||||||
|
die AS-/ES-Element-Merkmale 4427-4432 (Okt. 2026).
|
||||||
|
|
||||||
## ILS 2.0 Kreisel (SivasNr 6200, Dispogruppe 20)
|
## ILS 2.0 Kreisel (SivasNr 6200, Dispogruppe 20)
|
||||||
|
|
||||||
@@ -59,6 +60,7 @@ immer 1. Sivas kennt je Streckengruppe nur EIN Gefaelle-Segment-Paar
|
|||||||
| 4381 | Streckengruppe - Anzahl der Separatoren - Variofoerderer | `ANZAHL_SEPARATOR` | **voller Blockwert** (Aufteilung noch offen, siehe 4337) |
|
| 4381 | Streckengruppe - Anzahl der Separatoren - Variofoerderer | `ANZAHL_SEPARATOR` | **voller Blockwert** (Aufteilung noch offen, siehe 4337) |
|
||||||
| 4382 | (dieselbe Bezeichnung wie 4338 im Merkmalstamm) | - | fest `SEPARATOR_BEARBEITUNG_ANZEIGE` |
|
| 4382 | (dieselbe Bezeichnung wie 4338 im Merkmalstamm) | - | fest `SEPARATOR_BEARBEITUNG_ANZEIGE` |
|
||||||
| 4383 | Streckengruppe - Anzahl der Scanner (Vario-Anteil) | `ANZAHL_SCANNER` | **voller Blockwert** |
|
| 4383 | Streckengruppe - Anzahl der Scanner (Vario-Anteil) | `ANZAHL_SCANNER` | **voller Blockwert** |
|
||||||
|
| 4427-4432 | AS-/ES-Element (vorhanden/Winkel/Seite) | `WINKEL_AS`/`SEITE_AS`/`WINKEL_ES`/`SEITE_ES` | siehe eigener Abschnitt unten |
|
||||||
| 3992 | Geruest fuer Einzelmodul | `GERUEST_EINZELMODUL` | wie Kreisel |
|
| 3992 | Geruest fuer Einzelmodul | `GERUEST_EINZELMODUL` | wie Kreisel |
|
||||||
| 3993 | Geruestoption fuer Einzelmodul | `GERUEST_TYP` | wie Kreisel |
|
| 3993 | Geruestoption fuer Einzelmodul | `GERUEST_TYP` | wie Kreisel |
|
||||||
|
|
||||||
@@ -86,9 +88,56 @@ Stueckzahl der Gruppe steht im Merkmal 4311.
|
|||||||
| 4337 | Streckengruppe - Anzahl der Separatoren - Gefaellestrecke | `ANZAHL_SEPARATOR` | direkt (kein Split noetig, kein Vario-Anteil vorhanden) |
|
| 4337 | Streckengruppe - Anzahl der Separatoren - Gefaellestrecke | `ANZAHL_SEPARATOR` | direkt (kein Split noetig, kein Vario-Anteil vorhanden) |
|
||||||
| 4338 | Streckengruppe - Bearbeitung Gefaellestreckenteilstueck fuer Separator (829516050) | - | fest `SEPARATOR_BEARBEITUNG_ANZEIGE` |
|
| 4338 | Streckengruppe - Bearbeitung Gefaellestreckenteilstueck fuer Separator (829516050) | - | fest `SEPARATOR_BEARBEITUNG_ANZEIGE` |
|
||||||
| 4339 | Streckengruppe - Anzahl der Scanner | `ANZAHL_SCANNER` | direkt |
|
| 4339 | Streckengruppe - Anzahl der Scanner | `ANZAHL_SCANNER` | direkt |
|
||||||
|
| 4427-4432 | AS-/ES-Element (vorhanden/Winkel/Seite) | `WINKEL_AS`/`SEITE_AS`/`WINKEL_ES`/`SEITE_ES` | siehe eigener Abschnitt unten |
|
||||||
| 3992 | Geruest fuer Einzelmodul | `GERUEST_EINZELMODUL` | wie Kreisel |
|
| 3992 | Geruest fuer Einzelmodul | `GERUEST_EINZELMODUL` | wie Kreisel |
|
||||||
| 3993 | Geruestoption fuer Einzelmodul | `GERUEST_TYP` | wie Kreisel |
|
| 3993 | Geruestoption fuer Einzelmodul | `GERUEST_TYP` | wie Kreisel |
|
||||||
|
|
||||||
|
Die Gruppierung (`gefaellestrecke_signature`) beruecksichtigt AS-/ES-Element
|
||||||
|
mit: zwei sonst baugleiche Gefaellestrecken mit AS links bzw. AS rechts
|
||||||
|
bleiben getrennte Zeilen, sonst zeigte die gemeinsame Zeile nur die Seite des
|
||||||
|
ersten Blocks.
|
||||||
|
|
||||||
|
## AS-/ES-Element (4427-4432) - gilt fuer VF_N UND GF_N
|
||||||
|
|
||||||
|
Die Zuordnung steht vollstaendig in `cfg/sivas.cfg` - mit denselben sechs
|
||||||
|
Zeilen in `[gefaellestrecke]` UND `[variofoerderer]`, weil beide Blockarten
|
||||||
|
dieselben Attribute des gemeinsamen Strecken-Schemas tragen
|
||||||
|
(`*strecke-attr-front*` in `ssg_core.lsp`). In `export_sivas.py` stehen nur
|
||||||
|
die Transform-Funktionen.
|
||||||
|
|
||||||
|
Sivas-Hierarchie (Merkmalstamm): 4431/4432 (`"Ja"`/`"Nein"`) sind die
|
||||||
|
Oberknoten, Winkel und Seite haengen als Unterknoten darunter - darum auch
|
||||||
|
diese Reihenfolge in der Config.
|
||||||
|
|
||||||
|
| Merkmalnr | Bezeichnung (Merkmalstamm) | Block-Attribut | Transform | Berechnung |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| 4431 | AS-Element | `WINKEL_AS` | `as_es_vorhanden` | `"Ja"`, wenn ein Winkel gesetzt ist, sonst `"Nein"` |
|
||||||
|
| 4427 | AS-Element - Winkel | `WINKEL_AS` | `as_es_winkel` | Optionswert der Auswahlliste (`"30"` -> `"30 °"`, Tabelle `[as_es_winkel_anzeige]`); leer, wenn kein AS-Element |
|
||||||
|
| 4428 | AS-Element - Seite | `SEITE_AS` | `as_seite` | kleingeschrieben (`"links"`/`"rechts"`); leer, wenn kein AS-Element |
|
||||||
|
| 4432 | ES-Element | `WINKEL_ES` | `as_es_vorhanden` | wie 4431 |
|
||||||
|
| 4429 | ES-Element - Winkel | `WINKEL_ES` | `as_es_winkel` | wie 4427 |
|
||||||
|
| 4430 | ES-Element - Seite | `SEITE_ES` | `es_seite` | wie 4428 |
|
||||||
|
|
||||||
|
**Warum der Winkel ueber das Vorhandensein entscheidet und nicht die Seite:**
|
||||||
|
das Schema laesst `WINKEL_AS`/`WINKEL_ES` leer, wenn kein Element gewaehlt
|
||||||
|
wurde, waehrend `SEITE_AS`/`SEITE_ES` mit `"rechts"` immer einen Vorgabewert
|
||||||
|
tragen. Ohne Element bleiben darum Winkel UND Seite leer - sonst stuende in
|
||||||
|
Sivas eine Seite unter einem `"Nein"`-Knoten.
|
||||||
|
|
||||||
|
**Winkel-Schreibweise:** die Sivas-Auswahlliste fuehrt `"30 °"`/`"90 °"` (mit
|
||||||
|
Leerzeichen vor dem Gradzeichen), das Block-Attribut dagegen die nackte Zahl.
|
||||||
|
Die Uebersetzung steht als Tabelle `[as_es_winkel_anzeige]` in `sivas.cfg`
|
||||||
|
(gleiche Bauart wie `[geruest_typ_anzeige]`) - weicht Sivas davon ab, ist das
|
||||||
|
die einzige Stelle zum Nachziehen. Ein Winkel ohne Eintrag dort wird
|
||||||
|
unveraendert uebernommen.
|
||||||
|
|
||||||
|
**Neu im Mapping-Mechanismus:** `4428`/`4430` brauchen ein ZWEITES Attribut
|
||||||
|
(die Seite haengt am Winkel). Dafuer gibt es in `sivas_mapping.py` den
|
||||||
|
Dekorator `@braucht_attribs` - ein so markierter Transform wird als
|
||||||
|
`fn(wert, attribs)` statt `fn(wert)` aufgerufen und sieht damit die uebrigen
|
||||||
|
Attribute des Blocks. Ohne diese Klammer muessten bedingte Merkmale wieder
|
||||||
|
als Python-Code aus der Config herauswandern.
|
||||||
|
|
||||||
## ILS 2.0 Zusatzmodul (SivasNr 6215, Dispogruppe 20)
|
## ILS 2.0 Zusatzmodul (SivasNr 6215, Dispogruppe 20)
|
||||||
|
|
||||||
BTMT-Beladestationen UND Abwurfstationen (Klammerbuegel-Entladung) in EINER
|
BTMT-Beladestationen UND Abwurfstationen (Klammerbuegel-Entladung) in EINER
|
||||||
|
|||||||
+89
-2
@@ -120,14 +120,94 @@ def mm_zu_m(wert_mm):
|
|||||||
return str(round(safe_float(wert_mm, 0.0) / 1000.0, 3))
|
return str(round(safe_float(wert_mm, 0.0) / 1000.0, 3))
|
||||||
|
|
||||||
|
|
||||||
|
# --- AS-/ES-Element (Merkmale 4427-4432) ---------------------------------
|
||||||
|
# Zuordnung komplett in cfg/sivas.cfg ([gefaellestrecke]/[variofoerderer]),
|
||||||
|
# hier stehen nur die Transforms. Die Sivas-Hierarchie ist: 4431/4432
|
||||||
|
# ("AS-Element"/"ES-Element", Ja/Nein) schalten die Unterknoten Winkel
|
||||||
|
# (4427/4429) und Seite (4428/4430) frei.
|
||||||
|
#
|
||||||
|
# Ob ein Element vorhanden ist, entscheidet AUSSCHLIESSLICH WINKEL_AS/
|
||||||
|
# WINKEL_ES: das gemeinsame Strecken-Schema (*strecke-attr-front* in
|
||||||
|
# ssg_core.lsp) laesst den Winkel leer, wenn kein Element gewaehlt wurde.
|
||||||
|
# SEITE_AS/SEITE_ES taugen dafuer NICHT - sie tragen mit "rechts" immer einen
|
||||||
|
# Schema-Vorgabewert. Ohne Element bleiben Winkel UND Seite leer, damit in
|
||||||
|
# Sivas keine Seite unter einem "Nein"-Knoten haengt.
|
||||||
|
|
||||||
|
# Attributwert -> Sivas-Optionswert der Auswahlliste ("30"/"90" -> "30 °"/
|
||||||
|
# "90 °", siehe Merkmalstamm). Wie [geruest_typ_anzeige] in der Config, damit
|
||||||
|
# die exakte Schreibweise ohne Code-Aenderung nachgezogen werden kann.
|
||||||
|
AS_ES_WINKEL_ANZEIGE = sivas_mapping.load_flat_mapping("as_es_winkel_anzeige")
|
||||||
|
|
||||||
|
|
||||||
|
def winkel_text(wert):
|
||||||
|
"""Elementwinkel ganzzahlig normiert ("90.0" -> "90"), ohne Sivas-
|
||||||
|
Anzeigeform. Basis fuer as_es_winkel UND fuer die Gruppierung (dort darf
|
||||||
|
die Anzeigeform keine Rolle spielen). Leerer Wert bleibt leer."""
|
||||||
|
wert = str(wert or "").strip()
|
||||||
|
if not wert:
|
||||||
|
return ""
|
||||||
|
zahl = safe_float(wert, None)
|
||||||
|
return wert if zahl is None else str(int(zahl))
|
||||||
|
|
||||||
|
|
||||||
|
def as_es_vorhanden(winkel):
|
||||||
|
"""Merkmal 4431/4432: "Ja", sobald ein Elementwinkel gesetzt ist."""
|
||||||
|
return "Ja" if winkel_text(winkel) else "Nein"
|
||||||
|
|
||||||
|
|
||||||
|
def as_es_winkel(winkel):
|
||||||
|
"""Merkmal 4427/4429: Elementwinkel in der Sivas-Schreibweise der
|
||||||
|
Auswahlliste (cfg/sivas.cfg [as_es_winkel_anzeige]). Ein Winkel ohne
|
||||||
|
Eintrag dort wird unveraendert (nur ganzzahlig normiert) uebernommen."""
|
||||||
|
winkel = winkel_text(winkel)
|
||||||
|
return AS_ES_WINKEL_ANZEIGE.get(winkel, winkel)
|
||||||
|
|
||||||
|
|
||||||
|
def _seite_text(seite, winkel):
|
||||||
|
"""Gemeinsamer Kern von as_seite/es_seite: Seite nur, wenn es das Element
|
||||||
|
ueberhaupt gibt."""
|
||||||
|
if not winkel_text(winkel):
|
||||||
|
return ""
|
||||||
|
return str(seite or "").strip().lower()
|
||||||
|
|
||||||
|
|
||||||
|
@sivas_mapping.braucht_attribs
|
||||||
|
def as_seite(wert, attribs):
|
||||||
|
"""Merkmal 4428: AS-Seite, aber nur bei vorhandenem AS-Element."""
|
||||||
|
return _seite_text(wert, attribs.get("WINKEL_AS", ""))
|
||||||
|
|
||||||
|
|
||||||
|
@sivas_mapping.braucht_attribs
|
||||||
|
def es_seite(wert, attribs):
|
||||||
|
"""Merkmal 4430: ES-Seite, aber nur bei vorhandenem ES-Element."""
|
||||||
|
return _seite_text(wert, attribs.get("WINKEL_ES", ""))
|
||||||
|
|
||||||
|
|
||||||
# --- Transform-Namen, wie sie in cfg/sivas.cfg hinter "|" stehen koennen ---
|
# --- Transform-Namen, wie sie in cfg/sivas.cfg hinter "|" stehen koennen ---
|
||||||
TRANSFORMS = {
|
TRANSFORMS = {
|
||||||
"ja_nein": ja_nein,
|
"ja_nein": ja_nein,
|
||||||
"geruest_typ_anzeige": geruest_typ_anzeige,
|
"geruest_typ_anzeige": geruest_typ_anzeige,
|
||||||
"mm_zu_m": mm_zu_m,
|
"mm_zu_m": mm_zu_m,
|
||||||
|
"as_es_vorhanden": as_es_vorhanden,
|
||||||
|
"as_es_winkel": as_es_winkel,
|
||||||
|
"as_seite": as_seite,
|
||||||
|
"es_seite": es_seite,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def as_es_signatur(attribs):
|
||||||
|
"""AS-/ES-Anteil des Gruppierungsschluessels (siehe
|
||||||
|
gefaellestrecke_signature). Nutzt dieselben Transforms wie der Export,
|
||||||
|
damit Schluessel und Zeileninhalt nicht auseinanderlaufen: ohne Element
|
||||||
|
ist die Seite leer und darf dann auch nicht trennen."""
|
||||||
|
return (as_es_vorhanden(attribs.get("WINKEL_AS", "")),
|
||||||
|
winkel_text(attribs.get("WINKEL_AS", "")),
|
||||||
|
as_seite(attribs.get("SEITE_AS", ""), attribs),
|
||||||
|
as_es_vorhanden(attribs.get("WINKEL_ES", "")),
|
||||||
|
winkel_text(attribs.get("WINKEL_ES", "")),
|
||||||
|
es_seite(attribs.get("SEITE_ES", ""), attribs))
|
||||||
|
|
||||||
|
|
||||||
def streckengruppe_objekt_text(attribs):
|
def streckengruppe_objekt_text(attribs):
|
||||||
"""Merkmal 4300 "Streckengruppe": "mehrere Objekte", wenn der Block ein
|
"""Merkmal 4300 "Streckengruppe": "mehrere Objekte", wenn der Block ein
|
||||||
kombinierter Streckengruppe-Block (Gefaelle+Vario, TYP-Attribut
|
kombinierter Streckengruppe-Block (Gefaelle+Vario, TYP-Attribut
|
||||||
@@ -195,8 +275,14 @@ def gefaellestrecke_signature(block):
|
|||||||
"""
|
"""
|
||||||
Schluessel zur Gruppierung gleichartiger Gefaellestrecken: Bloecke mit
|
Schluessel zur Gruppierung gleichartiger Gefaellestrecken: Bloecke mit
|
||||||
identischen Massen (Hoehe, Laenge, Winkel, Separatoren, Scanner, Typ,
|
identischen Massen (Hoehe, Laenge, Winkel, Separatoren, Scanner, Typ,
|
||||||
Geruest fuer Einzelmodul/Geruestoption) landen in derselben Sivas-Zeile -
|
Geruest fuer Einzelmodul/Geruestoption, AS-/ES-Element) landen in
|
||||||
nur IDs/Bezeichnung unterscheiden sich.
|
derselben Sivas-Zeile - nur IDs/Bezeichnung unterscheiden sich.
|
||||||
|
|
||||||
|
AS-/ES-Element (Merkmale 4427-4432) gehoeren mit in den Schluessel: die
|
||||||
|
Merkmale der Zeile entstehen aus dem ERSTEN Block der Gruppe, zwei sonst
|
||||||
|
baugleiche Gefaellestrecken mit AS links bzw. AS rechts wuerden sonst zu
|
||||||
|
einer Zeile mit nur einer der beiden Seiten verschmelzen (siehe
|
||||||
|
as_es_signatur).
|
||||||
"""
|
"""
|
||||||
attribs = block.get("attribs", {})
|
attribs = block.get("attribs", {})
|
||||||
return (
|
return (
|
||||||
@@ -209,6 +295,7 @@ def gefaellestrecke_signature(block):
|
|||||||
attribs.get("TYP", "Gefaellestrecke"),
|
attribs.get("TYP", "Gefaellestrecke"),
|
||||||
attribs.get("GERUEST_EINZELMODUL", "0"),
|
attribs.get("GERUEST_EINZELMODUL", "0"),
|
||||||
attribs.get("GERUEST_TYP", "Schoenenberger Geruest"),
|
attribs.get("GERUEST_TYP", "Schoenenberger Geruest"),
|
||||||
|
as_es_signatur(attribs),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+24
-4
@@ -97,14 +97,31 @@ def load_flat_mapping(section, cfg_path=None):
|
|||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
|
||||||
|
def braucht_attribs(fn):
|
||||||
|
"""Markiert einen Transform, der NEBEN seinem Rohwert auch das komplette
|
||||||
|
Attribut-Dict des Blocks braucht - er wird dann als fn(wert, attribs)
|
||||||
|
aufgerufen statt als fn(wert).
|
||||||
|
|
||||||
|
Noetig fuer Merkmale, deren Wert von einem ZWEITEN Attribut abhaengt: die
|
||||||
|
AS-/ES-Seite (4428/4430) darf nur gefuellt werden, wenn der zugehoerige
|
||||||
|
WINKEL_AS/WINKEL_ES ueberhaupt ein Element ausweist. Ohne diese Klammer
|
||||||
|
muessten solche Merkmale wieder aus der Config heraus in Python-Code
|
||||||
|
wandern - genau das soll sivas.cfg vermeiden.
|
||||||
|
"""
|
||||||
|
fn.braucht_attribs = True
|
||||||
|
return fn
|
||||||
|
|
||||||
|
|
||||||
def anwenden(section_mapping, attribs, transforms):
|
def anwenden(section_mapping, attribs, transforms):
|
||||||
"""Wendet eine per load_section_mapping() gelesene Zuordnung auf ein
|
"""Wendet eine per load_section_mapping() gelesene Zuordnung auf ein
|
||||||
Block-Attribut-Dict an.
|
Block-Attribut-Dict an.
|
||||||
|
|
||||||
transforms: dict transform_name -> Funktion(wert) -> wert. Ein in der
|
transforms: dict transform_name -> Funktion(wert) -> wert. Ein mit
|
||||||
Config genannter, aber hier unbekannter Transform-Name wird ignoriert
|
@braucht_attribs markierter Transform wird stattdessen als
|
||||||
(Rohwert bleibt unveraendert) statt abzubrechen - ein Tippfehler in
|
fn(wert, attribs) aufgerufen und sieht damit die uebrigen Attribute des
|
||||||
sivas.cfg darf den Export nicht zum Stillstand bringen.
|
Blocks. Ein in der Config genannter, aber hier unbekannter Transform-Name
|
||||||
|
wird ignoriert (Rohwert bleibt unveraendert) statt abzubrechen - ein
|
||||||
|
Tippfehler in sivas.cfg darf den Export nicht zum Stillstand bringen.
|
||||||
|
|
||||||
Rueckgabe: dict merkmal -> wert. Ohne Transform wird der Rohwert zu str()
|
Rueckgabe: dict merkmal -> wert. Ohne Transform wird der Rohwert zu str()
|
||||||
gewandelt (bisheriges Verhalten der build_*_details-Funktionen: alles
|
gewandelt (bisheriges Verhalten der build_*_details-Funktionen: alles
|
||||||
@@ -124,6 +141,9 @@ def anwenden(section_mapping, attribs, transforms):
|
|||||||
if transform:
|
if transform:
|
||||||
fn = transforms.get(transform)
|
fn = transforms.get(transform)
|
||||||
if fn is not None:
|
if fn is not None:
|
||||||
|
if getattr(fn, "braucht_attribs", False):
|
||||||
|
ergebnis[merkmal] = fn(wert, attribs)
|
||||||
|
else:
|
||||||
ergebnis[merkmal] = fn(wert)
|
ergebnis[merkmal] = fn(wert)
|
||||||
continue
|
continue
|
||||||
ergebnis[merkmal] = str(wert)
|
ergebnis[merkmal] = str(wert)
|
||||||
|
|||||||
@@ -0,0 +1,181 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
test_export_sivas_as_es.py - Sivas-Merkmale 4427-4432 (AS-/ES-Element) fuer
|
||||||
|
Gefaellestrecke (GF_N) und Streckengruppe (VF_N).
|
||||||
|
|
||||||
|
Pruefpunkte: Vorhandensein haengt am Winkel (nicht an der Seite, die immer
|
||||||
|
einen Vorgabewert traegt), der Winkel wird in die Sivas-Schreibweise der
|
||||||
|
Auswahlliste uebersetzt, ohne Element bleiben Winkel UND Seite leer, die
|
||||||
|
Zuordnung steht vollstaendig in cfg/sivas.cfg, und die GF-Gruppierung trennt
|
||||||
|
Bloecke mit unterschiedlichem AS-/ES-Element.
|
||||||
|
|
||||||
|
Laeuft komplett ohne BricsCAD (reine Python-Logik).
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "lib"))
|
||||||
|
|
||||||
|
import export_sivas # noqa: E402
|
||||||
|
import sivas_mapping # noqa: E402
|
||||||
|
|
||||||
|
# Sivas-Schreibweise der Winkel-Auswahlliste (cfg/sivas.cfg
|
||||||
|
# [as_es_winkel_anzeige]) - die Tests vergleichen gegen die Config, damit ein
|
||||||
|
# Nachziehen der Schreibweise dort nicht die halbe Testdatei bricht.
|
||||||
|
W30 = export_sivas.as_es_winkel("30")
|
||||||
|
W90 = export_sivas.as_es_winkel("90")
|
||||||
|
|
||||||
|
|
||||||
|
def _strecke(nr, typ="Gefaellestrecke", **attr):
|
||||||
|
"""GF_N-/VF_N-Block mit dem gemeinsamen Strecken-Attributschema."""
|
||||||
|
attribs = {"ID": f"000{nr}", "Bezeichnung": f"GF_{nr}", "ARTINR": "6220",
|
||||||
|
"MONTAGEHOEHE_m": "2.000", "HOEHE_VON_mm": "2000",
|
||||||
|
"HOEHE_BIS_mm": "1000", "TYP": typ,
|
||||||
|
"L_GF_m": "3.000", "GF_WINKEL": "3",
|
||||||
|
"SEITE_AS": "links", "WINKEL_AS": "90",
|
||||||
|
"SEITE_ES": "links", "WINKEL_ES": "90"}
|
||||||
|
attribs.update(attr)
|
||||||
|
return {"block_name": f"GF_{nr}", "x": 0.0, "y": 0.0, "z": 2000.0,
|
||||||
|
"rotation": 0.0, "attribs": attribs}
|
||||||
|
|
||||||
|
|
||||||
|
def test_as_es_vorhanden_mit_winkel_und_seite():
|
||||||
|
details = export_sivas.build_gefaellestrecke_details(_strecke(1))
|
||||||
|
assert details["4431"] == "Ja"
|
||||||
|
assert details["4427"] == W90
|
||||||
|
assert details["4428"] == "links"
|
||||||
|
assert details["4432"] == "Ja"
|
||||||
|
assert details["4429"] == W90
|
||||||
|
assert details["4430"] == "links"
|
||||||
|
|
||||||
|
|
||||||
|
def test_zuordnung_steht_in_der_config():
|
||||||
|
"""Die sechs Merkmale muessen in BEIDEN Strecken-Abschnitten von
|
||||||
|
sivas.cfg stehen (GF_N und VF_N lesen dieselben Attribute)."""
|
||||||
|
for abschnitt in ("gefaellestrecke", "variofoerderer"):
|
||||||
|
mapping = sivas_mapping.load_section_mapping(abschnitt)
|
||||||
|
for merkmal, attribut, transform in (
|
||||||
|
("4431", "WINKEL_AS", "as_es_vorhanden"),
|
||||||
|
("4427", "WINKEL_AS", "as_es_winkel"),
|
||||||
|
("4428", "SEITE_AS", "as_seite"),
|
||||||
|
("4432", "WINKEL_ES", "as_es_vorhanden"),
|
||||||
|
("4429", "WINKEL_ES", "as_es_winkel"),
|
||||||
|
("4430", "SEITE_ES", "es_seite")):
|
||||||
|
assert merkmal in mapping, f"{merkmal} fehlt in [{abschnitt}]"
|
||||||
|
ist_attribut, _alt, _default, ist_transform = mapping[merkmal]
|
||||||
|
assert ist_attribut == attribut, f"[{abschnitt}] {merkmal}"
|
||||||
|
assert ist_transform == transform, f"[{abschnitt}] {merkmal}"
|
||||||
|
assert ist_transform in export_sivas.TRANSFORMS
|
||||||
|
|
||||||
|
|
||||||
|
def test_winkel_in_sivas_schreibweise():
|
||||||
|
"""4427/4429 tragen den Optionswert der Auswahlliste, nicht die nackte
|
||||||
|
Attributzahl (Vorgabe aus cfg/sivas.cfg [as_es_winkel_anzeige])."""
|
||||||
|
details = export_sivas.build_gefaellestrecke_details(
|
||||||
|
_strecke(1, WINKEL_AS="30", WINKEL_ES="90.0"))
|
||||||
|
assert details["4427"] == W30
|
||||||
|
assert details["4429"] == W90
|
||||||
|
# Unbekannter Winkel faellt auf die ganzzahlige Rohzahl zurueck
|
||||||
|
assert export_sivas.as_es_winkel("60.0") in (W30, W90, "60")
|
||||||
|
|
||||||
|
|
||||||
|
def test_ohne_winkel_kein_element_und_keine_seite():
|
||||||
|
"""Leerer WINKEL_AS = kein AS-Element; die Seite darf dann NICHT
|
||||||
|
durchgereicht werden (SEITE_AS traegt mit "rechts" immer einen
|
||||||
|
Schema-Vorgabewert)."""
|
||||||
|
details = export_sivas.build_gefaellestrecke_details(
|
||||||
|
_strecke(1, WINKEL_AS="", SEITE_AS="rechts"))
|
||||||
|
assert details["4431"] == "Nein"
|
||||||
|
assert details["4427"] == ""
|
||||||
|
assert details["4428"] == ""
|
||||||
|
# ES bleibt davon unberuehrt
|
||||||
|
assert details["4432"] == "Ja"
|
||||||
|
assert details["4430"] == "links"
|
||||||
|
|
||||||
|
|
||||||
|
def test_seite_rechts():
|
||||||
|
details = export_sivas.build_gefaellestrecke_details(
|
||||||
|
_strecke(1, SEITE_AS="rechts", SEITE_ES="rechts"))
|
||||||
|
assert details["4428"] == "rechts"
|
||||||
|
assert details["4430"] == "rechts"
|
||||||
|
|
||||||
|
|
||||||
|
def test_variofoerderer_hat_dieselben_merkmale():
|
||||||
|
block = _strecke(1, typ="Streckengruppe", L_VF_m="2.000", VF_WINKEL="0",
|
||||||
|
ANTRIEBFAHRTRICHTUNG="Auf", MOTORSEITE="rechts",
|
||||||
|
WINKEL_AS="30", SEITE_AS="rechts")
|
||||||
|
details = export_sivas.build_variofoerderer_details(block)
|
||||||
|
assert details["4431"] == "Ja"
|
||||||
|
assert details["4427"] == W30
|
||||||
|
assert details["4428"] == "rechts"
|
||||||
|
assert details["4429"] == W90
|
||||||
|
|
||||||
|
|
||||||
|
def test_gruppierung_trennt_nach_as_seite():
|
||||||
|
"""Sonst baugleiche Gefaellestrecken mit AS links bzw. rechts duerfen
|
||||||
|
nicht in einer Sivas-Zeile landen (die Zeile wuerde nur eine der beiden
|
||||||
|
Seiten zeigen)."""
|
||||||
|
links = export_sivas.gefaellestrecke_signature(_strecke(1, SEITE_AS="links"))
|
||||||
|
rechts = export_sivas.gefaellestrecke_signature(_strecke(2, SEITE_AS="rechts"))
|
||||||
|
assert links != rechts
|
||||||
|
assert links == export_sivas.gefaellestrecke_signature(_strecke(3, SEITE_AS="links"))
|
||||||
|
|
||||||
|
|
||||||
|
def test_gruppierung_trennt_nach_as_winkel():
|
||||||
|
assert (export_sivas.gefaellestrecke_signature(_strecke(1, WINKEL_AS="30"))
|
||||||
|
!= export_sivas.gefaellestrecke_signature(_strecke(2, WINKEL_AS="90")))
|
||||||
|
|
||||||
|
|
||||||
|
def test_gruppierung_ohne_element_ignoriert_die_seite():
|
||||||
|
"""Ohne AS-Element ist die Seite bedeutungslos und steht auch nicht in der
|
||||||
|
Zeile - sie darf die Gruppierung dann nicht aufspalten."""
|
||||||
|
assert (export_sivas.gefaellestrecke_signature(
|
||||||
|
_strecke(1, WINKEL_AS="", SEITE_AS="links"))
|
||||||
|
== export_sivas.gefaellestrecke_signature(
|
||||||
|
_strecke(2, WINKEL_AS="", SEITE_AS="rechts")))
|
||||||
|
|
||||||
|
|
||||||
|
def test_reihenfolge_im_details_json():
|
||||||
|
"""Die sechs Merkmale stehen im details-JSON direkt HINTER 2950
|
||||||
|
(Anlagenhoehe) - so vorgegeben, und so steht es in beiden Abschnitten von
|
||||||
|
sivas.cfg. Die Reihenfolge der JSON-Keys folgt der Zeilenreihenfolge der
|
||||||
|
Config (configparser und dict erhalten beide die Einfuegereihenfolge)."""
|
||||||
|
erwartet = ["2950", "4431", "4427", "4428", "4432", "4429", "4430"]
|
||||||
|
gf = list(export_sivas.build_gefaellestrecke_details(_strecke(1)))
|
||||||
|
vf = list(export_sivas.build_variofoerderer_details(
|
||||||
|
_strecke(2, typ="Streckengruppe", L_VF_m="2.000")))
|
||||||
|
assert gf[:len(erwartet)] == erwartet
|
||||||
|
assert vf[:len(erwartet)] == erwartet
|
||||||
|
|
||||||
|
|
||||||
|
def test_altbestand_ohne_die_attribute():
|
||||||
|
"""Bloecke aus Zeichnungen, die vor der Einfuehrung von WINKEL_AS gebaut
|
||||||
|
wurden, haben die Attribute gar nicht - dann greift der leere Default und
|
||||||
|
es wird "Nein" gemeldet (statt KeyError). Das ist die einzig moegliche
|
||||||
|
Aussage: Sivas kennt nur Ja/Nein, kein "unbekannt"."""
|
||||||
|
block = _strecke(1)
|
||||||
|
for tag in ("WINKEL_AS", "SEITE_AS", "WINKEL_ES", "SEITE_ES"):
|
||||||
|
del block["attribs"][tag]
|
||||||
|
details = export_sivas.build_gefaellestrecke_details(block)
|
||||||
|
assert details["4431"] == "Nein"
|
||||||
|
assert details["4432"] == "Nein"
|
||||||
|
assert details["4427"] == details["4428"] == ""
|
||||||
|
assert details["4429"] == details["4430"] == ""
|
||||||
|
|
||||||
|
|
||||||
|
def test_transform_mit_attribs_kontext():
|
||||||
|
"""Der @braucht_attribs-Transform muss das komplette Attribut-Dict sehen -
|
||||||
|
sonst koennte die Seite ihre Abhaengigkeit vom Winkel nicht pruefen."""
|
||||||
|
assert getattr(export_sivas.as_seite, "braucht_attribs", False)
|
||||||
|
assert getattr(export_sivas.es_seite, "braucht_attribs", False)
|
||||||
|
assert not getattr(export_sivas.ja_nein, "braucht_attribs", False)
|
||||||
|
|
||||||
|
mapping = {"4428": ("SEITE_AS", None, "", "as_seite")}
|
||||||
|
attribs = {"SEITE_AS": "links", "WINKEL_AS": "90"}
|
||||||
|
assert sivas_mapping.anwenden(mapping, attribs, export_sivas.TRANSFORMS) \
|
||||||
|
== {"4428": "links"}
|
||||||
|
attribs_ohne = {"SEITE_AS": "links", "WINKEL_AS": ""}
|
||||||
|
assert sivas_mapping.anwenden(mapping, attribs_ohne, export_sivas.TRANSFORMS) \
|
||||||
|
== {"4428": ""}
|
||||||
Reference in New Issue
Block a user