Commit Graph

177 Commits

Author SHA1 Message Date
karim 04c7334cc4 Bauteil: Ansichtsschraffur neben Schnittschraffur
Bauteil trägt jetzt zwei Schraffuren: die bestehende hatchId als
Schnittschraffur (nur wo tatsächlich aufgeschnitten) und ein neues
optionales Feld viewHatchId als Ansichtsschraffur für die frontale,
ungeschnittene Sicht. Die Deckenpoché im Grundriss — die Decke liegt
über der horizontalen Schnittebene, wird also frontal gesehen — nutzt
nun die Ansichtsschraffur (Default weiss/leer) statt pauschal keiner.
Schnitt-Pfade und die echt geschnittene Wand-Grundriss-Poché bleiben
auf der Schnittschraffur. Editierbar im Ressourcen-Manager.
2026-07-03 23:30:48 +02:00
karim 93b70fa95a Deckenpoché im Grundriss ohne Schraffur
Die Decke wird in der Aufsicht frontal gesehen, nicht aufgeschnitten
— Bauteil-Schraffuren gehoeren nur auf Schnittflaechen. Die neue
3-schichtige Betondecke zeigte sonst ihre dichte Schraffur ueber dem
ganzen Raum im Grundriss.
2026-07-03 23:11:42 +02:00
karim fae4f6fcb6 Deckenstile: solide oder mehrschichtige Decke
Analog zu den Wandstilen erhalten Decken jetzt einen eigenen
Deckentyp mit Schichtaufbau (CeilingType, ceilingTypeId). Der
Schichtaufbau erscheint nur im Schnitt als gestapelte Bänder von OK
bis UK; der Grundriss bleibt eine flächige Poché wie bisher, da die
Schichtung von oben ohnehin nicht sichtbar ist. Auswahl solide/
mehrschichtig im Objektinfo-Panel wie bei Wänden, neuer
"Deckenstile"-Tab im Ressourcen-Manager mit Fugenlinien je Schicht.
2026-07-03 22:09:02 +02:00
karim d65d84183a Zeichnungsebenen merken sich eigenen 2D/3D-Zustand
Bisher war viewType (Grundriss/Perspektive) ein einziger globaler
Wert. Beim Tab-Wechsel blieb er unverändert stehen, was wirkte, als
würde die Ansicht "durchsickern". Jede Ebene merkt sich jetzt ihren
zuletzt gewählten Ansichtstyp und stellt ihn beim Zurückwechseln
wieder her.
2026-07-03 21:51:51 +02:00
karim 1f6da09b2b render3d: Wandverschneidung an Ecken + sichtbare Schichten
mesh.rs berechnet die Ecken-Verschneidung jetzt selbst (portiert aus dem
Web-Kern computeJoins/clippedBand): Wandenden werden per Rundungs-Key
gruppiert, ueber Hoehen-Ueberlappung geclustert (gestapelte Geschosse mit
gleichem Grundriss verschneiden sich NICHT), und Zweier-Cluster ueber die
gemeinsame Gehrungslinie geschnitten. T-/X-Stoesse und freie Enden bleiben
stumpf, wie im Web-Kern. Endkappen-Normalen geometrisch aus dem Kreuzprodukt.

WallInput bekommt optional layers (WallLayer{thickness,color}, serde-default,
rueckwaertskompatibel): jede Schicht wird als eigenes Band ueber dieselbe
gehrte Grundflaeche extrudiert und materialgefaerbt. toWalls3d.ts loest die
WallType-Schichten je Wand auf (hexToRgb) und reicht sie durch.

39/39 Rust-Tests (7 neue: Gehrung, T-Stoss, freies Ende, Schichten, Kombi).
2026-07-03 21:45:01 +02:00
karim 5fd0161bc7 Kopfzeile der Zeichenflaeche: Dokument-Tabs statt Geschoss-Eigenschaften
Die alte Eigenschaften-Leiste (Geschosshoehe/Schnitthoehe/OKFF) weicht einer
Tab-Leiste 'Zeichnungen': ein Tab je Geschoss-Grundriss, Klick wechselt die
aktive Zeichnungsebene. Bindet an activeLevelId/setActiveLevelId — dieselbe
Store-Quelle wie das Panel 'Zeichnungsebenen', beide bleiben synchron.
Geschosshoehe/Schnitthoehe werden in den Geschoss-Einstellungen gepflegt.

Der Drawing-Typ (kind: 'plan') und der switch beim Aktivieren lassen spaeter
Schnitt-/Layout-Tabs zu, ohne die Leiste umzubauen.
2026-07-03 21:39:56 +02:00
karim f4e70902d0 Raumstempel: Ausrichtung pro Zeile + Anker als Snappunkt
Jede Stempelzeile (Name, Name-2, Bodenflaeche, Nutzung) hat jetzt eine
eigene Ausrichtung links/mitte/rechts, im Stempel-Editor pro Zeile
waehlbar und in SVG- wie nativer Darstellung honoriert (text-anchor bzw.
align). Bodenflaeche/Nutzung fallen auf mitte zurueck (bisheriges Bild).

