neuer Schalter --chain-graph, BTMT Eingang/Ausgang erkannt, Foerderer-Merkmal in tro_flow

--chain-graph zeichnet einen massstabsgetreuen Chain-/Lageplan der groben
Objekte (Kreisel-Bahnhaelften, Strecke/Gefaellestrecke) als <name>_chain.svg,
ohne Graphviz. BTMT-Stationen werden jetzt auch an "Eingang"/"Ausgang" statt
nur "Beladung"/"Entladung" erkannt und bevorzugt ueber TrackIds statt Nachbarn
verbunden. tro_flow.py erkennt bei Aus-/Einschleuselementen jetzt auch
"Foerderer" als Merkmal-Schreibweise fuer die Strecke, nicht nur "Strecke".

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Samer Ayadi
2026-09-17 13:15:50 +02:00
co-authored by Claude Sonnet 5
parent 516f30278b
commit 80e7acc8dd
5 changed files with 604 additions and 64 deletions
+27 -9
View File
@@ -114,6 +114,17 @@ Reads the CSV export and builds a directed graph of the mechanical objects:
counter-clockwise = left→right).
- **Separator** / **Scanner** → no node of their own; shown via `Zuordnung`
(assignment) on the label of their owning node.
- **`TrackIds`** (added Sept. 2026): a Kreisel/Strecke/Gefällestrecke row lists the
`TeileId`s of every fine element (Separator, Scanner, Weiche, Ein-/Ausschleuselement,
BTMT Be-/Entladung) that belongs to it. `Zuordnung` on the fine element itself stays
authoritative whenever it resolves to a real node — it's more precise than `TrackIds`
for a separator sitting right at a Kreisel↔Strecke boundary, which `TrackIds` lists
under *both* neighbouring containers (normal, not a conflict). `TrackIds` only fills
gaps `Zuordnung` can't resolve: a bare Kreisel id with no lane suffix (attached to
*both* lanes then), a missing/empty `Zuordnung`, or (for BTMT stations, which never had
a reliable `Zuordnung`) the nearest-neighbour distance guess this replaces. An older
export without the `TrackIds` column behaves exactly as before. See `_build_track_owners`/
`_track_owner`/`_attach_devices`/`_attach_stations` in `lib/material_flow.py`.
- **Einschleuselement** / **Ausschleuselement** / **Weiche** (from the richer export)
→ no node of their own; they supply the **direction** of the Kreisel↔Strecke edges
(`Ausschleusung` = Kreisel→Strecke at the strecke's *Anfang*, `Einschleusung` =
@@ -122,13 +133,18 @@ Reads the CSV export and builds a directed graph of the mechanical objects:
ends touch the *same* Kreisel (return loop) is split across that Kreisel's two lanes.
This makes Kreisel↔Strecke direction deterministic instead of height-inferred.
- **BTMT Be-/Entladestation** (entry/exit points) → one node each, recognised by
`TeileArt`/`Bezeichnung` containing `Beladung`/`BTMT-Beladung` (→ **entry**, a
material *source*) or `Entladung`/`SC_Entladung`/`Abwurf` (→ **exit**, a *sink*).
An entry gets an outgoing edge, an exit an incoming edge, to the object named in
its `Nachbarn`; if the export lists no neighbour (dxfmakros does not export BTMT
yet — see below), the nearest object by 2-D distance is used and a note is
printed. Recognition is **sps_skel-side only** — nothing in dxfmakros changes;
it simply activates when such a row appears in the CSV.
`TeileArt`/`Bezeichnung` containing `Beladung`/`BTMT-Beladung`/`Eingang` (→ **entry**, a
material *source*) or `Entladung`/`SC_Entladung`/`Abwurf`/`Ausgang` (→ **exit**, a *sink*).
Some exports name these same entry/exit points plainly `Eingang`/`Ausgang` instead of the
BTMT-specific terms — same role, recognised the same way.
An entry gets an outgoing edge, an exit an incoming edge, to the object its owning
Kreisel/Strecke names it under in `TrackIds` (a Kreisel picks the Eingangs-/
Ausgangsbahn from `Drehrichtung`, same as `_weiche_lane_roles`); failing that, to
the object named in its own `Nachbarn` (ignoring another station — BTMT `Nachbarn`
often just names nearby separators or the paired station, not a real flow target);
failing that, the nearest Kreisel, then the nearest object by 2-D distance, each
with a note printed. Recognition is **sps_skel-side only** — nothing in dxfmakros
changes; it simply activates when such a row appears in the CSV.
> **Note on BTMT / entry-exit data.** dxfmakros' `EXPORTCSV` currently does **not**
> emit the BTMT stations (their block names match no export pattern; documented as
@@ -190,14 +206,16 @@ See `doc/track.md` for the fuller derivation notes.
| `--use-cords` (alias `--use-coords`) | — | off | Place every node at its plant coordinate and render with `neato -n` (fixed positions) instead of `dot`, so the material graph matches the plant layout — the same option `tro_flow.py` has. The two Kreisel lanes (`-L`/`-R`) are nudged apart by `LANE_NUDGE_MM`; scale is `COORD_SCALE` (0.25 pt/mm, identical to `tro_flow.py`). Only has an effect together with `--tosvg`; fails (exit 1) if any flow node has no coordinate. |
| `--doc` | — | off | Also write a Markdown report (`<name>_material_flow.md`) with object list, connections and plausibility findings. |
| `--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` | — | 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. 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. |
| `--show-bbs` | — | 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. |
| `--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`. |
| `--chain-graph` | — | off | Write **one** to-scale "chain-/Lageplan" SVG of the **grobe Objekte** (big items) as `<name>_chain.svg`: every Kreisel split into its Bahn L/R halves (`_kreisel_lane_rects()`, same to-scale split as `--show-bbs`) and every Strecke/Gefällestrecke ("VF"/"GF") drawn as rectangles at their real `Position`/`Boundingbox` coordinates, connected by the already-resolved top-level `graph.edges` (material flow, Kreisel-Umlauf, unresolved). Step 1 of the new chain-graph build-up — no Separator/Scanner/Weiche/Ausschleus-/Einschleuselement and no BTMT Ein-/Ausgang yet; an edge touching a node that isn't drawn (e.g. a station) is simply skipped. Hand-built SVG, no Graphviz. |
**Output** (in `%SKEL_RESULTS%`): `<name>_material_flow.dot` (always, with `pos`
attributes when `--use-cords` was used), `<name>_material_flow.svg` (with `--tosvg`),
`<name>_material_flow.md` (with `--doc`), `<name>_connect.ini` (with `--connect`),
`<name>_bbs.svg` (with `--show-bbs`), `<name>_track.dot` / `<name>_track.svg` (with `--track`).
`<name>_bbs.svg` (with `--show-bbs`), `<name>_track.dot` / `<name>_track.svg` (with `--track`),
`<name>_chain.svg` (with `--chain-graph`).
**Exit codes:** `0` ok · `1` input/CLI error · `2` SVG rendering failed
(Graphviz).