8 Commits

Author SHA1 Message Date
karim 059cbf8d4d Schnitt/Ansicht-Feature + Terrain-Volumen + Geschoss-Add-Dialog
Schnitt-Feature V1+V2:
- Neues rhino/schnitte.py mit Pick-Workflow, Activation (Clipping-Planes +
  Parallel-View), 2D-Plan-Symbol auf 18_Schnittlinien-Sublayer
- Doppelklick auf Symbol aktiviert den Schnitt
- Schnitt-Settings (cutAtLine/Tiefe/Höhen/Blickrichtung) im GeschossSettingsDialog
- View-Snapshot + Restore beim Wechsel Schnitt → Geschoss
- Symbol-Cleanup bei Delete via normalem Ebenen-Menü

Terrain als Volumen:
- swisstopo.volumize_terrain_object: Skirt + Bottom-Cap auf Mesh/Brep
  damit Clipping-Planes gefuellte Querschnitte erzeugen
- UI im SwisstopoApp mit Nachbearbeitung-Section + Tiefen-Eingabe

Geschoss-Add mit Dialog:
- + im GeschossManager oeffnet 3-Optionen-Picker (Geschoss/Schnitt/Zeichnung)
- Geschoss-Dialog mit Anker-Dropdown, Position über/unter, Auto-Name,
  Höhen-Prefill aus Anker

Fix: _send_state fallback — Element gilt als selektiert wenn Source ODER
Volume in der Selection ist (robust gegen Layer-Visibility wenn Referenz-
linien-Layer im aktuellen Mode versteckt ist)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 18:28:59 +02:00
karim 3277f61ced Oeffnungen-Sublayer + Sturzlinien + Referenz-Layer + Pill-Inputs + Anordnen-Pill
- Oeffnungen-Subtree (Rahmen/Glas/Tuerblatt/Sims/Pane/Schwung/Sturz) als
  nested Children unter WAENDE im dossier_ebenen-Tree registriert + per-Kind
  Material (Glas mit Transparenz)
- Sturzlinien bei 1:100 Tueren mit Innen/Aussen/Beide/Keine-Dropdown
- Referenzlinien-Layer (19) als eigene Ebene fuer wand_axis + oeffnung_point
- Swisstopo Patch-Terrain (Brep.CreatePatch) ersetzt das falsche Loft
- Pill-Style fuer alle Inputs zentral via index.css
- 2x2 Anordnen-Pill in der Oberleiste (BringToFront/Forward/Backward/SendToBack
  via Rhinos DisplayOrder, kein Z-Offset)
- Chevron-Verschiebung in Ebenen-Panel ohne dass Siblings shiften
- Fix: _update_ebene_field walked nur Top-Level, nested Sublayer-Style-
  Changes wurden nicht persistiert
- Fix: Sturz-Linetype wurde bei jedem Wand-Regen zurueckgesetzt

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 16:07:44 +02:00
karim 68411a0ce9 swissALTI3D Multi-Tile-Naht: Sub-Sampling global statt tile-lokal
Bug: Jedes Tile berechnete origin_e/origin_n aus seinem eigenen Sample-
Punkt-Set und filterte Sub-Sampling-Punkte modulo factor_e relativ dazu.
Wenn das File-Ordering tile-individuell andere ersten 200 Punkte lieferte,
landete jedes Tile auf einer leicht anderen Phase im 0.5m-Raster — am
Tile-Boundary fehlten Faces / das Mesh hatte sichtbare Naht.

Fix: Phase aus dem ersten Sample-Punkt detect (e_phase = e mod raw_step).
Sub-Sampling-Filter benutzt den GLOBALEN LV95-Raster-Index
`round((e - e_phase) / raw_e_step)`. Da swissALTI3D ein globales Raster
ist, hat jedes Tile dieselbe Phase → konsistente Punkte am Boundary.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 13:24:25 +02:00
karim b425421fdd 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>
2026-05-20 02:42:45 +02:00
karim 1e6bc68156 Ortho-PictureFrame Position: Plane-Origin als Bottom-Left (statt Center)
AddPictureFrame interpretiert plane.Origin als BOTTOM-LEFT corner, nicht
als Zentrum — width geht in +X, height in +Y vom Origin aus. Mit Center-
basierter Plane landete die Picture um (width/2, height/2) verschoben
nach oben/rechts. Fix: plane.Origin = (x_min, y_min, z_doc).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 00:51:02 +02:00
karim 85f09390bc Ortho-Foto sichtbar (PictureFrame) + Oberleiste-Polish
Swisstopo Ortho
- AddPictureFrame statt Mesh+Material — Rhinos eigener Picture-Pfad mit
  embedBitmap=True + selfIllumination=True macht die Textur in allen
  Display-Modi sichtbar (Wireframe / Shaded / Rendered / Raytraced)
- asMesh=False (Brep-Variante) — asMesh=True ist auf Mac Rhino 8 broken
  (alle Pictures landen am gleichen Punkt unabhaengig von der Plane)
- Per-Tile Sub-Ebenen unter 80_swisstopo (z.B. 80_swisstopo/2763-1254_Ortho)
  via dossier_ebenen JSON registriert → erscheinen im Dossier-Ebenen-Manager
  mit eigener Visibility
- target_layer_idx wird vor AddPictureFrame als Active-Layer gesetzt,
  Picture landet direkt auf richtigem Sub-Layer (Move-danach broeselte
  das Material)
- Regex-Fix in _parse_swisstopo_tile_bbox: Separator zwischen den beiden
  Coords MUSS Hyphen sein, sonst matcht es faelschlich auf `_YEAR_EAST_`
  Patterns wie `_2025_2763_`

