PENDENZEN.md: mullionCols + swissBUILDINGS3D/Terrain als erledigt markieren

Korrigiert zugleich die veraltete Nordstern-Geo-Rendering-Notiz (war schon
seit 35299307d erledigt) und dokumentiert die neu gefundene Dach-Wand-
Verschneidungslücke (Z-Fighting) als nächsten Arbeitsschritt.
This commit is contained in:
2026-07-12 17:41:37 +02:00
parent ed724be481
commit 6ac054ea71
+5 -8
View File
@@ -24,6 +24,8 @@
## 🔧 In Arbeit
- [ ] **Dach-Wand-Verschneidung fehlt (Z-Fighting im 3D)** — Nutzer-Report 2026-07-12 (Screenshot: flackerndes Rausch-Muster wo Wand-Oberkante die Dachschräge kreuzt). Root Cause: `collectCeilingCutters` (`toWalls3d.ts:819`) kappt Wände nur gegen `project.ceilings`, NIE gegen `project.roofs` — die Wand bekommt ihre Höhe unabhängig vom Dach (`wallVerticalExtent`), das Dach wird komplett separat gerendert (`emitRoofs`, `:1779`). Wo die geneigte Dachfläche den flachen Wand-Top kreuzt, überlappen sich beide Volumen (Interpenetration → Z-Fighting). Kein Quick-Fix: braucht echte Giebelwand-Geometrie (Wand-Top folgt der Dachschräge statt flach zu enden), nicht nur einen weiteren Cutter-Eintrag in der bestehenden `terminateOrSubtractSpans`-1D-z-Intervall-Logik (die nur horizontale Schnitte kann). Verwandt: [[design-schicht-verschneidung-3d-schnitt]] (gleiche Kategorie Problem wie „Wand endet an Decke", nur für geneigte statt horizontale Cutter). Nutzer bestätigt: erst umsetzen (kein Hermes-Task, direkt).
- [ ] **truck-Integration (Profil-Extrusion / B-Rep)** (Plan: [docs/design/truck-plan.md](docs/design/truck-plan.md)). Ziel: Nutzer zeichnet 2D-Querschnitt → truck-Extrusion → 3D-Körper + später Boolean gegen Wand/Decke. Umfang gesamt: ~46 Wochen. Fortschritt:
- [x] Phase 1: Geometrie-Schicht — Crate `src-tauri/trucksolid` (`extrude_polygon_core`/`extrude_circle_core`, `truck_modeling` nur zur B-Rep-Validierung/`try_attach_plane`/`tsweep`, Tessellierung manuell aus den Ring-Koordinaten — truck-rendimesh-Tessellierung für Solids in 0.3 nicht verfügbar, daher Abweichung vom Übergabe-Dokument), WASM-Bindings (Feature `web`) + `build:truck`-Script + `exclude`-Eintrag, TS-Wrapper `src/engine/truckSolid.ts` (`extrudePolygon`/`extrudeCircle`), `RMeshKind` um `"extrusion"` erweitert (`toWalls3d.ts`). Verifiziert: `cargo test` 5/5 grün, `npm run build:truck` sauber, `tsc --noEmit` 0 Fehler, `vitest run` 339/339 grün.
- [x] Phase 2 (MVP, Nutzer-Entscheid 2026-07-06: **"Nur Viewer-Wiring"**, kein Werkzeug/Store) — Ende-zu-Ende-Beweis, dass die Pipeline bis ins Bild funktioniert: ein fest verdrahtetes L-Profil (`emitTruckFixture` in `toWalls3d.ts`, 2 m abseits vom Ursprung) wird bei Bedarf per `trucksolid`-WASM extrudiert und erscheint im 3D-Viewport. **Zwei echte Lücken dabei gefunden und geschlossen:** (1) `render3d::types::MeshKind` kannte nur `Terrain`/`Imported` — ein `kind:"extrusion"` ohne passende Rust-Variante hätte die serde-Deserialisierung des GESAMTEN Modell-Pushes zum Absturz gebracht (nicht nur die Fixture); `Extrusion`-Variante + warmes Orange als Default-Farbe ergänzt (`cargo test` render3d 58/58 weiterhin grün). (2) `updateModel(project)` läuft nur bei Projektänderung (`useEffect`-Dep `project`) — die asynchron ladende Fixture hätte trotz Erfolg NIE einen Re-Push ausgelöst; Fix via Browser-Event `TRUCK_FIXTURE_READY_EVENT` (`toWalls3d.ts` dispatcht, `Wasm3DViewport.tsx` hört + stösst `updateModel` erneut an). **Visuell verifiziert** (Playwright, `?engine=wasm`, Chromium mit `--use-angle=metal` für echten WebGPU-Adapter headed): orangene Extrusion sichtbar neben dem Demo-Haus im Viewport. `tsc --noEmit` + `vitest run` 339/339 + `cargo test` render3d 58/58 grün. **Noch uncommittet** (Bearbeiter committet nicht selbst).
@@ -67,7 +69,7 @@
- [x] ~~**RoofType-ResourceManager-Tab**~~**erledigt `83abc1d`** (RoofStylesTab auf LayeredStylesTab-Rumpf; anlegen/editieren/löschen, Löschen geschützt bei Verwendung).
- [ ] **Decken-Randschicht-Override** (`Ceiling.edgeOverride`, Ringzone anderer Aufbau, Tropfkante/Randdämmung) — P1; **Deckentrenn-Werkzeug** für thermisch getrennte Auskragung (Isokorb, UI-only) — P1.
- [ ] **Tür 1:1 Rest:** `glazingRatio` (Teilverglasung), Kassettentür-Geometrie, `frameKind` im 3D (Zarge vs. Blockrahmen), echtes Schwellenprofil; Alt-`Door[]`-Pfad in `Opening` konsolidieren (technische Schuld, zwei Datenwege).
- [ ] **Fenster 1:1 Rest:** asymmetrische Rahmenbreiten, echtes Sprossengitter, Bank/Nische, Laibungsverkleidung, Form (Rund/Spitz/Schräg).
- [ ] **Fenster 1:1 Rest:** asymmetrische Rahmenbreiten, Bank/Nische, Laibungsverkleidung, Form (Rund/Spitz/Schräg). ~~echtes Sprossengitter~~**erledigt 2026-07-12 (`00bff27`):** `mullionCols` (vertikale Sprossen-Spalten) spiegelbildlich zu `mullionRows` — 3D-Rahmen-Riegel, Ansichts-Trennlinien + Glasscheiben als echtes rows×cols-Raster, Eingabefelder in `OpeningEditorDialog`/`ResourceManager`.
- [ ] **Dach 1:1 Rest:** Kniestock/Drempel, Krüppelwalm, Kehlen bei L-Grundriss (Straight-Skeleton), Gauben/Dachfenster, Aufschieblinge. ~~Dach im Vertikalschnitt~~`f248e2a`.
- [ ] **Geneigte Decke** (Rampe/Gefälle), Deckenspiegel (zweite abgehängte Fläche) — P2/P3.
- **Nicht bauen** (Doc §6): VW-Massketten-Apparat, volle Sichtbarkeitsmatrix, Eck-Fenster/-Dach generisch, Beschlags-Produktbibliothek, IFC-Void-Semantik nachrüsten.
@@ -104,16 +106,11 @@
- [x] ~~**Ebene-Schraffur editierbar**~~**gelandet `dcb6ed5`**: Kategorie-Dialog (`App.tsx`, `editor.hatch`-Feld) hat `<select>` auf `cat.hatch` + `HatchSwatch`-Vorschau. Verifiziert vorhanden.
- [ ] **GEO-BLOCK** (gemeinsame Dateien io/geoContext/swissTopo/terrain/ContextImportDialog/Viewport3D/siteSlice):
-**Research 2026-07-12 (Nutzer-Report „swissbuildings-Import stark vereinfacht, will 1:1 mit Höhe/Dach"):** Root Cause gefunden — `swissTopo.ts::fetchBuildings` nutzt `ch.swisstopo.vec25-gebaeude` (generalisierter **1:25'000-Kartografie-Layer**, NUR Grundriss, KEINE Höhe); `geoContext.ts::buildingsToMesh` extrudiert jeden Footprint pauschal mit `DEFAULT_BUILDING_HEIGHT=9` als flache Kiste. **Fix-Bausteine bereits im Repo vorhanden:**
- Echte Quelle: **STAC-API** `https://data.geo.admin.ch/api/stac/v1` (offen, kein Auth/Key) mit ZWEI echten Collections — `ch.swisstopo.swissbuildings3d_2` (stabil, 1-km-Tiles, ~50 MB) und `ch.swisstopo.swissbuildings3d_3_0` (Beta, Solid/Separated-Varianten, in Städten aber teils >700 MB/Tile, nicht 1-km-strukturiert). Assets als DXF/DWG/OBJ/IFC (teils `.zip`).
- **Vollständige Referenzimplementierung** im Rhino-Vorgänger-Plugin: `git.kgva.ch/karim/DOSSIER`, Datei `rhino/swisstopo.py` (STAC-Query, bbox LV95↔WGS84, Tile-Dedupe nach Jahr, Asset-Prio DXF/DWG>OBJ>IFC, v3→v2-Auto-Fallback bei leeren/zu grossen v3-Tiles, ZIP-Entpacken) — 1:1 als Blaupause für einen TS-Port nutzbar. Enthält auch Terrain (`swissalti3d`, GeoTIFF/XYZ→Grid→Mesh) und Orthofoto-Draping (`swissimage-dop10`), relevant für die zwei Punkte darunter.
- **Kein neuer Parser nötig:** `src/io/dxfParser.ts` kann `3DFACE`/`MESH`/Polyface-`POLYLINE`-Entities bereits verlustfrei zu `ImportedMesh` (positions/indices, echtes Z) parsen — genau das Format der swissBUILDINGS3D-DXF-Kacheln (Wände+Dachflächen als 3D-Mesh). Downloadete Kachel-DXF einfach durch `parseDxf()` schicken.
- **Nutzer-Entscheid 2026-07-12:** BEIDE Versionen (2.0 UND 3.0) als Wahlmöglichkeit anbieten (Collection-Parameter durchreichen, v3→v2-Fallback wie im Rhino-Plugin).
- **Ziel-Pipeline: render3d, NICHT Three.js** (Nutzer-Entscheid 2026-07-12: „scheiss auf three.js darstellung render3d ist fokus" — Three.js/`Viewport3D.tsx` ist nur Fallback ohne WASM/WebGPU, bekommt keine neuen Features mehr; sobald Terrain+Kontext über `projectToModel3d` laufen, ist Three.js komplett verzichtbar — Browser ohne WASM wäre dann reines 2D-CAD, akzeptiert). Das ist zugleich der Grund für den nächsten Punkt (Nordstern-Geo-Rendering wird damit zur Voraussetzung, nicht nur "nice to have").
-**swissBUILDINGS3D 1:1 + swissALTI3D-Terrain erledigt 2026-07-12 (`ed724be`):** Root Cause war `swissTopo.ts::fetchBuildings` (generalisierter 1:25'000-Kartografie-Layer, nur Grundriss, `DEFAULT_BUILDING_HEIGHT=9`-Pauschalkiste) + grobe `profile.json`-Terrain-Näherung. Fix: neues `stacApi.ts` (gemeinsamer STAC-Client) + `swissBuildings3d.ts` (echte Wände/Dach-Meshes aus swissBUILDINGS3D-DXF-Kacheln, Generation **2.0 (stabil) UND 3.0 (Beta)** wählbar, über den bestehenden `dxfParser.ts` eingelesen — kein neuer Parser nötig) + `swissAlti3d.ts` (echtes swissALTI3D-Höhenraster, **0.5 m/2 m** wählbare Punktdichte statt Näherung). `ContextImportDialog.tsx` entsprechend erweitert (Gebäude-Modus aus/vereinfacht/2.0/3.0, Terrain-Auflösung). Referenz war das Rhino-Vorgänger-Plugin (`git.kgva.ch/karim/DOSSIER`, `rhino/swisstopo.py`). Pipeline nutzt **render3d** (nicht Three.js, Nutzer-Entscheid 2026-07-12 „scheiss auf three.js darstellung render3d ist fokus").
- ~~**Nordstern-Geo-Rendering**~~ — **war bereits erledigt** (`35299307d`, 2026-07-09, stand hier fälschlich noch als offen): `emitMeshes` in `toWalls3d.ts` liest `project.context` (`importedMesh`/`terrainMesh`) bereits und speist sie in `projectToModel3d` ein — keine weitere Verdrahtung nötig, war Voraussetzung für den swissBUILDINGS3D-Fix oben und stand schon.
- Reale Höhen + **Projekt-MüM** (EG-Referenzhöhe): Terrain georeferenziert bei realem z relativ dazu, Gebäude auf Terrain drapiert (heute alles z=0).
- **Luftbild/SWISSIMAGE**-Orthofoto als Textur aufs Terrain-Mesh.
- Importierte Geo-Elemente auf **aktives Geschoss** (`viewSlice.activeLevelId`) + Gelände-Ebene.
- **Nordstern-Geo-Rendering:** importierte Meshes (heute nur three.js `importedMesh`/`terrainMesh`) auch in `projectToModel3d` einspeisen — jetzt Voraussetzung für swissBUILDINGS3D-Fix oben, nicht mehr optional.
- **3D-Mesh-DXF/DWG-Import** (heute DXF nur 2D bei manuellem Import — der Mesh-Pfad selbst ist über `dxfParser.ts` schon 3D-fähig, s. o.); Building-Draping; höhere DTM-Auflösung.
- [x] ~~**ResourceManager Bauteile-Tab** auf Master-Detail~~**bereits Master-Detail** (`ComponentsTab`/`ComponentDetail` in `src/ui/ResourceManager.tsx`, Liste links `res-md-list` / Detail rechts). Verifiziert vorhanden.
- [x] ~~**Einstellungs-Fenster (Rest)**~~**erledigt:** Verdrahtung war schon **da** (`viewSlice.snapColor`/`marqueeColor` → PlanView `SnapMarker`/Marquee, Defaults aus `theme/accents.ts`, Projekt-MüM-Feld `referenceElevationMasl`); der einzig offene Punkt (Snap/Endpunkt-Default „aki") ist längst entschieden (2026-07-04: Sora #5FA1C9, s. „❓ Offene Rückfragen"). Zeile war stehen geblieben, obwohl die Frage schon geschlossen war.