Aufbau der Planquadrate nur durch Boundingboxen. Ansonsten werden die Bereiche der Lage nicht korrekt erzeugt
This commit is contained in:
+68
-12
@@ -54,17 +54,42 @@ def load_planquadrat_config(cfg_path=None):
|
||||
}
|
||||
|
||||
|
||||
def _bbox_min(block, axis):
|
||||
"""Untere Bounding-Box-Kante eines Blocks auf einer Achse ("x"/"y"), oder
|
||||
dessen Einfuegepunkt, falls kein bbox-Feld vorhanden ist (z.B.
|
||||
EXPORTSIVAS, das keine Bounding-Box mitschickt - siehe include-bbox in
|
||||
csv:block-to-json, Lisp/export.lsp).
|
||||
|
||||
MUSS dieselbe Referenz (BBox statt nur Einfuegepunkt) wie
|
||||
compute_planquadrat/planquadrat_column verwenden, sonst driften Ursprung
|
||||
(Index 1) und Zellzuordnung auseinander: ein Element, dessen Bounding-Box-
|
||||
Mitte weit von seinem Einfuegepunkt abweicht (z.B. ein um 90 Grad
|
||||
gedrehter Kreisel, dessen Insertpunkt an einem Rand statt der Mitte
|
||||
liegt), wuerde sonst in eine andere Spalte/Zeile einsortiert als der
|
||||
Ursprung erwarten laesst.
|
||||
"""
|
||||
bbox = block.get("bbox")
|
||||
if bbox:
|
||||
c = bbox.get("c" + axis)
|
||||
d = bbox.get("d" + axis)
|
||||
if c is not None and d is not None:
|
||||
return float(c) - float(d) / 2.0
|
||||
v = block.get(axis)
|
||||
return float(v) if v is not None else None
|
||||
|
||||
|
||||
def resolve_origins(cfg, blocks):
|
||||
"""Loest x_origin_mm/y_origin_mm auf, falls in export.cfg nicht gesetzt.
|
||||
|
||||
cfg = Rueckgabe von load_planquadrat_config() (kann None sein).
|
||||
blocks = alle Bloecke des aktuellen Exportlaufs (Liste von dicts mit
|
||||
"x"/"y", wie im Roh-JSON von export.lsp).
|
||||
blocks = alle Bloecke des aktuellen Exportlaufs (Liste von dicts, wie im
|
||||
Roh-JSON von export.lsp - "x"/"y" und optional "bbox").
|
||||
|
||||
Automatik: das am weitesten links liegende Element (min x) setzt
|
||||
x_origin, das am weitesten unten liegende (min y) setzt y_origin -
|
||||
beide landen damit exakt in Planquadrat-Index 1 auf ihrer Achse.
|
||||
Explizit in export.cfg gesetzte Werte werden nicht ueberschrieben.
|
||||
Automatik: die am weitesten links liegende Bounding-Box-Kante (min x)
|
||||
setzt x_origin, die am weitesten unten liegende (min y) setzt y_origin -
|
||||
beide landen damit exakt in Planquadrat-Index 1 auf ihrer Achse. Fehlt
|
||||
einem Block die Bounding-Box, faellt _bbox_min auf dessen Einfuegepunkt
|
||||
zurueck. Explizit in export.cfg gesetzte Werte werden nicht ueberschrieben.
|
||||
|
||||
Rueckgabe: neues dict (cfg bleibt unveraendert) oder None, wenn cfg None ist.
|
||||
"""
|
||||
@@ -72,10 +97,12 @@ def resolve_origins(cfg, blocks):
|
||||
return None
|
||||
resolved = dict(cfg)
|
||||
if resolved.get("x_origin_mm") is None:
|
||||
xs = [float(b["x"]) for b in blocks if b.get("x") is not None]
|
||||
xs = [_bbox_min(b, "x") for b in blocks]
|
||||
xs = [v for v in xs if v is not None]
|
||||
resolved["x_origin_mm"] = min(xs) if xs else 0.0
|
||||
if resolved.get("y_origin_mm") is None:
|
||||
ys = [float(b["y"]) for b in blocks if b.get("y") is not None]
|
||||
ys = [_bbox_min(b, "y") for b in blocks]
|
||||
ys = [v for v in ys if v is not None]
|
||||
resolved["y_origin_mm"] = min(ys) if ys else 0.0
|
||||
return resolved
|
||||
|
||||
@@ -104,10 +131,39 @@ def _index_for(coord_mm, step_mm, origin_mm=0.0):
|
||||
return int((coord_mm - origin_mm) // step_mm) + 1
|
||||
|
||||
|
||||
def compute_planquadrat(x_mm, y_mm, cfg):
|
||||
"""Berechnet die Planquadrat-Bezeichnung fuer eine x/y-Koordinate (mm)."""
|
||||
x_idx = _index_for(x_mm, cfg["x_step_mm"], cfg.get("x_origin_mm", 0.0))
|
||||
y_idx = _index_for(y_mm, cfg["y_step_mm"], cfg.get("y_origin_mm", 0.0))
|
||||
def _cell_label(x_idx, y_idx, cfg):
|
||||
x_label = _index_to_alpha(x_idx) if cfg["x_alpha"] else str(x_idx)
|
||||
y_label = _index_to_alpha(y_idx) if cfg["y_alpha"] else str(y_idx)
|
||||
return cfg["format"].format(x=x_label, y=y_label)
|
||||
|
||||
|
||||
def compute_planquadrat(x_mm, y_mm, cfg, dx_mm=0.0, dy_mm=0.0):
|
||||
"""Berechnet die Planquadrat-Bezeichnung fuer ein Element.
|
||||
|
||||
x_mm/y_mm = Mittelpunkt (Bounding-Box-Zentrum bzw. Einfuegepunkt, mm).
|
||||
dx_mm/dy_mm = Ausdehnung der Bounding-Box (mm), optional (Default 0).
|
||||
|
||||
Ohne Ausdehnung (dx_mm/dy_mm <= 0, z.B. Sensoren/Weichen ohne eigene BBox)
|
||||
wird wie bisher NUR die Zelle des Mittelpunkts geliefert (z.B. "A/1").
|
||||
|
||||
Mit Ausdehnung > 0 wird die Zelle der unteren/linken UND der oberen/
|
||||
rechten Bounding-Box-Ecke berechnet - deckt das Element mehr als eine
|
||||
Zelle ab (z.B. ein Kreisel ueber A/1 bis J/1, ein VarioFoerderer ueber
|
||||
B/2 bis C/3), wird eine SPANNE "start-ende" geliefert (z.B. "A/1-J/1",
|
||||
"B/2-C/3"); liegen beide Ecken in derselben Zelle, wird weiterhin nur
|
||||
diese eine Zelle geliefert (kein "A/1-A/1").
|
||||
"""
|
||||
if dx_mm and dx_mm > 0 and dy_mm and dy_mm > 0:
|
||||
x_lo_idx = _index_for(x_mm - dx_mm / 2.0, cfg["x_step_mm"], cfg.get("x_origin_mm", 0.0))
|
||||
x_hi_idx = _index_for(x_mm + dx_mm / 2.0, cfg["x_step_mm"], cfg.get("x_origin_mm", 0.0))
|
||||
y_lo_idx = _index_for(y_mm - dy_mm / 2.0, cfg["y_step_mm"], cfg.get("y_origin_mm", 0.0))
|
||||
y_hi_idx = _index_for(y_mm + dy_mm / 2.0, cfg["y_step_mm"], cfg.get("y_origin_mm", 0.0))
|
||||
if x_lo_idx == x_hi_idx and y_lo_idx == y_hi_idx:
|
||||
return _cell_label(x_lo_idx, y_lo_idx, cfg)
|
||||
start = _cell_label(x_lo_idx, y_lo_idx, cfg)
|
||||
ende = _cell_label(x_hi_idx, y_hi_idx, cfg)
|
||||
return f"{start}-{ende}"
|
||||
|
||||
x_idx = _index_for(x_mm, cfg["x_step_mm"], cfg.get("x_origin_mm", 0.0))
|
||||
y_idx = _index_for(y_mm, cfg["y_step_mm"], cfg.get("y_origin_mm", 0.0))
|
||||
return _cell_label(x_idx, y_idx, cfg)
|
||||
|
||||
Reference in New Issue
Block a user