Der Stempel-Anker (stampAnchor bzw. Schwerpunkt) meldet sich zusaetzlich
als Endpunkt-Snapkandidat an — gefiltert nach Geschoss und sichtbarer
Kategorie; der ziehbare Griff war bereits verdrahtet.
2026-07-03 21:29:13 +02:00
karim af0b044fca render2d: Rundungen an Strichen — Round-Caps und Round-Joins wie glPlan
stroke_polyline tesselliert Segmente jetzt einzeln (Butt-Enden) und
setzt an Innenknoten Fächer-Bögen auf der Aussenseite sowie an offenen
Enden Halbkreis-Kappen. Fächerdichte 18°/Schritt, identisch zur
WebGL2-Darstellung. Geschlossene Ringe: Bögen an allen Knoten, keine
Kappen; offene Polylinien inkl. Strich-Segmente: Kappen an den Enden.
2026-07-03 21:24:28 +02:00
karim 692dd3f719 Engine-3D-Presets ueber die TopBar + orthografisch (Top/Front/Seite), Iso korrekt
Die Kamera-Presets liefen zuvor als Viewport-Overlay mit eigenen JS-yaw/pitch-
Winkeln, rein perspektivisch (Iso falsch, keine Parallelprojektion). Jetzt
haengt der Engine-Viewport am app-weiten view3d-State (TopBar-CameraMenu, wie
three.js) und nutzt die vorhandene Rust-preset_camera:

- web.rs: set_view_preset(preset) + model_bounds/fit; Front/Top/Side echt
  orthografisch, Iso/Perspektive perspektivisch - wie das native Fenster.
  default_fov() pub(crate), damit Fit denselben FOV nutzt.
- useWasm3dRenderer: applyViewPreset; render(null) ueberschreibt die
  Preset-Kamera nicht.
- Wasm3DViewport: konsumiert view3d/renderMode als Props (Overlay + lokaler
  Umschalter entfernt, wasm3dOverlay.css geloescht); Orbit bleibt frei
  (Preset = Sprung, kein Lock), three.js-Verhalten gespiegelt.
- Viewport3D-Switcher reicht view3d/renderMode an den Engine-Viewport durch
  (kein three.js-Szenencode angefasst).
2026-07-03 21:13:53 +02:00
karim 4d721a62f7 Raeume: Umriss auf die Wand-Innenflaeche + neutral statt farbig
- Sample-Raum R1: boundary auf die echte Innenkante der Aussenwaende
  (Achse +/- halbe Wanddicke 0.1725 bei Wandtyp aw 0.345 m) statt 0.1-Inset -
  der Umriss lag bisher ~7 cm im Wandkoerper.
- Raumfarbe #5a7a9a -> neutrales Grau #6b7280 (Umriss + Stempel).
- ROOM_FILL_ALPHA 33 -> 00: keine transluzente Farbfuellung mehr
  (Plandarstellung schwarz/grau); das Polygon bleibt fuer die Auswahl
  erhalten (Hit-Test laeuft ueber pointInPolygon, nicht ueber die Fuellung).

Offen: automatische Ableitung der Raum-Boundary aus den Wand-Innenflaechen
fuer spaeter gezeichnete Raeume.
2026-07-03 21:07:11 +02:00
karim b028fc6b31 Engine-3D: Kamera-Presets + Weiss-Modus im render3d-Viewport
Der Engine-3D-Viewport (render3d/wgpu) war reines Ansehen (Orbit/Zoom). Jetzt:

- Kamera-Presets als Overlay: Top/Unten/Vorne/Hinten/Links/Rechts/Iso.
  Richtungen exakt wie der three.js-Pfad (applyView3d); framen die aktuelle
  Modell-Bounding-Box (fitTargetDist) und springen auf den Preset-Winkel,
  danach Orbit/Pan/Zoom weiter frei. Rein JS.
- Render-Modus Schattiert/Weiss: mode-Uniform in Globals (WGSL/Rust),
  Weiss = beleuchtetes Clay-Grau; wasm-Binding set_render_mode_white,
  durchgereicht via useWasm3dRenderer.
- Overlay-CSS self-contained (wasm3dOverlay.css), Theme-aware.

three.js unangetastet. Auswahl/Grips/Zeichnen + Wireframe/HLR bewusst noch
offen (naechste Scheibe).
2026-07-03 20:56:56 +02:00
karim 581ddccf1a Wandstile: Schichtfuge pro Fuge als LineStyle waehlbar + ResourceManager-Abteilung
Mehrschichtige Waende zeichnen die Trennlinie an jeder Materialfuge jetzt mit
einem pro Fuge waehlbaren LineStyle statt einer festen Haarlinie.

