# 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.