God-Files aufgeteilt (ResourceManager/generatePlan/toWalls3d/App.tsx-Handler), Totcode entfernt (geometry-Crate, OCCT/HLR-Spike), PDF/Bild-Import ergänzt.
ResourceManager.tsx, generatePlan.ts und toWalls3d.ts sind nach Bauteil- Domäne in src/ui/resourceManager/, src/plan/generatePlan/ und src/plan/toWalls3d/ aufgeteilt (reine Verschiebung, keine Verhaltens- änderung). App.tsx verliert weitere Handler-Gruppen an eigene Hooks (useExportHandlers, useImportHandling, useKeyboardShortcuts) sowie Hit-Testing an src/viewport/planHitTest.ts. Unbenutzte Rust-geometry-Crate (durch WASM-Joins abgelöst) sowie der alte OCCT/HLR-Schnitt-Spike (hlr.ts/occt.ts, vite occt-Aliases) entfernt. Neu: PDF-Import als Rasterbild (src/io/pdfImport.ts) + gemeinsamer Bild-Asset-Helfer (src/io/imageAsset.ts) für Plan- und Layout-Bilder. tsc -b sauber, vitest 891/891 grün.
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
// Freie-2D-Geometrie-Domäne der 3D-Ableitung: zeigt jede 2D-Zeichnung
|
||||
// (line/polyline/rect) als dünnes Boden-Ribbon-Mesh knapp über ihrer
|
||||
// Geschossebene — die "2D-Referenz im 3D", die der drei.js-Fallback
|
||||
// (`addDrawing2DLines` in Viewport3D.tsx) zeigt.
|
||||
|
||||
import type { Drawing2D, Project, Vec2 } from "../../model/types";
|
||||
import { flattenCategories, getFloor } from "../../model/types";
|
||||
import { DRAWING_LINE_FALLBACK_RGB, hexToRgb, type RMesh, type RRgb } from "./shared";
|
||||
|
||||
/** Halbe Linienbreite der 2D-Boden-Spuren im 3D (Meter) — liest sich als dünne Linie. */
|
||||
const DRAWING_LINE_HALF_WIDTH = 0.008;
|
||||
/** Höhen-Offset über der Geschossebene gegen Z-Fighting (wie addDrawing2DLines in Viewport3D.tsx). */
|
||||
const DRAWING_LINE_ELEVATION_EPS = 0.01;
|
||||
|
||||
/**
|
||||
* Strecken eines 2D-Zeichenelements für die Boden-Spur im 3D — exakt dieselbe
|
||||
* Teilmenge wie `drawing2DSegments` im drei.js-Fallback (`Viewport3D.tsx`):
|
||||
* line/polyline/rect. Kreis/Bogen/Text bleiben aussen vor (keine neue
|
||||
* Fähigkeit gegenüber dem Fallback, nur Parität).
|
||||
*/
|
||||
function drawingSegments3d(d: Drawing2D): [Vec2, Vec2][] {
|
||||
const g = d.geom;
|
||||
const out: [Vec2, Vec2][] = [];
|
||||
if (g.shape === "line") out.push([g.a, g.b]);
|
||||
else if (g.shape === "polyline") {
|
||||
for (let i = 0; i < g.pts.length - 1; i++) out.push([g.pts[i], g.pts[i + 1]]);
|
||||
if (g.closed && g.pts.length > 2) out.push([g.pts[g.pts.length - 1], g.pts[0]]);
|
||||
} else if (g.shape === "rect") {
|
||||
const c1 = g.min, c3 = g.max;
|
||||
const c2 = { x: g.max.x, y: g.min.y }, c4 = { x: g.min.x, y: g.max.y };
|
||||
out.push([c1, c2], [c2, c3], [c3, c4], [c4, c1]);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/** Modellfarbe einer 2D-Zeichnung (color → LineStyle → Kategorie), analog `drawing2DColor`. */
|
||||
function drawingColor3d(project: Project, d: Drawing2D): RRgb {
|
||||
if (d.color) return hexToRgb(d.color, DRAWING_LINE_FALLBACK_RGB);
|
||||
const ls = d.lineStyleId ? project.lineStyles.find((l) => l.id === d.lineStyleId) : undefined;
|
||||
if (ls?.color) return hexToRgb(ls.color, DRAWING_LINE_FALLBACK_RGB);
|
||||
const cat = flattenCategories(project.layers).find((c) => c.code === d.categoryCode);
|
||||
return cat?.color ? hexToRgb(cat.color, DRAWING_LINE_FALLBACK_RGB) : DRAWING_LINE_FALLBACK_RGB;
|
||||
}
|
||||
|
||||
/**
|
||||
* Emittiert je 2D-Zeichnung ein dünnes Ribbon-Mesh knapp über ihrer
|
||||
* Geschossebene — die "2D-Referenz im 3D" (z. B. ein Boden-Raster), die der
|
||||
* drei.js-Fallback (`addDrawing2DLines`) zeigt, bisher aber im nativen
|
||||
* render3d/wgpu-Pfad fehlte (`RModel3d` kannte nur walls/slabs/meshes).
|
||||
* `positions` in MODELL-Metern (x, y, z=Höhe) wie `emitOpeningGlass`; render3d
|
||||
* rendert Kontext-Meshes ohnehin doppelseitig (`append_context_mesh`), daher
|
||||
* genügt ein flaches Ribbon (kein Quader) pro Strecke.
|
||||
*/
|
||||
export function emitDrawingLines(project: Project): RMesh[] {
|
||||
const out: RMesh[] = [];
|
||||
for (const d of project.drawings2d) {
|
||||
const segs = drawingSegments3d(d);
|
||||
if (segs.length === 0) continue;
|
||||
let baseZ = 0;
|
||||
try {
|
||||
baseZ = getFloor(project, d.levelId).baseElevation ?? 0;
|
||||
} catch {
|
||||
// Geschoss nicht (mehr) auflösbar: bei UK 0 zeichnen (Fallback).
|
||||
}
|
||||
const elev = baseZ + DRAWING_LINE_ELEVATION_EPS;
|
||||
const positions: number[] = [];
|
||||
const indices: number[] = [];
|
||||
for (const [a, b] of segs) {
|
||||
const dx = b.x - a.x;
|
||||
const dy = b.y - a.y;
|
||||
const len = Math.hypot(dx, dy);
|
||||
if (len < 1e-9) continue;
|
||||
const nx = (-dy / len) * DRAWING_LINE_HALF_WIDTH;
|
||||
const ny = (dx / len) * DRAWING_LINE_HALF_WIDTH;
|
||||
const base = positions.length / 3;
|
||||
positions.push(
|
||||
a.x + nx, a.y + ny, elev,
|
||||
a.x - nx, a.y - ny, elev,
|
||||
b.x - nx, b.y - ny, elev,
|
||||
b.x + nx, b.y + ny, elev,
|
||||
);
|
||||
indices.push(base, base + 1, base + 2, base, base + 2, base + 3);
|
||||
}
|
||||
if (positions.length === 0) continue;
|
||||
out.push({ positions, indices, kind: "imported", color: drawingColor3d(project, d) });
|
||||
}
|
||||
return out;
|
||||
}
|
||||
Reference in New Issue
Block a user