- Layer.jointLineStyleId (optional): LineStyle der Fuge an der Innenkante
  dieser Schicht; fehlt er, gilt die Default-Haarlinie (0.02) in Wandfarbe.
- generatePlan: Schicht-Baender tragen nur noch Fuellung + Schraffur (kein
  Band-Umriss); jede innere Fuge wird als eigene Linie mit ihrem LineStyle
  (Gewicht/Farbe/Dash, x Detailfaktor) gezeichnet. Wand-Umriss (0.35) und
  grob-Pfad unveraendert.
- ResourceManager: neue Abteilung "Wandstile" - je Wandtyp die Schichten
  mit Fugen-LineStyle-Dropdown.
- Sample: LineStyle "Schichtfuge 0.13"; der Daemmung-Backstein-Fuge (massiv/
  massiv) zugewiesen, Putzfugen bleiben Haarlinie.
- 2 Joint-Tests ergaenzt.
2026-07-03 20:55:07 +02:00
karim 1fd688896c glPlan: bildschirm-adaptive Bogen-Tessellierung (LOD)
Boegen (Tuer-Schwenkbogen) wurden mit fester Segmentzahl (16/90 Grad) beim
Kompilieren tesselliert und beim Zoom nur per Matrix neu gezeichnet - beim
Reinzoomen daher sichtbare Facetten. Jetzt skaliert die Segmentzahl mit der
Bildschirmgroesse des Bogens: Sagitta < 0.5 px (segs = clamp(ceil(|dPhi|/theta),
8, 2048)), theta = 2*acos(1 - 0.5/rPx). Weit weg wenige Segmente (Perf),
nah rund.

Anti-Thrash per LOD-Bucket round(log2(pxPerMeter)): Neu-Tessellierung nur
bei Bucket-Wechsel, sonst bleibt Zoom/Pan reiner Matrix-Update. Bogen laeuft
weiter durch strokePolyline - runde Caps/Joins bleiben erhalten.
2026-07-03 20:29:12 +02:00
karim f9a5e763fd Plandarstellung schwarz: Tür/Fenster-Symbole als Haarlinie, Decke weiss hinterlegt
Plandarstellung ist schwarz/grau; Farbe bleibt spaeteren Schemaelementen
vorbehalten.

- Tuerblatt, Schwenkbogen, Fensterscheibe und Anschlagstriche: einheitlich
  #1a1a1a statt blau (#2b3039/#4a86c7/#6b7280), im render2d/PDF-Pfad
  (CLS_STROKE) und im SVG-CSS.
- Schwenkbogen als Volllinie (Strichelung entfernt).
- Tuer-/Fenstersymbol-Linien auf Haarlinie 0.02 mm (SYMBOL_HAIRLINE_MM).
- Decken-Poche: Schraffur auf weissem Grund wie mehrschichtige Waende
  (pocheFill), solid schwarz - nicht mehr die Bauteil-Fuellfarbe.
2026-07-03 20:28:03 +02:00
karim ec2568276d PDF/Print: Haarlinien unter der Stift-Leiter exakt drucken
quantizePen hob bisher jede Breite <= 0.13 mm auf die unterste Stift-Stufe
(0.13 mm) an. Dadurch druckte die 0.02-mm-Schraffur/Schichtfuge im PDF und
im SVG-Print-Modus als 0.13 mm - im Viewport duenn, im Export dick.
Breiten unter MIN_PEN_MM gelten jetzt als bewusste Haarlinien und werden
exakt (unquantelt) durchgereicht; ab 0.13 mm rundet die Leiter wie gehabt.
2026-07-03 20:15:10 +02:00
karim 2b6b99059d Fang-Optionen und Display/Print-Umschalter in die Footerbar
Der Linien-Modus (Display/Print) wandert aus der Oberleiste und die
Fang-Optionen aus der Werkzeug-Palette in die Statusleiste unten:

- StatusBar: segmentierter Display/Print-Umschalter (Stil wie der
  Renderer-Umschalter) plus Fang-Pill mit nach oben öffnendem Popover
  (Master-Schalter + Endpunkt/Mittelpunkt/Schnittpunkt/Kante/Raster/
  Ortho + Rastermass).
- TopBar: Linien-Modus-Gruppe entfernt.
- ToolsPanel: Fang-Abschnitt entfernt.
- App reicht lineMode/snap an die StatusBar durch.
2026-07-03 20:08:03 +02:00
karim 658536029b Schraffur + Schichtfugen als 0.02-mm-Haarlinien im einheitlichen Neutralschwarz
Schraffurlinien verlassen den screenPx-Sonderpfad und laufen wie jede
andere Linie durch die Papier-mm-Pipeline (glPlan, SVG, PDF): im Display
konstante Haarlinie (paperScaleForGl-Kehrwert von meet), im Print echte
0.02 mm - deckungsgleich mit den Schichtfugen in beiden Modi.

