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
+18 -11
View File
@@ -32,7 +32,8 @@ window.HousePdf = (() => {
list.push({ kind: 'floor', element: u.floorElement, label: `Unit ${u.id} vloer`, unit: u });
u.walls.forEach(w => w.pieces.forEach(p => list.push({ kind: 'wall', element: p.element, label: p.label, piece: p })));
u.roof.planes.forEach(pl => list.push({ kind: 'roof', element: pl.element, label: pl.label, plane: pl }));
if (u.roof.unitRoof && u.roof.unitRoof.cap) list.push({ kind: 'cap', element: `${u.id}-D${u.roof.planes.length + 1}`, label: `Unit ${u.id} dak bovenste deel (wolfsdak)`, unit: u });
const cap = u.roof.unitRoof && u.roof.unitRoof.cap;
if (cap) list.push({ kind: 'cap', element: `${u.id}-D${u.roof.planes.length + 1}`, label: cap.kind === 'join' ? `Unit ${u.id} dak (aansluiting)` : `Unit ${u.id} dak bovenste deel (wolfsdak)`, unit: u });
});
parts.interior.forEach(p => list.push({ kind: 'wall', element: p.element, label: p.label, piece: p }));
list.push({ kind: 'totals', element: 'TOT', label: 'Totalen' });
@@ -235,10 +236,10 @@ window.HousePdf = (() => {
const W = p.place.width, T = p.place.thickness;
const c = WallModel.claddingOffset(p.buitenMateriaal, p.stone, p.stuc), e = p.skinExt || {};
const xl = -W / 2 - (e.left > 0 ? e.left + c : 0), xr = W / 2 + (e.right > 0 ? e.right + c : 0);
const tl = WallModel.topLine(p.config), up = p.skinAbove || 0;
const top = (x) => tl.at(Math.max(-W / 2, Math.min(W / 2, x))) + up;
const tl = WallModel.topLine(WallModel.skinConfig(p.config, p.skinAbove || 0, p.skinTop));
const top = (x) => Math.min(tl.at(x), tl.at(Math.max(-W / 2, Math.min(W / 2, x))));
const loc = [{ x: xl, y: y0 }, { x: xr, y: y0 }, { x: xr, y: top(xr) }]
.concat(tl.pts.slice().reverse().filter(q => q.x > xl + 1 && q.x < xr - 1).map(q => ({ x: q.x, y: q.y + up })))
.concat(tl.pts.slice().reverse().filter(q => q.x > xl + 1 && q.x < xr - 1).map(q => ({ x: q.x, y: q.y })))
.concat([{ x: xl, y: top(xl) }]);
return loc;
};
@@ -282,7 +283,7 @@ window.HousePdf = (() => {
};
RoofModel.capRegions(r.unitRoof).forEach(rg => {
pushRoof(rg.poly.map(pt => {
const x = u.rect.cx + (sh.axis === 'x' ? pt.x : pt.z), z = u.rect.cz + (sh.axis === 'x' ? pt.z : pt.x);
const ax = r.unitRoof.alongX, x = u.rect.cx + (ax ? pt.x : pt.z), z = u.rect.cz + (ax ? pt.z : pt.x);
return { x, y: u.layout.floorTop + rg.under(pt) + rg.vThick, z };
}));
});
@@ -457,7 +458,7 @@ window.HousePdf = (() => {
PdfSheet.titleBlock(doc, sheetOpts.project, sheetOpts);
}
const CAP_KINDS = { spoor: 'Spoor', hoekkeper: 'Hoekkeper', nokbalk: 'Nokbalk', kopbalk: 'Kopbalk' };
const CAP_KINDS = { spoor: 'Spoor', hoekkeper: 'Hoekkeper', kilkeper: 'Kilkeper', nokbalk: 'Nokbalk', knikbalk: 'Knikbalk', kopbalk: 'Kopbalk' };
function drawCapSheet(doc, u, sheetOpts) {
const { RED, BLUE, BLACK, GREY } = PdfSheet.COLORS;
const ur = u.roof.unitRoof, c = ur.cap;
@@ -474,7 +475,8 @@ window.HousePdf = (() => {
};
doc.setTextColor(...BLACK);
doc.setFontSize(11);
doc.text('Bovenaanzicht bovenste deel (wolfseinden en nok)', X0, 20);
const join = c.kind === 'join';
doc.text(join ? 'Bovenaanzicht dak (aansluiting: kil- en hoekkepers, kreupele sporen)' : 'Bovenaanzicht bovenste deel (wolfseinden en nok)', X0, 20);
doc.setDrawColor(...GREY);
doc.setLineWidth(0.15);
c.regions.forEach(rg => poly(rg.poly.map(xz), 'S'));
@@ -505,17 +507,22 @@ window.HousePdf = (() => {
const H = (p) => RoofModel.profileHeight(ur.shape.profile, p);
const deg = (t) => String(Math.round(Math.atan(t) * 1800 / Math.PI) / 10).replace('.', ',');
const hip = c.regions.find(rg => rg.key === 'h1');
const facts = [
const facts = (join ? [
['Goot (onderkant dak)', `${Math.round(c.eave)} mm`],
['Nok (onderkant dak)', `${Math.round(c.ridgeH)} mm`],
['Helling dakvlakken', `${deg(c.slope)}°`]
] : [
['Wolfseind (onderkant dak)', `${Math.round(c.hipH)} mm`],
['Nok (onderkant dak)', `${Math.round(H(c.pR))} mm`],
['Helling dakvlakken', `${deg(c.slope)}°`],
['Helling wolfseinden', hip ? `${deg(Math.tan(Math.acos(hip.cos)))}°` : '-'],
['Helling wolfseinden', hip ? `${deg(Math.tan(Math.acos(hip.cos)))}°` : '-']
]).concat([
['Balken', `${c.joistW} x ${c.joistH} mm`],
['Oppervlak (schuin)', `${fmt(c.specs.osbAreaM2, 2)} m²`],
['Hout', `${fmt(c.specs.joistWoodM3, 3)} m³`]
];
]);
doc.setTextColor(...BLACK);
let y = PdfSheet.table(doc, 290, 20, [0, 52], ['Gegeven', 'Waarde'], facts, { title: 'Wolfsdak, bovenste deel', fontSize: 7, rowH: 4.6, lastColW: 40 });
let y = PdfSheet.table(doc, 290, 20, [0, 52], ['Gegeven', 'Waarde'], facts, { title: join ? 'Dak met aansluiting' : 'Wolfsdak, bovenste deel', fontSize: 7, rowH: 4.6, lastColW: 40 });
PdfSheet.table(doc, 290, y + 6, [0, 32, 56, 78], ['Soort', 'Lengte (mm)', 'Hoek (°)', 'Aantal'], rows, { title: 'Stuklijst balken', fontSize: 7, rowH: 4.6, lastColW: 14, maxY: 240 });
doc.setFontSize(7);
doc.setTextColor(...GREY);