2D: By-Layer/By-Object-Attribute für Wand/Decke konsistent verdrahtet
resolveBackground (generatePlan/shared.ts) existierte korrekt implementiert, wurde aber nirgends aufgerufen — Wand-/Decken-Poché nutzte überall fest HATCH_INK/HATCH_PAPER, die By-Layer-Hintergrundfarbe kam nie im Renderer an. Signatur an resolveForeground angeglichen (string | undefined statt erzwungenem Component.color-Fallback), damit "kein Override gesetzt" weiter auf die neutrale SIA-Poché-Konvention fällt statt auf die rohe Bauteilfarbe — sonst hätte jedes bestehende Projekt ohne gesetzten Override optisch umgeschlagen. Verdrahtet in walls.ts/ceilings.ts (Grundriss) und neu auch in splitWallLayers/splitSlabLayers (Schnitt, toSection.ts) — dort fehlte bei MEHRSCHICHTIGEM Wand-/Deckentyp zusätzlich foreground/hatchId komplett (owner.foreground/hatchSource wurden nie an resolveForeground/resolveHatchId übergeben, nur der Default lief); splitSlabLayers bekam dafür einen neuen `owner: Ceiling`-Parameter (die einschichtigen Pfade über resolveWallSectionStyle/resolveCeilingSectionStyle waren bereits korrekt). Ceiling.strokeWeight/strokeWeightSource war komplett unverdrahtet (fixe LAYER_LINE_MM-Konstante) — das Attribut-Panel bietet aber einen Editier- Umschalter dafür (identisch zur Wand). addCeilingPoche bekommt jetzt eine aufgelöste lwMm (resolveStrokeWeight, wie schon bei der Wand); die Deckenkontur bleibt weiterhin die gestrichelte Überkopf-Ansichtslinie, nur die Dicke folgt jetzt dem Override — Verhaltensänderung auch im Default-Fall, wenn eine Kategorie eine von LAYER_LINE_MM abweichende Strichstärke trägt. Bewusst NICHT angefasst: Wand-/Decken-Strichstärke im Schnitt-Umriss (SECTION_CUT_OUTLINE_MM in generateSectionPlan) — eine einzige, uniforme Konstante für ALLE Schnitt-Polygone, kein Per-Bauteil-Wert; das wirkt wie eine bewusste Zeichnungskonvention (analog zur "grob"-Vollschwarz-Poché nach SIA 400 B.9/36), nicht wie der "UI verspricht etwas, Renderer hält es nicht"- Bugmuster der übrigen Funde. Würde ausserdem eine Erweiterung von SectionCutPolygon um ein Gewichtsfeld brauchen (heute keins) — grösserer, separat zu scopender Eingriff. 6 neue Tests (splitWallLayers/splitSlabLayers mit/ohne Override, Grundriss weiterhin über die 907 Gesamttests abgedeckt). tsc -b / vitest run (907/907) / npm run build grün.
This commit is contained in:
@@ -58,6 +58,7 @@ import {
|
|||||||
MONO_INK,
|
MONO_INK,
|
||||||
SHOW_ALL,
|
SHOW_ALL,
|
||||||
WALL_FALLBACK_MM,
|
WALL_FALLBACK_MM,
|
||||||
|
resolveBackground,
|
||||||
resolveForeground,
|
resolveForeground,
|
||||||
resolveHatch,
|
resolveHatch,
|
||||||
resolveHatchId,
|
resolveHatchId,
|
||||||
@@ -81,7 +82,7 @@ import { addReferenceLine, addWallPoche, buildWallFootprints, wallGaps } from ".
|
|||||||
// Re-Export des gemeinsamen Vokabulars — externe Konsumenten (Export-Pipeline,
|
// Re-Export des gemeinsamen Vokabulars — externe Konsumenten (Export-Pipeline,
|
||||||
// PlanView, toSection.ts, toWalls3d.ts, toRenderScene.ts, …) importieren
|
// PlanView, toSection.ts, toWalls3d.ts, toRenderScene.ts, …) importieren
|
||||||
// weiterhin ausschliesslich von hier, unverändert zur Zeit vor dem Domänen-Split.
|
// weiterhin ausschliesslich von hier, unverändert zur Zeit vor dem Domänen-Split.
|
||||||
export { HATCH_INK, HATCH_PAPER, resolveForeground, resolveHatch };
|
export { HATCH_INK, HATCH_PAPER, resolveBackground, resolveForeground, resolveHatch, resolveHatchId };
|
||||||
export type { CategoryDisplayResolver, DetailLevel, HatchRender, Primitive };
|
export type { CategoryDisplayResolver, DetailLevel, HatchRender, Primitive };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -309,9 +310,16 @@ export function generatePlan(
|
|||||||
for (const ceiling of ceilings) {
|
for (const ceiling of ceilings) {
|
||||||
const greyed = categoryDisplay(ceiling.categoryCode).greyed;
|
const greyed = categoryDisplay(ceiling.categoryCode).greyed;
|
||||||
const category = catByCode.get(ceiling.categoryCode);
|
const category = catByCode.get(ceiling.categoryCode);
|
||||||
// Kein lwMm mehr: der Decken-Umriss ist eine feste Überkopf-Haarlinie
|
// Strichstärke wie bei der Wand (Attribut-Override > Kategorie > Fallback);
|
||||||
// (gestrichelt), unabhängig von der Kategorie-Strichstärke.
|
// der Umriss bleibt trotzdem eine gestrichelte Überkopf-Ansichtslinie
|
||||||
addCeilingPoche(primitives, project, ceiling, greyed, detail, category, wallFootprints);
|
// (Dash-Muster unverändert, s. addCeilingPoche) — nur die Dicke ist editierbar.
|
||||||
|
const ceilingLwMm = resolveStrokeWeight(
|
||||||
|
ceiling.strokeWeight,
|
||||||
|
ceiling.strokeWeightSource,
|
||||||
|
category,
|
||||||
|
lwByCode.get(ceiling.categoryCode) ?? LAYER_LINE_MM,
|
||||||
|
);
|
||||||
|
addCeilingPoche(primitives, project, ceiling, greyed, detail, category, wallFootprints, ceilingLwMm);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dächer dieses Geschosses (Dachaufsicht): reine Grundriss-Linien (Traufe/
|
// Dächer dieses Geschosses (Dachaufsicht): reine Grundriss-Linien (Traufe/
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ import {
|
|||||||
OVERHEAD_DASH,
|
OVERHEAD_DASH,
|
||||||
POCHE_STROKE,
|
POCHE_STROKE,
|
||||||
LAYER_DETAIL_FACTOR,
|
LAYER_DETAIL_FACTOR,
|
||||||
LAYER_LINE_MM,
|
|
||||||
pocheFill,
|
pocheFill,
|
||||||
|
resolveBackground,
|
||||||
resolveForeground,
|
resolveForeground,
|
||||||
resolveHatch,
|
resolveHatch,
|
||||||
resolveHatchId,
|
resolveHatchId,
|
||||||
@@ -38,7 +38,8 @@ import { segmentInsideWallBand, subtractIntervals, type WallFootprint } from "./
|
|||||||
* hier. Im Detailgrad „grob" entfällt die Schraffur (nur Fläche + Umriss);
|
* hier. Im Detailgrad „grob" entfällt die Schraffur (nur Fläche + Umriss);
|
||||||
* „mittel"/„fein" zeigen die Ansichts-Schraffur des Bauteils (`viewHatchId`,
|
* „mittel"/„fein" zeigen die Ansichts-Schraffur des Bauteils (`viewHatchId`,
|
||||||
* Default weiss) — die frontal gesehene Aufsicht ist kein Schnitt. `lwMm` ist
|
* Default weiss) — die frontal gesehene Aufsicht ist kein Schnitt. `lwMm` ist
|
||||||
* die Kategorie-Strichstärke.
|
* die aufgelöste Umriss-Strichstärke (Attribut-Override > Kategorie > Fallback,
|
||||||
|
* vom Aufrufer via `resolveStrokeWeight` bestimmt, analog zur Wand).
|
||||||
*/
|
*/
|
||||||
export function addCeilingPoche(
|
export function addCeilingPoche(
|
||||||
out: Primitive[],
|
out: Primitive[],
|
||||||
@@ -48,6 +49,7 @@ export function addCeilingPoche(
|
|||||||
detail: DetailLevel,
|
detail: DetailLevel,
|
||||||
category: LayerCategory | undefined,
|
category: LayerCategory | undefined,
|
||||||
wallFootprints: WallFootprint[],
|
wallFootprints: WallFootprint[],
|
||||||
|
lwMm: number,
|
||||||
): void {
|
): void {
|
||||||
const pts = ceiling.outline;
|
const pts = ceiling.outline;
|
||||||
if (pts.length < 3) return;
|
if (pts.length < 3) return;
|
||||||
@@ -86,6 +88,11 @@ export function addCeilingPoche(
|
|||||||
resolveForeground(comp, ceiling.foreground, category, ceiling.foregroundSource),
|
resolveForeground(comp, ceiling.foreground, category, ceiling.foregroundSource),
|
||||||
)
|
)
|
||||||
: NO_HATCH;
|
: NO_HATCH;
|
||||||
|
// Poché-Füllfarbe: Attribut-Override (By-Layer/By-Object) hat Vorrang vor der
|
||||||
|
// neutralen SIA-Fläche, analog zur Wand-Poché (siehe walls.ts).
|
||||||
|
const bgOverride = comp
|
||||||
|
? resolveBackground(comp, ceiling.background, category, ceiling.backgroundSource)
|
||||||
|
: undefined;
|
||||||
// Gefüllte Fläche OHNE eigenen Umriss (stroke:"none"): die Decke liegt unter
|
// Gefüllte Fläche OHNE eigenen Umriss (stroke:"none"): die Decke liegt unter
|
||||||
// der Wand-Poché; ihre Kante wird separat als verdeckungs-geclippte Linie
|
// der Wand-Poché; ihre Kante wird separat als verdeckungs-geclippte Linie
|
||||||
// gezeichnet (s. u.), damit sie nicht durch die darüberstehenden Wände schlägt.
|
// gezeichnet (s. u.), damit sie nicht durch die darüberstehenden Wände schlägt.
|
||||||
@@ -93,7 +100,7 @@ export function addCeilingPoche(
|
|||||||
out.push({
|
out.push({
|
||||||
kind: "polygon",
|
kind: "polygon",
|
||||||
pts: ring,
|
pts: ring,
|
||||||
fill: comp ? pocheFill(hatch.pattern) : "none",
|
fill: comp ? bgOverride ?? pocheFill(hatch.pattern) : "none",
|
||||||
stroke: "none",
|
stroke: "none",
|
||||||
strokeWidthMm: 0,
|
strokeWidthMm: 0,
|
||||||
hatch,
|
hatch,
|
||||||
@@ -128,8 +135,9 @@ export function addCeilingPoche(
|
|||||||
b: add(a, scale(d, t1)),
|
b: add(a, scale(d, t1)),
|
||||||
cls: "ceiling-outline",
|
cls: "ceiling-outline",
|
||||||
// Überkopf-Ansichtslinie (Decke liegt als Slab über der Schnittebene) →
|
// Überkopf-Ansichtslinie (Decke liegt als Slab über der Schnittebene) →
|
||||||
// gestrichelte Haarlinie statt kräftiger Volllinie (BIM-Konvention).
|
// gestrichelt statt durchgezogen (BIM-Konvention) — die DICKE folgt
|
||||||
weightMm: LAYER_LINE_MM * LAYER_DETAIL_FACTOR[detail],
|
// aber ceiling.strokeWeight/-Source wie bei der Wand (s. Aufrufer).
|
||||||
|
weightMm: lwMm * LAYER_DETAIL_FACTOR[detail],
|
||||||
dash: OVERHEAD_DASH,
|
dash: OVERHEAD_DASH,
|
||||||
color: stroke,
|
color: stroke,
|
||||||
greyed,
|
greyed,
|
||||||
|
|||||||
@@ -438,21 +438,25 @@ export function resolveForeground(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kollabiert die Hintergrund-/Füllfarbkette (Poché) eines Bauteils, analog zu
|
* Kollabiert die Hintergrund-/Füllfarbkette (Poché-Override) eines Bauteils zu
|
||||||
* {@link resolveForeground}:
|
* einem einzelnen Wert, exakt analog zu {@link resolveForeground}:
|
||||||
* (Attribut-Override `override`) ?? (`source==="layer"` ⇒ `category.color`) ??
|
* (Attribut-Override `override`) ?? (`source==="layer"` ⇒ `category.color`) ??
|
||||||
* (`Component.background`) ?? `Component.color`.
|
* (`Component.background`) ?? `undefined`.
|
||||||
* Immer definiert (endet spätestens bei `Component.color` = heutiges Verhalten).
|
* `undefined` als Endergebnis heißt „kein Override gesetzt" — Aufrufer fallen
|
||||||
|
* dann auf ihren eigenen Default zurück (bei Wand/Decke die neutrale SIA-
|
||||||
|
* Poché-Farbe HATCH_INK/HATCH_PAPER, NICHT `Component.color` — die reale
|
||||||
|
* Bauteilfarbe soll die Schnitt-Konvention nicht überschreiben, nur ein
|
||||||
|
* bewusster Override).
|
||||||
*/
|
*/
|
||||||
export function resolveBackground(
|
export function resolveBackground(
|
||||||
comp: Component,
|
comp: Component,
|
||||||
override?: string,
|
override?: string,
|
||||||
category?: LayerCategory,
|
category?: LayerCategory,
|
||||||
source?: AttributeSource,
|
source?: AttributeSource,
|
||||||
): string {
|
): string | undefined {
|
||||||
if (override != null) return override;
|
if (override != null) return override;
|
||||||
if (source === "layer") return category?.color ?? comp.background ?? comp.color;
|
if (source === "layer") return category?.color ?? comp.background;
|
||||||
return comp.background ?? comp.color;
|
return comp.background;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import {
|
|||||||
NO_HATCH,
|
NO_HATCH,
|
||||||
OUTLINE_DETAIL_FACTOR,
|
OUTLINE_DETAIL_FACTOR,
|
||||||
POCHE_STROKE,
|
POCHE_STROKE,
|
||||||
|
resolveBackground,
|
||||||
resolveForeground,
|
resolveForeground,
|
||||||
resolveHatch,
|
resolveHatch,
|
||||||
resolveHatchId,
|
resolveHatchId,
|
||||||
@@ -341,6 +342,7 @@ export function addWallPoche(
|
|||||||
// Schichtschraffur (fest in HATCH_INK, siehe resolveHatch) liegt darüber;
|
// Schichtschraffur (fest in HATCH_INK, siehe resolveHatch) liegt darüber;
|
||||||
// Vollmuster ("solid") = Tinten-Poché.
|
// Vollmuster ("solid") = Tinten-Poché.
|
||||||
const layerSolid = layerHatch.pattern === "solid";
|
const layerSolid = layerHatch.pattern === "solid";
|
||||||
|
const bgOverride = resolveBackground(comp, wall.background, category, wall.backgroundSource);
|
||||||
const layerStartCut = s <= 1e-6 ? (layerCuts ? layerCuts.start[li] : startCut) : null;
|
const layerStartCut = s <= 1e-6 ? (layerCuts ? layerCuts.start[li] : startCut) : null;
|
||||||
const layerEndCut = e >= axisLen - 1e-6 ? (layerCuts ? layerCuts.end[li] : endCut) : null;
|
const layerEndCut = e >= axisLen - 1e-6 ? (layerCuts ? layerCuts.end[li] : endCut) : null;
|
||||||
// Durchgangswand-Aussparung: liegt der Quer-Offsetbereich dieses Bandes
|
// Durchgangswand-Aussparung: liegt der Quer-Offsetbereich dieses Bandes
|
||||||
@@ -363,7 +365,7 @@ export function addWallPoche(
|
|||||||
out.push({
|
out.push({
|
||||||
kind: "polygon",
|
kind: "polygon",
|
||||||
pts: clippedBand(axisPt(a), axisPt(b), off, off + layer.thickness, sc, ec),
|
pts: clippedBand(axisPt(a), axisPt(b), off, off + layer.thickness, sc, ec),
|
||||||
fill: layerSolid ? HATCH_INK : HATCH_PAPER,
|
fill: bgOverride ?? (layerSolid ? HATCH_INK : HATCH_PAPER),
|
||||||
// Band ohne Umriss: keine Schichtfuge über die Bandkante, keine 45°-Naht
|
// Band ohne Umriss: keine Schichtfuge über die Bandkante, keine 45°-Naht
|
||||||
// am Knoten. Die Fugen kommen als separate `line`-Primitive (siehe unten).
|
// am Knoten. Die Fugen kommen als separate `line`-Primitive (siehe unten).
|
||||||
stroke: "none",
|
stroke: "none",
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
/**
|
||||||
|
* `splitWallLayers`/`splitSlabLayers` — Attribut-Override (By-Layer/By-Object)
|
||||||
|
* bei MEHRSCHICHTIGEM Wand-/Deckentyp im Schnitt. Vorher wurde `owner.foreground`/
|
||||||
|
* `hatchId`/`hatchSource`/`background`/`backgroundSource` hier komplett ignoriert
|
||||||
|
* (nur der einschichtige Pfad über resolveWallSectionStyle/resolveCeilingSectionStyle
|
||||||
|
* respektierte den Override) — Regressionsschutz für den Nachzieh-Fix
|
||||||
|
* (2D-Vervollständigung, Fund D).
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { describe, it, expect } from "vitest";
|
||||||
|
import { sampleProject } from "../model/sampleProject";
|
||||||
|
import { getCeilingType, getWallType } from "../model/types";
|
||||||
|
import { splitWallLayers, splitSlabLayers, type SectionCutPolygon } from "./toSection";
|
||||||
|
|
||||||
|
const cp: SectionCutPolygon = {
|
||||||
|
component: { kind: "wall", index: 0 },
|
||||||
|
color: [0.5, 0.5, 0.5],
|
||||||
|
pts: [
|
||||||
|
[0, 0],
|
||||||
|
[1, 0],
|
||||||
|
[1, 2],
|
||||||
|
[0, 2],
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
describe("splitWallLayers — Attribut-Override greift auf ALLE Schichten", () => {
|
||||||
|
const wall = sampleProject.walls.find((w) => w.id === "W1")!; // wallTypeId "aw", 4 Schichten
|
||||||
|
const wt = getWallType(sampleProject, wall);
|
||||||
|
|
||||||
|
it("Testvoraussetzung: Wandtyp ist tatsächlich mehrschichtig", () => {
|
||||||
|
expect(wt.layers.length).toBeGreaterThan(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("ohne Override: Füllung bleibt SIA-neutral, nicht die Override-Testfarbe", () => {
|
||||||
|
const bands = splitWallLayers(cp, sampleProject, wt, wall, { x: 1, y: 0 });
|
||||||
|
expect(bands.length).toBe(wt.layers.length);
|
||||||
|
for (const b of bands) {
|
||||||
|
expect(typeof b.fill).toBe("string");
|
||||||
|
expect(b.fill).not.toBe("#ff00ff");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("mit explizitem background-Override: JEDE Schicht bekommt die Override-Farbe", () => {
|
||||||
|
const overridden = { ...wall, background: "#ff00ff" };
|
||||||
|
const bands = splitWallLayers(cp, sampleProject, wt, overridden, { x: 1, y: 0 });
|
||||||
|
expect(bands.length).toBe(wt.layers.length);
|
||||||
|
for (const b of bands) expect(b.fill).toBe("#ff00ff");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("splitSlabLayers — Attribut-Override greift auf ALLE Schichten", () => {
|
||||||
|
const ceiling = (sampleProject.ceilings ?? []).find((c) => c.id === "C1")!; // ceilingTypeId "dg-massiv"
|
||||||
|
const wt = getCeilingType(sampleProject, ceiling);
|
||||||
|
|
||||||
|
it("Testvoraussetzung: Deckentyp ist tatsächlich mehrschichtig", () => {
|
||||||
|
expect(wt.layers.length).toBeGreaterThan(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("mit explizitem background-Override: JEDE Schicht bekommt die Override-Farbe", () => {
|
||||||
|
const overridden = { ...ceiling, background: "#00ffff" };
|
||||||
|
const bands = splitSlabLayers(cp, sampleProject, wt, overridden);
|
||||||
|
expect(bands.length).toBe(wt.layers.length);
|
||||||
|
for (const b of bands) expect(b.fill).toBe("#00ffff");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("mit backgroundSource:'layer': category.color wird für ALLE Schichten übernommen", () => {
|
||||||
|
const category = sampleProject.layers.find((l) => l.code === ceiling.categoryCode)!;
|
||||||
|
const overridden = { ...ceiling, backgroundSource: "layer" as const };
|
||||||
|
const bands = splitSlabLayers(cp, sampleProject, wt, overridden);
|
||||||
|
expect(bands.length).toBe(wt.layers.length);
|
||||||
|
for (const b of bands) expect(b.fill).toBe(category.color);
|
||||||
|
});
|
||||||
|
});
|
||||||
+28
-8
@@ -18,7 +18,7 @@
|
|||||||
// v = absolute Höhe (world.y). Siehe src-tauri/render3d/src/section.rs.
|
// v = absolute Höhe (world.y). Siehe src-tauri/render3d/src/section.rs.
|
||||||
|
|
||||||
import type { Ceiling, DrawingLevel, Project, Vec2, Wall } from "../model/types";
|
import type { Ceiling, DrawingLevel, Project, Vec2, Wall } from "../model/types";
|
||||||
import { getCeilingType, getComponent, getWallType, openingsOfWall, roofLayers } from "../model/types";
|
import { getCeilingType, getComponent, getLayerCategory, getWallType, openingsOfWall, roofLayers } from "../model/types";
|
||||||
import { ceilingVerticalExtent, wallVerticalExtent } from "../model/wall";
|
import { ceilingVerticalExtent, wallVerticalExtent } from "../model/wall";
|
||||||
import { dot, leftNormal, normalize, sub } from "../model/geometry";
|
import { dot, leftNormal, normalize, sub } from "../model/geometry";
|
||||||
import { openingInterval, openingVerticalExtent } from "../geometry/opening";
|
import { openingInterval, openingVerticalExtent } from "../geometry/opening";
|
||||||
@@ -28,9 +28,11 @@ import { loadEngine3d } from "../engine/engine3d";
|
|||||||
import {
|
import {
|
||||||
HATCH_INK,
|
HATCH_INK,
|
||||||
HATCH_PAPER,
|
HATCH_PAPER,
|
||||||
|
resolveBackground,
|
||||||
resolveCeilingSectionStyle,
|
resolveCeilingSectionStyle,
|
||||||
resolveForeground,
|
resolveForeground,
|
||||||
resolveHatch,
|
resolveHatch,
|
||||||
|
resolveHatchId,
|
||||||
resolveWallSectionStyle,
|
resolveWallSectionStyle,
|
||||||
} from "./generatePlan";
|
} from "./generatePlan";
|
||||||
import type { HatchRender } from "./generatePlan";
|
import type { HatchRender } from "./generatePlan";
|
||||||
@@ -343,7 +345,7 @@ function attachCutStyles(output: SectionOutput, project: Project, plane: Section
|
|||||||
if (owner) {
|
if (owner) {
|
||||||
const wt = getCeilingType(project, owner);
|
const wt = getCeilingType(project, owner);
|
||||||
if (wt.layers.length > 1) {
|
if (wt.layers.length > 1) {
|
||||||
bands.push(...splitSlabLayers(cp, project, wt));
|
bands.push(...splitSlabLayers(cp, project, wt, owner));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const style = resolveCeilingSectionStyle(project, owner);
|
const style = resolveCeilingSectionStyle(project, owner);
|
||||||
@@ -761,10 +763,11 @@ function bandFromRect(src: SectionCutPolygon, r: Rect): SectionCutPolygon {
|
|||||||
* aneinanderstoßenden Rechtecken (jedes bekommt in `generateSectionPlan` die
|
* aneinanderstoßenden Rechtecken (jedes bekommt in `generateSectionPlan` die
|
||||||
* generische Schnitt-Umrisslinie).
|
* generische Schnitt-Umrisslinie).
|
||||||
*/
|
*/
|
||||||
function splitSlabLayers(
|
export function splitSlabLayers(
|
||||||
cp: SectionCutPolygon,
|
cp: SectionCutPolygon,
|
||||||
project: Project,
|
project: Project,
|
||||||
wt: ReturnType<typeof getCeilingType>,
|
wt: ReturnType<typeof getCeilingType>,
|
||||||
|
owner: Ceiling,
|
||||||
): SectionCutPolygon[] {
|
): SectionCutPolygon[] {
|
||||||
const totalT = wt.layers.reduce((s, l) => s + l.thickness, 0);
|
const totalT = wt.layers.reduce((s, l) => s + l.thickness, 0);
|
||||||
const us = cp.pts.map((p) => p[0]);
|
const us = cp.pts.map((p) => p[0]);
|
||||||
@@ -776,17 +779,23 @@ function splitSlabLayers(
|
|||||||
const vSpan = vMax - vMin;
|
const vSpan = vMax - vMin;
|
||||||
if (totalT <= 1e-9 || vSpan <= 1e-9) return [cp];
|
if (totalT <= 1e-9 || vSpan <= 1e-9) return [cp];
|
||||||
const scale = vSpan / totalT;
|
const scale = vSpan / totalT;
|
||||||
|
// Attribut-Override der Decke (By-Layer/By-Object) gilt uniform für ALLE
|
||||||
|
// Schichten — analog zu splitWallLayers und dem Grundriss (addCeilingPoche).
|
||||||
|
const category = getLayerCategory(project, owner.categoryCode);
|
||||||
|
|
||||||
const out: SectionCutPolygon[] = [];
|
const out: SectionCutPolygon[] = [];
|
||||||
let acc = 0; // kumulierte Dicke von OK (oben) nach UK (unten)
|
let acc = 0; // kumulierte Dicke von OK (oben) nach UK (unten)
|
||||||
for (const layer of wt.layers) {
|
for (const layer of wt.layers) {
|
||||||
const comp = getComponent(project, layer.componentId);
|
const comp = getComponent(project, layer.componentId);
|
||||||
|
const hatchId =
|
||||||
|
resolveHatchId(owner.hatchId, owner.hatchSource, category, comp.hatchId) ?? comp.hatchId;
|
||||||
const hatch = resolveHatch(
|
const hatch = resolveHatch(
|
||||||
project,
|
project,
|
||||||
comp.hatchId,
|
hatchId,
|
||||||
SECTION_SLAB_AXIS_ANGLE_DEG,
|
SECTION_SLAB_AXIS_ANGLE_DEG,
|
||||||
resolveForeground(comp),
|
resolveForeground(comp, owner.foreground, category, owner.foregroundSource),
|
||||||
);
|
);
|
||||||
|
const bgOverride = resolveBackground(comp, owner.background, category, owner.backgroundSource);
|
||||||
const vTop = vMax - acc * scale;
|
const vTop = vMax - acc * scale;
|
||||||
acc += layer.thickness;
|
acc += layer.thickness;
|
||||||
const vBottom = vMax - acc * scale;
|
const vBottom = vMax - acc * scale;
|
||||||
@@ -799,7 +808,7 @@ function splitSlabLayers(
|
|||||||
[uMax, vBottom],
|
[uMax, vBottom],
|
||||||
[uMin, vBottom],
|
[uMin, vBottom],
|
||||||
],
|
],
|
||||||
fill: hatch.pattern === "solid" ? HATCH_INK : HATCH_PAPER,
|
fill: bgOverride ?? (hatch.pattern === "solid" ? HATCH_INK : HATCH_PAPER),
|
||||||
hatch,
|
hatch,
|
||||||
joinPriority: comp.joinPriority,
|
joinPriority: comp.joinPriority,
|
||||||
componentId: comp.id,
|
componentId: comp.id,
|
||||||
@@ -870,6 +879,9 @@ export function splitWallLayers(
|
|||||||
// Aussen/Innen-Orientierung: per Default liegt layers[0] an uMin; zeigt die
|
// Aussen/Innen-Orientierung: per Default liegt layers[0] an uMin; zeigt die
|
||||||
// Wand-Aufbaurichtung gegen die Schnitt-u-Achse, werden die Bänder gespiegelt.
|
// Wand-Aufbaurichtung gegen die Schnitt-u-Achse, werden die Bänder gespiegelt.
|
||||||
const layers = wallLayersReversedInU(owner, uWorld) ? [...wt.layers].reverse() : wt.layers;
|
const layers = wallLayersReversedInU(owner, uWorld) ? [...wt.layers].reverse() : wt.layers;
|
||||||
|
// Attribut-Override der Wand (By-Layer/By-Object) gilt uniform für ALLE
|
||||||
|
// Schichten — analog zum Grundriss (addWallPoche in walls.ts).
|
||||||
|
const category = getLayerCategory(project, owner.categoryCode);
|
||||||
|
|
||||||
const out: SectionCutPolygon[] = [];
|
const out: SectionCutPolygon[] = [];
|
||||||
let acc = 0; // kumulierte Dicke von uMin (erste einsortierte Schicht) nach uMax
|
let acc = 0; // kumulierte Dicke von uMin (erste einsortierte Schicht) nach uMax
|
||||||
@@ -880,7 +892,15 @@ export function splitWallLayers(
|
|||||||
// entlang v, Modellwinkel 90°). Wie im Grundriss (`addWallPoche` übergibt
|
// entlang v, Modellwinkel 90°). Wie im Grundriss (`addWallPoche` übergibt
|
||||||
// die Wandachse) wird der Achswinkel mitgegeben, sonst liefe die Dämmung
|
// die Wandachse) wird der Achswinkel mitgegeben, sonst liefe die Dämmung
|
||||||
// vertikal statt quer zur Wanddicke (horizontal).
|
// vertikal statt quer zur Wanddicke (horizontal).
|
||||||
const hatch = resolveHatch(project, comp.hatchId, SECTION_WALL_AXIS_ANGLE_DEG, resolveForeground(comp));
|
const hatchId =
|
||||||
|
resolveHatchId(owner.hatchId, owner.hatchSource, category, comp.hatchId) ?? comp.hatchId;
|
||||||
|
const hatch = resolveHatch(
|
||||||
|
project,
|
||||||
|
hatchId,
|
||||||
|
SECTION_WALL_AXIS_ANGLE_DEG,
|
||||||
|
resolveForeground(comp, owner.foreground, category, owner.foregroundSource),
|
||||||
|
);
|
||||||
|
const bgOverride = resolveBackground(comp, owner.background, category, owner.backgroundSource);
|
||||||
const uLeft = uMin + acc * scale;
|
const uLeft = uMin + acc * scale;
|
||||||
acc += layer.thickness;
|
acc += layer.thickness;
|
||||||
const uRight = uMin + acc * scale;
|
const uRight = uMin + acc * scale;
|
||||||
@@ -893,7 +913,7 @@ export function splitWallLayers(
|
|||||||
[uRight, vMin],
|
[uRight, vMin],
|
||||||
[uLeft, vMin],
|
[uLeft, vMin],
|
||||||
],
|
],
|
||||||
fill: hatch.pattern === "solid" ? HATCH_INK : HATCH_PAPER,
|
fill: bgOverride ?? (hatch.pattern === "solid" ? HATCH_INK : HATCH_PAPER),
|
||||||
hatch,
|
hatch,
|
||||||
joinPriority: comp.joinPriority,
|
joinPriority: comp.joinPriority,
|
||||||
componentId: comp.id,
|
componentId: comp.id,
|
||||||
|
|||||||
Reference in New Issue
Block a user