#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ export_neighbors.py - Ermittelt benachbarte Elemente ueber die Bounding-Box (STRtree). Zwei Elemente gelten als benachbart, wenn ihre Bounding-Boxes sich in der x/y-Ebene (Grundriss, Z/Hoehe wird ignoriert) ueberschneiden. Um auch nah beieinander liegende, aber nicht direkt beruehrende Elemente (z.B. Kreisel) als benachbart zu erkennen, wird jede Bounding-Box vor der Pruefung um die Haelfte der konfigurierten Toleranz nach allen Seiten erweitert - zwei Elemente mit einem Abstand <= toleranz_mm gelten dann ebenfalls als benachbart. Die Toleranz wird aus cfg/export.cfg ([Nachbarschaft] -> toleranz_mm) gelesen. Nur von export_csv.py genutzt (EXPORTCSV), nicht von export_sivas.py. """ import configparser from shapely.geometry import box from shapely.strtree import STRtree from export_blockpatterns import cfg_path_from_env def load_neighbor_tolerance_mm(cfg_path=None): """Liest die Nachbarschafts-Toleranz (mm) aus export.cfg. Default: 0.""" if cfg_path is None: cfg_path = cfg_path_from_env() parser = configparser.ConfigParser(inline_comment_prefixes=("#",)) parser.read(cfg_path, encoding="utf-8") return parser.getfloat("Nachbarschaft", "toleranz_mm", fallback=0.0) def compute_neighbor_ids(items, tolerance_mm): """Ermittelt je Item die IDs (item["teileid"]) ueberschneidender Nachbarn. items = Liste von dict mit "teileid" und optional "_bbox" ({"cx","cy","dx","dy",...}, siehe export.lsp csv:get-bbox / export_csv.py bbox_columns). Items ohne _bbox (z.B. die synthetische Omniflo-Sum-Zeile) haben keine Nachbarn. Rueckgabe: Liste von kommaseparierten Nachbar-ID-Strings, positionsgleich zu items (nicht ueber die ID dedupliziert, da TeileId nicht zwingend eindeutig ist). """ idx_with_bbox = [i for i, it in enumerate(items) if it.get("_bbox")] result = [""] * len(items) if len(idx_with_bbox) < 2: return result half_tol = tolerance_mm / 2.0 geoms = [] for i in idx_with_bbox: bb = items[i]["_bbox"] minx = bb["cx"] - bb["dx"] / 2.0 - half_tol maxx = bb["cx"] + bb["dx"] / 2.0 + half_tol miny = bb["cy"] - bb["dy"] / 2.0 - half_tol maxy = bb["cy"] + bb["dy"] / 2.0 + half_tol geoms.append(box(minx, miny, maxx, maxy)) tree = STRtree(geoms) for local_i, global_i in enumerate(idx_with_bbox): hits = tree.query(geoms[local_i], predicate="intersects") neighbor_ids = [ items[idx_with_bbox[int(local_j)]]["teileid"] for local_j in hits if int(local_j) != local_i ] result[global_i] = ", ".join(neighbor_ids) return result