Dach: Auswahl-Hervorhebung auch im 3D (Draht-Umriss der Dachflächen)
selectionHighlightLines bekommt roofIds und emittiert die Kanten aller Dachflächen + Giebel (roofGeometry, Modell→World) als Akzent-Draht — ein selektiertes Dach leuchtet jetzt im wgpu-Viewport wie Wand/Decke. App reicht selectedRoofIds durch. +1 Test. tsc + vitest grün.
This commit is contained in:
+4
-1
@@ -5984,7 +5984,8 @@ function Content({
|
|||||||
selectedWallIds.length === 0 &&
|
selectedWallIds.length === 0 &&
|
||||||
selectedCeilingIds.length === 0 &&
|
selectedCeilingIds.length === 0 &&
|
||||||
selectedOpeningIds.length === 0 &&
|
selectedOpeningIds.length === 0 &&
|
||||||
selectedStairIds.length === 0
|
selectedStairIds.length === 0 &&
|
||||||
|
selectedRoofIds.length === 0
|
||||||
? null
|
? null
|
||||||
: selectionHighlightLines(
|
: selectionHighlightLines(
|
||||||
project,
|
project,
|
||||||
@@ -5993,6 +5994,7 @@ function Content({
|
|||||||
HIGHLIGHT_RGB,
|
HIGHLIGHT_RGB,
|
||||||
selectedOpeningIds,
|
selectedOpeningIds,
|
||||||
selectedStairIds,
|
selectedStairIds,
|
||||||
|
selectedRoofIds,
|
||||||
),
|
),
|
||||||
[
|
[
|
||||||
project,
|
project,
|
||||||
@@ -6000,6 +6002,7 @@ function Content({
|
|||||||
selectedCeilingIds,
|
selectedCeilingIds,
|
||||||
selectedOpeningIds,
|
selectedOpeningIds,
|
||||||
selectedStairIds,
|
selectedStairIds,
|
||||||
|
selectedRoofIds,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,15 @@ describe("selectionHighlightLines", () => {
|
|||||||
expect(lines.length).toBe(0);
|
expect(lines.length).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("ein Dach -> Draht-Kanten der Dachflächen/Giebel (nicht leer, mit Farbe)", () => {
|
||||||
|
// sampleProject enthält das Demo-Satteldach RF1.
|
||||||
|
const lines = selectionHighlightLines(sampleProject, [], [], RGB, [], [], ["RF1"]);
|
||||||
|
expect(lines.length).toBeGreaterThan(0);
|
||||||
|
// Farbe in jedem Vertex (erstes Vertex: [px,py,pz,r,g,b]).
|
||||||
|
expect(lines[3]).toBeCloseTo(RGB[0], 6);
|
||||||
|
expect(lines[5]).toBeCloseTo(RGB[2], 6);
|
||||||
|
});
|
||||||
|
|
||||||
it("eine Wand ohne Öffnungen -> je Materiallage ein Quader, Kern-Band unter der Decke gespalten (5·12 Kanten)", () => {
|
it("eine Wand ohne Öffnungen -> je Materiallage ein Quader, Kern-Band unter der Decke gespalten (5·12 Kanten)", () => {
|
||||||
// W2 (EG, Ost) trägt keine Tür/kein Fenster im Sample-Projekt (nur W1/W3
|
// W2 (EG, Ost) trägt keine Tür/kein Fenster im Sample-Projekt (nur W1/W3
|
||||||
// haben Öffnungen, s. sampleProject.ts) -> ein Achsen-Teilquader. Wandtyp
|
// haben Öffnungen, s. sampleProject.ts) -> ein Achsen-Teilquader. Wandtyp
|
||||||
|
|||||||
+22
-1
@@ -2254,12 +2254,14 @@ export function selectionHighlightLines(
|
|||||||
rgb: RRgb,
|
rgb: RRgb,
|
||||||
openingIds: string[] = [],
|
openingIds: string[] = [],
|
||||||
stairIds: string[] = [],
|
stairIds: string[] = [],
|
||||||
|
roofIds: string[] = [],
|
||||||
): Float32Array {
|
): Float32Array {
|
||||||
if (
|
if (
|
||||||
wallIds.length === 0 &&
|
wallIds.length === 0 &&
|
||||||
ceilingIds.length === 0 &&
|
ceilingIds.length === 0 &&
|
||||||
openingIds.length === 0 &&
|
openingIds.length === 0 &&
|
||||||
stairIds.length === 0
|
stairIds.length === 0 &&
|
||||||
|
roofIds.length === 0
|
||||||
) {
|
) {
|
||||||
return new Float32Array(0);
|
return new Float32Array(0);
|
||||||
}
|
}
|
||||||
@@ -2268,6 +2270,7 @@ export function selectionHighlightLines(
|
|||||||
const ceilingSet = new Set(ceilingIds);
|
const ceilingSet = new Set(ceilingIds);
|
||||||
const openingSet = new Set(openingIds);
|
const openingSet = new Set(openingIds);
|
||||||
const stairSet = new Set(stairIds);
|
const stairSet = new Set(stairIds);
|
||||||
|
const roofSet = new Set(roofIds);
|
||||||
const out: number[] = [];
|
const out: number[] = [];
|
||||||
const pushEdge = (a: RVec3, b: RVec3) => {
|
const pushEdge = (a: RVec3, b: RVec3) => {
|
||||||
out.push(a[0], a[1], a[2], rgb[0], rgb[1], rgb[2]);
|
out.push(a[0], a[1], a[2], rgb[0], rgb[1], rgb[2]);
|
||||||
@@ -2332,5 +2335,23 @@ export function selectionHighlightLines(
|
|||||||
for (const o of openings) if (openingSet.has(o.openingId)) boxEdges(o);
|
for (const o of openings) if (openingSet.has(o.openingId)) boxEdges(o);
|
||||||
for (const s of slabs) if (ceilingSet.has(s.ceilingId)) prismEdges(s.outline, s.zBottom, s.zTop);
|
for (const s of slabs) if (ceilingSet.has(s.ceilingId)) prismEdges(s.outline, s.zBottom, s.zTop);
|
||||||
for (const st of stairs) if (stairSet.has(st.stairId)) prismEdges(st.outline, st.zBottom, st.zTop);
|
for (const st of stairs) if (stairSet.has(st.stairId)) prismEdges(st.outline, st.zBottom, st.zTop);
|
||||||
|
// Dach: die Kanten aller Dachflächen + Giebel als Draht-Umriss (roofGeometry
|
||||||
|
// liefert 3D-Polygone in MODELL-Koordinaten [x, y, z=Höhe]; world = [x, z, y]).
|
||||||
|
if (roofSet.size > 0) {
|
||||||
|
for (const roof of project.roofs ?? []) {
|
||||||
|
if (!roofSet.has(roof.id)) continue;
|
||||||
|
const g = roofGeometry(roof, roofBaseElevation(project, roof));
|
||||||
|
const polyEdges = (pts: readonly (readonly [number, number, number])[]) => {
|
||||||
|
const m = pts.length;
|
||||||
|
for (let i = 0, j = m - 1; i < m; j = i++) {
|
||||||
|
const a = pts[j];
|
||||||
|
const b = pts[i];
|
||||||
|
pushEdge([a[0], a[2], a[1]], [b[0], b[2], b[1]]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
for (const pl of g.planes) polyEdges(pl.pts);
|
||||||
|
for (const gab of g.gables) polyEdges(gab);
|
||||||
|
}
|
||||||
|
}
|
||||||
return new Float32Array(out);
|
return new Float32Array(out);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user