Weichenknoten zwischen Kreiseln, Track-Mouseover, Parameter in cfg/parameter.ini

TRO-Typen an Kreisel-Beruehrpunkten (lib/kreisel_junctions.py, derive_tros
Schritt 3c): jeder Kreisel als Stadion-Form mit Laufrichtung; jeder
gleichlaufende Beruehrpunkt ist eine Weiche (exportierte ILS Weiche oder
abgeleitet W<a>_<b>), Beruehrpunkte derselben Umlenkung bilden einen
Knoten. Ein Separator steuert ihn, wenn er in Laufrichtung unmittelbar
davor liegt (keine andere Weiche dazwischen). Typ = Separatoren x Weichen.
export.csv: 1Sep1Swi (9/1, 9/8, 8/7), 2Sep1Swi (7/2), 2Sep2Swi (2/3/4),
3Sep2Swi (4/5/6). Neuer Katalogtyp 3Sep2Swi (nicht aus SCL belegt).
Gegenlaeufige Beruehrpunkte (Mubea, Dematic) bleiben bei der alten Regel;
Mubea/HundM05/Dematic unveraendert, Showroom 0018+0019 jetzt 2Sep1Swi.

material_flow --track: Mouseover je Knoten mit Zugehoerigkeit zu
Kreisel/VF/GF (Zuordnung, TrackIds-Kette, Lage laut Geometrie), Weiche mit
beiden Kreiseln, Be-/Entladung mit ihrem Kreisel; Widersprueche mit "!".

Zahlenwerte (Toleranzen, Schwellen, Massstaebe, Groessen) aus allen
lib-Modulen nach cfg/parameter.ini (lib/parameter.py, Abschnitt je Modul,
Ueberschreiben je Anlage ueber %SKEL_CFG%/parameter.ini). Ausgaben aller
Anlagen bytegleich.

tro_flow.py: Docstrings mit Parametern/Rueckgabe, fehlende Typangaben.