- POCHE_STROKE #2b3039 -> #1a1a1a: kein Blaustich mehr, gleicher
  Neutralton wie die Schraffur (Wände/Öffnungen/Decken/Treppen).
- Schichtfuge LAYER_LINE_MM 0.13 -> 0.02 (Haarlinie).
- Schraffur-Stift hatch-hair/hatch-dash 0.05 -> 0.02.
- Wand-Umriss Kategorie 20 lw 0.5 -> 0.35 (Standard-Aussenlinie war zu dick).
- SVG-Schraffur nutzt HAIRLINE_PX/printStrokeVb statt hatchStrokePx;
  PDF-Export echte mm statt widthScreen.
2026-07-03 20:02:18 +02:00
karim 675c68de55 3D-View: Engine (render3d/wgpu) als Standard-Renderer, three.js nur Fallback
WASM_ENGINE_ACTIVE nimmt die Engine, sofern nicht explizit WebGL2 gewählt ist
(?engine=webgl2 bzw. localStorage cad.rendererMode==="webgl2") oder WebGPU
fehlt. three.js bleibt der stille Fallback. Der Engine-3D-Viewport ist vorerst
nur Ansehen (Orbit/Zoom); Auswahl/Griffe/Zeichnen folgen.
2026-07-03 19:47:03 +02:00
karim e9dc423a12 SIA-Wandschraffuren: Beton-Kreuz, Backstein/Dämmung wandrelativ, hairline
- HatchStyle.relativeToWall: der Wandwinkel (aus wall.start/end) wird in
  addWallPoche und resolveWallSectionStyle auf hatch.angle addiert (Vorzeichen
  zur SVG-CW-Konvention passend), sodass die Schraffur der Wandachse folgt.
- sampleProject: sia-concrete (crosshatch 45° absolut), sia-brick (diagonal
  wandrelativ), sia-insulation (diagonal 90° wandrelativ, solide Haarlinie);
  Komponenten Beton/Backstein/Dämmung darauf umgehängt. Dichte Muster (scale
  0.5/0.5/0.45), hairline (Strichgewicht 0.05 → 0.6px-Boden).
- Poché-Hinterlegung: mehrschichtige Wände (und einschichtige) weiss, solid
  schwarz (Fill + Schraffurfarbe), konsistent in SVG- und glPlan-Fill; Mono
  behält Schwarz für solid. Gilt auch für den Schnitt-Cut.
- ResourceManager: Wandbezug-Schalter im Hatch-Manager. exportDxf: Dash-
  Splitting für gestrichelte Schraffuren.
2026-07-03 19:47:03 +02:00
karim 6aaef8f46a glPlan: runde Linien-Caps/Joins + Schraffurbreite bildschirm-konstant
- Runde Enden und Ecken statt Butt-Caps/Miter: jedes Segment als eigenes
  Quad, an Innenecken ein Dreiecks-Fächer über den Aussenwinkel (addRoundJoin),
  an offenen Enden ein Halbkreis-Fächer (addRoundCap). Gilt für Wandumrisse,
  Linien, Bögen und Schraffurläufe — Look wie das Vektor-PDF. Keine Shader-
  Änderung nötig (Radius weiterhin zur Render-Zeit aus strokePx*strokeScale).
- Schraffur-Dicke-Bug behoben: glPlan schickte die Schraffur-mm durch die
  Papier-mm-Pipeline (strokeMm*mmToDevicePx); im Display-Modus ist der darin
  steckende paperScaleN ein zoom-abgeleiteter, nicht auf 0.13/mm kalibrierter
  Wert → Breite explodierte. Jetzt hatchStrokeVb = max(0.6, hatchMm/0.13) als
  screenPx-Batch (skaliert nur mit meet/Zoom) — byte-genau wie SVG-<pattern>
  und der PDF-Export (widthScreen). Wandumrisse unverändert (echte mm).
2026-07-03 19:47:03 +02:00
karim eaf6d8ed7b render3d: 4× MSAA im wgpu-Renderer — glatte 3D-Kanten
Multisampled Farbtarget (SAMPLE_COUNT=4) + resolve_target in die Surface-View je
Frame; Depth-Textur-sample_count synchron auf 4; MSAA-/Depth-Textur werden bei
Resize gemeinsam neu erzeugt; multisample.count=4 auf der Render-Pipeline. Nur
gpu.rs — mesh/section/openings unberührt.

