v0.7.3: elektraleidingen nooit meer door een raam of deur (makeOpeningTest): een stijgleiding boven/onder een opening (wcd onder een raam) gaat eerst op dezelfde hoogte opzij tot naast de opening, langs dezelfde wand met een deur of raam ertussen via het plafond, gevellampen om verspringende gevelhoeken heen en het uit elkaar schuiven van buizen eindigt nooit in een opening (alle modellen 0 kruisingen); felsplaten als gevelafwerking (zink/antraciet/zwart, per woning, wand of wandstuk, opbouw als verticale rabat, kleuren gedeeld met het felsdak, in 3D, PDF en kosten); felsplaat op dak én gevel = geen boeideel, de dakplaat zet om over de rand zonder opstand, een boeideel ernaast stopt gelijk met zo'n rand (ook naast daktrim); zijwand bij een overkapping (Palen overkapping › Zijwand) in plaats van een hoekpaal, gestuukt, met de bekleding van de gevel in hetzelfde vlak aan de buitenkant (in 3D, plattegrond, PDF, DXF en kosten); model Reest (12,9 × 7,85 m, lessenaarsdak hoog aan de noordgevel over twee units in één vlak, overkapping bij de voordeur met witte zijwand, aanbouw met plat dak en daktrim, zuidgevel en dak in antraciet felsplaten, verder verticale rabat)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
89cadbebf7
commit
51921650e3
@@ -200,6 +200,7 @@ window.HouseDxf = (() => {
|
||||
const s = pp.size / 2;
|
||||
dxf.polyline([{ x: pp.x - s, z: pp.z - s }, { x: pp.x + s, z: pp.z - s }, { x: pp.x + s, z: pp.z + s }, { x: pp.x - s, z: pp.z + s }].map(T), true, 'PL-PALEN');
|
||||
});
|
||||
parts.posts.walls.forEach(w => dxf.polyline([{ x: w.x0, z: w.z0 }, { x: w.x1, z: w.z0 }, { x: w.x1, z: w.z1 }, { x: w.x0, z: w.z1 }].map(T), true, 'PL-PALEN'));
|
||||
(parts.chimneys || []).forEach(ch => {
|
||||
dxf.polyline(ch.footprint.map(T), true, 'PL-SCHOORSTEEN');
|
||||
dxf.polyline(ch.flueFootprint.map(T), true, 'PL-SCHOORSTEEN');
|
||||
|
||||
+149
-21
@@ -34,7 +34,7 @@ window.HouseModel = (() => {
|
||||
function createDefaultSettings() {
|
||||
return {
|
||||
spacing: { exterior: { min: 240, max: 480 }, interior: { min: 300, max: 600 } },
|
||||
facade: { type: 'rabat', stone: 'K490', rabatColor: 'naturel', stucColor: 'wit' },
|
||||
facade: { type: 'rabat', stone: 'K490', rabatColor: 'naturel', stucColor: 'wit', felsColor: 'antraciet' },
|
||||
cladding: 'horizontaal',
|
||||
trasraam: { enabled: true, height: WallModel.TRASRAAM_DEFAULT_MM, finish: 'cementplaat' },
|
||||
interiorPaint: true,
|
||||
@@ -54,7 +54,7 @@ window.HouseModel = (() => {
|
||||
return { id, attach, unit, roof: RoofModel.createDefaultRoof(unit.floor), lighting: LightingModel.createDefaultUnitLighting(), facade: { walls: {} } };
|
||||
}
|
||||
|
||||
const FACADE_TYPES = { rabat: 'Rabat', steen: 'Steen', stuc: 'Stucwerk' };
|
||||
const FACADE_TYPES = { rabat: 'Rabat', steen: 'Steen', stuc: 'Stucwerk', fels: 'Felsplaten' };
|
||||
function facadeFor(state, u, side, piece) {
|
||||
const f = state.settings.facade;
|
||||
const ow = (u.facade && u.facade.walls && u.facade.walls[side]) || null;
|
||||
@@ -62,15 +62,18 @@ window.HouseModel = (() => {
|
||||
const type = o && FACADE_TYPES[o.type] ? o.type : f.type;
|
||||
const stone = o && o.type === 'steen' && WallModel.isStoneFinish(o.stone) ? o.stone : f.stone;
|
||||
const stuc = o && o.type === 'stuc' && WallModel.isStucColor(o.stuc) ? o.stuc : f.stucColor;
|
||||
return { type, stone, stuc, override: !!o };
|
||||
const fels = o && o.type === 'fels' && WallModel.isFelsColor(o.fels) ? o.fels : f.felsColor;
|
||||
return { type, stone, stuc, fels, override: !!o };
|
||||
}
|
||||
function facadeMaterials(state, fc) {
|
||||
const tr = state.settings.trasraam;
|
||||
const trasraam = tr.enabled ? WallModel.trasraamFor(tr.height, tr.finish) : null;
|
||||
const cladding = state.settings.cladding;
|
||||
if (fc.type === 'steen') return { exterior: 'cementplaat', stone: fc.stone, stuc: null, cladding, trasraam, rabatColor: null };
|
||||
if (fc.type === 'stuc') return { exterior: 'cementplaat', stone: null, stuc: fc.stuc, cladding, trasraam, rabatColor: null };
|
||||
return { exterior: 'vochtdoek', stone: null, stuc: null, cladding, trasraam, rabatColor: state.settings.facade.rabatColor };
|
||||
if (fc.type === 'steen') return { exterior: 'cementplaat', stone: fc.stone, stuc: null, cladding, trasraam, rabatColor: null, fels: null };
|
||||
if (fc.type === 'stuc') return { exterior: 'cementplaat', stone: null, stuc: fc.stuc, cladding, trasraam, rabatColor: null, fels: null };
|
||||
// Felsplaten: opbouw als verticale rabat (latten liggend), de banen staan altijd.
|
||||
if (fc.type === 'fels') return { exterior: 'vochtdoek', stone: null, stuc: null, cladding: 'verticaal', trasraam, rabatColor: null, fels: fc.fels };
|
||||
return { exterior: 'vochtdoek', stone: null, stuc: null, cladding, trasraam, rabatColor: state.settings.facade.rabatColor, fels: null };
|
||||
}
|
||||
|
||||
function newModelState(naam) {
|
||||
@@ -660,6 +663,103 @@ window.HouseModel = (() => {
|
||||
return st;
|
||||
}
|
||||
|
||||
// Model Reest (examples/ontwerp_reest.pdf): 12,9 × 7,85 m. Hoofdvolume 11,5 × 4,8 m onder één lessenaarsdak (hoog
|
||||
// aan de noordgevel) dat aan de westkop 1,4 m doorloopt als overkapping bij de voordeur, aan de zuidkant dicht met
|
||||
// een witte zijwand (PostModel sideWall, geen palen). 4,8 m is te diep voor één unit: twee units (3,4 + 1,4 m, de
|
||||
// naad ten zuiden van het glas in de westgevel) met elk een lessenaar in hetzelfde vlak. Aan de noordwestkant een
|
||||
// aanbouw van 3,89 × 3,05 m met plat dak (toilet, berging, entree), die met een open doorgang op de woonkamer
|
||||
// uitkomt; de voordeur zit onder de overkapping. Zuidgevel en dak in felsplaten (daar geen boeideel: de dakplaat
|
||||
// zet om, en de felsplaten lopen over de zijwand door), de rest verticale rabat; de aanbouw heeft daktrim. De
|
||||
// aanbouw is de eerste unit, zodat alle maten buitenwerks vanaf zijn noordwesthoek gelden, zoals de tekening.
|
||||
// De tekening heeft de zuidgevel van de aanbouw 240 mm zuidelijker (3290); in de configurator ligt hij op de naad.
|
||||
function createReest() {
|
||||
const st = newModelState('Reest');
|
||||
const S = st.settings, HA = 2800, HN = 3500, HM = 2820, HS = 2540, DN = 3400, DS = 1400, V = 1400, FELS = 'antraciet';
|
||||
Object.assign(S.facade, { type: 'rabat', rabatColor: 'naturel', felsColor: FELS });
|
||||
S.cladding = 'verticaal';
|
||||
S.trasraam.enabled = false;
|
||||
Object.assign(S.roof, { fasciaColor: 'wit', overhang: 300, fasciaHeight: 300 });
|
||||
S.roof.posts = PostModel.normalizeSettings({ enabled: true, sideWall: true, sideColor: 'wit', maxSpan: 6000 });
|
||||
S.lighting.mode = 'gevel';
|
||||
S.lighting.direction = 'both';
|
||||
if (S.elektra && S.elektra.apparaten) Object.assign(S.elektra.apparaten, { koken: true, oven: true, vaatwasser: true });
|
||||
if (S.elektra) S.elektra.plateColor = 'antraciet';
|
||||
|
||||
const A = createUnitEntry('A', null, { width: 3890, depth: 3050, height: HA, windowOn: [] });
|
||||
const B = createUnitEntry('B', { to: 'A', side: 'achter', align: 'start', offset: V }, { width: 11500, depth: DN, height: HM, windowOn: [] });
|
||||
const C = createUnitEntry('C', { to: 'B', side: 'achter', align: 'start', offset: 0 }, { width: 11500, depth: DS, height: HS, windowOn: [] });
|
||||
st.units.push(A, B, C);
|
||||
UnitModel.applyRoofForm(B.unit, { type: 'lessenaar', dir: 'voor', low: HM, high: HN });
|
||||
UnitModel.applyRoofForm(C.unit, { type: 'lessenaar', dir: 'voor', low: HS, high: HM });
|
||||
[B, C].forEach(u => { u.roof.covering = 'fels_' + FELS; u.roof.extend = { f: 0, r: 0, b: 0, l: V }; });
|
||||
A.roof.fascia = false;
|
||||
C.facade.walls.achter = { type: 'fels', fels: FELS };
|
||||
[A, B, C].forEach(u => ['voor', 'achter', 'links', 'rechts'].forEach(side => { u.lighting.walls[side] = 'geen'; }));
|
||||
B.lighting.walls.links = 'openingen';
|
||||
|
||||
const { K, binnen, ops } = modelKit(st, HS, 90);
|
||||
// Noord 'right' en zuid 'left' = vanaf de westhoek van de unit; west 'left' = vanaf het noordeind van de wand.
|
||||
ops(A.unit.walls.voor, [['raam', 500, 700, 1400, 'right', 475, K('raam')], ['raam', 800, 1100, 1000, 'right', 2175, K('raam')]]);
|
||||
ops(A.unit.walls.achter, [['voordeur', 1100, 2100, 0, 'left', 230, K('deur', { hinge: 'links', swing: 'buiten', glas: true })]]);
|
||||
ops(B.unit.walls.voor, [
|
||||
['raam', 600, 2100, 0, 'right', 3390, K('raam')],
|
||||
['deur', 900, 2100, 0, 'right', 3990, K('deur', { leaf: 'rechts', hinge: 'links', swing: 'buiten', volglas: true })],
|
||||
['deur', 900, 2100, 0, 'right', 4890, K('deur', { leaf: 'links', hinge: 'rechts', swing: 'buiten', volglas: true })],
|
||||
['raam', 600, 2100, 0, 'right', 5790, K('raam')],
|
||||
['raam', 500, 1400, 700, 'right', 7525, K('raam')],
|
||||
['raam', 500, 1400, 700, 'right', 9975, K('raam')]]);
|
||||
ops(B.unit.walls.links, [['raam', 1800, 2600, 0, 'left', 1480, K('raam')]]);
|
||||
ops(C.unit.walls.achter, [['raam', 1500, 500, 1600, 'left', 2050, K('raam')], ['raam', 1500, 500, 1600, 'left', 7440, K('raam')]]);
|
||||
|
||||
ensureSeamWalls(st, 'A');
|
||||
const seam = st.interiorWalls.find(w => w.seam);
|
||||
if (seam) {
|
||||
// Open doorgang entree → woonkamer (x 1855–3045), gemeten vanaf de binnenkant van de westgevel van B.
|
||||
const tB = WallModel.thicknessOf(WallModel.configFromState(B.unit.walls.links));
|
||||
seam.wall.openings = [{ id: 1, type: 'deur', w: 1190, h: 2300, y: 0, anchor: 'left', offset: Math.round(1855 - V - tB),
|
||||
fill: Object.assign(KozijnModel.defaultFill('deur'), { type: 'geen' }) }];
|
||||
}
|
||||
|
||||
const DH = 2115;
|
||||
// Aanbouw: wanden tot het platte dak. Noord–zuid: 'buiten' = west, 'left' = vanaf de noordkant; west–oost: 'buiten' = zuid, 'left' = vanaf de westkant.
|
||||
const ann = modelKit(st, HA, 90);
|
||||
ann.iw(1335, 190, 1335, 1690); // toilet | berging
|
||||
ann.iw(190, 1735, 3700, 1735, [ // toilet, berging | entree
|
||||
['deur', 930, DH, 'left', 70, binnen({ hinge: 'links', swing: 'buiten' })],
|
||||
['deur', 930, DH, 'left', 1260, binnen({ hinge: 'links', swing: 'buiten' })]]);
|
||||
// Hoofdvolume: wanden onder het laagste punt van het dak, slaapkamer en badkamer met een vlak plafond.
|
||||
const main = modelKit(st, HS - 40, 90);
|
||||
main.iw(8715, 3240, 8715, 7660, [['deur', 930, DH, 'left', 1890, binnen({ hinge: 'rechts', swing: 'buiten' })]]); // woonkamer | slaapkamer, badkamer
|
||||
main.iw(8760, 6215, 12710, 6215, [['deur', 930, DH, 'left', 1815, // slaapkamer | badkamer
|
||||
Object.assign(binnen(), { type: 'schuifdeur', leaves: 1, mount: 'opbouw', side: 'binnen', dir: 'links' })]]);
|
||||
|
||||
const { room, fx } = main;
|
||||
const plafond = { ceiling: HS - 40 };
|
||||
room('A', 700, 1000, 'toilet');
|
||||
room('A', 2500, 1000, 'berging', 'Berging');
|
||||
room('A', 1800, 2400, 'hal', 'Entree');
|
||||
room('B', 3000, 1500, 'woonkeuken', 'Woonkamer/keuken');
|
||||
room('B', 9000, 1500, 'slaapkamer', 'Slaapkamer', plafond);
|
||||
room('C', 9500, 600, 'badkamer', '', plafond);
|
||||
|
||||
const xB = (x) => x - V, zB = (z) => z - 3050, zC = (z) => z - 3050 - DN;
|
||||
fx('toilet', 'A', 735, 640, 0, { w: 1100 });
|
||||
fx('boiler', 'A', 3400, 1430, 90);
|
||||
fx('keuken', 'C', xB(3390), zC(7360), 180, { w: 3600 }, { front: 'antraciet', hogeKast: 'geen', spoelbak: 0.29, kookplaat: true, kookplaatPlek: 0.71 });
|
||||
fx('eettafel', 'B', xB(2490), zB(5160), 0, { w: 1000, d: 1000 }, { vorm: 'rond', stoelen: 4 });
|
||||
fx('bank', 'B', xB(5200), zB(4360), 270, { w: 1600, d: 800 }, { chaise: 'geen' });
|
||||
fx('salontafel', 'B', xB(6740), zB(4200), 0, { w: 800, d: 800 }, { vorm: 'rond' });
|
||||
fx('fauteuil', 'B', xB(6940), zB(5600), 90);
|
||||
fx('bed', 'B', xB(10390), zB(4320), 0, { w: 1600, d: 2100 }, { nachtkastjes: false });
|
||||
fx('kledingkast', 'B', xB(12420), zB(4705), 90, { w: 2900, anchor: 'oost' });
|
||||
fx('toilet', 'C', xB(9420), zC(7300), 180, { w: 1000 });
|
||||
fx('wastafel', 'C', xB(10890), zC(7420), 180, { w: 800 });
|
||||
fx('douche', 'C', xB(12260), zC(6960), 180, { w: 900, d: 1400 }, { glas: 'rechts', glasLengte: 800 });
|
||||
|
||||
computeParts(st, { skip3D: true });
|
||||
return st;
|
||||
}
|
||||
|
||||
// Standaardmodellen: Bestand › Snel nieuw en het venster Nieuw. De sleutel is de template.
|
||||
const MODELS = {
|
||||
amstel: { label: 'Woning Amstel', icon: 'house-heart', create: createAmstel },
|
||||
@@ -667,7 +767,8 @@ window.HouseModel = (() => {
|
||||
ijssel: { label: 'Woning IJssel', icon: 'houses', create: createIJssel },
|
||||
waal: { label: 'Woning Waal', icon: 'house-add', create: createWaal },
|
||||
maas: { label: 'Woning Maas', icon: 'house-check', create: createMaas },
|
||||
rijn: { label: 'Woning Rijn', icon: 'house-gear', create: createRijn }
|
||||
rijn: { label: 'Woning Rijn', icon: 'house-gear', create: createRijn },
|
||||
reest: { label: 'Woning Reest', icon: 'house-up', create: createReest }
|
||||
};
|
||||
|
||||
function createDefaultState(template) {
|
||||
@@ -1259,10 +1360,10 @@ window.HouseModel = (() => {
|
||||
});
|
||||
const ridgePairs = houseShape ? {} : doubleLessenaarPairs(state, rects, cuts);
|
||||
|
||||
function buildWall(config, frame, buitenMateriaal, cladding, trasraam, skinExt, facade, skinFrom, spaanplaatBelow, stone, skinAbove, trimTop, battenAbove, stuc, skinTop) {
|
||||
function buildWall(config, frame, buitenMateriaal, cladding, trasraam, skinExt, facade, skinFrom, spaanplaatBelow, stone, skinAbove, trimTop, battenAbove, stuc, skinTop, fels) {
|
||||
if (!build) return { group: null, stats: null, specs: null };
|
||||
const built = WallModel.build3D(config, frame, {
|
||||
materials: o.wallMaterials, buitenMateriaal, cladding, trasraam, skinExt, facade, skinFrom, spaanplaatBelow, stone, skinAbove, trimTop, battenAbove, stuc, skinTop,
|
||||
materials: o.wallMaterials, buitenMateriaal, cladding, trasraam, skinExt, facade, skinFrom, spaanplaatBelow, stone, skinAbove, trimTop, battenAbove, stuc, skinTop, fels,
|
||||
painted: state.settings.interiorPaint && shows('afwerking'), layers, rabatColor: state.settings.facade.rabatColor
|
||||
});
|
||||
return { group: built.group, stats: built.stats, specs: WallModel.computeSpecs(config, built.stats, buitenMateriaal) };
|
||||
@@ -1282,11 +1383,12 @@ window.HouseModel = (() => {
|
||||
const cladding = m.cladding || 'horizontaal';
|
||||
const stone = buitenMateriaal === 'cementplaat' ? (m.stone || null) : null;
|
||||
const stuc = buitenMateriaal === 'cementplaat' && !stone ? (m.stuc || null) : null;
|
||||
const fels = buitenMateriaal === 'vochtdoek' ? (m.fels || null) : null;
|
||||
const trasraam = buitenMateriaal === 'vochtdoek' || stone || stuc ? (m.trasraam || null) : null;
|
||||
return Object.assign(p, {
|
||||
element: `${u.id}-W${wl.nr}${p.suffix}`,
|
||||
label: `Unit ${u.id} ${wl.label.toLowerCase()}` + (base ? ` opbouw (vanaf ${base} mm)` : p.suffix ? ` (${p.suffix})` : ''),
|
||||
buitenMateriaal, cladding, trasraam: base ? null : trasraam, stone, stuc, facadeOwn: own,
|
||||
buitenMateriaal, cladding, trasraam: base ? null : trasraam, stone, stuc, fels, facadeOwn: own,
|
||||
place: { cx: rect.cx + c.x, cz: rect.cz + c.z, rotY: wl.rotY, width: p.config.wallWidth, thickness: wl.thickness, normal: wl.normal, floorTop: layout.floorTop + base, baseY: base }
|
||||
}); // 3D volgt na assignFacades (latwerk/doek per gevel)
|
||||
});
|
||||
@@ -1634,10 +1736,11 @@ window.HouseModel = (() => {
|
||||
});
|
||||
}));
|
||||
});
|
||||
const facadeDepth = (a, b, nrm) => {
|
||||
// Gevelstuk onder een dakrand (grootste overlap langs de rand); dot < 0 = gevel van een hoger deel ertegenover.
|
||||
const edgePiece = (a, b, nrm) => {
|
||||
const horiz = Math.abs(nrm.z) > 0.5;
|
||||
const line = horiz ? a.z : a.x, s0 = Math.min(horiz ? a.x : a.z, horiz ? b.x : b.z), s1 = Math.max(horiz ? a.x : a.z, horiz ? b.x : b.z);
|
||||
let best = 0, bestOv = 1;
|
||||
let best = null, bestOv = 1;
|
||||
extPieces.forEach(p => {
|
||||
const pn = { x: p.place.normal.x, z: p.place.normal.y };
|
||||
const dot = pn.x * nrm.x + pn.z * nrm.z;
|
||||
@@ -1647,15 +1750,20 @@ window.HouseModel = (() => {
|
||||
const ov = Math.min(s1, Math.max(horiz ? q0.x : q0.z, horiz ? q1.x : q1.z)) - Math.max(s0, Math.min(horiz ? q0.x : q0.z, horiz ? q1.x : q1.z));
|
||||
if (ov <= bestOv) return;
|
||||
bestOv = ov;
|
||||
best = Math.sign(dot) * WallModel.claddingOffset(p.buitenMateriaal, p.stone, p.stuc);
|
||||
best = { p, dot };
|
||||
});
|
||||
return best;
|
||||
};
|
||||
const facadeDepth = (a, b, nrm) => {
|
||||
const e = edgePiece(a, b, nrm);
|
||||
return e ? Math.sign(e.dot) * WallModel.claddingOffset(e.p.buitenMateriaal, e.p.stone, e.p.stuc) : 0;
|
||||
};
|
||||
const facadeFels = (a, b, nrm) => { const e = edgePiece(a, b, nrm); return !!(e && e.dot > 0 && e.p.fels); };
|
||||
const roofEdge = units.length ? RoofModel.computeEdge(state.settings.roof,
|
||||
units.map(u => ({
|
||||
unitId: u.id, rect: u.roof.rect, fascia: state.units.find(su => su.id === u.id).roof.fascia !== false,
|
||||
topAt: u.roof.topAt, ridges: u.roof.ridges
|
||||
})), facadeDepth) : null;
|
||||
covering: u.roof.covering, topAt: u.roof.topAt, ridges: u.roof.ridges
|
||||
})), facadeDepth, facadeFels) : null;
|
||||
const pointInPoly = (q, poly) => {
|
||||
let inside = false;
|
||||
for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) {
|
||||
@@ -1671,13 +1779,13 @@ window.HouseModel = (() => {
|
||||
const sg = [10, 60, 150].map(d => ({ x: m.x + nrm.x * d, z: m.z + nrm.z * d }))
|
||||
.map(q => roofEdge.segments.find(e => pointInPoly(q, [e.a, e.b, e.outerB, e.outerA]))).find(Boolean);
|
||||
if (!sg) return;
|
||||
const h = sg.fascia ? roofEdge.fasciaHeight : roofEdge.trimHeight + roofEdge.edgeAbove;
|
||||
p.battenAbove = (p.skinAbove || 0) + roofEdge.edgeAbove - h;
|
||||
const above = sg.fels ? RoofModel.FELS_EDGE.aboveMM : roofEdge.edgeAbove;
|
||||
p.battenAbove = (p.skinAbove || 0) + above - RoofModel.edgeHeight(roofEdge, sg);
|
||||
});
|
||||
assignFacades(extPieces.concat(interior.filter(p => p.skinFrom !== undefined)));
|
||||
const rooms = RoomModel.compute(state.rooms || [], units, extPieces.concat(interior));
|
||||
extPieces.concat(interior).forEach(p => {
|
||||
const built = buildWall(p.config, p.frame, p.buitenMateriaal, p.cladding, p.trasraam, p.skinExt, p.facade, p.skinFrom, p.spaanplaatBelow, p.stone, p.skinAbove, p.trimTop, p.battenAbove, p.stuc, p.skinTop);
|
||||
const built = buildWall(p.config, p.frame, p.buitenMateriaal, p.cladding, p.trasraam, p.skinExt, p.facade, p.skinFrom, p.spaanplaatBelow, p.stone, p.skinAbove, p.trimTop, p.battenAbove, p.stuc, p.skinTop, p.fels);
|
||||
if (built.group && p.shiftZ) {
|
||||
const outer = new THREE.Group();
|
||||
built.group.position.z = p.shiftZ * 0.001;
|
||||
@@ -1703,7 +1811,21 @@ window.HouseModel = (() => {
|
||||
const elektraGroup = build ? ElektraModel.build3D(elektra, o.elektraMaterials, layers, o.finishedOnly ? false : o.elektraRough) : null;
|
||||
if (elektraGroup) elektraGroup.visible = shows('elektra');
|
||||
|
||||
const posts = PostModel.compute(state.settings.roof.posts, units, groundY);
|
||||
// Zijwand van een overkapping in het vlak van een gevel: die bekleding loopt erover door.
|
||||
const postOutside = (w, out) => {
|
||||
const line = out.x > 0 ? w.x1 : out.x < 0 ? w.x0 : out.z > 0 ? w.z1 : w.z0;
|
||||
const p = extPieces.find(pc => {
|
||||
const n = { x: pc.place.normal.x, z: pc.place.normal.y }, q = UnitModel.localToWorld(pc.place, 0, pc.place.thickness / 2);
|
||||
return n.x * out.x + n.z * out.z > 0.5 && Math.abs((out.x ? q.x : q.z) - line) < 2 && !pc.place.baseY;
|
||||
});
|
||||
if (!p || (p.buitenMateriaal === 'cementplaat' && !p.stone && !p.stuc)) return null;
|
||||
const kind = p.fels ? 'fels' : p.stone ? 'steen' : p.stuc ? 'stuc' : 'rabat';
|
||||
return {
|
||||
kind, depth: WallModel.claddingOffset(p.buitenMateriaal, p.stone, p.stuc),
|
||||
finish: { fels: p.fels, stone: p.stone, stuc: p.stuc, rabatColor: kind === 'rabat' ? state.settings.facade.rabatColor : null, cladding: p.cladding }
|
||||
};
|
||||
};
|
||||
const posts = PostModel.compute(state.settings.roof.posts, units, groundY, postOutside);
|
||||
const postsGroup = build ? PostModel.build3D(posts, o.postMaterials) : null;
|
||||
const chimneysGroup = build && chimneys.length ? ChimneyModel.build3D(chimneys, {
|
||||
materials: o.chimneyMaterials, wallMaterial: o.wallMaterials && o.wallMaterials.spaanplaatMaterial
|
||||
@@ -1957,6 +2079,10 @@ window.HouseModel = (() => {
|
||||
{
|
||||
naam: `Rabat ${WallModel.CLADDING_THICK_MM} mm (gevelbekleding)`, m2: byMat('vochtdoek').reduce((a, p) => a + (p.stats.rabatAreaM2 || 0), 0),
|
||||
m3: null, kg: 0 // gewicht volgt
|
||||
},
|
||||
{
|
||||
naam: 'Felsplaten gevel (staande naad)', m2: byMat('vochtdoek').reduce((a, p) => a + (p.stats.felsAreaM2 || 0), 0),
|
||||
m3: null, kg: byMat('vochtdoek').reduce((a, p) => a + (p.stats.felsAreaM2 || 0), 0) * RoofModel.FELS.kgM2
|
||||
}
|
||||
],
|
||||
weights,
|
||||
@@ -1966,9 +2092,10 @@ window.HouseModel = (() => {
|
||||
return { unit: u.id, name: rb.profile.name, kgM: rb.profile.kgM, lengthM: rb.length / 1000, kg: rb.steelKg, fillM3: rb.fillM3, fillKg: rb.fillKg,
|
||||
util: rb.util, defl: rb.defl, deflMax: rb.deflMax, ok: rb.ok, below: rb.below, loadKNm: rb.loadKNm };
|
||||
}),
|
||||
posts: parts.posts.count ? {
|
||||
posts: parts.posts.count || parts.posts.walls.length ? {
|
||||
count: parts.posts.count, size: parts.posts.size, wood: (PostModel.WOODS[parts.posts.wood] || {}).label || '',
|
||||
lengthM: parts.posts.lengthMM / 1000, m3: parts.posts.m3, kg: parts.posts.kg
|
||||
lengthM: parts.posts.lengthMM / 1000, m3: parts.posts.m3, kg: parts.posts.kg,
|
||||
walls: parts.posts.walls.length, wallM2: parts.posts.wallM2, outsideM2: parts.posts.outsideM2
|
||||
} : null,
|
||||
roofEdge: parts.roofEdge ? {
|
||||
fasciaLengthM: parts.roofEdge.fasciaLengthMM / 1000,
|
||||
@@ -2037,6 +2164,7 @@ window.HouseModel = (() => {
|
||||
if (!WallModel.isStoneFinish(state.settings.facade.stone)) state.settings.facade.stone = def.facade.stone;
|
||||
if (!WallModel.RABAT_COLORS[state.settings.facade.rabatColor]) state.settings.facade.rabatColor = def.facade.rabatColor;
|
||||
if (!WallModel.isStucColor(state.settings.facade.stucColor)) state.settings.facade.stucColor = def.facade.stucColor;
|
||||
if (!WallModel.isFelsColor(state.settings.facade.felsColor)) state.settings.facade.felsColor = def.facade.felsColor;
|
||||
state.settings.trasraam = Object.assign(def.trasraam, state.settings.trasraam || {});
|
||||
state.settings.trasraam.enabled = state.settings.trasraam.enabled !== false;
|
||||
if (!(state.settings.trasraam.height > 0)) state.settings.trasraam.height = WallModel.TRASRAAM_DEFAULT_MM;
|
||||
|
||||
+10
-6
@@ -139,6 +139,8 @@ window.HousePdf = (() => {
|
||||
doc.setLineWidth(0.2);
|
||||
doc.setFillColor(160, 124, 84);
|
||||
parts.posts.posts.forEach(pp => doc.rect(px(pp.x - pp.size / 2), py(pp.z - pp.size / 2), pp.size * scale, pp.size * scale, 'FD'));
|
||||
doc.setFillColor(235, 235, 232);
|
||||
parts.posts.walls.forEach(w => doc.rect(px(w.x0), py(w.z0), (w.x1 - w.x0) * scale, (w.z1 - w.z0) * scale, 'FD'));
|
||||
(parts.chimneys || []).forEach(ch => {
|
||||
doc.setFillColor(150, 150, 150);
|
||||
poly(ch.footprint, 'FD');
|
||||
@@ -257,7 +259,8 @@ window.HousePdf = (() => {
|
||||
const addWall = (p, y0) => {
|
||||
const n = { x: p.place.normal.x, z: p.place.normal.y };
|
||||
const zOut = p.place.thickness / 2 + WallModel.claddingOffset(p.buitenMateriaal, p.stone, p.stuc);
|
||||
const color = p.stone ? (WallModel.STONE_COLORS[p.stone] || '#a0724f') : p.stuc ? WallModel.stucHex(p.stuc) : WallModel.rabatHex(state.settings.facade.rabatColor);
|
||||
const color = p.stone ? (WallModel.STONE_COLORS[p.stone] || '#a0724f') : p.stuc ? WallModel.stucHex(p.stuc) : p.fels ? WallModel.felsHex(p.fels)
|
||||
: WallModel.rabatHex(state.settings.facade.rabatColor);
|
||||
faces.push({ kind: 'wand', pts: wallFace(p, y0).map(q => toWorld(p, q.x, q.y, zOut)), n, color, bias: 0 });
|
||||
const tr = p.trasraam;
|
||||
if (tr && tr.top > y0) {
|
||||
@@ -312,10 +315,9 @@ window.HousePdf = (() => {
|
||||
|
||||
const edge = parts.roofEdge;
|
||||
if (edge) {
|
||||
const fc = (RoofModel.FASCIA_COLORS[edge.fasciaColor] || RoofModel.FASCIA_COLORS.antraciet).hex;
|
||||
const lerp = (a, b, t) => ({ x: a.x + (b.x - a.x) * t, z: a.z + (b.z - a.z) * t });
|
||||
edge.segments.forEach(sg => {
|
||||
const h = sg.fascia ? edge.fasciaHeight : edge.trimHeight + edge.edgeAbove;
|
||||
const h = RoofModel.edgeHeight(edge, sg);
|
||||
const n = Math.max(1, Math.ceil(Math.hypot(sg.outerB.x - sg.outerA.x, sg.outerB.z - sg.outerA.z) / 100));
|
||||
const top = [], bottom = [];
|
||||
for (let k = 0; k <= n; k++) {
|
||||
@@ -324,7 +326,7 @@ window.HousePdf = (() => {
|
||||
top.push({ x: O.x, y: Math.max(tI, tO), z: O.z });
|
||||
bottom.push({ x: O.x, y: Math.min(tI, tO) - h, z: O.z });
|
||||
}
|
||||
faces.push({ kind: 'dakrand', pts: top.concat(bottom.reverse()), n: { x: sg.normal.x, z: sg.normal.z }, color: sg.fascia ? fc : 0xb8bcc0, bias: 3 });
|
||||
faces.push({ kind: 'dakrand', pts: top.concat(bottom.reverse()), n: { x: sg.normal.x, z: sg.normal.z }, color: RoofModel.edgeColor(edge, sg), bias: 3 });
|
||||
});
|
||||
}
|
||||
(parts.chimneys || []).forEach(ch => {
|
||||
@@ -351,14 +353,16 @@ window.HousePdf = (() => {
|
||||
UnitModel.normalizeSplits(u.unit.walls[side].splits).filter(sp => sp.facade).forEach(sp => facades.push(HouseModel.facadeFor(state, u, side, sp.facade)));
|
||||
}));
|
||||
facades.forEach(fc => {
|
||||
const key = fc.type === 'steen' ? 'steen:' + fc.stone : fc.type === 'stuc' ? 'stuc:' + fc.stuc : 'rabat';
|
||||
const key = fc.type === 'steen' ? 'steen:' + fc.stone : fc.type === 'stuc' ? 'stuc:' + fc.stuc : fc.type === 'fels' ? 'fels:' + fc.fels : 'rabat';
|
||||
if (seen.has(key)) return;
|
||||
seen.add(key);
|
||||
items.push(fc.type === 'steen'
|
||||
? { label: 'Gevel', value: `Steen ${fc.stone}`, thumb: WallModel.stoneThumbUrl(fc.stone, 64), color: WallModel.STONE_COLORS[fc.stone] }
|
||||
: fc.type === 'stuc'
|
||||
? { label: 'Gevel', value: `Stucwerk ${((WallModel.STUC_COLORS[fc.stuc] || {}).label || '').toLowerCase()}`, color: WallModel.stucHex(fc.stuc) }
|
||||
: { label: 'Gevel', value: `Rabat ${((WallModel.RABAT_COLORS[st.facade.rabatColor] || {}).label || '').toLowerCase()} (${(WallModel.CLADDING_DIRECTIONS[st.cladding] || st.cladding).toLowerCase()})`, color: WallModel.rabatHex(st.facade.rabatColor) });
|
||||
: fc.type === 'fels'
|
||||
? { label: 'Gevel', value: `Felsplaten ${((WallModel.FELS.COLORS[fc.fels] || {}).label || '').toLowerCase()} (staande naad)`, color: WallModel.felsHex(fc.fels) }
|
||||
: { label: 'Gevel', value: `Rabat ${((WallModel.RABAT_COLORS[st.facade.rabatColor] || {}).label || '').toLowerCase()} (${(WallModel.CLADDING_DIRECTIONS[st.cladding] || st.cladding).toLowerCase()})`, color: WallModel.rabatHex(st.facade.rabatColor) });
|
||||
});
|
||||
if (st.trasraam.enabled) {
|
||||
const tf = st.trasraam.finish;
|
||||
|
||||
+30
-9
@@ -1188,6 +1188,11 @@ function mountHouseEditor(container, callbacks) {
|
||||
const a = toPx(pp.x - pp.size / 2, pp.z - pp.size / 2), sz = pp.size * scale;
|
||||
ctx.fillRect(a.x, a.y, sz, sz); ctx.strokeRect(a.x, a.y, sz, sz);
|
||||
});
|
||||
if (L.dak) parts.posts.walls.forEach(w => {
|
||||
const a = toPx(w.x0, w.z0);
|
||||
ctx.fillStyle = WallModel.stucHex(w.color); ctx.strokeStyle = '#8a8a8a';
|
||||
ctx.fillRect(a.x, a.y, (w.x1 - w.x0) * scale, (w.z1 - w.z0) * scale); ctx.strokeRect(a.x, a.y, (w.x1 - w.x0) * scale, (w.z1 - w.z0) * scale);
|
||||
});
|
||||
(L.gevel ? parts.chimneys || [] : []).forEach(ch => {
|
||||
const path = (pts) => { ctx.beginPath(); pts.forEach((p, i) => { const q = toPx(p.x, p.z); if (i) ctx.lineTo(q.x, q.y); else ctx.moveTo(q.x, q.y); }); ctx.closePath(); };
|
||||
const sn = chDrag && chDrag.moved && chDrag.snap && chDrag.id === ch.id ? chDrag.snap : null;
|
||||
@@ -1343,6 +1348,7 @@ function mountHouseEditor(container, callbacks) {
|
||||
const stoneOptions = Object.assign({}, ...WallModel.TRASRAAM_STONES.map(c => ({ [c]: `Steen ${c}` })));
|
||||
const trasraamFinishes = Object.assign({ cementplaat: 'Cementplaat' }, stoneOptions);
|
||||
const stucColors = Object.fromEntries(Object.entries(WallModel.STUC_COLORS).map(([k, c]) => [k, c.label]));
|
||||
const felsColors = Object.fromEntries(Object.entries(WallModel.FELS.COLORS).map(([k, c]) => [k, c.label]));
|
||||
const swatchOf = (hex) => `<div class="ins-swatch" style="background:${hex}"></div>`;
|
||||
function wireButtons(body) {
|
||||
body.querySelectorAll('[data-go]').forEach(b => b.addEventListener('click', () => showPart(b.dataset.go)));
|
||||
@@ -1362,16 +1368,21 @@ function mountHouseEditor(container, callbacks) {
|
||||
const rabatUi = sel('hs-cladding', 'Richting', WallModel.CLADDING_DIRECTIONS, st.cladding, { hint: 'Rabat op vochtdoek en kruislat' }) +
|
||||
pair(sel('hs-rabat-color', 'Kleur', rabatColors, st.facade.rabatColor, { hint: 'Ook voor rabat-overrides per wand' }),
|
||||
`<div class="ins-swatch" style="background:${WallModel.rabatHex(st.facade.rabatColor)}"></div>`);
|
||||
const usesRabat = state.units.some(u => Object.keys(u.unit.walls).some(side => HouseModel.facadeFor(state, u, side).type === 'rabat' ||
|
||||
UnitModel.normalizeSplits(u.unit.walls[side].splits).some(sp => sp.facade && sp.facade.type === 'rabat')));
|
||||
const uses = (type) => state.units.some(u => Object.keys(u.unit.walls).some(side => HouseModel.facadeFor(state, u, side).type === type ||
|
||||
UnitModel.normalizeSplits(u.unit.walls[side].splits).some(sp => sp.facade && sp.facade.type === type)));
|
||||
const usesRabat = uses('rabat');
|
||||
const felsUi = pair(sel('hs-fels-color', 'Kleur', felsColors, st.facade.felsColor,
|
||||
{ hint: `Staande naad, banen van ${WallModel.FELS.SEAM_MM} mm, op latten zoals verticale rabat; ook voor fels-overrides per wand` }),
|
||||
swatchOf(WallModel.felsHex(st.facade.felsColor)));
|
||||
return [
|
||||
{ label: 'Bekleding', html: sel('hs-facade', 'Type', HouseModel.FACADE_TYPES, st.facade.type, { hint: 'Voor alle buitenwanden; per wand of wandstuk aan te passen (selecteer de wand)' }) +
|
||||
(st.facade.type === 'steen'
|
||||
? pair(sel('hs-facade-stone', 'Steen', stoneOptions, st.facade.stone, { hint: `Steenstrip op isolatieblok, samen ${WallModel.STONE.THICK_MM} mm dik` }), thumb(WallModel.stoneThumbUrl(st.facade.stone, 64), st.facade.stone))
|
||||
: st.facade.type === 'stuc'
|
||||
? pair(sel('hs-stuc-color', 'Kleur', stucColors, st.facade.stucColor, { hint: `Pleisterlaag ${WallModel.STUC.THICK_MM} mm op cement-gebonden plaat` }), swatchOf(WallModel.stucHex(st.facade.stucColor)))
|
||||
: rabatUi) },
|
||||
: st.facade.type === 'fels' ? felsUi : rabatUi) },
|
||||
st.facade.type !== 'rabat' && usesRabat ? { label: 'Rabat (overrides)', html: rabatUi } : null,
|
||||
st.facade.type !== 'fels' && uses('fels') ? { label: 'Felsplaten (overrides)', html: felsUi } : null,
|
||||
{ label: 'Trasraam', html: toggle('hs-trasraam', 'Trasraam', st.trasraam.enabled, { hint: 'Strook onderaan de gevel, onder rabat én steen' }) +
|
||||
(st.trasraam.enabled
|
||||
? UI.range('hs-trasraam-h', 'Hoogte', st.trasraam.height, { min: 100, max: 1000, step: 10, hint: 'Vanaf bovenkant vloer' }) +
|
||||
@@ -1391,6 +1402,7 @@ function mountHouseEditor(container, callbacks) {
|
||||
UI.onSel('hs-rabat-color', v => { st.facade.rabatColor = v; }, rerender);
|
||||
UI.onSel('hs-facade-stone', v => { st.facade.stone = v; }, rerender);
|
||||
UI.onSel('hs-stuc-color', v => { st.facade.stucColor = v; }, rerender);
|
||||
UI.onSel('hs-fels-color', v => { st.facade.felsColor = v; }, rerender);
|
||||
UI.onToggle('hs-trasraam', v => { st.trasraam.enabled = v; }, rerender);
|
||||
UI.onRange('hs-trasraam-h', v => { if (v > 0) st.trasraam.height = v; }, after);
|
||||
UI.onSel('hs-trasraam-finish', v => { st.trasraam.finish = v; }, rerender);
|
||||
@@ -1431,7 +1443,9 @@ function mountHouseEditor(container, callbacks) {
|
||||
{ label: 'Daktrim', html: num('hs-trim-h', 'Hoogte', r.trimHeight, { step: 5, hint: 'Bij units zonder boeidelen' }) },
|
||||
{ label: 'Palen overkapping', html:
|
||||
toggle('hs-posts', 'Palen', r.posts.enabled, { hint: `Onder een dak dat minstens de min. uitkraging buiten de vloer steekt (veranda); per unit: Overkapping. Nu ${parts ? parts.posts.count : 0} st.` }) +
|
||||
(r.posts.enabled ? sel('hs-posts-wood', 'Hout', Object.fromEntries(Object.entries(PostModel.WOODS).map(([k, w]) => [k, w.label])), r.posts.wood) +
|
||||
(r.posts.enabled ? toggle('hs-posts-side', 'Zijwand', r.posts.sideWall, { hint: `Vrije hoek dicht met een gestuukte wand (${PostModel.SIDE_MM} mm) terug tot de gevel, in plaats van een hoekpaal` }) +
|
||||
(r.posts.sideWall ? pair(sel('hs-posts-side-color', 'Kleur zijwand', stucColors, r.posts.sideColor), swatchOf(WallModel.stucHex(r.posts.sideColor))) : '') +
|
||||
sel('hs-posts-wood', 'Hout', Object.fromEntries(Object.entries(PostModel.WOODS).map(([k, w]) => [k, w.label])), r.posts.wood) +
|
||||
UI.range('hs-posts-size', 'Maat', r.posts.size, { min: 100, max: 300, step: 10, hint: 'Vierkant, mm' }) +
|
||||
num('hs-posts-span', 'Max. h.o.h.', r.posts.maxSpan, { step: 100, hint: 'Grootste afstand tussen palen (of paal en gevel)' }) +
|
||||
num('hs-posts-min', 'Min. uitkraging', r.posts.minExt, { step: 100, hint: 'Kleinere overstekken krijgen geen palen' }) : '') },
|
||||
@@ -1449,6 +1463,8 @@ function mountHouseEditor(container, callbacks) {
|
||||
UI.onSel('hs-fascia-color', v => { r.fasciaColor = v; }, rerender);
|
||||
UI.onNum('hs-trim-h', v => { r.trimHeight = v; }, after, pos);
|
||||
UI.onToggle('hs-posts', v => { r.posts.enabled = v; }, rerender);
|
||||
UI.onToggle('hs-posts-side', v => { r.posts.sideWall = v; }, rerender);
|
||||
UI.onSel('hs-posts-side-color', v => { r.posts.sideColor = v; }, rerender);
|
||||
UI.onSel('hs-posts-wood', v => { r.posts.wood = v; }, rerender);
|
||||
UI.onRange('hs-posts-size', v => { if (v > 0) r.posts.size = v; }, after);
|
||||
UI.onNum('hs-posts-span', v => { if (v >= 1000) r.posts.maxSpan = v; }, after, pos);
|
||||
@@ -2136,7 +2152,8 @@ function mountHouseEditor(container, callbacks) {
|
||||
{ label: 'Gevel (hele zijde)', html:
|
||||
sel('hw-facade', 'Type', Object.assign({ woning: woningLabel }, HouseModel.FACADE_TYPES), ov ? ov.type : 'woning') +
|
||||
(ov && ov.type === 'steen' ? pair(sel('hw-facade-stone', 'Steen', stoneOptions, fc.stone), thumb(WallModel.stoneThumbUrl(fc.stone, 64), fc.stone)) : '') +
|
||||
(ov && ov.type === 'stuc' ? pair(sel('hw-facade-stuc', 'Kleur', stucColors, fc.stuc), swatchOf(WallModel.stucHex(fc.stuc))) : '') },
|
||||
(ov && ov.type === 'stuc' ? pair(sel('hw-facade-stuc', 'Kleur', stucColors, fc.stuc), swatchOf(WallModel.stucHex(fc.stuc))) : '') +
|
||||
(ov && ov.type === 'fels' ? pair(sel('hw-facade-fels', 'Kleur', felsColors, fc.fels), swatchOf(WallModel.felsHex(fc.fels))) : '') },
|
||||
{ label: 'Wandstukken', html:
|
||||
num('hw-split-at', 'Splitsen op', Math.round(e0 + (piece.u0 + piece.u1) / 2), { step: 10, hint: 'Afstand vanaf de linker vloerhoek, van buitenaf gezien. Elk stuk wordt een eigen wand-element (eigen regelwerk) en kan een eigen gevel krijgen.' }) +
|
||||
small('Splitsen', 'scissors', 'data-hw="split"') +
|
||||
@@ -2144,6 +2161,7 @@ function mountHouseEditor(container, callbacks) {
|
||||
(own ? sel('hw-piece-facade', 'Gevel dit stuk', Object.assign({ zijde: 'Zoals de zijde' }, HouseModel.FACADE_TYPES), own.facade ? own.facade.type : 'zijde', { hint: 'Gevel van dit wandstuk (rechts van de splitsing)' }) +
|
||||
(own.facade && own.facade.type === 'steen' ? sel('hw-piece-stone', 'Steen', stoneOptions, own.facade.stone || fc.stone) : '') +
|
||||
(own.facade && own.facade.type === 'stuc' ? sel('hw-piece-stuc', 'Kleur', stucColors, own.facade.stuc || fc.stuc) : '') +
|
||||
(own.facade && own.facade.type === 'fels' ? sel('hw-piece-fels', 'Kleur', felsColors, own.facade.fels || fc.fels) : '') +
|
||||
small('Splitsing weg', 'x-lg', 'data-hw="unsplit"') : '') },
|
||||
chimneyGroup(pu, wl, piece, e0),
|
||||
{ label: 'Gevellampen', html: lt.mode === 'gevel'
|
||||
@@ -2162,16 +2180,18 @@ function mountHouseEditor(container, callbacks) {
|
||||
wireChimneys(body, pu, wl);
|
||||
UI.onSel('hw-facade', v => {
|
||||
if (v === 'woning') delete su.facade.walls[wl.side];
|
||||
else su.facade.walls[wl.side] = v === 'steen' ? { type: v, stone: fc.stone } : v === 'stuc' ? { type: v, stuc: fc.stuc } : { type: v };
|
||||
else su.facade.walls[wl.side] = v === 'steen' ? { type: v, stone: fc.stone } : v === 'stuc' ? { type: v, stuc: fc.stuc } : v === 'fels' ? { type: v, fels: fc.fels } : { type: v };
|
||||
}, rerender);
|
||||
UI.onSel('hw-facade-stone', v => { su.facade.walls[wl.side].stone = v; }, rerender);
|
||||
UI.onSel('hw-facade-stuc', v => { su.facade.walls[wl.side].stuc = v; }, rerender);
|
||||
UI.onSel('hw-facade-fels', v => { su.facade.walls[wl.side].fels = v; }, rerender);
|
||||
UI.onSel('hw-piece-facade', v => {
|
||||
if (!own) return;
|
||||
own.facade = v === 'zijde' ? null : v === 'steen' ? { type: v, stone: fc.stone } : v === 'stuc' ? { type: v, stuc: fc.stuc } : { type: v };
|
||||
own.facade = v === 'zijde' ? null : v === 'steen' ? { type: v, stone: fc.stone } : v === 'stuc' ? { type: v, stuc: fc.stuc } : v === 'fels' ? { type: v, fels: fc.fels } : { type: v };
|
||||
}, rerender);
|
||||
UI.onSel('hw-piece-stone', v => { if (own && own.facade) own.facade.stone = v; }, rerender);
|
||||
UI.onSel('hw-piece-stuc', v => { if (own && own.facade) own.facade.stuc = v; }, rerender);
|
||||
UI.onSel('hw-piece-fels', v => { if (own && own.facade) own.facade.fels = v; }, rerender);
|
||||
body.querySelectorAll('[data-hw]').forEach(b => b.addEventListener('click', () => {
|
||||
if (b.dataset.hw === 'split') {
|
||||
const v = Number(document.getElementById('hw-split-at').value);
|
||||
@@ -2354,9 +2374,10 @@ function mountHouseEditor(container, callbacks) {
|
||||
}
|
||||
if (totals.posts) {
|
||||
const pp = totals.posts;
|
||||
cards.push(UI.specCard('Overkapping', 'columns', [
|
||||
cards.push(UI.specCard('Overkapping', 'columns', (pp.count ? [
|
||||
[`${pp.wood} palen ${pp.size}×${pp.size} mm`, pp.count, 'st.'],
|
||||
['Lengte totaal', f(pp.lengthM, 2), 'm'], ['Hout', f(pp.m3, 3), 'm³'], ['Gewicht', f(pp.kg), 'kg'], ['Paalvoeten', pp.count, 'st.']]));
|
||||
['Lengte totaal', f(pp.lengthM, 2), 'm'], ['Hout', f(pp.m3, 3), 'm³'], ['Gewicht', f(pp.kg), 'kg'], ['Paalvoeten', pp.count, 'st.']] : [])
|
||||
.concat(pp.walls ? [[`Zijwand (${pp.walls} st.)`, f(pp.wallM2, 2), 'm²']] : [])));
|
||||
}
|
||||
// TIJDELIJK (verwijderen voor productie): zaagmachine-overzicht.
|
||||
const sw = totals.saw, cs = cost.saw;
|
||||
|
||||
Reference in New Issue
Block a user