tro_annotate: selten gebrauchte Optionen entfernt

- --max-residual: feste Grenze DEFAULT_MAX_RESIDUAL (600 mm), Meldung
  verweist auf --offset
- --layer-prefix: Layer immer mit Praefix TRO_
- --use-overrides: cfg/tro_overrides.ini wird nie gelesen, Marker passen
  damit immer zum TRO-Fluss
- damit toter Code entfernt: draw_open_points, Layer TRO_OPENPOINT,
  Berichtszeilen Offene Punkte/Typkorrekturen (Daten kamen nur aus der INI)
- --emit-lisp bleibt (einziger Weg, tro_types.lsp fuer TRO_INSERT/TRO_EDIT
  nach einem neuen Katalogtyp neu zu schreiben)
- doc/Python_Scripts.md nachgezogen

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Samer Ayadi
2026-10-05 15:54:13 +02:00
co-authored by Claude Opus 5.5
parent e2f1a558a2
commit a5fab7e2dc
2 changed files with 21 additions and 84 deletions
+12 -11
View File
@@ -337,19 +337,21 @@ overridden.
| `--legend` | — | off | Draw a legend of the color groups. |
| `--marker-size` | `MM` (float) | `300.0` | Marker radius in mm. |
| `--text-height` | `MM` (float) | `220.0` | Text height in mm. |
| `--layer-prefix` | `P` | `TRO_` | Prefix for the layers this tool creates. |
| `--offset` | `DX,DY` | — | Set the CSV↔DXF offset by hand instead of deriving/loading it. |
| `--offset` | `DX,DY` | — | Set the CSV↔DXF offset by hand instead of deriving/loading it. For a drawing built with dxfmakros (CSV exported from the same drawing) this is `0,0`. |
| `--re-register` | — | off | Re-derive the coordinate offset even if a verified one is already cached in `%SKEL_CFG%`. |
| `--max-residual` | `MM` (float) | `600.0` | Largest residual error of the coordinate registration that is still accepted; above it the run fails (exit 4). |
| `--check` | — | off | Dry run: only analyze and report, write no output file. |
| `--emit-lisp` | — | off | Regenerate `cad/tro_types.lsp` (the type list for the `TRO_INSERT`/`TRO_EDIT` dialogs) from `tro_catalog.py` and exit — no `--dxf` needed. Written under `%DXFM_LISP%` if set (next to the `dxfmakros` SSG_LIB modules that provide the dialogs), otherwise under `<SPS_SKEL>/cad`. |
Layers always carry the prefix `TRO_`. `cfg/tro_overrides.ini` is never read,
so the markers always match `tro_flow.py` (which reads it only with
`--use-overrides`).
**Output** (in `%SKEL_RESULTS%`, unless `--check`): `<name>_annotated.dxf`,
`<name>_registration.json` (the coordinate transform used, with its proof).
**Exit codes:** `0` ok · `1` input/CLI error · `4` coordinate registration
could not be proven (or exceeds `--max-residual`) — resolve with `--offset` or
by raising `--max-residual`.
could not be proven (or its residual error exceeds 600 mm) — resolve with
`--offset`.
## 5a. `tro_extract.py` — read the TROs back out of the drawing into JSON
@@ -534,13 +536,12 @@ Three kinds of entry, deliberately different in weight:
flow node is primary, the rest stay attached so the linking still sees both
sides of a transition. Like splits, this renumbers.
- **`openpoint`** — a spot reported in a review that is **not** turned into a
TRO. The structure stays untouched; the point is only marked, in the doc
(section 6) and in the annotated drawing on layer `TRO_OPENPOINT` as a red
crossed circle with plain-text label. This keeps "derived" and "asserted"
distinguishable until the spot has been checked in BricsCAD.
TRO. The structure stays untouched; the point is only marked in the doc
(section 6). This keeps "derived" and "asserted" distinguishable until the
spot has been checked in BricsCAD.
Consumers: `tro_flow.py` (type corrections + doc section 6), `tro_annotate.py`
(corrected marker types + open-point markers), `material_flow.py` (writes the
Consumers: `tro_flow.py` (only with `--use-overrides`: type corrections + doc
section 6), `material_flow.py` (writes the
`[<plant>.manual]` section into `connect.ini`). Unknown TRO IDs and types are
not applied silently — they are reported as warnings in the console output and
in doc section 6.3, which catches the common trap: **TRO IDs are running
+9 -73
View File
@@ -109,7 +109,6 @@ from tro_flow import (
_station_positionen,
analyse_tros,
)
from tro_overrides import Overrides, load_overrides
# ---------------------------------------------------------------------------
# Konstanten
@@ -319,15 +318,13 @@ def build_layers(doc, prefix: str) -> dict[str, str]:
doc.layers.add(name, dxfattribs={
"true_color": ezdxf.rgb2int(hex_to_rgb(style.stroke)),
})
# openpoint: im Review gemeldete Stellen, die noch KEIN TRO sind. Kraeftiges
# Rot, damit sie sich von den abgeleiteten Markern klar abheben.
# Kantenfarben wie im TRO-Fluss-SVG (tro_flow.render_dot): Uebergabe blau,
# Weiche orange, Materialeingang gruen, Materialausgang rot.
for key, colour in (("label", "#404040"), ("flow", "#2f5597"),
("weiche", "#cc8800"),
("eingang", STATION_FARBE[BOUNDARY_ENTRY]),
("ausgang", STATION_FARBE[BOUNDARY_EXIT]),
("legend", "#808080"), ("openpoint", "#e00000")):
("legend", "#808080")):
name = f"{prefix}{key.upper()}"
names[key] = name
if name not in doc.layers:
@@ -530,47 +527,6 @@ def place_markers(
return placed, internal
def draw_open_points(
msp, analysis: Analysis, transform: Transform, layers: dict[str, str],
marker: float, text: float,
) -> int:
"""Offene Punkte aus cfg/tro_overrides.ini als Fragezeichen-Marker setzen.
Das sind im Review gemeldete Stellen, die noch kein TRO sind. Sie werden
bewusst NICHT als TRO-Symbol gezeichnet, sondern als durchgestrichener
Kreis mit Klartext daneben - damit in der Zeichnung sofort erkennbar ist,
dass hier eine Entscheidung aussteht und nichts abgeleitet wurde.
"""
drawn = 0
radius = marker * 1.35
for point in analysis.overrides.open_points:
x, y = transform.to_dxf(point.x, point.y)
ring = msp.add_circle((x, y), radius,
dxfattribs={"layer": layers["openpoint"]})
tag(ring, f"OFFEN:{point.name}")
diag = radius * 0.7071
for (x1, y1), (x2, y2) in (((-diag, -diag), (diag, diag)),
((-diag, diag), (diag, -diag))):
line = msp.add_line((x + x1, y + y1), (x + x2, y + y2),
dxfattribs={"layer": layers["openpoint"]})
tag(line, f"OFFEN:{point.name}")
lines = [f"OFFEN - noch kein TRO: {point.name}"]
if point.expect:
lines.append(f"erwartet: {point.expect}")
if point.belongs_to:
lines.append(f"heute Teil von: {point.belongs_to}")
lines.append(f"Anlage x/y: {point.describe_position()}")
label = msp.add_mtext("\\P".join(lines), dxfattribs={
"layer": layers["openpoint"],
"char_height": text,
})
label.set_location((x + radius * 1.3, y + radius))
tag(label, f"OFFEN:{point.name}")
drawn += 1
return drawn
def place_stations(
msp, analysis: Analysis, placed: dict[str, tuple[float, float]],
layers: dict[str, str], text: float,
@@ -826,13 +782,6 @@ def report(
if counts.get("first_id"):
print(f"Interne IDs ab = {format_internal_id(counts['first_id'])} "
f"(ID-Raum von SSG_LIB, siehe IDSCHECK)")
print(f"Offene Punkte = {counts['openpoints']} (Layer TRO_OPENPOINT, "
f"noch kein TRO)")
if analysis.overrides.applied:
print(f"Typkorrekturen = {len(analysis.overrides.applied)} aus "
f"{analysis.overrides.source}")
for entry in analysis.overrides.applied:
print(f" * {entry}")
print(f"Entfernte Objekte= {counts['removed']} (aus frueherem Lauf)")
print(f"Layer = {counts['layers']}, Bloecke: {counts['blocks']}")
print(f"DXF = {out_file if out_file else '- (--check)'}")
@@ -887,26 +836,16 @@ def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
metavar="MM", help="Markerradius in mm. Standard: %(default)s")
parser.add_argument("--text-height", type=float, default=DEFAULT_TEXT,
metavar="MM", help="Texthoehe in mm. Standard: %(default)s")
parser.add_argument("--layer-prefix", default=LAYER_PREFIX, metavar="P",
help="Praefix der erzeugten Layer. Standard: %(default)s")
parser.add_argument("--offset", metavar="DX,DY",
help="Lagebezug von Hand setzen statt ermitteln.")
parser.add_argument("--re-register", action="store_true",
help="Lagebezug neu ermitteln, auch wenn in %%SKEL_CFG%% "
"einer abgelegt ist.")
parser.add_argument("--max-residual", type=float, default=DEFAULT_MAX_RESIDUAL,
metavar="MM",
help="Groesster zugelassener Restfehler des Lagebezugs. "
"Standard: %(default)s")
parser.add_argument("--check", action="store_true",
help="Nur pruefen und berichten, keine Datei schreiben.")
parser.add_argument("--emit-lisp", action="store_true",
help="cad/tro_types.lsp aus dem Typkatalog neu schreiben "
"(Auswahlliste des Dialogs TROEDIT) und beenden.")
parser.add_argument("--use-overrides", action="store_true",
help="Manuelle Korrekturen aus cfg/tro_overrides.ini "
"anwenden. Standard ist AUS - wie bei tro_flow, "
"damit Marker und Flussdiagramm zusammenpassen.")
return parser.parse_args(argv)
@@ -959,9 +898,9 @@ def main(argv: list[str] | None = None) -> int:
print(f"FEHLER: {csv_file} nicht lesbar: {exc}", file=sys.stderr)
return 1
graph = build_graph(elements, csv_file.name, read_warnings)
overrides = (load_overrides(csv_file.name, cfg_dir) if args.use_overrides
else Overrides())
analysis = analyse_tros(graph, elements, overrides)
# Ohne cfg/tro_overrides.ini - wie tro_flow, damit Marker und
# Flussdiagramm zusammenpassen.
analysis = analyse_tros(graph, elements)
if not analysis.tros:
print(f"FEHLER: keine TROs aus {csv_file} ableitbar.", file=sys.stderr)
return 1
@@ -981,16 +920,15 @@ def main(argv: list[str] | None = None) -> int:
except RegistrationError as exc:
print(f"FEHLER: Lagebezug nicht bestimmbar: {exc}", file=sys.stderr)
return 4
if transform.residual_max > args.max_residual:
if transform.residual_max > DEFAULT_MAX_RESIDUAL:
print(f"FEHLER: Restfehler des Lagebezugs {transform.residual_max:.1f} mm "
f"ueber der Grenze von {args.max_residual:.1f} mm.", file=sys.stderr)
f"ueber der Grenze von {DEFAULT_MAX_RESIDUAL:.1f} mm.", file=sys.stderr)
print(f" {transform.describe()}", file=sys.stderr)
print(" Mit --offset von Hand setzen oder --max-residual anheben.",
file=sys.stderr)
print(" Mit --offset von Hand setzen.", file=sys.stderr)
return 4
counts = {"marker": 0, "flow": 0, "removed": 0, "layers": 0, "blocks": 0,
"openpoints": 0, "first_id": 0}
"first_id": 0}
if args.check:
counts["marker"] = sum(1 for t in analysis.tros if t.position)
@@ -999,7 +937,7 @@ def main(argv: list[str] | None = None) -> int:
ensure_appid(doc)
counts["removed"] = remove_previous(msp)
layers = build_layers(doc, args.layer_prefix)
layers = build_layers(doc, LAYER_PREFIX)
counts["layers"] = len({v for v in layers.values()})
# Interne IDs erst NACH remove_previous suchen: die Marker des letzten Laufs
@@ -1013,8 +951,6 @@ def main(argv: list[str] | None = None) -> int:
counts["blocks"] = sum(1 for b in doc.blocks if b.name.startswith(BLOCK_PREFIX))
counts["first_id"] = next_id
counts["openpoints"] = draw_open_points(msp, analysis, transform, layers,
args.marker_size, args.text_height)
if args.flow:
# Stationen nur mit --flow: sie bestehen aus ihrem Zu-/Ablaufpfeil