Geprueft: 90 Tests gruen; tro_flow/material_flow/scl_skeleton auf 5 CSVs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Samer Ayadi
2026-10-14 17:20:30 +02:00
co-authored by Claude Opus 5.5
parent 0c69faf3db
commit 550bdeb464
17 changed files with 1634 additions and 125 deletions
+50 -3
View File
@@ -265,7 +265,7 @@ See `doc/track.md` for the fuller derivation notes.
| `--connect` | — | off | Also write the topology as `<name>_connect.ini` (item/flow level): `[…nodes]` (Kreisel lanes, Strecke, Gefällestrecke), `[…connections]` with a `kind` per edge (`normal`/`umlauf`/`weiche`/`einschleusung`/`ausschleusung`), and `[…externals]` — the BTMT entry/exit if present, otherwise the open lane-ends listed as entry candidates. A hand-editable bridge into the TRO step, styled after `doc/TRO_Katalog/connect.ini`. |
| `--show-bbs [flow\|all]` | `flow` | off | Also write `<name>_bbs.svg`: a plain 2-D top-down view of every CSV row (not just flow nodes — Separator/Scanner/Ein-/Ausschleuselement too), one axis-aligned rectangle per row from the `Position` column (its center, X/Y) and the `Boundingbox` column (its width/depth, X/Y — the Z extent is ignored), with the row's `Bezeichnung` centered in it. A Kreisel is the one exception: instead of one rectangle for the whole ring, it's split into its two Bahn L/R halves (`_kreisel_lane_rects()` — short axis divided in half, `Zuordnung`-majority-vote decides which half is L vs R), each drawn and labelled separately; its K1–K4 points (with `--show-kx`) still belong to the Kreisel as a whole and are drawn once, not per half. No rotation, no Graphviz — hand-built SVG; the `viewBox` stays in plant millimetres (Y flipped so plant "up" renders as screen "up") but the printed page size is scaled to DIN A3 (landscape or portrait, whichever matches the layout's aspect ratio) instead of the plant's real-world extent. Larger objects are drawn first so small ones (Separator, Scanner, …) stay visible on top. A legend column right of the plant lists every drawn kind with its row count, and each rectangle carries a `<title>` tooltip (row, TeileId, TeileArt, name). Mode `flow` (default, also bare `--show-bbs`) skips the VF/GF chain detail rows exported by dxfmakros since Sept. 2026 (`Bogen`, `Streckenelement`, `Motorstation`, `Umlenkstation` — `BBS_DETAIL_KINDS`), because they fully overlap their Strecke/Gefällestrecke box; `all` draws every row, detail kinds in their own stronger colours. dxfmakros calls this via `bin/show_exportcsv.bat` (mode `all`). |
| `--show-kx` | — | off | Only valid together with `--show-bbs` (else exit 1). Additionally draw each object's connection coordinate systems K1–K4 into the `_bbs.svg`: the K1–K4 columns are 12-char base64 strings (three 24-bit fixed-point values `x,y,z`, factor 10, `csv:trans-encode` in `dxfmakros/Lisp/export.lsp`) decoded to a plant-mm X/Y. Each present K-point is drawn as a small red cross (two lines) with a small `K1`…`K4` label, and consecutive points are joined `K1→K2→K3→K4` by a blue line. Empty K columns are skipped, so an object with only K1/K2 gets two crosses and one link. |
| `--track` | — | off | Additionally write the finer Separator/Ausschleus/Einschleus/Weiche graph described above (`<name>_track.dot`, and `<name>_track.svg` with `--tosvg`). Does not change the normal `_material_flow.*` output. See `doc/track.md`. |
| `--track` | — | off | Additionally write the finer Separator/Ausschleus/Einschleus/Weiche graph described above (`<name>_track.dot`, and `<name>_track.svg` with `--tosvg`). Does not change the normal `_material_flow.*` output. See `doc/track.md`. Every node has a **mouseover text** (`tooltip`, shown on hover in the SVG): for a separator its `Zuordnung`, the container whose `TrackIds` list it (Kreisel/VF/GF) and the Kreisel lane it lies on by geometry (`lib/kreisel_junctions.py`); for an ILS Weiche the two Kreisel that created it (`Kreisel A`/`B`) and the touch point by geometry; for Beladung/Entladung the Kreisel they sit on. Contradictions between these sources get a line starting with `!` (e.g. `export.csv` 0015: `Zuordnung` Kreisel 0003, lies on Kreisel 0002). |
| `--chain-graph` | — | off | Write a "chain-/Lageplan" of the **grobe Objekte** (big items): every Kreisel split into its Bahn L/R halves (`_kreisel_lane_rects()`, same split as `--show-bbs`), every Strecke/Gefällestrecke ("VF"/"GF"), and every Ein-/Ausgabestation (BTMT `Beladung`/`Entladung`, or the generic `Eingang`/`Ausgang` symbol where no BTMT station absorbed it — see `_merge_station_symbols()`) — the plant runs as a closed loop, so these stations are its only material sources/sinks and are drawn like any other node, not skipped. Connected by the already-resolved top-level `graph.edges` (material flow, Kreisel-Umlauf, unresolved). Rendering method and output file are chosen by `--graphtype`. |
| `--graphtype` | `coarsebox`\|`compound`\|`subgraph` | `coarsebox` | Only valid together with `--chain-graph` (else exit 1). `coarsebox`: containers only (as above), to real scale, hand-built `<name>_chain.svg`, no Graphviz — the original behaviour. `compound`: the same to-scale picture, **plus** each container's Anbauteile (Separator, Scanner, Ausschleus-/Einschleuselement, Weiche) drawn nested inside it at their real position (`_container_children()` reads them off `Element.track_ids`, the same source `build_track_graph()`/`--track` uses — not a re-derivation from `Nachbarn` like the old `data/gen_chain_svg.py` prototype), linked by the already-resolved `TrackGraph.edges`; still `<name>_chain.svg`, no Graphviz. `subgraph`: the same containment expressed as **nested Graphviz clusters** (`subgraph cluster_*` — one per Kreisel, nested one per Bahn L/R, plus one per Strecke/Gefällestrecke, each containing its Anbauteile as child nodes) — schematic (`dot` auto-layout), **not** to scale; writes `<name>_chain.dot` always, and `<name>_chain.svg` additionally with `--tosvg` (needs Graphviz `dot`, unlike the other two graph types). |
@@ -293,8 +293,27 @@ draws *their* flow. Derivation rules (see
| Gefällestrecke, single line | `1Sep` |
| Strecke (driven) | `Vario` (one per segment) |
| Kreisel lane | `1Sep` |
| Separator before an Ausschleuselement (one / two in a row) | `1Sep1Swi` / `1Sep2Swi` |
| Junction between Kreisel: *n* separators directly upstream of *m* touch points on one pulley | `1Sep1Swi`, `2Sep1Swi`, `2Sep2Swi`, `3Sep2Swi` |
| — additionally: 2 or 3 outgoing paths | upgraded to `1Sep1Swi` / `1Sep2Swi` |
**Junctions between Kreisel** (`lib/kreisel_junctions.py`, step 3c in
`derive_tros`). Every Kreisel is modelled as a stadium (two pulleys plus two
straight lanes, from position, `Drehung` and bounding box) with its direction of
travel (`Drehrichtung`). Wherever two Kreisel touch and run the same way, there
is a switch. An exported `ILS Weiche` is matched to it by position; a touch point
without one gets the ID `W<KreiselA>_<KreiselB>` and a finding (in
`export.csv` three are missing: 2/3, 3/4, 8/9). Touch points on the same pulley
form one junction (Kreisel 5 touches 4 and 6 with its west pulley → 2 switches).
A separator controls a junction if, walking **against** the direction of travel
from the junction on one of its Kreisel, it is the first thing reached — before
any other switch. The type follows from the count: separators × switches. The
host of each separator is the lane it physically lies on, not its `Zuordnung`.
If the two Kreisel run against each other at the touch point (both `UZS` at a
pulley-to-pulley touch, as in Mubea and Dematic — probably an export error), no
junction is formed, a finding is written, and the ILS Weiche is handled by the
older neighbour rule (`_find_weiche_separators`, step 3c').
A scanner mounted on a separator does **not** change the type (stays `1Sep`);
the `1Sep_SSCC` special case can't be recognized from the mechanical layout
alone and is only raised as a finding. TRO types, FB blocks, sub-components and
@@ -641,12 +660,12 @@ into `scl_context` and `scl_skeleton --eplan`).
The single source of truth for everything needed to generate or draw a TRO
type: short name (as used in `FB_Main`/`connect.ini`), Siemens FB block,
sub-components and their counts, color group (for Graphviz/Mermaid/CAD) and
CAD marker shape. **Eleven** types are defined in `TRO_CATALOG`. Ten of them are
CAD marker shape. **Twelve** types are defined in `TRO_CATALOG`. Ten of them are
verified against `data/*.scl` where the source is vendored locally, and against
`TRO_Typen.md`'s mapping table otherwise (see the module docstring,
`CATALOG_AS_OF`, for provenance per type).
> **`2Sep2Swi` is the exception — it is not backed by any SCL.** It was added on
> **`2Sep2Swi` and `3Sep2Swi` are the exceptions — they are not backed by any SCL.** It was added on
> 2026-08-12 for project 500573 (Mubea), to model the transfer point at the
> Kreisel2/Kreisel1 touch as a single control object with 2 separators,
> 2 scanners and 2 switches. **`FB_ILS_MTRO_2Sep2Swi` does not exist** in this
@@ -654,6 +673,9 @@ verified against `data/*.scl` where the source is vendored locally, and against
> the ILSLib — otherwise a future SCL generator will emit a call to a missing
> block. The closest verified type is `2Sep1Swi` (2 separators, 2 scanners,
> **1** switch), which matches the hardware actually present in that export.
> `3Sep2Swi` (3 separators, 3 scanners, 2 switches) was added on 2026-10-14
> for the test plant `data/export.csv`, where one Kreisel pulley touches two
> others; **`FB_ILS_MTRO_3Sep2Swi` does not exist either.**
Everything is a Pydantic v2 model
(`TroDefinition`/`TroStyle`), so it validates on every assignment and comes
@@ -825,6 +847,31 @@ shows a larger `residual_max` than either role alone. That is expected; the
mean residual is the number to watch, and only pairs within `FIT_TOL` (50 mm)
enter the Procrustes fit.
## 7a. `parameter.py` — numeric settings from `cfg/parameter.ini` (library, no CLI)
Tolerances, thresholds, scales and drawing sizes of the libraries are not
written in the code but read from **`cfg/parameter.ini`**: one section per
module, the key is the constant's name in lower case
(`[kreisel_junctions] contact_tolerance` → `kreisel_junctions.CONTACT_TOLERANCE`).
Meaning and unit of every value are documented as comments in the INI file.
- The base file in the repository is read first and must be complete — a
missing key or a non-number stops the import with `ParameterError`; there are
deliberately no fallback values in the code.
- A second `parameter.ini` in `%SKEL_CFG%` (when it points somewhere else)
overrides single values, e.g. a different contact tolerance for one plant.
- Read by `kreisel_junctions`, `tro_flow`, `tro_ids`, `material_flow`,
`dxf_registration`, `tro_annotate` and `e_planning` (fallback for
`toleranz_mm` in `e_planning.ini`). `tests/test_parameter.py` checks that
every key is read by its module.
- Not in the INI, on purpose: format constants (`KX_TRANS_FAKTOR`, the coding
of the CSV columns K1–K4), mathematical epsilons, and style tables
(colours, fonts, `COORD_SYMBOL_SIZE`, symbol proportions in the drawing
code).
Changing a value that drives the derivation (a tolerance or threshold) can
change TRO types and IDs — compare the outputs of all plants afterwards.
## 8. `gen_tro_graphs.py` — documentation image generator (doc tooling, not part of the generator)
Lives under `doc/TRO_Katalog/tro_graphs/`, not `lib/` — it produces the