v0.4.16: PDF-aanzichten (vlakke render) met legenda afwerking en afmetingen, zaaglijst/zaagmachine eigen blad, infopaneel afmetingen, lopen (Shift+T) met camera-menu, zachter licht, naadwanden volgen koppeling, boeideel over de gevel (gevel tot bovenkant dak), thumbnails riet/vloer
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
12c2579471
commit
23bfe153a2
+37
-5
@@ -69,12 +69,18 @@ window.RoofModel = (() => {
|
||||
// de stengels lopen langs de helling.
|
||||
// Riet: één keuze per textuur assets/textures/dak/riet_<nr>.jpg (nummer
|
||||
// hier toevoegen); zelfde opbouw (180 mm, 3,8 kg/m2).
|
||||
const RIET = { thickMM: 180, kgM2: 3.8, tileMM: 1000, nrs: ['001', '002', '003'] };
|
||||
// colors: gemiddelde kleur per textuur (vlakke weergave, PDF-aanzichten).
|
||||
const RIET = { thickMM: 180, kgM2: 3.8, tileMM: 1000, nrs: ['001', '002', '003'], colors: { '001': '#947d69', '002': '#7c4c3f', '003': '#735e43' } };
|
||||
const COVERINGS = Object.assign({
|
||||
dakleer: { label: 'Dakleer (EPDM)', thickMM: DAKLEER_MM, kgM2: DENSITY_DAKLEER_KGM2 }
|
||||
dakleer: { label: 'Dakleer (EPDM)', color: '#2a2a2a', thickMM: DAKLEER_MM, kgM2: DENSITY_DAKLEER_KGM2 }
|
||||
}, ...RIET.nrs.map(nr => ({
|
||||
['riet_' + nr]: { label: 'Riet ' + nr, thickMM: RIET.thickMM, kgM2: RIET.kgM2, file: `assets/textures/dak/riet_${nr}.jpg`, tileMM: RIET.tileMM, sloped: true }
|
||||
['riet_' + nr]: { label: 'Riet ' + nr, color: RIET.colors[nr] || '#8a7560', thickMM: RIET.thickMM, kgM2: RIET.kgM2, file: `assets/textures/dak/riet_${nr}.jpg`, tileMM: RIET.tileMM, sloped: true }
|
||||
})));
|
||||
// Voorvertoning (assets/textures/dak/thumb/<px>/<naam>.png) of null.
|
||||
function coveringThumbUrl(key, px) {
|
||||
const c = COVERINGS[key];
|
||||
return c && c.file ? c.file.replace(/[^/]+$/, (f) => `thumb/${px || 64}/` + f.replace(/\.jpg$/, '.png')) : null;
|
||||
}
|
||||
// Werkelijke bedekking voor een dakvorm (riet niet op een plat dak).
|
||||
function coveringFor(key, shapeType) {
|
||||
const c = COVERINGS[key];
|
||||
@@ -379,7 +385,14 @@ window.RoofModel = (() => {
|
||||
// dakleer (absoluut, loopt buiten het dak door met de helling). Geeft per
|
||||
// ribbe (segments) de geometrie terug; edge.spots wordt door LightingModel
|
||||
// gevuld (met y = onderkant boeideel ter plaatse).
|
||||
function computeEdge(settings, roofs) {
|
||||
// facadeDepth(a, b, normal) (optioneel, mm): dikte van de gevelafwerking
|
||||
// (doek + latwerk, steen) buiten het wandvlak langs die ribbe. De gevel
|
||||
// loopt achter het boeideel door tot de bovenkant van het dak; het
|
||||
// boeideel / de daktrim valt er overheen en sluit aan de dakkant aan op
|
||||
// het dak (binnenrand = dakrand, van boven dicht). De spots komen in de
|
||||
// onderplaat vóór de gevel. Negatief = gevel van een ander (hoger) deel
|
||||
// die naar dit dak toe kijkt: de rand stopt tegen die afgewerkte gevel.
|
||||
function computeEdge(settings, roofs, facadeDepth) {
|
||||
const s = normalizeSettings(settings);
|
||||
const rects = roofs.map(r => r.rect);
|
||||
if (!roofs.length) return null;
|
||||
@@ -441,6 +454,25 @@ window.RoofModel = (() => {
|
||||
overRoof: !!nb && !dropped, dropped
|
||||
};
|
||||
});
|
||||
// Binnenrand: alleen tegen de gevel van een hoger deel (negatieve
|
||||
// diepte) inkorten; spotlijn vóór de gevel. Op een hoek van twee haakse
|
||||
// ribben het snijpunt van beide verschoven lijnen, anders loodrecht.
|
||||
const depRaw = segs.map(sg => (facadeDepth ? facadeDepth(sg.a, sg.b, sg.normal) || 0 : 0));
|
||||
const dep = depRaw.map(d => Math.min(0, d));
|
||||
const spotD = depRaw.map(d => Math.max(0, d) + (s.overhang - Math.max(0, d)) * SPOT_RATIO);
|
||||
const perp = (m1, m2) => Math.abs(m1.x * m2.x + m1.z * m2.z) < 0.5;
|
||||
const shifted = segs.map((sg, i) => {
|
||||
const pi = (i - 1 + n) % n, ni = (i + 1) % n, pv = segs[pi], nx = segs[ni];
|
||||
const at = (v, own, ownD, other, otherD) => perp(own, other)
|
||||
? { x: v.x + own.x * ownD + other.x * otherD, z: v.z + own.z * ownD + other.z * otherD }
|
||||
: { x: v.x + own.x * ownD, z: v.z + own.z * ownD };
|
||||
return {
|
||||
a: at(sg.a, sg.normal, dep[i], pv.normal, dep[pi]), b: at(sg.b, sg.normal, dep[i], nx.normal, dep[ni]),
|
||||
spotA: at(sg.a, sg.normal, spotD[i], pv.normal, spotD[pi]), spotB: at(sg.b, sg.normal, spotD[i], nx.normal, spotD[ni])
|
||||
};
|
||||
});
|
||||
segs.forEach((sg, i) => Object.assign(sg, shifted[i], { facadeDepth: depRaw[i] }));
|
||||
|
||||
// Naast een vervallen ribbe (tegen een hoger dak):
|
||||
// - ligt het verlengde van de rand in het hoge deel, dan loopt hij
|
||||
// recht door tot die gevel (spot op spotafstand van de gevel);
|
||||
@@ -559,7 +591,7 @@ window.RoofModel = (() => {
|
||||
}
|
||||
|
||||
return {
|
||||
DAKLEER_MM, EDGE_ABOVE_MM, RIET, OVERHANG_MIN, OVERHANG_MAX, DEFAULT_SETTINGS, SPOT_RATIO, FASCIA_COLORS, COVERINGS, coveringFor,
|
||||
DAKLEER_MM, EDGE_ABOVE_MM, RIET, OVERHANG_MIN, OVERHANG_MAX, DEFAULT_SETTINGS, SPOT_RATIO, FASCIA_COLORS, COVERINGS, coveringFor, coveringThumbUrl,
|
||||
createDefaultRoof, thickness, createMaterials, build3D, computeSpecs,
|
||||
computeShape, wallProfile, profileHeight, computeUnitRoof, buildUnit3D,
|
||||
computeEdge, buildEdge3D, normalizeSettings
|
||||
|
||||
Reference in New Issue
Block a user