Oberleiste
- DOSSIER. Logo (Krungthep + Petrol-Punkt) + Launcher-Version
  (via __LAUNCHER_VERSION__ Vite-Define aus launcher/package.json)
- Overrides + Kombi vertikal gestapelt, gleiche Label-Spalte + Dropdown-
  Breite → Dropdowns auf gleicher X-Linie
- View-Icons neu zugeordnet:
    Top=view_quilt (Raster), Front=north (Pfeil), Persp=view_in_ar (3D)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 00:44:19 +02:00
karim afb59b6626 Swisstopo Iter 2 + hierarchische Ebenen + 0-Kote m.ü.M
Swisstopo
- swissBUILDINGS3D 3.0 + Variant-Toggle (separated/solid) im Dialog
- Auto-Fallback auf 2.0 wenn 3.0-Tiles ueber 200 MB sind (Stadt-Fall)
- Defensiver Variant-Filter auf 3 Ebenen (Item, Asset, ZIP-Extract) — keine
  Doppelimporte mehr
- Auto-Skala korrigiert jetzt die importierten Objekte (×1000) statt die
  User-bbox zu schrumpfen — Buildings bleiben in m-Doc-Skala
- merge_grids: XYZ-Tiles werden vor dem Mesh-Bau vereint, kein 1m-Streifen
  zwischen Tiles mehr
- Layer-Konsolidierung: Build_*/Roof_*/Wall_*/Floor_* DWG-Source-Layer
  werden auf Sub-Sub-Layer unter 81_Swissbuildings/{Build,Roof,Wall,Floor}
  gemappt; solid-Variante landet flach direkt auf dem Parent
- 0-Kote m.ü.M (Projekt-Nullpunkt) wird beim Import als Z-Offset angewandt

Hierarchische Ebenen
- dossier_ebenen unterstuetzt jetzt 'children'-Array (rekursiv)
- layer_builder.build_layers rekursiv (Parent + Children unter jedem Geschoss)
- apply_visibility/update_layer_style/set_ebene_visible/set_ebene_locked
  walken den Tree (Sub-Sub-Layer mit gleichem Code-Prefix werden mit-gepflegt)
- EbenenManager mit Chevron-Toggle + Indent pro Level + Context-Menue-Item
  'Sub-Ebene hinzufuegen'
- rhinoBridge.applyVisibility schickt Children-Tree (nicht nur Top-Level) —
  sonst kommen Sub-Toggles nicht beim Backend an
- Visibility-Key in App.jsx rekursiv durch Children — useEffect feuert jetzt
  auch bei Sub-Eye-Toggles

0-Kote m.ü.M
- Eingabefeld im Geschoss-Settings-Dialog (projektweit)
- Speicherung als dossier_project_zero_mum in doc.Strings
- Wird im Swisstopo-Import als Z-Offset (m + doc-units) angewandt

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-19 23:21:45 +02:00
karim 4111f12f32 Swisstopo Importer: STAC-API + Terrain-Mesh + Ortho-Drape (Iteration 1)
Frontend:
- src/SwisstopoApp.jsx NEU: Satelliten-Fenster mit Adresse-Suche, Radius-
  Wahl, Daten-Checkboxen (Gebäude/Terrain/Luftbild), Origin-Handling, Live-
  Log
- ElementeApp Swisstopo-Gruppe: Importer-Button + Karte-Button

Backend:
- rhino/swisstopo.py NEU: STAC-API-Client, Geocoding via swisstopo Search,
  LV95↔WGS84-Konvertierung, GeoTIFF/XYZ-Cache, mesh_from_grid + Ortho-Material
- swissBUILDINGS3D 2.0 (DXF/DWG) via STAC; Per-Tile-Filter (_NNNN-NN_)
  schuetzt vor versehentlichem Download der 3.5 GB National-Geodatabase
- swissALTI3D als XYZ-ZIP mit zipfile-Extraction, raeumliches Sub-Sampling
  statt Zeilen-Step (keine Streifen mehr im Terrain-Mesh)
- SWISSIMAGE 10cm GeoTIFF als RenderMaterial-DiffuseBitmap mit planarem
  UV-Mapping auf den Terrain-Mesh-bbox

Robustheit:
- Auto-Skala-Erkennung: Rhinos DXF-Parser scaliert je nach \$INSUNITS auf
  unerwartete Doc-Units; wir messen aus ersten 50 Objekten + snappen auf
  Zehnerpotenz (1, 0.001, 1000)
- bbox + origin_shift in doc-units (m_to_unit aus UnitScale + Auto-Detect)
- Tags via UserString dossier_swisstopo_kind=buildings/terrain fuer
  Replace-Detection bei erneutem Import desselben Gebiets
- BBox-Clip jetzt OPTIONAL (Default OFF, Checkbox) — bei InstanceReferences
  GetBoundingBox + Delete teuer
- Batch-Transform via System.Collections.Generic.List[Guid] statt
  Python-Loop (Python.NET-Overload-Match)
- Listener-Suppression in elemente.py + gestaltung.py + dimensionen.py
  via sticky dossier_swisstopo_busy — kein Per-Object-Spam mehr bei
  Selection/Add/Delete waehrend 5000+ Imports
- Auto-Zoom via view.ZoomBoundingBox(combined) statt Select-Loop
- Year-Dedupe auf Tile-Coord (Pattern YYYY oder YYYY-MM unterstuetzt) fuer
  alle Collections — aeltere Versionen werden ausgefiltert
- Download-Safety: > 200 MB wird abgebrochen + Live-Progress alle 2 MB
  mit UI-Yield via Rhino.RhinoApp.Wait()

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-19 18:22:48 +02:00