Joins Phase 1b: T-Stoss-Kern sticht nur durch den Nah-Putz (keine Achs-Ueberlappung)
Der verschmelzende Abzweig-Kern (Backstein) lief seit Phase 1 bis zur ACHSE der Durchgangswand und ueberlappte deren Koerper. Jetzt stoppt er an der Nahflaeche des Durchgangs-Rueckgrats: mergeCut bei offT + sign*(tT/2 - nearPlaster), wobei nearPlaster die Summe der Durchgangs-Schichten zwischen Nahseite und Rueckgrat-Kern ist. Die L-Seitenlinien der Putzschichten liegen ebenfalls auf dieser Tiefe. Naht zwischen den beiden Kernen entfaellt ueber die bestehenden Mechanismen (stroke:none am Fuellband, noStrokeEdges an den Stirnkanten, Zeichenreihenfolge bricht die Nahflaechenlinie auf) - kein generatePlan-Umbau noetig. Rust-Paritaet in geometry/lib.rs analog (Aggregat-Cuts unveraendert, parity.test gruen). 216 Tests + cargo 7/7.
This commit is contained in:
+14
-7
@@ -267,7 +267,7 @@ function iwWall(id: string, start: Vec2, end: Vec2): Wall {
|
||||
}
|
||||
|
||||
describe("computeJoins — materialbewusster T-Stoss (layerCuts)", () => {
|
||||
it("W9-artiger T-Knoten: Backstein-Kern des Abzweigs verschmilzt (kein Cut), Putz wird getrimmt + L-Seitenlinie", () => {
|
||||
it("W9-artiger T-Knoten: Backstein-Kern des Abzweigs sticht bis zur Rückgrat-Nahfläche durch, Putz wird getrimmt + L-Seitenlinie an derselben Fläche", () => {
|
||||
// Durchgangswand WA1 (0,0)→(5,0) / WA2 (5,0)→(10,0), Abzweig WB (5,0)→(5,3),
|
||||
// alle vom selben Wandtyp "iw" (Innenputz/Backstein/Innenputz, T=0.15).
|
||||
const proj = layeredWallProject(
|
||||
@@ -287,8 +287,14 @@ describe("computeJoins — materialbewusster T-Stoss (layerCuts)", () => {
|
||||
const lc = cuts.layerCuts!;
|
||||
expect(lc.start.length).toBe(3);
|
||||
|
||||
// Schicht 1 (Backstein-Kern, Index 1) verschmilzt: KEIN Cut.
|
||||
expect(lc.start[1]).toBeNull();
|
||||
// Schicht 1 (Backstein-Kern, Index 1) verschmilzt: Cut an der Nahfläche des
|
||||
// Durchgangs-Rückgrats — NICHT null (Achse) und NICHT die Aggregat-Nahfläche
|
||||
// (0.075). Durchgangswand-Halbdicke 0.075 minus Nah-Putz 0.015 → y = 0.06.
|
||||
expect(lc.start[1]).not.toBeNull();
|
||||
expect(distToLine(lc.start[1]!, { x: 5, y: 0.06 })).toBeCloseTo(0, 6);
|
||||
expect(distToLine(lc.start[1]!, { x: 0, y: 0.06 })).toBeCloseTo(0, 6);
|
||||
// Der Kern läuft NICHT bis zur Achse (y=0) durch.
|
||||
expect(distToLine(lc.start[1]!, { x: 5, y: 0 })).not.toBeCloseTo(0, 6);
|
||||
expect(lc.startSide[1]).toBeNull();
|
||||
|
||||
// Schichten 0 und 2 (Innenputz) werden getrimmt: derselbe Nahflächen-Cut
|
||||
@@ -297,12 +303,13 @@ describe("computeJoins — materialbewusster T-Stoss (layerCuts)", () => {
|
||||
expect(lc.start[2]).not.toBeNull();
|
||||
expect(distToLine(lc.start[0]!, { x: 5, y: 0.075 })).toBeCloseTo(0, 6);
|
||||
expect(distToLine(lc.start[2]!, { x: 5, y: 0.075 })).toBeCloseTo(0, 6);
|
||||
// ... UND bekommen die zusätzliche L-Seitenlinie entlang der
|
||||
// Durchgangsachse (durch den Knoten (5,0), Richtung parallel zur x-Achse).
|
||||
// ... UND bekommen die zusätzliche L-Seitenlinie an der Rückgrat-Nahfläche
|
||||
// (y = 0.06, parallel zur Durchgangsachse) — dort endet der durchstechende
|
||||
// Kern.
|
||||
expect(lc.startSide[0]).not.toBeNull();
|
||||
expect(lc.startSide[2]).not.toBeNull();
|
||||
expect(distToLine(lc.startSide[0]!, { x: 5, y: 0 })).toBeCloseTo(0, 6);
|
||||
expect(distToLine(lc.startSide[0]!, { x: 0, y: 0 })).toBeCloseTo(0, 6);
|
||||
expect(distToLine(lc.startSide[0]!, { x: 5, y: 0.06 })).toBeCloseTo(0, 6);
|
||||
expect(distToLine(lc.startSide[0]!, { x: 0, y: 0.06 })).toBeCloseTo(0, 6);
|
||||
|
||||
// Die kollinearen Hälften der Durchgangswand bleiben unangetastet
|
||||
// (unverändertes Verhalten, keine layerCuts für sie).
|
||||
|
||||
+50
-16
@@ -285,7 +285,7 @@ function applyTJunction(
|
||||
const faceCut: Line = { point: facePoint, dir: uT };
|
||||
|
||||
setCut(result, branchEnd, faceCut);
|
||||
applyLayerCuts(project, result, branchEnd, branchWall, throughWall, faceCut, j, uT);
|
||||
applyLayerCuts(project, result, branchEnd, branchWall, throughWall, faceCut, j, uT, sign);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -293,16 +293,22 @@ function applyTJunction(
|
||||
* {@link resolveJoinPriority}): vergleicht jede Schicht der ABZWEIG-Wand mit
|
||||
* dem Rückgrat (höchste `joinPriority`) der DURCHGANGSWAND. Verschmilzt eine
|
||||
* Schicht (gleiche Komponente + Priorität wie das Rückgrat, oder die
|
||||
* Abzweig-Schicht ist sogar prioritärer), bekommt sie KEINEN Cut — das Band
|
||||
* läuft bis zum Wandachsenpunkt durch (die Durchgangswand selbst ist an einem
|
||||
* T-Stoss unzerschnitten und deckt den Rest ab, s. `applyTJunction`-Doc).
|
||||
* Abzweig-Schicht ist sogar prioritärer), bekommt sie einen Cut an der
|
||||
* NAHFLÄCHE DES RÜCKGRAT-KERNS der Durchgangswand: der verschmelzende Abzweig-
|
||||
* Kern (z. B. Backstein) sticht nur durch den Nah-Putz der Durchgangswand und
|
||||
* stoppt am Durchgangs-Kern — er läuft NICHT bis zur Achse durch und überlappt
|
||||
* die Durchgangswand nicht (dort verschmelzen die beiden Kerne nahtlos).
|
||||
* Getrimmte Schichten, die direkt an eine verschmelzende Nachbarschicht
|
||||
* grenzen, bekommen zusätzlich eine seitliche Cut-Linie entlang der
|
||||
* Durchgangsachse (L-Anschluss, z. B. Putz neben durchlaufendem Kern).
|
||||
* grenzen, bekommen zusätzlich eine seitliche Cut-Linie an eben dieser
|
||||
* Rückgrat-Nahfläche (L-Anschluss, z. B. Putz neben durchstechendem Kern).
|
||||
*
|
||||
* Setzt `WallCuts.layerCuts` NUR, wenn mindestens eine Schicht verschmilzt —
|
||||
* sonst bleibt das Feld `undefined` (additiv, bit-identisches Default-
|
||||
* Verhalten für den ganz überwiegenden Fall ohne Materialübereinstimmung).
|
||||
*
|
||||
* `sign` ist die Nahseite der Durchgangswand (der Abzweig-zugewandte `nT`-
|
||||
* Vorzeichen, aus {@link applyTJunction}/{@link applyMidSpanTee}); er bestimmt,
|
||||
* welche Durchgangswand-Schichten als Nah-Putz vor dem Rückgrat liegen.
|
||||
*/
|
||||
function applyLayerCuts(
|
||||
project: Project,
|
||||
@@ -313,16 +319,22 @@ function applyLayerCuts(
|
||||
faceCut: Line,
|
||||
axisPoint: Vec2,
|
||||
throughDir: Vec2,
|
||||
sign: number,
|
||||
): void {
|
||||
const branchWt = getWallType(project, branchWall);
|
||||
const throughWt = getWallType(project, throughWall);
|
||||
if (branchWt.layers.length === 0 || throughWt.layers.length === 0) return;
|
||||
|
||||
// Rückgrat der Durchgangswand: die Schicht mit der höchsten joinPriority.
|
||||
// Rückgrat der Durchgangswand: die Schicht mit der höchsten joinPriority
|
||||
// (Index mitgeführt, um die Nah-Putz-Dicke davor zu bestimmen).
|
||||
let backbone = getComponent(project, throughWt.layers[0].componentId);
|
||||
for (const l of throughWt.layers) {
|
||||
const c = getComponent(project, l.componentId);
|
||||
if (c.joinPriority > backbone.joinPriority) backbone = c;
|
||||
let backboneIdx = 0;
|
||||
for (let i = 0; i < throughWt.layers.length; i++) {
|
||||
const c = getComponent(project, throughWt.layers[i].componentId);
|
||||
if (c.joinPriority > backbone.joinPriority) {
|
||||
backbone = c;
|
||||
backboneIdx = i;
|
||||
}
|
||||
}
|
||||
|
||||
const n = branchWt.layers.length;
|
||||
@@ -352,13 +364,35 @@ function applyLayerCuts(
|
||||
|
||||
const faceArr = branchEnd.end === "start" ? lc.start : lc.end;
|
||||
const sideArr = branchEnd.end === "start" ? lc.startSide : lc.endSide;
|
||||
// Seitliche Cut-Linie entlang der Durchgangsachse, auf Höhe des Wand-
|
||||
// Achsenpunkts (= die Tiefe, bis zu der eine verschmelzende Nachbarschicht
|
||||
// ungekappt durchläuft).
|
||||
const sideLine: Line = { point: axisPoint, dir: throughDir };
|
||||
|
||||
// Nahflächen-Cut des verschmelzenden Kerns: von der Durchgangswand-Nahfläche
|
||||
// (`offT + sign·tT/2`) um die Nah-Putz-Dicke nach innen versetzt — also genau
|
||||
// die dem Abzweig zugewandte Fläche des Rückgrat-Kerns. Nah-Putz = Summe der
|
||||
// Durchgangswand-Schichten, die zwischen der Nahseite (sign) und dem Rückgrat
|
||||
// liegen. Die Schichten stapeln entlang +nT (Index 0 = −tT/2); auf der
|
||||
// +nT-Nahseite (sign>0) sind das die Schichten HINTER dem Rückgrat
|
||||
// (Index > backboneIdx), auf der −nT-Nahseite die davor (Index < backboneIdx).
|
||||
const tT = wallTypeThickness(throughWt);
|
||||
const offT = wallReferenceOffset(throughWall, tT);
|
||||
let nearPlaster = 0;
|
||||
for (let i = 0; i < throughWt.layers.length; i++) {
|
||||
if (sign > 0 ? i > backboneIdx : i < backboneIdx)
|
||||
nearPlaster += throughWt.layers[i].thickness;
|
||||
}
|
||||
const nT = leftNormal(throughDir);
|
||||
const mergePoint = add(
|
||||
axisPoint,
|
||||
scale(nT, offT + sign * (tT / 2 - nearPlaster)),
|
||||
);
|
||||
const mergeCut: Line = { point: mergePoint, dir: throughDir };
|
||||
|
||||
// Getrimmte Nachbarschichten schließen mit ihrer L-Seitenlinie an eben dieser
|
||||
// Rückgrat-Nahfläche (nicht an der Wandachse) — dort endet der Kern und die
|
||||
// Nachbarschicht kappt ihre Breite.
|
||||
const sideLine: Line = mergeCut;
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
faceArr[i] = merged[i] ? null : faceCut;
|
||||
faceArr[i] = merged[i] ? mergeCut : faceCut;
|
||||
const adjMerged =
|
||||
!merged[i] && ((i > 0 && merged[i - 1]) || (i < n - 1 && merged[i + 1]));
|
||||
sideArr[i] = adjMerged ? sideLine : null;
|
||||
@@ -420,5 +454,5 @@ function applyMidSpanTee(
|
||||
// Endes (nicht zwingend w.start) — Anker für die materialbewusste
|
||||
// Pro-Schicht-Erweiterung (analog zum T-Knoten-Fall).
|
||||
const axisPoint = add(w.start, scale(uW, best.distAlong));
|
||||
applyLayerCuts(project, result, freeEnd, freeWall, w, faceCut, axisPoint, uW);
|
||||
applyLayerCuts(project, result, freeEnd, freeWall, w, faceCut, axisPoint, uW, sign);
|
||||
}
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
* an einem T-Stoss zweier verputzter Mauerwerkswände (W9-artig: Innenputz/
|
||||
* Backstein-Kern/Innenputz) darf der Abzweig nicht mehr naiv über die volle
|
||||
* Dicke an der Durchgangswand-Fläche gekappt werden.
|
||||
* • Der Backstein-Kern des Abzweigs läuft UNGEKAPPT bis zur Durchgangsachse
|
||||
* durch (kein Cut an der Nahfläche) — "durchgehender Kern".
|
||||
* • Der Backstein-Kern des Abzweigs sticht durch den Nah-Putz der Durchgangs-
|
||||
* wand und stoppt an deren Kern-Nahfläche (kein Durchlaufen bis zur Achse,
|
||||
* kein Überlappen) — "durchstechender Kern".
|
||||
* • Die Innenputz-Schichten des Abzweigs enden weiterhin an der Nahfläche
|
||||
* UND bekommen eine zusätzliche seitliche L-Linie (cls "layer-joint-l").
|
||||
*/
|
||||
@@ -88,10 +89,11 @@ describe("generatePlan — materialbewusster T-Stoss (Poché-Bänder)", () => {
|
||||
expect(render2.pts[0].y).toBeCloseTo(0.075, 6);
|
||||
expect(render2.pts[3].y).toBeCloseTo(0.075, 6);
|
||||
|
||||
// Der Backstein-Kern verschmilzt: KEIN Cut an der Nahfläche → die
|
||||
// Randpunkte liegen auf der Durchgangsachse (y=0), nicht auf y=0.075.
|
||||
expect(brick.pts[0].y).toBeCloseTo(0, 6);
|
||||
expect(brick.pts[3].y).toBeCloseTo(0, 6);
|
||||
// Der Backstein-Kern verschmilzt, sticht aber nur durch den Nah-Putz der
|
||||
// Durchgangswand bis zur Nahfläche des Durchgangs-Kerns (y = 0.075 − 0.015 =
|
||||
// 0.06) — nicht bis zur Nahfläche (0.075) und NICHT bis zur Achse (0).
|
||||
expect(brick.pts[0].y).toBeCloseTo(0.06, 6);
|
||||
expect(brick.pts[3].y).toBeCloseTo(0.06, 6);
|
||||
});
|
||||
|
||||
it("zeichnet die L-Seitenlinie nur für die getrimmten Putzschichten, nicht für den durchlaufenden Kern", () => {
|
||||
@@ -103,11 +105,11 @@ describe("generatePlan — materialbewusster T-Stoss (Poché-Bänder)", () => {
|
||||
// bekommt keine (er verschmilzt, kein Sprung im Material).
|
||||
expect(lLines.length).toBe(2);
|
||||
|
||||
// Jede L-Linie verläuft entlang der Durchgangsachse (y=0, parallel zur
|
||||
// Jede L-Linie verläuft an der Rückgrat-Nahfläche (y=0.06, parallel zur
|
||||
// x-Achse) und spannt genau die Breite EINER Putzschicht (0.015 m) auf.
|
||||
for (const l of lLines) {
|
||||
expect(l.a.y).toBeCloseTo(0, 6);
|
||||
expect(l.b.y).toBeCloseTo(0, 6);
|
||||
expect(l.a.y).toBeCloseTo(0.06, 6);
|
||||
expect(l.b.y).toBeCloseTo(0.06, 6);
|
||||
expect(Math.abs(l.a.x - l.b.x)).toBeCloseTo(0.015, 6);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user