2D-Plan-Renderer auf WebGL2 (GPU) + akkumulierter Funktionsstand
Neuer GPU-Renderer fuer den Grundriss (src/plan/glPlan/): Earcut-Tessellierung (konkav-faehig), gehrte Linienzuege (Miter), echte Papier-mm-Strichbreiten im Massstab (repliziert den SVG-printStrokeVb-Pfad), Hybrid mit scharfem SVG-Text- Overlay. GPU ist der Standardpfad; der SVG-Renderer bleibt automatischer Fallback, falls WebGL2/Shader nicht verfuegbar sind. Imperativer Pan (rAF + CSS-transform) fuer fluessige Interaktion ohne React-Re-Render je Frame. Enthaelt zudem den bisher nicht committeten Arbeitsstand des Browser-BIM (Oeffnungen, Treppen, Raeume, Decken, DXF-Export, Materialbibliothek, Kontext- Import, Tauri-Compute-Boundary-PoC).
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
# Welle C — HLR-Spike: Feasibility-Report
|
||||
|
||||
> 2D-Vektor-Schnitte/-Ansichten aus dem 3D-Modell via Hidden-Line-Removal (HLR)
|
||||
> mit opencascade.js (OCCT-WASM). Isolierter De-Risking-Spike, NICHT in die App
|
||||
> verdrahtet. Einheiten: Meter.
|
||||
|
||||
## Ergebnis (kurz)
|
||||
|
||||
**HLR funktioniert in diesem Browser-Projekt.** opencascade.js initialisiert im
|
||||
Vite-Build, und der HLR-Lauf liefert korrekte, getrennte sichtbare/verdeckte
|
||||
2D-Kanten. Verifiziert im echten Browser (Chromium via Vite-Dev-Server) an einer
|
||||
L-Wand + Bodenplatte, Front-Ansicht:
|
||||
|
||||
| Messwert | Wert |
|
||||
|---|---|
|
||||
| Sichtbare Kanten (sharp) | **9** |
|
||||
| Verdeckte Kanten | **16** |
|
||||
| Reine HLR-Rechenzeit | **~21 ms** |
|
||||
| WASM-Größe (unkomprimiert) | **62.8 MB** (65 864 037 Bytes) |
|
||||
| WASM-Größe (gzip) | **~19.6 MB** |
|
||||
| WASM-Fetch (lokal, Dev) | ~113 ms |
|
||||
| Modul-Init (Emscripten instanziieren) | ~450 ms (Browser) / ~680 ms (Node) |
|
||||
|
||||
Beweis-Artefakte: `hlr-elevation-proof.svg` / `.png` in diesem Ordner — sichtbare
|
||||
Kanten durchgezogen, verdeckte gestrichelt. Die Zeichnung liest sich als korrekte
|
||||
Hidden-Line-Ansicht (Silhouette + sichtbare Front-Kanten voll, verdeckte hinten
|
||||
gestrichelt).
|
||||
|
||||
## Der genutzte API-Pfad (wichtig!)
|
||||
|
||||
Der geplante klassische Pfad (`HLRBRep_Algo`/`HLRBRep_PolyAlgo` +
|
||||
`HLRBRep_HLRToShape`/`HLRBRep_PolyHLRToShape`) ist im **prebuilt Vollbuild
|
||||
1.1.1 NICHT verfügbar**: diese Klassen sind nur als `Handle_…`-Smart-Pointer
|
||||
gebunden, ohne konstruierbare Roh-Klasse und ohne den `HLRToShape`-Extraktor.
|
||||
Ein direkter Aufbau darüber ist damit nicht möglich.
|
||||
|
||||
**Verwendeter, funktionierender Pfad:** `HLRAppli_ReflectLines` — der High-Level-
|
||||
OCCT-Wrapper, der intern GENAU den exakten HLR-Algorithmus (`HLRBRep_Algo`)
|
||||
fährt. Er ist als Klasse gebunden und liefert getrennt sichtbare/verdeckte
|
||||
Kanten nach Kanten-Typ:
|
||||
|
||||
```
|
||||
const rl = new oc.HLRAppli_ReflectLines(shape);
|
||||
rl.SetAxes(dirX, dirY, dirZ, atX, atY, atZ, upX, upY, upZ); // Ortho-Projektion
|
||||
rl.Perform();
|
||||
const T = oc.HLRBRep_TypeOfResultingEdge;
|
||||
// (typ, visible, in3d) → in3d=false liefert 2D-projizierte Kanten (Z≈0)
|
||||
const visSharp = rl.GetCompoundOf3dEdges(T.HLRBRep_Sharp, true, false);
|
||||
const visOutline = rl.GetCompoundOf3dEdges(T.HLRBRep_OutLine, true, false);
|
||||
const hidSharp = rl.GetCompoundOf3dEdges(T.HLRBRep_Sharp, false, false);
|
||||
```
|
||||
|
||||
Kanten-Extraktion: `TopExp_Explorer_2(compound, TopAbs_EDGE, TopAbs_SHAPE)` →
|
||||
`TopoDS.Edge_1(current)` → `new BRepAdaptor_Curve_2(edge)` →
|
||||
`FirstParameter/LastParameter/Value(u)` (`gp_Pnt` mit `.X() .Y() .Z()`).
|
||||
|
||||
**embind-Überladungen sind versioniert** (`_1`, `_2`, …) und die Nummerierung im
|
||||
Vollbuild folgt NICHT der Argumentzahl. Empirisch verifiziert:
|
||||
`BRepPrimAPI_MakeBox_1(dx,dy,dz)`, `BRepPrimAPI_MakeBox_3(gp_Pnt, gp_Pnt)`,
|
||||
`BRepAlgoAPI_Fuse_3(a, b)`, `gp_Pnt_3(x,y,z)`. Bei einem Versionswechsel des
|
||||
Pakets müssen diese Suffixe neu geprüft werden (Fehlermeldung nennt die
|
||||
erwartete Parameterzahl).
|
||||
|
||||
## Vite-/package.json-Änderungen (genau)
|
||||
|
||||
- `package.json`: Dependency `opencascade.js@^1.1.1` (Vollbuild).
|
||||
- `vite.config.ts` (additiv, analog zum bestehenden LibreDWG-Muster):
|
||||
- Zwei Aliase → virtuelle Module auf die echten Paket-Dateien:
|
||||
`virtual:occt-glue` → `dist/opencascade.wasm.js`,
|
||||
`virtual:occt-wasm-url` → `dist/opencascade.wasm.wasm?url`.
|
||||
- `optimizeDeps.exclude: ["opencascade.js"]` (esbuild kommt mit dem
|
||||
UMD-Wrapper + Node-Shims der Glue nicht klar → Vor-Bündeln ausschließen).
|
||||
- `src/section/occt-wasm.d.ts`: Ambient-Stubs für die zwei virtuellen Module.
|
||||
- Geladen wird per **dynamischem Import** in `src/section/occt.ts` → die 62-MB-
|
||||
WASM landet NICHT im Haupt-Bundle, sondern als separater Lazy-Chunk + Asset.
|
||||
|
||||
Verifiziert: `vite build` der App bleibt grün und unverändert groß (kein
|
||||
OCCT-Chunk, da der Spike nicht verdrahtet ist). Ein Lib-Build, der `hlr.ts`
|
||||
referenziert, splittet OCCT sauber in einen eigenen Glue-Chunk + WASM-Asset ab.
|
||||
`tsc` ist für die neuen Dateien grün. (`npm run build` schlägt aktuell in
|
||||
`tsc -b` fehl — ausschließlich wegen fehlender i18n-Keys in den parallel
|
||||
bearbeiteten Dateien `commands/cmds/stair.ts` / `state/*`, NICHT wegen dieses
|
||||
Spikes.)
|
||||
|
||||
## Dateien dieses Spikes
|
||||
|
||||
- `src/section/hlr.ts` — Kernmodul: Box-Specs → Fuse → HLR → 2D-Polylinien
|
||||
(`hlrFromBoxes`, `hlrShape`, `VIEWS`, `hlrToSvg`).
|
||||
- `src/section/occt.ts` — Lazy-Loader + schmale Typ-Fassade + Lade-Metriken.
|
||||
- `src/section/occt-wasm.d.ts` — Ambient-Deklarationen der virtuellen Module.
|
||||
- `docs/welle-c-hlr-spike/` — dieser Report + Proof-SVG/-PNG.
|
||||
|
||||
## Bewertung für Welle C
|
||||
|
||||
**Viabel.** Der exakte HLR liefert saubere, normgerechte Vektor-Kanten mit
|
||||
korrekter Sichtbarkeit — genau das, was Schnitt/Ansicht brauchen und was reines
|
||||
three.js-Kanten-Projizieren nicht robust liefert (dort fehlt echte
|
||||
Flächen-Verdeckung). Die 2D-Polylinien passen direkt in die bestehende
|
||||
SVG-Plan-Pipeline (`Pt2`/`Vec2`-kompatibel).
|
||||
|
||||
**Der Kostenpunkt ist die WASM-Größe (62.8 MB / ~19.6 MB gzip).** Für einen
|
||||
Spike akzeptabel; für Produktion zu groß, um sie eager zu laden.
|
||||
|
||||
### Empfohlener Integrations- + Größenreduktions-Plan
|
||||
|
||||
1. **Lazy laden** (bereits so gebaut): OCCT erst bei erster Schnitt-/Ansichts-
|
||||
Erzeugung dynamisch importieren; Ladezustand in der UI anzeigen. Der
|
||||
Grundriss läuft weiter ohne OCCT (parametrisch, wie bisher).
|
||||
2. **Web-Worker**: HLR im Worker fahren, damit der UI-Thread frei bleibt (die
|
||||
WASM ist groß, aber der HLR-Lauf selbst ist mit ~20 ms günstig).
|
||||
3. **Größe reduzieren — lohnt sich klar**: ein **Custom-Build** von
|
||||
opencascade.js (das Paket unterstützt `make.py`/Docker-Build mit einer
|
||||
Symbol-Whitelist). Für Welle C reicht ein minimaler Satz:
|
||||
`BRepPrimAPI_*` (bzw. der spätere Solid-Erzeuger), `BRepAlgoAPI_Fuse/Common`,
|
||||
`HLRAppli_ReflectLines` + `HLRBRep_TypeOfResultingEdge`, `TopExp_Explorer`,
|
||||
`TopoDS`, `BRepAdaptor_Curve`, `gp_*`. Erfahrungswerte solcher Minimal-Builds
|
||||
liegen bei **~5–15 MB WASM** statt 62 MB — Aufwand: ein reproduzierbarer
|
||||
Docker-Build in CI, der die `.wasm`/`.js` als Projekt-Asset eincheckt.
|
||||
Alternativ die **beta 2.0** prüfen (moderneres Build-System, evtl. bereits
|
||||
schlankere Module + die klassischen HLR-Klassen konstruierbar).
|
||||
4. **Fallback, falls die Größe untragbar bleibt**: three.js-basierte
|
||||
Kanten-Extraktion (`EdgesGeometry`) + eigene Sichtbarkeit via Depth-Peeling /
|
||||
GPU-Occlusion. Deutlich mehr Eigenaufwand, weniger robust bei Verschneidungen
|
||||
— daher nur zweite Wahl; OCCT-HLR bleibt der empfohlene Weg.
|
||||
Reference in New Issue
Block a user