v0.7.0: exports voor CAD, BIM en renders (Bestand › Exporteren, los van Opslaan/Ctrl+S): CAD (DXF R12, plattegrond met wanden/sparingen/gevelbekleding/kozijnen met draaicirkel, ruimtes, inrichting, dakrand, elektra en echte maatvoering, plus vier gevels als lijntekening met verborgen lijnen weg; lagen PL-/AZ-, 1:1 mm, afgestemd op 1:50; in CAD op te slaan als DWG), BIM (IFC4 met alleen de bouwconstructie: stijlen, regels, vloer- en dakbalken, stalen nokbalk, palen, spaanplaat/OSB/cementplaat en elektra per leiding, gegroepeerd per unit en element met Pset_Tectum en kleur per soort) en Render (OBJ + MTL + texturen in een ZIP voor Blender, volledige afgewerkte woning, kleuren lineair, PBR); schoorsteen tegen een buitenwand (ChimneyModel: sparing in wand en dak met raveelwerk, steenstrip/stuc, verslepen langs de gevel); kozijnen koppelen met een eigen schakelaar; kozijnindeling (deurblad, zij-/bovenlicht, schuifbladen) gedeeld tussen 3D, plattegrond en aanzicht
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
86fcd57b96
commit
adb3c74f85
+46
-17
@@ -125,18 +125,8 @@ window.RoofModel = (() => {
|
||||
deck.position.y = deckH;
|
||||
group.add(deck);
|
||||
|
||||
const wM = calcData.width * toM, dM = calcData.depth * toM;
|
||||
const shape = new THREE.Shape();
|
||||
shape.moveTo(-wM / 2, -dM / 2);
|
||||
shape.lineTo(wM / 2, -dM / 2);
|
||||
shape.lineTo(wM / 2, dM / 2);
|
||||
shape.lineTo(-wM / 2, dM / 2);
|
||||
shape.closePath();
|
||||
resolvedOpenings.filter(o => !o.removed && o.r > 0).forEach(o => {
|
||||
const hole = new THREE.Path();
|
||||
hole.absarc(o.x * toM, o.y * toM - dM / 2, o.r * toM, 0, Math.PI * 2, false);
|
||||
shape.holes.push(hole);
|
||||
});
|
||||
const dM = calcData.depth * toM;
|
||||
const shape = FloorModel.surfaceShapes(calcData, resolvedOpenings, toM);
|
||||
const cov = COVERINGS[opts.covering] || COVERINGS.dakleer;
|
||||
const covMat = coveringMaterial(opts.covering) || m.dakleerMaterial;
|
||||
const bT = BESCHOT_MM * toM;
|
||||
@@ -269,7 +259,9 @@ window.RoofModel = (() => {
|
||||
};
|
||||
const ridgeTypes = ['zadel', 'wolf'];
|
||||
// span: [q0, q1] waar de nok echt loopt (dakaansluiting: tot de hoekkeper).
|
||||
function computeRidgeBeam(roofState, shape, rect, alongX, cd, kgM2, span) {
|
||||
// cuts: sparingen (schoorsteen) in plattegrondmaten; ligt er een op de nok, dan stopt de balk bear mm erin
|
||||
// (negatief: ervoor).
|
||||
function computeRidgeBeam(roofState, shape, rect, alongX, cd, kgM2, span, cuts) {
|
||||
if (roofState.steelRidge === false || !ridgeTypes.includes(shape.type)) return null;
|
||||
const pr = shape.profile, inner = pr.slice(1, -1);
|
||||
if (!inner.length) return null;
|
||||
@@ -285,6 +277,12 @@ window.RoofModel = (() => {
|
||||
q1 = Math.min(uq1, Math.max(g.qM, g.q1 - g.inset));
|
||||
}
|
||||
if (span) { q0 = Math.max(q0, span[0]); q1 = Math.min(q1, span[1]); }
|
||||
(cuts || []).forEach(c => {
|
||||
const [pa, pb] = alongX ? [c.x0, c.x1] : [c.z0, c.z1], [qa, qb] = alongX ? [c.z0, c.z1] : [c.x0, c.x1];
|
||||
if (R.p < pa - 100 || R.p > pb + 100 || qb < q0 || qa > q1) return;
|
||||
if ((qa + qb) / 2 > (q0 + q1) / 2) q1 = Math.min(q1, qa + (c.bear || 0));
|
||||
else q0 = Math.max(q0, qb - (c.bear || 0));
|
||||
});
|
||||
const L = q1 - q0;
|
||||
if (L < 100) return null;
|
||||
// q in N/mm = kN/m.
|
||||
@@ -350,7 +348,9 @@ window.RoofModel = (() => {
|
||||
return out;
|
||||
}
|
||||
|
||||
function computeUnitRoof(roofState, shape, rect, rims) {
|
||||
// cuts: rechthoekige sparingen (schoorsteen) in plattegrondmaten van de unit: { x0, x1, z0, z1, bear }.
|
||||
function computeUnitRoof(roofState, shape, rect, rims, cutRects) {
|
||||
const roofCuts = cutRects || [];
|
||||
const alongX = shape.axis === 'x';
|
||||
const W = rect.x1 - rect.x0, D = rect.z1 - rect.z0;
|
||||
const xc = (rect.x0 + rect.x1) / 2, zc = (rect.z0 + rect.z1) / 2;
|
||||
@@ -372,10 +372,18 @@ window.RoofModel = (() => {
|
||||
const slopeLen = Math.hypot(run, h1 - h0), cos = run / slopeLen;
|
||||
const plane = { p0, p1, h0, h1, theta: Math.atan2(h1 - h0, run), cos, yaw: alongX ? Math.PI / 2 : 0 };
|
||||
let data;
|
||||
if (cuts.length === 2 && !alongX && Math.abs(h1 - h0) < 0.5) {
|
||||
const deckCuts = roofCuts.map(c => {
|
||||
const [qa, qb] = alongX ? [c.x0, c.x1] : [c.z0, c.z1];
|
||||
const a = Math.max(qa, p0), b = Math.min(qb, p1);
|
||||
if (b - a < 1) return null;
|
||||
const [x0, x1] = alongX ? [zc - c.z1, zc - c.z0] : [c.x0 - xc, c.x1 - xc];
|
||||
return { x0, x1, y0: (a - p0) / cos, y1: (b - p0) / cos };
|
||||
}).filter(Boolean);
|
||||
if (cuts.length === 2 && !alongX && Math.abs(h1 - h0) < 0.5 && !deckCuts.length) {
|
||||
data = flat;
|
||||
} else {
|
||||
const deck = clone(roofState.deck);
|
||||
deck.cuts = deckCuts;
|
||||
deck.floor.width = Math.round(alongX ? D : W);
|
||||
deck.floor.depth = Math.round(slopeLen);
|
||||
deck.openings = holes.filter(hl => hl.q >= p0 && (hl.q < p1 || last)).map(hl => ({
|
||||
@@ -419,7 +427,7 @@ window.RoofModel = (() => {
|
||||
topAt = (x, z) => Math.min(mainTop(x, z), ...cap.regions.map(rg => rg.under(at(x, z)) + rg.vThick));
|
||||
}
|
||||
const specs = sumSpecs(outPlanes.map(pl => pl.specs).concat(cap ? [cap.specs] : []));
|
||||
const ridgeBeam = computeRidgeBeam(roofState, shape, rect, alongX, flat.calcData, specs.totalKg / Math.max(0.1, W * D / 1e6));
|
||||
const ridgeBeam = computeRidgeBeam(roofState, shape, rect, alongX, flat.calcData, specs.totalKg / Math.max(0.1, W * D / 1e6), null, roofCuts);
|
||||
addRidgeSpecs(specs, ridgeBeam);
|
||||
return {
|
||||
shape, covering, planes: outPlanes, specs, ridgeBeam,
|
||||
@@ -429,6 +437,21 @@ window.RoofModel = (() => {
|
||||
};
|
||||
}
|
||||
|
||||
// Stalen nok onder de naad van een dubbel lessenaardak (HouseModel): shape is het samengestelde zadel en rect
|
||||
// de twee units samen, beide in de lokale maten van deze unit; de balk hoort bij deze unit (3D, kosten).
|
||||
function sharedRidgeBeam(roofState, unitRoof, shape, rect, span, cuts) {
|
||||
const pl = unitRoof.planes[0];
|
||||
if (!pl || !pl.data) return null;
|
||||
const r = unitRoof.rect, kgM2 = unitRoof.specs.totalKg / Math.max(0.1, (r.x1 - r.x0) * (r.z1 - r.z0) / 1e6);
|
||||
const rb = computeRidgeBeam(roofState, shape, rect, shape.axis === 'x', pl.data.calcData, kgM2, span, cuts);
|
||||
if (!rb) return null;
|
||||
rb.alongX = shape.axis === 'x';
|
||||
rb.shared = true;
|
||||
unitRoof.ridgeBeam = rb;
|
||||
addRidgeSpecs(unitRoof.specs, rb);
|
||||
return rb;
|
||||
}
|
||||
|
||||
function addRidgeSpecs(specs, ridgeBeam) {
|
||||
Object.assign(specs, {
|
||||
nokStaalM: ridgeBeam ? ridgeBeam.length / 1000 : 0, nokStaalKg: ridgeBeam ? ridgeBeam.steelKg : 0,
|
||||
@@ -1046,6 +1069,12 @@ window.RoofModel = (() => {
|
||||
const f = (p) => r.axis === 'x' ? p.x - r.value : p.z - r.value;
|
||||
polys = polys.flatMap(pl => [clipPoly(pl, f), clipPoly(pl, p => -f(p))]).filter(pl => pl.length >= 3);
|
||||
});
|
||||
// Schoorsteen: de rand stopt ertegen (gaps langs de rand, in wereld-mm).
|
||||
const alongZ = Math.abs(sg.a.x - sg.b.x) < 0.5;
|
||||
(sg.gaps || []).forEach(([g0, g1]) => {
|
||||
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;
|
||||
polys.forEach(pl => {
|
||||
const mesh = new THREE.Mesh(prismGeometry(pl, sg.topAt, h), sg.fascia ? materials.fasciaMaterial : materials.trimMaterial);
|
||||
@@ -1082,7 +1111,7 @@ window.RoofModel = (() => {
|
||||
return {
|
||||
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, joinValue, buildUnit3D, capRegions,
|
||||
computeShape, shapeFromProfile, shapeLines, wallProfile, profileHeight, computeUnitRoof, computeJoinedRoof, sharedRidgeBeam, joinValue, buildUnit3D, capRegions,
|
||||
computeEdge, buildEdge3D, normalizeSettings
|
||||
};
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user