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
+85
-7
@@ -7,6 +7,9 @@
|
||||
// Palen onder een overkapping: steekt een dak minstens minExt buiten de vloeren uit (veranda), dan komen er
|
||||
// palen onder de dakrand. Hoekpalen staan met hun buitenkant gelijk met de dakhoek; een eind dat op een gevel
|
||||
// uitkomt rust op die wand. Daartussen zo weinig palen dat de h.o.h.-afstand onder maxSpan blijft.
|
||||
// sideWall: een vrije hoek krijgt geen paal maar een dichte zijwand (gestuukt) van de dakhoek terug tot de gevel,
|
||||
// met de buitenkant gelijk met de zijkant van het dak. Ligt die buitenkant in het vlak van een gevel, dan loopt de
|
||||
// bekleding van die gevel erover door (outsideOf, bijv. felsplaten) en staat de wand gelijk met de bekleding.
|
||||
|
||||
window.PostModel = (() => {
|
||||
const EPS = 0.5;
|
||||
@@ -15,12 +18,16 @@ window.PostModel = (() => {
|
||||
eiken: { label: 'Eiken', hex: 0xa07c54, kgM3: 750 },
|
||||
douglas: { label: 'Douglas', hex: 0xb98a5e, kgM3: 530 }
|
||||
};
|
||||
const DEFAULT_SETTINGS = { enabled: true, size: 200, wood: 'eiken', maxSpan: 3600, minExt: 1000 };
|
||||
const DEFAULT_SETTINGS = { enabled: true, size: 200, wood: 'eiken', maxSpan: 3600, minExt: 1000, sideWall: false, sideColor: 'wit' };
|
||||
const SIDE_MM = 200; // dikte zijwand (regelwerk, plaat en stuc aan beide kanten)
|
||||
const SIDE_TOP_BELOW_MM = 40; // doorlopende gevelbekleding: tot zo ver onder de bovenkant van het dak
|
||||
|
||||
function normalizeSettings(settings) {
|
||||
const s = Object.assign({}, DEFAULT_SETTINGS, settings || {});
|
||||
s.enabled = s.enabled !== false;
|
||||
s.sideWall = !!s.sideWall;
|
||||
if (!WOODS[s.wood]) s.wood = DEFAULT_SETTINGS.wood;
|
||||
if (!WallModel.isStucColor(s.sideColor)) s.sideColor = DEFAULT_SETTINGS.sideColor;
|
||||
const num = (v, def, min, max) => (isFinite(v) ? Math.min(max, Math.max(min, Math.round(v))) : def);
|
||||
s.size = num(s.size, DEFAULT_SETTINGS.size, 100, 400);
|
||||
s.maxSpan = num(s.maxSpan, DEFAULT_SETTINGS.maxSpan, 1000, 8000);
|
||||
@@ -29,9 +36,10 @@ window.PostModel = (() => {
|
||||
}
|
||||
|
||||
// units: [{ rect (vloer), roof: { rect, ceilingAt } }] in wereld-mm; groundY = maaiveld (absoluut).
|
||||
function compute(settings, units, groundY) {
|
||||
// outsideOf(wall, out): { finish, kind, depth } van de gevel in het vlak van de buitenkant, of null.
|
||||
function compute(settings, units, groundY, outsideOf) {
|
||||
const s = normalizeSettings(settings);
|
||||
const out = { posts: [], count: 0, size: s.size, wood: s.wood, lengthMM: 0, m3: 0, kg: 0 };
|
||||
const out = { posts: [], count: 0, size: s.size, wood: s.wood, lengthMM: 0, m3: 0, kg: 0, walls: [], wallM2: 0, sideColor: s.sideColor };
|
||||
if (!s.enabled || !units.length) return out;
|
||||
const floors = units.map(u => u.rect);
|
||||
const onFloor = (x, z, m) => floors.some(f => x > f.x0 - m && x < f.x1 + m && z > f.z0 - m && z < f.z1 + m);
|
||||
@@ -79,11 +87,56 @@ window.PostModel = (() => {
|
||||
|
||||
const half = s.size / 2;
|
||||
const pts = [];
|
||||
const roofAt = (x, z) => units.map(u => u.roof).find(rf => x > rf.rect.x0 - EPS && x < rf.rect.x1 + EPS && z > rf.rect.z0 - EPS && z < rf.rect.z1 + EPS);
|
||||
const endFreeOf = (r, t) => { const p = r.axis === 'z' ? { x: r.at, z: t } : { x: t, z: r.at }; return !onFloor(p.x, p.z, s.size); };
|
||||
// Zijwand op het vrije eind t van run r (dir +1: wand van t de run in, -1: andersom), terug tot de gevel waar de
|
||||
// run naar kijkt. Delen twee runs een vrije hoek (veranda in een binnenhoek), dan is de run met de kortste weg
|
||||
// naar de gevel de voorkant en komt de wand langs de zijkant; het andere eind rust op die wand.
|
||||
const sideCands = [];
|
||||
if (s.sideWall) merged.forEach(r => [[r.a, 1], [r.b, -1]].forEach(([t, dir]) => {
|
||||
if (!endFreeOf(r, t)) return;
|
||||
const lo = Math.min(t, t + dir * SIDE_MM), hi = Math.max(t, t + dir * SIDE_MM);
|
||||
let reach = Infinity;
|
||||
floors.forEach(f => {
|
||||
const [s0, s1, c0, c1] = r.axis === 'z' ? [f.z0, f.z1, f.x0, f.x1] : [f.x0, f.x1, f.z0, f.z1];
|
||||
if (s0 > hi - EPS || s1 < lo + EPS) return;
|
||||
const d = r.n > 0 ? r.at - c1 : c0 - r.at;
|
||||
if (d > -EPS && d < reach) reach = d;
|
||||
});
|
||||
if (!isFinite(reach) || reach < s.size) return;
|
||||
const a = Math.min(r.at, r.at - r.n * reach), b = Math.max(r.at, r.at - r.n * reach);
|
||||
const corner = r.axis === 'z' ? { x: r.at, z: t } : { x: t, z: r.at };
|
||||
const outward = r.axis === 'z' ? { x: 0, z: -dir } : { x: -dir, z: 0 };
|
||||
sideCands.push({ r, t, corner, reach, out: outward, w: r.axis === 'z' ? { x0: a, x1: b, z0: lo, z1: hi } : { x0: lo, x1: hi, z0: a, z1: b } });
|
||||
}));
|
||||
const sameCorner = (p, q) => Math.abs(p.x - q.x) < EPS && Math.abs(p.z - q.z) < EPS;
|
||||
const sideAt = (r, t) => { const c = sideCands.find(d => d.r === r && d.t === t); return !!c && sideCands.some(d => d.built && sameCorner(d.corner, c.corner)); };
|
||||
sideCands.forEach(c => {
|
||||
if (sideCands.some(d => d !== c && sameCorner(d.corner, c.corner) && (d.reach < c.reach - EPS || (Math.abs(d.reach - c.reach) < EPS && sideCands.indexOf(d) < sideCands.indexOf(c))))) return;
|
||||
const w = c.w;
|
||||
const tops = [[w.x0 + 1, w.z0 + 1], [w.x1 - 1, w.z0 + 1], [w.x0 + 1, w.z1 - 1], [w.x1 - 1, w.z1 - 1]]
|
||||
.map(([x, z]) => { const rf = roofAt(x, z); return rf ? rf.ceilingAt(x, z) : null; }).filter(v => v !== null);
|
||||
if (!tops.length || !(Math.max(...tops) > groundY)) return;
|
||||
const wall = Object.assign({}, w, { y0: groundY, y1: Math.round(Math.max(...tops)), color: s.sideColor, out: c.out, outside: null });
|
||||
const o = outsideOf ? outsideOf(wall, c.out) : null;
|
||||
if (o) {
|
||||
if (c.out.x > 0) wall.x1 += o.depth; else if (c.out.x < 0) wall.x0 -= o.depth;
|
||||
if (c.out.z > 0) wall.z1 += o.depth; else if (c.out.z < 0) wall.z0 -= o.depth;
|
||||
Object.assign(wall, { outside: o.finish, outsideKind: o.kind });
|
||||
// Zoals de gevel: de bekleding loopt tot onder de dakrand door (over de kant van het dakpakket).
|
||||
const roofTops = [[w.x0 + 1, w.z0 + 1], [w.x1 - 1, w.z0 + 1], [w.x0 + 1, w.z1 - 1], [w.x1 - 1, w.z1 - 1]]
|
||||
.map(([x, z]) => { const rf = roofAt(x, z); return rf && rf.topAt ? rf.topAt(x, z) : null; }).filter(v => v !== null);
|
||||
if (roofTops.length) wall.y1 = Math.max(wall.y1, Math.round(Math.min(...roofTops) - SIDE_TOP_BELOW_MM));
|
||||
}
|
||||
out.walls.push(wall);
|
||||
c.built = true;
|
||||
});
|
||||
merged.forEach(r => {
|
||||
const pos = (t) => (r.axis === 'z' ? { x: r.at - r.n * half, z: t } : { x: t, z: r.at - r.n * half });
|
||||
// Een eind dat op of tegen een vloer uitkomt rust op die gevel.
|
||||
const endFree = (t) => { const p = r.axis === 'z' ? { x: r.at, z: t } : { x: t, z: r.at }; return !onFloor(p.x, p.z, s.size); };
|
||||
const fa = endFree(r.a), fb = endFree(r.b);
|
||||
// Een dichte zijwand neemt de plaats van de hoekpaal in; het eind rust dan op die wand.
|
||||
const fa = endFree(r.a) && !sideAt(r, r.a), fb = endFree(r.b) && !sideAt(r, r.b);
|
||||
const pa = fa ? r.a + half : r.a, pb = fb ? r.b - half : r.b;
|
||||
if (pb - pa < EPS) return;
|
||||
const n = Math.max(1, Math.ceil((pb - pa) / s.maxSpan - 1e-9));
|
||||
@@ -94,7 +147,8 @@ window.PostModel = (() => {
|
||||
});
|
||||
pts.forEach(p => {
|
||||
if (out.posts.some(q => Math.abs(q.x - p.x) < s.size && Math.abs(q.z - p.z) < s.size)) return;
|
||||
const roof = units.map(u => u.roof).find(rf => p.x > rf.rect.x0 - EPS && p.x < rf.rect.x1 + EPS && p.z > rf.rect.z0 - EPS && p.z < rf.rect.z1 + EPS);
|
||||
if (out.walls.some(w => p.x > w.x0 - half && p.x < w.x1 + half && p.z > w.z0 - half && p.z < w.z1 + half)) return;
|
||||
const roof = roofAt(p.x, p.z);
|
||||
if (!roof) return;
|
||||
// Hoogste hoek: bij een hellend dak verdwijnt de paal aan de lage kant in het dakpakket, zonder kier.
|
||||
const top = Math.max(...[[-1, -1], [1, -1], [-1, 1], [1, 1]].map(([a, b]) => roof.ceilingAt(p.x + a * (half - 1), p.z + b * (half - 1))));
|
||||
@@ -105,6 +159,10 @@ window.PostModel = (() => {
|
||||
out.lengthMM = out.posts.reduce((t, p) => t + p.y1 - p.y0 - SHOE_MM, 0);
|
||||
out.m3 = out.lengthMM * s.size * s.size / 1e9;
|
||||
out.kg = out.m3 * WOODS[s.wood].kgM3;
|
||||
const wallArea = (w) => Math.max(w.x1 - w.x0, w.z1 - w.z0) * (w.y1 - w.y0) / 1e6;
|
||||
out.wallM2 = out.walls.reduce((t, w) => t + wallArea(w), 0);
|
||||
out.outsideM2 = {};
|
||||
out.walls.filter(w => w.outsideKind).forEach(w => { out.outsideM2[w.outsideKind] = (out.outsideM2[w.outsideKind] || 0) + wallArea(w); });
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -117,7 +175,7 @@ window.PostModel = (() => {
|
||||
|
||||
function build3D(data, materials) {
|
||||
const toM = 0.001, group = new THREE.Group();
|
||||
if (!data || !data.posts.length) return group;
|
||||
if (!data || !(data.posts.length || (data.walls || []).length)) return group;
|
||||
const m = materials || createMaterials();
|
||||
const woodMat = m.wood[data.wood] || m.wood.eiken;
|
||||
data.posts.forEach(p => {
|
||||
@@ -132,8 +190,28 @@ window.PostModel = (() => {
|
||||
stem.position.set(p.x * toM, (p.y0 + 10 + (SHOE_MM - 10) / 2) * toM, p.z * toM);
|
||||
group.add(stem);
|
||||
});
|
||||
(data.walls || []).forEach(w => {
|
||||
const c = [(w.x0 + w.x1) / 2 * toM, (w.y0 + w.y1) / 2 * toM, (w.z0 + w.z1) / 2 * toM];
|
||||
const geo = new THREE.BoxGeometry((w.x1 - w.x0) * toM, (w.y1 - w.y0) * toM, (w.z1 - w.z0) * toM);
|
||||
// UV in wereldmeters, zoals de gevels: texturen op dezelfde schaal.
|
||||
const pos = geo.attributes.position, nrm = geo.attributes.normal, uv = geo.attributes.uv;
|
||||
for (let k = 0; k < pos.count; k++) {
|
||||
const x = pos.getX(k) + c[0], y = pos.getY(k) + c[1], z = pos.getZ(k) + c[2];
|
||||
if (Math.abs(nrm.getX(k)) > 0.5) uv.setXY(k, z, y); else if (Math.abs(nrm.getY(k)) > 0.5) uv.setXY(k, x, z); else uv.setXY(k, x, y);
|
||||
}
|
||||
uv.needsUpdate = true;
|
||||
// Volgorde van de vlakken in BoxGeometry: +x, -x, +y, -y, +z, -z.
|
||||
const stuc = WallModel.stucMaterial(w.color), mats = [stuc, stuc, stuc, stuc, stuc, stuc];
|
||||
const outMat = w.outside && w.out ? WallModel.claddingMaterial(w.outside) : null;
|
||||
if (outMat) mats[w.out.x > 0 ? 0 : w.out.x < 0 ? 1 : w.out.z > 0 ? 4 : 5] = outMat;
|
||||
const box = new THREE.Mesh(geo, mats);
|
||||
box.position.set(...c);
|
||||
box.castShadow = true;
|
||||
box.receiveShadow = true;
|
||||
group.add(box);
|
||||
});
|
||||
return group;
|
||||
}
|
||||
|
||||
return { WOODS, SHOE_MM, DEFAULT_SETTINGS, normalizeSettings, compute, createMaterials, build3D };
|
||||
return { WOODS, SHOE_MM, SIDE_MM, DEFAULT_SETTINGS, normalizeSettings, compute, createMaterials, build3D };
|
||||
})();
|
||||
|
||||
+49
-9
@@ -12,6 +12,9 @@ window.RoofModel = (() => {
|
||||
const DENSITY_DAKLEER_KGM2 = 1.4;
|
||||
const TRIM_THICK_MM = 25;
|
||||
const EDGE_ABOVE_MM = 80;
|
||||
// Felsplaat op dak én gevel: geen boeideel; de dakplaat zet om over de rand (net vóór de gevelbekleding), zonder
|
||||
// opstand (de waterkant van een lessenaar), tot over de bovenkant van de gevelplaten.
|
||||
const FELS_EDGE = { lipMM: 2, aboveMM: 2, heightMM: 120 };
|
||||
const SPOT_RATIO = 0.4;
|
||||
const OVERHANG_MIN = 200, OVERHANG_MAX = 400;
|
||||
|
||||
@@ -35,7 +38,9 @@ window.RoofModel = (() => {
|
||||
// Riet e.d. alleen bij een hellend dak; plat valt terug op dakleer.
|
||||
// Riet: één keuze per textuur assets/textures/dak/riet_<nr>.jpg (nummer hier toevoegen).
|
||||
const RIET = { thickMM: 180, kgM2: 3.8, tileMM: 1000, nrs: ['001', '002', '003'], colors: { '001': '#947d69', '002': '#7c4c3f', '003': '#735e43' } };
|
||||
const FELS = { thickMM: 25, kgM2: 6.5, seamMM: 500, colors: { zink: ['Felsplaat zink', '#8e9497'], antraciet: ['Felsplaat antraciet', '#3d4146'], zwart: ['Felsplaat zwart', '#1f2022'] } };
|
||||
// Kleuren en naadafstand gedeeld met felsplaten op de gevel (WallModel.FELS).
|
||||
const FELS = { thickMM: 25, kgM2: 6.5, seamMM: WallModel.FELS.SEAM_MM,
|
||||
colors: Object.fromEntries(Object.entries(WallModel.FELS.COLORS).map(([k, c]) => [k, ['Felsplaat ' + c.label.toLowerCase(), c.hex]])) };
|
||||
const COVERINGS = Object.assign({
|
||||
dakleer: { label: 'Dakleer (EPDM)', kind: 'dakleer', color: '#2a2a2a', thickMM: DAKLEER_MM, kgM2: DENSITY_DAKLEER_KGM2 }
|
||||
}, ...RIET.nrs.map(nr => ({
|
||||
@@ -923,7 +928,8 @@ window.RoofModel = (() => {
|
||||
}
|
||||
|
||||
// facadeDepth negatief = gevel van een hoger deel die naar dit dak kijkt: de rand stopt tegen die gevel.
|
||||
function computeEdge(settings, roofs, facadeDepth) {
|
||||
// facadeFels(a, b, normal): de gevel onder deze rand heeft felsplaten (met een felsdak: geen boeideel).
|
||||
function computeEdge(settings, roofs, facadeDepth, facadeFels) {
|
||||
const s = normalizeSettings(settings);
|
||||
const rects = roofs.map(r => r.rect);
|
||||
if (!roofs.length) return null;
|
||||
@@ -967,15 +973,18 @@ window.RoofModel = (() => {
|
||||
const j = (i + 1) % n, b = base[j];
|
||||
const mid = { x: (a.x + b.x) / 2, z: (a.z + b.z) / 2 };
|
||||
const owner = members.find(r => onRectEdge(r.rect, mid)) || members[0];
|
||||
const fascia = owner.fascia !== false;
|
||||
const normal = rectilinearNormal(a, b);
|
||||
const fels = coverKind(owner.covering) === 'fels' && !!facadeFels && !!facadeFels(a, b, normal);
|
||||
const fascia = owner.fascia !== false && !fels;
|
||||
const off = fascia ? offBoei : offTrim;
|
||||
// Tegen een hoger dak vervalt de ribbe (daar staat de gevel), boven een lager dak blijft hij zonder spots.
|
||||
const nb = others.find(r => onRectEdge(r.rect, mid));
|
||||
const dropped = !!nb && nb.topAt(mid.x, mid.z) > owner.topAt(mid.x, mid.z);
|
||||
const above = fels ? FELS_EDGE.aboveMM : EDGE_ABOVE_MM;
|
||||
return {
|
||||
a, b, owner: owner.unitId, fascia, normal: rectilinearNormal(a, b),
|
||||
a, b, owner: owner.unitId, fascia, fels, covering: owner.covering, normal,
|
||||
outerA: off[i], outerB: off[j], spotA: offSpot[i], spotB: offSpot[j],
|
||||
topAt: (p) => owner.topAt(p.x, p.z) + EDGE_ABOVE_MM, ridges: owner.ridges || [],
|
||||
topAt: (p) => owner.topAt(p.x, p.z) + above, ridges: owner.ridges || [],
|
||||
overRoof: !!nb && !dropped, dropped
|
||||
};
|
||||
});
|
||||
@@ -995,6 +1004,23 @@ window.RoofModel = (() => {
|
||||
});
|
||||
segs.forEach((sg, i) => Object.assign(sg, shifted[i], { facadeDepth: depRaw[i] }));
|
||||
|
||||
// Rand zonder overstek (daktrim, felsrand): de felsrand ligt net vóór de gevelbekleding en loopt bij een hoek
|
||||
// door tot de buitenkant van de buurrand; een boeideel ernaast stopt op de buitenkant van zo'n rand.
|
||||
const edgeOff = (k) => segs[k].fels ? Math.max(TRIM_THICK_MM, depRaw[k] + FELS_EDGE.lipMM) : TRIM_THICK_MM;
|
||||
const mv = (p, nrm, d) => ({ x: p.x + nrm.x * d, z: p.z + nrm.z * d });
|
||||
segs.forEach((sg, i) => {
|
||||
const ends = [['a', 'outerA', (i - 1 + n) % n], ['b', 'outerB', (i + 1) % n]];
|
||||
if (sg.fels) ends.forEach(([k, ok, j]) => {
|
||||
const nb = segs[j], q = mv(sg[k], sg.normal, edgeOff(i));
|
||||
sg[ok] = perp(sg.normal, nb.normal) && !nb.fascia && !nb.dropped ? mv(q, nb.normal, edgeOff(j)) : q;
|
||||
});
|
||||
else if (sg.fascia) ends.forEach(([k, ok, j]) => {
|
||||
const nb = segs[j];
|
||||
if (nb.fascia || nb.dropped || !perp(sg.normal, nb.normal)) return;
|
||||
sg[ok] = mv(mv(sg[k], sg.normal, s.overhang), nb.normal, edgeOff(j));
|
||||
});
|
||||
});
|
||||
|
||||
const insideOther = (p) => others.some(r => p.x > r.rect.x0 + 0.5 && p.x < r.rect.x1 - 0.5 && p.z > r.rect.z0 + 0.5 && p.z < r.rect.z1 - 0.5);
|
||||
segs.forEach((sg, i) => {
|
||||
if (sg.dropped) return;
|
||||
@@ -1024,7 +1050,9 @@ window.RoofModel = (() => {
|
||||
fasciaHeight: s.fasciaHeight, trimHeight: s.trimHeight, fasciaColor: s.fasciaColor,
|
||||
top, edgeAbove: EDGE_ABOVE_MM,
|
||||
fasciaLengthMM: segments.filter(sg => sg.fascia).reduce((t, sg) => t + segLen(sg), 0),
|
||||
trimLengthMM: segments.filter(sg => !sg.fascia).reduce((t, sg) => t + segLen(sg), 0),
|
||||
// Felsrand: zetwerk van de dakplaten, zit in de prijs van de felsplaten.
|
||||
trimLengthMM: segments.filter(sg => !sg.fascia && !sg.fels).reduce((t, sg) => t + segLen(sg), 0),
|
||||
felsEdgeLengthMM: segments.filter(sg => sg.fels).reduce((t, sg) => t + segLen(sg), 0),
|
||||
soffitM2: segments.filter(sg => sg.fascia).reduce((t, sg) => t + quadArea([sg.a, sg.b, sg.outerB, sg.outerA]), 0) / 1e6,
|
||||
spots: []
|
||||
};
|
||||
@@ -1056,6 +1084,17 @@ window.RoofModel = (() => {
|
||||
return geo;
|
||||
}
|
||||
|
||||
// Hoogte van de rand vanaf sg.topAt naar beneden: boeideel, felsrand of daktrim (met opstand boven het dak).
|
||||
function edgeHeight(edge, sg) {
|
||||
return sg.fascia ? edge.fasciaHeight : sg.fels ? FELS_EDGE.heightMM : edge.trimHeight + edge.edgeAbove;
|
||||
}
|
||||
// Kleur van de rand in tekeningen (hex-getal).
|
||||
function edgeColor(edge, sg) {
|
||||
if (sg.fascia) return (FASCIA_COLORS[edge.fasciaColor] || FASCIA_COLORS.antraciet).hex;
|
||||
const c = sg.fels && COVERINGS[sg.covering];
|
||||
return c ? parseInt(c.color.slice(1), 16) : 0xb8bcc0;
|
||||
}
|
||||
|
||||
function buildEdge3D(edge, materials, opts) {
|
||||
const o = opts || {};
|
||||
const toM = 0.001;
|
||||
@@ -1075,9 +1114,10 @@ window.RoofModel = (() => {
|
||||
const t = (p) => alongZ ? p.z : p.x;
|
||||
polys = polys.flatMap(pl => [clipPoly(pl, p => g0 - t(p)), clipPoly(pl, p => t(p) - g1)]).filter(pl => pl.length >= 3);
|
||||
});
|
||||
const h = sg.fascia ? edge.fasciaHeight : edge.trimHeight + edge.edgeAbove;
|
||||
const h = edgeHeight(edge, sg);
|
||||
const mat = sg.fascia ? materials.fasciaMaterial : sg.fels ? coveringMaterial(sg.covering) || materials.trimMaterial : materials.trimMaterial;
|
||||
polys.forEach(pl => {
|
||||
const mesh = new THREE.Mesh(prismGeometry(pl, sg.topAt, h), sg.fascia ? materials.fasciaMaterial : materials.trimMaterial);
|
||||
const mesh = new THREE.Mesh(prismGeometry(pl, sg.topAt, h), mat);
|
||||
mesh.visible = o.edgeVisible !== false;
|
||||
group.add(mesh);
|
||||
});
|
||||
@@ -1112,6 +1152,6 @@ window.RoofModel = (() => {
|
||||
DAKLEER_MM, BESCHOT_MM, EDGE_ABOVE_MM, RIET, FELS, coverKind, OVERHANG_MIN, OVERHANG_MAX, DEFAULT_SETTINGS, SPOT_RATIO, FASCIA_COLORS, COVERINGS, coveringFor, coveringThumbUrl,
|
||||
createDefaultRoof, thickness, createMaterials, build3D, computeSpecs,
|
||||
computeShape, shapeFromProfile, shapeLines, wallProfile, profileHeight, computeUnitRoof, computeJoinedRoof, sharedRidgeBeam, joinValue, buildUnit3D, capRegions,
|
||||
computeEdge, buildEdge3D, normalizeSettings
|
||||
FELS_EDGE, computeEdge, buildEdge3D, edgeHeight, edgeColor, normalizeSettings
|
||||
};
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user