Files
Tectum/js/sandwich/sandwich-model.js
T

73 lines
3.0 KiB
JavaScript

/*!
* Tectum
* Copyright © 2026 Machiel Heinen.
* Alle rechten voorbehouden. Gebruik uitsluitend met schriftelijke toestemming.
* Zie LICENTIE.md.
*/
window.SandwichModel = (() => {
const DEPTH_MM = 600;
const THICK_MM = 40;
const PANEL_WIDTH_MM = 495;
const PANEL_LENGTH_MM = 1000;
const PANEL_KG = 9.0;
function createMaterials() {
return {
panelMaterial: new THREE.MeshStandardMaterial({ color: 0x3b3e42, roughness: 0.55, metalness: 0.2 }),
seamMaterial: new THREE.LineBasicMaterial({ color: 0x24262a })
};
}
function compute(rects, topY) {
if (!rects.length) return null;
const segments = [];
rectUnionLoops(rects).forEach(loop => {
const base = loop.pts, off = offsetRectilinearLoop(base, THICK_MM), n = base.length;
base.forEach((a, i) => {
const j = (i + 1) % n;
segments.push({ a, b: base[j], outerA: off[i], outerB: off[j] });
});
});
const lengthMM = segments.reduce((t, sg) => t + (Math.hypot(sg.b.x - sg.a.x, sg.b.z - sg.a.z) + Math.hypot(sg.outerB.x - sg.outerA.x, sg.outerB.z - sg.outerA.z)) / 2, 0);
const areaM2 = lengthMM * DEPTH_MM / 1e6;
const panelCount = segments.reduce((t, sg) => t + Math.ceil(Math.hypot(sg.outerB.x - sg.outerA.x, sg.outerB.z - sg.outerA.z) / PANEL_WIDTH_MM - 1e-9), 0);
return {
segments, top: topY, bottom: topY - DEPTH_MM, depth: DEPTH_MM, thick: THICK_MM,
lengthMM, areaM2, panelCount, kg: panelCount * PANEL_KG,
wasteMM: PANEL_LENGTH_MM - DEPTH_MM
};
}
function build3D(data, materials, opts) {
const o = opts || {};
const toM = 0.001;
const group = new THREE.Group();
if (!data) return group;
data.segments.forEach(sg => {
const pts = [sg.a, sg.b, sg.outerB, sg.outerA];
const shape = new THREE.Shape(pts.map(p => new THREE.Vector2(p.x * toM, p.z * toM)));
const geo = new THREE.ExtrudeGeometry(shape, { steps: 1, depth: data.depth * toM, bevelEnabled: false });
const mesh = new THREE.Mesh(geo, materials.panelMaterial);
mesh.rotation.x = Math.PI / 2;
mesh.position.y = data.top * toM;
group.add(mesh);
const len = Math.hypot(sg.outerB.x - sg.outerA.x, sg.outerB.z - sg.outerA.z);
const pts3 = [];
for (let d = PANEL_WIDTH_MM; d < len - 1; d += PANEL_WIDTH_MM) {
const t = d / len, eps = 0.5;
const nx = sg.outerA.x - sg.a.x, nz = sg.outerA.z - sg.a.z, nl = Math.hypot(nx, nz) || 1;
const x = (sg.outerA.x + (sg.outerB.x - sg.outerA.x) * t + nx / nl * eps) * toM;
const z = (sg.outerA.z + (sg.outerB.z - sg.outerA.z) * t + nz / nl * eps) * toM;
pts3.push(new THREE.Vector3(x, data.top * toM, z), new THREE.Vector3(x, data.bottom * toM, z));
}
if (pts3.length) group.add(new THREE.LineSegments(new THREE.BufferGeometry().setFromPoints(pts3), materials.seamMaterial));
});
group.visible = o.visible !== false;
return group;
}
return { DEPTH_MM, THICK_MM, PANEL_WIDTH_MM, PANEL_LENGTH_MM, PANEL_KG, createMaterials, compute, build3D };
})();