Gates: cargo check (window) + wasm32 --features web grün, cargo test 32/32,
--features render 33/33.
2026-07-03 19:23:21 +02:00
karim d30f79e162 Vektor-PDF: Schraffurbreite skalenunabhängig (Audit-Fund #4)
appendStroke rechnete widthScreen-Schraffurbreiten über mmPerM=1000/
scaleDenominator um → die gedruckte mm-Breite hing vom Export-Massstab ab
(0.25mm bei 1:50 vs 0.13mm bei 1:200 für dieselbe Quellbreite). Jetzt
widthMm * HATCH_DENSITY_MM (0.13) — der exakte Kehrwert von toRenderScene
hatchPx = max(0.6, hatchMm/0.13) → identische Papier-mm bei jedem Massstab,
deckungsgleich zur Bildschirmvorschau. Ungenutzten mmPerM-Parameter entfernt.
2026-07-03 19:06:28 +02:00
karim bde1f3f8d1 PDF-Export: echten Massstab an planToRenderScene durchreichen (Audit-Fund #3, Abschluss)
buildPlanPdf ruft planToRenderScene(plan, opts.scaleDenominator) statt des
Default 1:100 → der Stempel-Zeilenabstand mehrzeiliger Texte ist jetzt auch im
PDF bei Nicht-1:100-Massstab papier-mm-genau (identischer Nenner wie an
sceneToPrintSvg). Schliesst den in der vorigen Änderung offen gelassenen
Aufrufer-Punkt.
2026-07-03 18:56:08 +02:00
karim 2dd7fe339d Stempeltext: Zeilenabstand skalenfest statt fix 1:100 (Audit-Fund #3)
planToRenderScene(plan, paperScaleN=100) leitet den Zeilenabstand mehrzeiliger
Stempeltexte jetzt aus dem tatsächlichen Massstab-Nenner ab (mmToM = paperScaleN
/1000) statt aus der bisher fest verdrahteten 1:100-Konstante. Deckt sich mit dem
nRef der SVG-Text-Formel in PlanView. Viewport/WASM-Aufrufer behalten den Default
100 (deren Referenzmassstab). Der PDF-Export reicht den echten Massstab im
Folgeschritt durch.
2026-07-03 18:54:39 +02:00
karim 3c4d983a7d Print-Vorschau: Strichbreiten auf die PEN_STEPS-Leiter quantisieren (Audit-Fund #2)
Die SVG-Print-Vorschau reichte rohe mm-Breiten in printStrokeVb, während der
PDF-Export jede Breite via quantizePen() auf die Stiftleiter (0.13/0.18/0.25/…)
rundete → Vorschau ≠ Druck. quantizePen ist jetzt aus sceneToPrintSvg.ts
exportiert und wird in den zwei Print-Zweigen von PlanView (DrawingRunShape,
renderPrimitive-weight) verwendet. Nur EINE Leiter, keine Kopie. Haarlinien-Pfad
und Dash-Arrays unangetastet (das PDF quantisiert Dashes ebenfalls nicht).
2026-07-03 18:54:39 +02:00
karim 094d8b4504 Schnitt: Cut-Polygone nutzen die echte Bauteil-Schraffur statt Albedo
Die geschnittenen Flächen erhielten bisher die rohe Albedo-Farbe der Engine plus
eine generische Diagonalschraffur. Jetzt löst attachCutStyles() jede Cut-Fläche
über den index-parallelen ComponentRef auf ihr Quell-Bauteil auf:
- toSection.ts: wallSegmentOwners()/slabSegmentOwners() bilden die exakte
  Segment-Zerlegung aus projectToModel3d nach (gleiche EPS-/Öffnungs-Logik) und
  liefern je emittiertem Segment das Quell-Wall/Ceiling — index-gleich zur
  WASM-Elementreihenfolge (per Test bewiesen: W1,W1,W1,W2).
- generatePlan.ts: resolveWallSectionStyle/resolveCeilingSectionStyle wählen die
  Komponente mit höchster joinPriority (wie die Grundriss-Poché) bzw. die erste
  Deckenschicht und liefern fill+HatchRender über resolveHatch. generateSectionPlan
  nutzt diese, im Mono-Modus weiss/SECTION_INK. Fallback bei fehlendem Bauteil =
  bisheriges Verhalten (Albedo + generische Schraffur).

Gates: tsc -b 0, build grün.
2026-07-03 18:50:31 +02:00
karim 330c01bbbd PlanView: Haarlinien-Modus auch im GPU-Pfad zoom-konstant (Audit-Fund #1)
paperScaleForGl nutzt im hairline-Modus den live aus dem Ausschnitt abgeleiteten
scaleFromView(v) statt des stabilen paperScale. Der GL-Term mm_to_device_px =
N/1000·PX_PER_M·meet wuchs bisher über meet mit dem Zoom, obwohl Display/Haarlinie
konstante Strichbreiten verspricht. scaleFromView ist der exakte Kehrwert von meet
→ N·meet kürzt sich, die Breite in Geräte-px bleibt zoom-unabhängig (dieselbe
Wirkung wie non-scaling-stroke im SVG-Pfad). Print-Modus unverändert.

Restlücke (separat, bräuchte Shader-Änderung): noch nicht wörtlich uniform 1px wie
der SVG-Haarlinienpfad — Breiten bleiben gewichts-proportional, aber zoom-konstant.
2026-07-03 18:47:40 +02:00
karim d2503c1191 render3d: Öffnungen im 3D-Vollkörper (mesh.rs) — geteilte Zerlegung mit section.rs
- openings.rs (neu): split_range_by_voids() — die bisher nur in section.rs
  liegende Pfeiler/Brüstung/Sturz-Zerlegung, herausgezogen als koordinaten-
  neutraler Helfer. section.rs und mesh.rs teilen jetzt EIN Öffnungsmodell.
- section.rs: wall_cut_rectangles delegiert den Sortier-/Rechteck-Teil an
  openings::split_range_by_voids (plane-spezifisches Clipping bleibt lokal).
- mesh.rs: extrude_wall emittiert nicht mehr einen Vollblock je Wand, sondern
  Teilkörper (Pfeiler in voller Höhe + Brüstung/Sturz je Öffnung) → echtes Loch;
  Tür (sill==0) lässt die Brüstung weg und reicht bis zum Boden. Ohne Öffnung
  exakt EIN Block, byte-identische Geometrie zu vorher (Alt-Tests unverändert grün).

Gates: cargo test 32/32 (29+3 neue), wasm32 --features web check grün, nativ grün.
2026-07-03 18:47:40 +02:00
karim e3f460c9f8 Doku: mm-Strichbreiten-Audit über den gesamten Engine-Pfad (Nordstern 1)
Traceanalyse der Strichbreiten von Modell → Bildschirm-bei-Massstab → Druck-mm
über alle vier Pfade (SVG-Display, SVG-Print, Vektor-PDF, render2d/WASM).
Befunde nach Schwere geordnet inkl. konkreter Fix-Vorschläge (Datei:Zeile) und
Verifikations-Rezept. Kernbefund: Hairline/Display-Modus wird von beiden
GPU-Renderern ignoriert; PEN_STEPS-Quantisierung existiert nur im PDF-Pfad.
2026-07-03 18:37:49 +02:00
karim 28b5492def Schnitt/Ansicht: SectionOutput aus render3d an die Zeichenebenen anbinden
- render3d/web.rs: GPU-freies WASM-Binding cut_section_json(model_json, p, n)
  → JSON {cutPolygons, visibleEdges, hiddenEdges} in (u,v)-Metern.
- src/plan/toSection.ts (neu): SectionOutput-Typen, sectionPlaneFromLevel()
  leitet die Schnittebene aus linePoints/directionSign ab, computeSection()
  flacht über projectToModel3d ab und ruft das Binding.
- src/engine/engine3d.ts (neu): geteilter memoisierter pkg3d-Loader, damit
  3D-Viewport und Schnittpfad EINE mod.default()-Init teilen.
- generatePlan.ts: generateSectionPlan() übersetzt SectionOutput in
  bestehende Primitive (Cut = polygon mit Poché-Schraffur, sichtbare Kante =
  line solid, verdeckte Kante = line dashed) — keine neue Primitive-Art nötig.
- App.tsx: SectionPlanView ersetzt den Stub für Ebenen vom Typ Schnitt/Ansicht;
  rendert dasselbe PlanView, mit lokalisierten Hinweisen (lädt/keine Linie/Fehler).
- i18n de/en: section.*-Schlüssel.
- Öffnungen erscheinen korrekt (Brüstung/Sturz-Teilrechtecke) über die
  projectToModel3d-Teilkörper-Zerlegung.

Gates: tsc -b 0, build grün (WASM = eigener Lazy-Chunk), render3d cargo test 29/29,
wasm32 --features web check grün.
2026-07-03 18:37:49 +02:00
karim 4a62dbf83c HANDOVER: Stand 2026-07-03 — Nordstern 2/3/4/5 gelandet, Schnitt-UI-Anbindung offen 2026-07-03 18:18:52 +02:00
karim 8a79f6cbaa wgpu 22 → 29, glyphon 0.6 → 0.11: requestDevice-Shim entfällt
glyphon 0.11 ist die neueste zu wgpu 29 passende Version (wgpu 30 existiert
bereits, glyphon pinnt aber ^29). Das 22er-Limit maxInterStageShaderComponents
wird von 29 nicht mehr in requiredLimits gesendet — src/engine/requestDeviceShim.ts
komplett entfernt, beide Hook-Importstellen (useWasmPlanRenderer, useWasm3dRenderer)
angepasst. pollster 0.3→0.4, naga 22→29 mitgezogen. Alle Draw-/Text-Pfade
(draw_sequence, glyphon ColorMode::Web, widthScreen-Polylinien, Headless/Golden)
unverändert funktionsfähig.

Verifiziert: cargo check nativ (render2d/render3d/src-tauri) grün, cargo test
render2d 17/17 + Golden bit-exakt, render3d 29/29, wasm32 --features web für
beide grün, npx tsc -b + npm run build grün.
2026-07-03 18:17:41 +02:00
karim 9371b65b3b Vektor-PDF aus der RenderScene: eine Szene, zwei Targets
exportPdf baut jetzt planToRenderScene(plan) — identischer Aufruf wie der
Engine-Viewport — und serialisiert über den neuen sceneToPrintSvg nach
Papier-mm: z-stabile Reihenfolge wie compile_scene, PEN_STEPS-Quantisierung
wie bisher, widthScreen-Schraffurbreiten via (widthPx/PX_PER_M)*(1000/N)
in mm umgerechnet, Texte neu als echte Vektor-Texte (alter Pfad liess sie
weg). planToPrintSvg bleibt als Referenz, im Kopf als abgeloest markiert.
probe-pdf.mjs: Icon-Button-Selektor nachgezogen, neue Assertions (Schraffur-
Polylinien vorhanden, alle stroke-widths auf PEN_STEPS). Messung: 3666
Vektor-Pfadoperatoren, 7 Text-Operatoren, 0 Rasterbilder; Inhalt per
pdftoppm 53.51x43.69 mm vs. erwartet 53.45x43.45 bei 1:100.
2026-07-03 08:46:35 +02:00
karim e8f5e7272d HANDOVER: Stand Stand 2026-07-03 (Engine-Meilensteine, offene Arbeit) 2026-07-03 08:42:27 +02:00
karim f95df75ea1 render3d-Schnitt: Öffnungen — Brüstung/Sturz-Teilpolygone und Durchblick
WallInput bekommt openings (from/to/sill/height, serde-default). Der Cut
durch eine Öffnung liefert mehrere einfache Rechtecke (Brüstung, Sturz,
Leibungen) statt Lochpolygon — kompatibel zu render2d::FillPolygon. Der
Verdeckungstest behandelt Öffnungen als Durchblick (u-Zuordnung exakt im
Elevationsfall, konservativ undurchsichtig bei kantennaher Ausrichtung);
Fensterrahmen-Kanten werden als projizierte Kanten ausgegeben. Tests
26 auf 29, Beweis-SVG mit Fenster + dahinterliegender Wand neu generiert
(sichtbares Band exakt im Fensterausschnitt). mesh.rs (3D-Vollkoerper)
beruecksichtigt Öffnungen weiterhin nicht — dokumentierte Luecke.
2026-07-03 08:36:35 +02:00
karim 918f60c498 render2d: Headless-Rendering — PNG ohne Fenster + Golden-Image-Test
HeadlessRenderer (Feature headless) baut Instance/Adapter/Device ohne
Surface (Vulkan, kein Display-Server); render_to_image rendert in eine
Rgba8Unorm-Texture (non-sRGB wie ColorMode::Web) und liest mit 256-Byte-
Row-Padding zurueck. Draw-Code unveraendert geteilt mit dem Fenster-Pfad.
CLI-Bin render_png (Demo-Szene, 990x630); Demo additiv um 45-Grad-
Schraffur, Tuerblatt und Schwenkbogen erweitert, damit das Golden alle
Pfade abdeckt. Golden-Test mit eingechecktem Referenzbild: 0/623700 Pixel
Abweichung, bit-exakt reproduzierbar; bei Abweichung Diff-Dump nach
target/. Doku in docs/design/engine-headless.md.
2026-07-03 08:31:38 +02:00
karim 23410f9b9e 2D-Engine-Parität: WASM-Pfad rendert deckungsgleich zum SVG-Referenzpfad
Sechs Lücken geschlossen: Text-Massstab vom Geometrie-Massstab entkoppelt
(set_text_scale, spiegelt SVG-Referenzskala); glyphon auf ColorMode::Web
(Text war linear-konvertiert zu dunkel); z-basierte Maler-Reihenfolge
(interleavte draw_sequence statt fills-vor-lines, Alt-Szenen unverändert);
CSS-Klassenfarben/-Opacities in toRenderScene gespiegelt (Türschwenk etc.);
greyed-Dimmung 0.3 auf allen Primitiven; Dämmschraffur am Modell-Ursprung
verankert (userSpaceOnUse), exakte Bézier-Wellenform statt Sinus und
kachelgekoppelte Strichbreite (widthScreen-Modus). Probe
scripts/probe-engine-parity.mjs vergleicht ?gl=0 gegen ?engine=wasm;
Rest-Diff nur AA/Glyphen-Rasterung. cargo 17/17, vitest 94/94, Builds grün.
2026-07-03 08:17:01 +02:00
karim 98994c96aa render3d: Schnitt-Modul — Cut-Polygone + sichtbare/verdeckte Kanten aus Prismen
Analytische Eigen-Engine-Alternative zum OCCT-HLR-Spike: Schnittebene
(Punkt+Normale) gegen extrudierte Fussabdruck-Prismen; Cut-Polygone in
(u,v)-Schnittkoordinaten mit Komponenten-Referenz (spaetere Schraffur),
Projektion der dahinterliegenden Kanten mit Verdeckungstest, getrennt
visible/hidden. SectionOutput serde-serialisierbar (Meter). 26 Tests,
Example section_svg schreibt docs/welle-c-hlr-spike/section-engine-proof.svg
(L-Wand+Bodenplatte: Poché, durchgezogene sichtbare, gestrichelte verdeckte
Kanten). Offene Punkte in docs/design/engine-section-pipeline.md.
2026-07-03 08:13:57 +02:00
karim 0e484746de render3d im Browser: WASM/WebGPU-3D-Viewport hinter ?engine=wasm
Feature web (wasm-bindgen) + cdylib analog render2d; WebModelRenderer
mit Canvas-Surface, set_model (walls/slabs wie der native Push) und
set_camera. Projektion liefert bereits [0,1]-Clip-Z, math.rs unveraendert.
wgpu-22-requestDevice-Shim in src/engine/requestDeviceShim.ts geteilt.
Neuer Hook useWasm3dRenderer + Wasm3DViewport (Orbit/Pan/Zoom wie three.js-
Sicht); Viewport3D dispatcht per ?engine=wasm bzw. localStorage, three.js
bleibt Default. Build-Script build:engine3d (wasm-pack, src/engine/pkg3d).
Verifiziert headful per scripts/probe-engine3d.mjs (37 % Geometrie-Pixel);
headless praesentiert Chromium keine WebGPU-Frames (auch bei render2d).
2026-07-03 07:41:37 +02:00
karim 87d12b976f Resource Manager: Materialien-Tab mit PBR-Kugel-Vorschau, Suche und Kategorie-Chips
Geteilter Offscreen-three.js-Renderer (ein Kontext, serielle Queue, Cache
per Map-Signatur) rendert 128px-Kugeln lazy via IntersectionObserver.
Kategorie-Chips aus der Bibliothek abgeleitet, uneinheitliche Manifest-
Schreibweisen normalisiert; Suche und Kategorie kombinierbar. Kachel-Klick
markiert aktiv (gleiche Sprache wie MaterialPicker). Puppeteer-Probe
scripts/probe-material-tiles.mjs prüft Grid, Lazy-Render und Filter.
2026-07-03 02:04:33 +02:00
karim 519735c782 README: kritisch überarbeitet — Parametric Walls, PDF/DXF-Export, Materials-Lib, HLR-Spike-Stand ergänzt; Dev-Port korrigiert 2026-07-03 00:19:54 +02:00
karim 47f1c24bb3 README: keine Browser-App mehr, sondern Electron-Desktop-Shell mit eigener Engine 2026-07-03 00:10:24 +02:00
karim 1bbcc7038f HANDOVER: Electron-WebGPU-Befund korrigieren (funktioniert, kein Fallback)
Der vorherige Eintrag ging von einem WebGL2-Fallback aus; genauere Messung
(GPU-Status erst nach Initialisierung abfragen statt sofort bei whenReady)
zeigt: WebGPU/?engine=wasm laeuft in Electron einwandfrei, per Screenshot
verifiziert (RENDERER-Anzeige zeigt Engine aktiv).
2026-07-03 00:00:00 +02:00
karim e6466a5027 Electron-Prototyp: eigenes App-Fenster statt Tauri/WebKitGTK
Ersetzt den Tauri-Webview-Weg testweise durch eine Electron-Shell (randlos,
ohne native Menüleiste, wie chromium-shell.sh), damit die WASM/WebGPU-Engine
zuverlässig laeuft statt in WebKitGTK. Rust-Backend nicht noetig, da
compute_joins einen TS-Fallback hat. npm run electron zum Starten.
2026-07-02 23:51:23 +02:00
karim 1ab8c7e496 Renderer-Umschalter: Wahl in localStorage persistieren (uebersteht Neustart ohne URL-Param) 2026-07-02 23:38:05 +02:00
karim 0e839b50d6 UI: Renderer-Umschalter (WebGL2 / eigene Engine) in der Statusleiste 2026-07-02 23:35:01 +02:00
karim 623b243306 WASM-Viewport: SVG-Raumtext bei aktiver Engine unterdruecken (kein Doppeltext) 2026-07-02 23:28:25 +02:00
karim 6a7bbeec2f HANDOVER: naechster Schritt = Electron-Prototyp 2026-07-02 23:18:27 +02:00
karim cbf54e6b65 HANDOVER: Richtungsentscheidung Electron/Chromium+WASM statt Tauri; all-native als Fernziel 2026-07-02 23:02:35 +02:00
karim 543d06adb5 HANDOVER: Engine-Nordstern — exakte Breiten, Druck=Bildschirm, Headless, HLR, WebKit-Unabhaengigkeit 2026-07-02 22:31:27 +02:00