Swisstopo + OSM Importer + Höhenlinien + Bulk-Op Performance
Swisstopo Iter 3:
- Ortho-Drape: TIN-Mesh aus Terrain-Grid mit per-vertex UVs + PictureFrame-Material
- Project-Cache: TIFs werden neben .3dm gespeichert (SMB-shareable)
- Layer-Restruktur: 80_swisstopo/{Terrain, Luftbild} Sub-Ebenen
- TIFs direkt (kein PNG-Downsampling) für volle Auflösung
- UV-Inset gegen weisse Streifen zwischen Kacheln
- Hoehenlinien (2D, swissALTI3D) auf aktives Geschoss OKFF projiziert
- TIN-Mesh + Schichtenmodell aus Contours (separate Optionen)
- TLM3D entfernt (swisstopo liefert nur GDB/SHP, kein DXF)
OSM Importer (neu):
- rhino/osm.py: Overpass-API-Client
- src/OsmApp.jsx: React-Dialog mit Adresse + Radius + 7 Kategorien
- Strassen/Gebäude/Wasser/Wasserläufe/Parks/Wald/Fusswege (Codes 7101-7107)
- ElementeApp: PillGroup "Importer" mit Swisstopo + OSM Buttons
Sub-Ebenen — rekursiv durch hierarchische Ebenen:
- Visibility-Toggle: slimEbene rekursiv (children bleiben erhalten)
- Settings-Dialog: _find_sublayer_by_code_recursive + _replace_in_tree
- Hatch Auto-Fill: refresh_layer_fills + _fill_signature + _ebene_fill_for_layer
alle rekursiv durch children
- EbenenSettingsApp: flattenEbenen-Helper
Bulk-Op Performance (Delete/Cut/etc.):
- _USER_BULK_CMDS + _BULK_ACTIVE_KEY Sticky-Flag
- CommandBegin: doc.Views.RedrawEnabled = False + Listener-Bail aktiv
- CommandEnd: RedrawEnabled restore + 1× Redraw + Selection-Refresh
- Bail-outs in dimensionen.on_idle/on_select, elemente._on_idle_selection,
gestaltung.on_idle_flush/on_delete
- Verhindert das sichtbare "Runterzählen" pro Element bei Bulk-Delete
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+40
-25
@@ -585,12 +585,24 @@ class EbenenBridge(panel_base.BaseBridge):
|
||||
try: e_list = json.loads(e_raw)
|
||||
except Exception as ex:
|
||||
print("[EBENEN] save_ebene JSON:", ex); return
|
||||
replaced = False
|
||||
for i, e in enumerate(e_list):
|
||||
if isinstance(e, dict) and e.get("code") == orig_code:
|
||||
e_list[i] = updated
|
||||
replaced = True
|
||||
break
|
||||
# Rekursive Suche + Replace durch den Tree — Sub-Ebenen
|
||||
# (children) liegen verschachtelt, nicht in der Top-Level-Liste.
|
||||
def _replace_in_tree(lst, target_code, new_data):
|
||||
for i, e in enumerate(lst):
|
||||
if not isinstance(e, dict): continue
|
||||
if e.get("code") == target_code:
|
||||
kids = e.get("children")
|
||||
merged = dict(new_data)
|
||||
if isinstance(kids, list) and "children" not in merged:
|
||||
merged["children"] = kids
|
||||
lst[i] = merged
|
||||
return True
|
||||
kids = e.get("children")
|
||||
if isinstance(kids, list):
|
||||
if _replace_in_tree(kids, target_code, new_data):
|
||||
return True
|
||||
return False
|
||||
replaced = _replace_in_tree(e_list, orig_code, updated)
|
||||
if not replaced:
|
||||
print("[EBENEN] save_ebene: code {} nicht gefunden".format(orig_code))
|
||||
return
|
||||
@@ -639,25 +651,28 @@ class EbenenBridge(panel_base.BaseBridge):
|
||||
def _fill_signature(e_list):
|
||||
out = {}
|
||||
if not isinstance(e_list, list): return out
|
||||
for e in e_list:
|
||||
if not isinstance(e, dict): continue
|
||||
f = e.get("fill")
|
||||
if not isinstance(f, dict): continue
|
||||
if f.get("pattern") in (None, "None"): continue
|
||||
# lw kann None sein -> als Sentinel ein eindeutiger Wert
|
||||
lw_raw = f.get("lw")
|
||||
try:
|
||||
lw_sig = round(float(lw_raw), 6) if lw_raw is not None else None
|
||||
except Exception:
|
||||
lw_sig = None
|
||||
out[e.get("code")] = (
|
||||
f.get("pattern"),
|
||||
f.get("source", "layer"),
|
||||
(f.get("color") or "").lower(),
|
||||
round(float(f.get("scale") or 1.0), 6),
|
||||
round(float(f.get("rotation") or 0.0), 6),
|
||||
lw_sig,
|
||||
)
|
||||
def _walk(lst):
|
||||
for e in lst:
|
||||
if not isinstance(e, dict): continue
|
||||
f = e.get("fill")
|
||||
if isinstance(f, dict) and f.get("pattern") not in (None, "None"):
|
||||
lw_raw = f.get("lw")
|
||||
try:
|
||||
lw_sig = round(float(lw_raw), 6) if lw_raw is not None else None
|
||||
except Exception:
|
||||
lw_sig = None
|
||||
out[e.get("code")] = (
|
||||
f.get("pattern"),
|
||||
f.get("source", "layer"),
|
||||
(f.get("color") or "").lower(),
|
||||
round(float(f.get("scale") or 1.0), 6),
|
||||
round(float(f.get("rotation") or 0.0), 6),
|
||||
lw_sig,
|
||||
)
|
||||
kids = e.get("children")
|
||||
if isinstance(kids, list) and kids:
|
||||
_walk(kids)
|
||||
_walk(e_list)
|
||||
return out
|
||||
old_e_raw = doc.Strings.GetValue("dossier_ebenen")
|
||||
old_sig = {}
|
||||
|
||||
Reference in New Issue
Block a user