v0.4.9: naadwanden (2 delen, deur), kopbalken op naden, isolatie niet meer getekend

- HouseModel: naadwand per naad (ensureSeamWalls bij nieuwe woning en unit toevoegen),
  twee delen met beplating alleen aan de kamerzijde, openingen gespiegeld
- WallModel: buitenzijde 'geen', thicknessOf eenzijdig
- FloorModel: kopbalken (rims) voor vloer en dak op naden, ook in PDF en totalen
- isolatie: 3D-lagen en filter verwijderd, berekening blijft

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Machiel
2026-09-30 13:13:07 +02:00
co-authored by Claude Opus 5.5
parent f163f4deb1
commit 9bd7faeaa6
11 changed files with 271 additions and 124 deletions
+17 -55
View File
@@ -98,7 +98,9 @@ window.WallModel = (() => {
// Buitenzijde-materialen (sleutel -> weergavenaam). 'spaanplaat' is voor
// binnenwanden (aan beide zijden spaanplaat).
const EXTERIOR_MATERIALS = { vochtdoek: 'Vochtdoek', cementplaat: 'Cement-gebonden platen', spaanplaat: 'Spaanplaat' };
// 'geen': geen beplating aan de buitenzijde — naadwand-deel dat tegen het
// deel van de andere unit aan staat (HouseModel, naadwanden).
const EXTERIOR_MATERIALS = { vochtdoek: 'Vochtdoek', cementplaat: 'Cement-gebonden platen', spaanplaat: 'Spaanplaat', geen: 'Geen (naadzijde)' };
// Heuristiek (geen volwaardige constraint-solver): elke opening wordt eerst
// individueel gepositioneerd op basis van zijn anker, dan van links naar
@@ -234,10 +236,12 @@ window.WallModel = (() => {
return buildConfig(state.wall, state.openings || []);
}
// Totale wanddikte (mm): regelwerk + beplating aan beide zijden. Gebruikt
// door de unit om wanden met hun buitenkant op de vloerrand te zetten.
function thicknessOf(config) {
return Math.max(config.studDepth, config.plateDepth) + 2 * (config.sheathingThick + SKIN_GAP_MM);
// Totale wanddikte (mm): regelwerk + beplating aan beide zijden (bij
// buitenMateriaal 'geen' alleen aan de binnenzijde). Gebruikt door de unit
// om wanden met hun buitenkant op de vloerrand te zetten.
function thicknessOf(config, buitenMateriaal) {
const sides = buitenMateriaal === 'geen' ? 1 : 2;
return Math.max(config.studDepth, config.plateDepth) + sides * (config.sheathingThick + SKIN_GAP_MM);
}
// Regelwerk: volledige stijlen (incl. koningsstijlen) + kreupele stijlen.
@@ -475,24 +479,19 @@ window.WallModel = (() => {
? new THREE.MeshStandardMaterial({ color: 0xffffff, map: doekMap, roughness: 0.7, side: THREE.DoubleSide })
: new THREE.MeshStandardMaterial({ color: DOEK_COLOR, roughness: 0.7, side: THREE.DoubleSide }),
cementplaatMaterial: new THREE.MeshStandardMaterial({ color: 0x808285, roughness: 0.8, side: THREE.DoubleSide }),
// Zelfde uitstraling als de vloer-isolatie (FloorModel).
battenMaterial: new THREE.MeshStandardMaterial({ color: 0xd9b77e, roughness: 0.7 }),
isolatieMaterial: new THREE.MeshStandardMaterial({
color: 0xffe08c, roughness: 0.9, transparent: true, opacity: 0.5, side: THREE.DoubleSide, depthWrite: false
})
battenMaterial: new THREE.MeshStandardMaterial({ color: 0xd9b77e, roughness: 0.7 })
};
}
// Bouwt de volledige 3D-wand (in meters, lokaal assenstelsel: X = breedte
// gecentreerd, Y = hoogte vanaf onderkant onderregel, +Z = buitenzijde/zuid)
// en geeft daarnaast de volume-boekhouding terug voor de specificaties.
// opts: { materials, buitenMateriaal, cladding, trasraam, spaanplaatVisible, buitenVisible, isolatieVisible }
// opts: { materials, buitenMateriaal, cladding, trasraam, spaanplaatVisible, buitenVisible }
// trasraam: { bottom, top } in mm (wand-coördinaten, zie trasraamFor) of null.
// skinExt: { left, right } in mm (zie cornerExt) of null.
// facade: { u0, extStart, isEnd } (zie computeBattens) of null.
function build3D(CONFIG, calcData, opts) {
const { woodMaterial, spaanplaatMaterial, doekMaterial, cementplaatMaterial, isolatieMaterial, battenMaterial } = opts.materials;
const isolatieVisible = opts.isolatieVisible !== false;
const { woodMaterial, spaanplaatMaterial, doekMaterial, cementplaatMaterial, battenMaterial } = opts.materials;
const buitenMateriaal = opts.buitenMateriaal || 'vochtdoek';
const spaanplaatVisible = opts.spaanplaatVisible !== false;
const buitenVisible = opts.buitenVisible !== false;
@@ -692,48 +691,7 @@ window.WallModel = (() => {
}
});
// D2. ISOLATIE — vult elk vak tussen twee opeenvolgende stijlen (vol of
// kreupel) over de stijldiepte, van bovenkant onderregel tot onderkant
// bovenregel (volgt de dakhelling). Binnen de breedte van een opening
// alleen onder de onderdorpel en boven de bovendorpel. Puur visueel,
// zelfde transparante laag als bij de vloer.
const members = calcData.fullStuds.map(x => x * toM)
.concat(calcData.jackStuds.map(j => j.x * toM))
.map(x => [x - sWidthM / 2, x + sWidthM / 2])
.sort((a, b) => a[0] - b[0]);
const merged = [];
members.forEach(m => {
const last = merged[merged.length - 1];
if (last && m[0] <= last[1] + 1e-9) last[1] = Math.max(last[1], m[1]);
else merged.push([m[0], m[1]]);
});
function addIsolatieBlock(x0, x1, yBottom, yTopLeft, yTopRight) {
if (x1 - x0 <= 1e-6 || Math.min(yTopLeft, yTopRight) - yBottom <= 1e-6) return;
const shape = new THREE.Shape();
shape.moveTo(x0, yBottom);
shape.lineTo(x1, yBottom);
shape.lineTo(x1, yTopRight);
shape.lineTo(x0, yTopLeft);
shape.closePath();
const mesh = new THREE.Mesh(new THREE.ExtrudeGeometry(shape, { steps: 1, depth: sDepthM, bevelEnabled: false }), isolatieMaterial);
mesh.position.set(0, 0, -sDepthM / 2);
mesh.visible = isolatieVisible;
wallGroup3D.add(mesh);
}
for (let i = 0; i < merged.length - 1; i++) {
const x0 = merged[i][1], x1 = merged[i + 1][0];
const yTopL = topYAt(x0) - vertOffset, yTopR = topYAt(x1) - vertOffset;
const mid = (x0 + x1) / 2;
const op = opsM.find(o => mid > o.xMin && mid < o.xMax);
if (!op) {
addIsolatieBlock(x0, x1, pThickM, yTopL, yTopR);
} else {
const sillBottom = op.yMin - sWidthM;
if (sillBottom > pThickM) addIsolatieBlock(x0, x1, pThickM, sillBottom, sillBottom);
const headerTop = op.yMax + sWidthM;
addIsolatieBlock(x0, x1, headerTop, Math.max(headerTop, yTopL), Math.max(headerTop, yTopR));
}
}
// (Isolatie wordt niet getekend; de spouwinhoud zit in computeSpecs.)
// E. VERTICALE PLATEN — gedeelde opbouw voor spaanplaat (binnenzijde,
// altijd) EN cement-gebonden platen (buitenzijde, als die gekozen is):
@@ -912,6 +870,8 @@ window.WallModel = (() => {
const spaanBuiten = buildVerticalBoardSkin(spaanplaatMaterial, 'front', buitenVisible);
spaanplaatBuitenAreaM2 = spaanBuiten.areaM2;
spaanplaatBuitenVolumeM3 = spaanBuiten.volumeM3;
} else if (buitenMateriaal === 'geen') {
// Naadzijde: geen beplating (het deel van de andere unit staat ertegen).
} else if (buitenMateriaal === 'cementplaat') {
const cementResult = buildVerticalBoardSkin(cementplaatMaterial, 'front', buitenVisible, null,
Object.assign(extM(0), { zOut: sThickM + 2 * skinGapM }));
@@ -1104,6 +1064,8 @@ window.WallModel = (() => {
buitenAreaM2 = stats.spaanplaatBuitenAreaM2;
buitenKg = stats.spaanplaatBuitenVolumeM3 * DENSITY_SPAANPLAAT_KGM3;
buitenVolumeM3 = stats.spaanplaatBuitenVolumeM3;
} else if (buitenMateriaal === 'geen') {
buitenAreaM2 = 0; buitenKg = 0; buitenVolumeM3 = 0;
} else if (buitenMateriaal === 'cementplaat') {
buitenAreaM2 = stats.cementplaatAreaM2;
buitenKg = stats.cementplaatVolumeM3 * DENSITY_CEMENTPLAAT_KGM3;
+2 -5
View File
@@ -1231,16 +1231,13 @@ function mountWallEditor(container, callbacks) {
let spaanplaatVisible = true;
let buitenVisible = true;
let isolatieVisible = true;
// Weergave-filter (core/view-filter.js): beplating binnen/buiten + isolatie.
createViewFilter(document.getElementById('wall-toolbar-3d'), [
{ key: 'binnen', label: 'Beplating binnenzijde' },
{ key: 'buiten', label: 'Beplating buitenzijde' },
{ key: 'isolatie', label: 'Isolatie' }
{ key: 'buiten', label: 'Beplating buitenzijde' }
], (v) => {
spaanplaatVisible = v.binnen;
buitenVisible = v.buiten;
isolatieVisible = v.isolatie;
update3DScene();
});
// Omgeving (core/skybox.js: geen/dag/nacht); de wand staat op de tegelvloer.
@@ -1259,7 +1256,7 @@ function mountWallEditor(container, callbacks) {
function update3DScene() {
if (wallGroup3D) scene.remove(wallGroup3D);
const result = WallModel.build3D(CONFIG, calcData, {
materials: wallMaterials, buitenMateriaal, cladding, trasraam, spaanplaatVisible, buitenVisible, isolatieVisible
materials: wallMaterials, buitenMateriaal, cladding, trasraam, spaanplaatVisible, buitenVisible
});
wallGroup3D = result.group;
lastWallStats = result.stats;