v0.6.2: dakaansluiting L/T (vleugel met nokdak loopt het hoofddak in met kilkepers, of de kop wordt een schild met hoekkeper; eigen dakdeel en PDF-blad per unit, ook in de kosten), model IJssel (L-vorm met zadeldaken in riet), unit max 4,7 m breed; mansarde vervallen (oude ontwerpen worden een zadeldak met dezelfde nok); gevelbekleding volgt voorbij het wandeinde de daklijn (geen blok meer boven een steil dakvlak) en bij een bolle daklijn per punt de bovenkant van het dak; gevellampen standaard min. 500 mm h.o.h. (geen samengevoegde lamp meer boven een smal raam)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Machiel
2026-10-11 10:19:43 +02:00
co-authored by Claude Opus 5.5
parent bd084e4a96
commit b137a458d4
12 changed files with 589 additions and 172 deletions
+19 -12
View File
@@ -269,6 +269,17 @@ window.WallModel = (() => {
};
}
function raiseTop(CONFIG, d) {
return d ? Object.assign({}, CONFIG, {
wallHeightLeft: CONFIG.wallHeightLeft + d, wallHeightRight: CONFIG.wallHeightRight + d,
wallTop: CONFIG.wallTop.map(q => ({ x: q.x, h: q.h + d }))
}) : CONFIG;
}
// Bovenrand van de buitenlagen: per punt op het dak (skinTop) of de wandrand + skinAbove.
function skinConfig(CONFIG, skinAbove, skinTop) {
return skinTop ? Object.assign({}, CONFIG, { wallHeightLeft: skinTop.hL, wallHeightRight: skinTop.hR, wallTop: skinTop.pts }) : raiseTop(CONFIG, skinAbove);
}
function topPlateOutlines(tl) {
const n = tl.segs.length, L = tl.pts[0], R = tl.pts[n];
return tl.segs.map((sg, i) => [
@@ -769,16 +780,10 @@ window.WallModel = (() => {
const startXM = -halfW;
const topYAt = tl.at;
const skinAbove = opts.skinAbove > 0 ? opts.skinAbove : 0;
const CONFIG_OUT = skinAbove ? Object.assign({}, CONFIG, {
wallHeightLeft: CONFIG.wallHeightLeft + skinAbove, wallHeightRight: CONFIG.wallHeightRight + skinAbove,
wallTop: CONFIG.wallTop.map(q => ({ x: q.x, h: q.h + skinAbove }))
}) : CONFIG;
const tlOut = skinAbove ? topLine(CONFIG_OUT, toM) : tl;
const CONFIG_OUT = skinConfig(CONFIG, skinAbove, opts.skinTop);
const tlOut = CONFIG_OUT === CONFIG ? tl : topLine(CONFIG_OUT, toM);
const battenAbove = typeof opts.battenAbove === 'number' ? opts.battenAbove : skinAbove;
const CONFIG_BAT = battenAbove ? Object.assign({}, CONFIG, {
wallHeightLeft: CONFIG.wallHeightLeft + battenAbove, wallHeightRight: CONFIG.wallHeightRight + battenAbove,
wallTop: CONFIG.wallTop.map(q => ({ x: q.x, h: q.h + battenAbove }))
}) : CONFIG;
const CONFIG_BAT = raiseTop(CONFIG_OUT, battenAbove - skinAbove);
const underPts = tl.underPts;
// LET OP: xMin/xMax zijn wereld-coördinaten (-halfW..+halfW), niet lokaal (0..wallWidth).
@@ -940,7 +945,9 @@ window.WallModel = (() => {
uv.needsUpdate = true;
return geo;
};
const topClampedOut = (x) => tlOut.at(Math.max(-halfW, Math.min(halfW, x)));
// Voorbij het wandeinde (hoekdoorloop) de daklijn volgen: vlak doorgetrokken steekt hij boven een steil dakvlak uit.
const beyondEnd = (T) => (x) => Math.min(T.at(x), T.at(Math.max(-halfW, Math.min(halfW, x))));
const topClampedOut = beyondEnd(tlOut);
const layerShapes = (a, b, y0, yCap) => {
if (b - a <= edgeEps) return [];
const capped = yCap === Infinity;
@@ -1216,7 +1223,7 @@ window.WallModel = (() => {
const rExt = extM(rabatDepthMM);
const rxL = -halfW - rExt.left, rxR = halfW + rExt.right;
const rY0 = Math.max(skinStartY(trasraam), skinFrom) * toM;
const rTop = (x) => tlBat.at(Math.max(-halfW, Math.min(halfW, x)));
const rTop = beyondEnd(tlBat);
const rabatShapes = (rxR - rxL > edgeEps && tlBat.maxY > rY0 + edgeEps)
? columnMinusRects(rxL, rxR, rY0, rTop, outerHoles.map(holeRect), { extraXs: tlBat.kinks.concat([-halfW, halfW]) }).map(piece => {
const shape = new THREE.Shape(piece.outer.map(q => new THREE.Vector2(q.x, q.y)));
@@ -1546,7 +1553,7 @@ window.WallModel = (() => {
return {
STANDARD_BEAM, STOCK_LENGTHS_MM, CORNER_STUDS, EXTERIOR_MATERIALS, OPENING_TYPES, BATTEN, CLADDING_DIRECTIONS, CLADDING_THICK_MM, RABAT, RABAT_COLORS, rabatHex, STUC, STUC_COLORS, isStucColor, stucHex, claddingOffset, cornerExt, TRASRAAM_DEFAULT_MM, STONE, STONE_COLORS, TRASRAAM_STONES, isStoneFinish, stoneThumbUrl, trasraamFor, skinStartY, computeBattens, planPurchase, purchaseText,
sheathingHoles, skinSegmentsAtY, topLine, wallTopPoints, topPlateOutlines, openingTopAt, openingTopMax, openingArea, openingSpanAtY,
sheathingHoles, skinSegmentsAtY, topLine, skinConfig, wallTopPoints, topPlateOutlines, openingTopAt, openingTopMax, openingArea, openingSpanAtY,
validateState, resolveOpenings, computeBOM, groupBOM, buildConfig, configFromState, thicknessOf, computeFrame,
createMaterials, build3D, computeSpecs
};
+1 -1
View File
@@ -1380,7 +1380,7 @@ function mountWallEditor(container, callbacks) {
const inputs = document.querySelectorAll('#tab-wall input');
inputs.forEach(input => {
// Hoogte met de hand gewijzigd: de knikken van een mansarde-/wolfsdak vervallen.
// Hoogte met de hand gewijzigd: de knikken van een wolfsdak vervallen.
if (/^inp-wall-(h-|peak)/.test(input.id)) input.addEventListener('input', () => { wallTopPts = null; });
input.addEventListener('input', updateAll);
});