@adatechnology/game-floorplan-three 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -0
- package/dist/index.d.ts +34 -1
- package/dist/index.global.js +1070 -14
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +66 -3
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
package/dist/index.global.js
CHANGED
|
@@ -42,7 +42,9 @@ var GameFloorplanThree = (() => {
|
|
|
42
42
|
ptBR: () => ptBR,
|
|
43
43
|
rectsOf: () => rectsOf,
|
|
44
44
|
specimenSpec: () => specimenSpec,
|
|
45
|
-
tapSpec: () => tapSpec
|
|
45
|
+
tapSpec: () => tapSpec,
|
|
46
|
+
wallPiece: () => wallPiece,
|
|
47
|
+
wallPlan: () => wallPlan
|
|
46
48
|
});
|
|
47
49
|
|
|
48
50
|
// ../game-props3d/dist/index.js
|
|
@@ -3461,7 +3463,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
3461
3463
|
light(M, x, y, z, color2, range2, kind) {
|
|
3462
3464
|
into(M).push({ kind: "point", position: [x, y, z], data: { light: true, color: color2, range: range2, kind } });
|
|
3463
3465
|
},
|
|
3464
|
-
part(id, pivot, ry,
|
|
3466
|
+
part(id, pivot, ry, draw2) {
|
|
3465
3467
|
let children = partChildren.get(id);
|
|
3466
3468
|
if (!children) {
|
|
3467
3469
|
children = [];
|
|
@@ -3472,7 +3474,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
3472
3474
|
const outer = current;
|
|
3473
3475
|
current = children;
|
|
3474
3476
|
try {
|
|
3475
|
-
|
|
3477
|
+
draw2();
|
|
3476
3478
|
} finally {
|
|
3477
3479
|
current = outer;
|
|
3478
3480
|
}
|
|
@@ -4257,7 +4259,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
4257
4259
|
// src/house/walls.ts
|
|
4258
4260
|
function installHouseWalls(K, shared) {
|
|
4259
4261
|
const { EPS: EPS3, Y0, boxC, bx, cursor, effectiveHeight, pieceRecord, structurePiece, wallColor } = K;
|
|
4260
|
-
function
|
|
4262
|
+
function wallBox2(alongU, L, a, b, ya, yb, th, cL, cH, mL, mH) {
|
|
4261
4263
|
if (yb - ya < 1e-4 || b - a < 1e-4) return;
|
|
4262
4264
|
if (alongU) {
|
|
4263
4265
|
bx(mL, a, ya, L - th / 2, b, yb, L, cL);
|
|
@@ -4324,7 +4326,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
4324
4326
|
continue;
|
|
4325
4327
|
}
|
|
4326
4328
|
const seg = (a, b, ya, yb) => {
|
|
4327
|
-
|
|
4329
|
+
wallBox2(alongU, L, a, b, y0 + ya, y0 + yb, th, sideL.color, sideH.color, sideL.mat, sideH.mat);
|
|
4328
4330
|
};
|
|
4329
4331
|
const win = R.windows.filter((j) => j.floor === f && j.axis === w.axis && Math.abs(j.pos - L) < EPS3 && j.at + j.width / 2 > s0 + EPS3 && j.at - j.width / 2 < s1 - EPS3).sort((p, q) => p.at - q.at);
|
|
4330
4332
|
let cur = s0;
|
|
@@ -4356,13 +4358,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
4356
4358
|
bx(e.color.mat, e.pu - e.th / 2, e.y0, e.pv - e.th / 2, e.pu + e.th / 2, e.y0 + e.hh, e.pv + e.th / 2, e.color.color);
|
|
4357
4359
|
}
|
|
4358
4360
|
}
|
|
4359
|
-
Object.assign(K, { wallBox, sideOf, pieceOf, nearestWall, walls });
|
|
4361
|
+
Object.assign(K, { wallBox: wallBox2, sideOf, pieceOf, nearestWall, walls });
|
|
4360
4362
|
}
|
|
4361
4363
|
|
|
4362
4364
|
// src/house/doors.ts
|
|
4363
4365
|
function installHouseDoors(K, shared) {
|
|
4364
4366
|
const seedKey = (id) => K.seedKey(id);
|
|
4365
|
-
const { EPS: EPS3, Y0, boxC, bx, cursor, effectiveHeight, nearestWall, part, pieceOf, pieceRecord, roomAt, sideOf, wallBox } = K;
|
|
4367
|
+
const { EPS: EPS3, Y0, boxC, bx, cursor, effectiveHeight, nearestWall, part, pieceOf, pieceRecord, roomAt, sideOf, wallBox: wallBox2 } = K;
|
|
4366
4368
|
const SEED = (...a) => K.SEED(...a);
|
|
4367
4369
|
const definePiece = (...a) => K.definePiece(...a);
|
|
4368
4370
|
const rngString = (...a) => K.rngString(...a);
|
|
@@ -4387,7 +4389,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
4387
4389
|
if (!cut && wallHeight > dH + 1e-3) {
|
|
4388
4390
|
const wv = nearestWall(f, p.axis, L, p.at);
|
|
4389
4391
|
cursor.pc = wv ? pieceOf(wv) : null;
|
|
4390
|
-
|
|
4392
|
+
wallBox2(alongU, L, a, b, y0 + dH, y0 + effectiveHeight(f, wallHeight), th, lL.color, lH.color, lL.mat, lH.mat);
|
|
4391
4393
|
cursor.pc = null;
|
|
4392
4394
|
}
|
|
4393
4395
|
const fb = (u0, y_0, u1, y_1, tt = th + 0.02, color2 = frame2) => alongU ? bx("wood", u0, y0 + y_0, L - tt / 2, u1, y0 + y_1, L + tt / 2, color2) : bx("wood", L - tt / 2, y0 + y_0, u0, L + tt / 2, y0 + y_1, u1, color2);
|
|
@@ -5335,8 +5337,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
5335
5337
|
t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
|
|
5336
5338
|
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
5337
5339
|
};
|
|
5338
|
-
const
|
|
5339
|
-
void
|
|
5340
|
+
const draw2 = rnd() < p, light = rnd() < 0.6;
|
|
5341
|
+
void draw2;
|
|
5340
5342
|
const on = true;
|
|
5341
5343
|
return { on, rnd, color: high ? 3816770 : light ? 15527921 : 10857392, bad: (shared.ctx.colors.meta && shared.ctx.colors.meta.state) === "abandoned" || R.state === "abandoned", fallback: false };
|
|
5342
5344
|
}
|
|
@@ -16157,6 +16159,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
16157
16159
|
};
|
|
16158
16160
|
|
|
16159
16161
|
// ../game-floorplan-structure/dist/index.js
|
|
16162
|
+
var __defProp2 = Object.defineProperty;
|
|
16163
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
16164
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
16160
16165
|
var uniform = (joint) => ({ wall: joint, slab: joint, beam: joint, column: joint, truss: joint });
|
|
16161
16166
|
var CONSTRUCTION_SYSTEMS = /* @__PURE__ */ new Map([
|
|
16162
16167
|
["masonry", { walls: "brick_wall_plastered", joints: { wall: "mortar", slab: "rebar", beam: "mortar", column: "rebar", truss: "bolt" }, slabThickness: 0.12, plateThickness: 0.2, timber: false, wallRole: "rules", wallFill: 1 }],
|
|
@@ -16165,10 +16170,59 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
16165
16170
|
["improvised", { walls: "sheet_metal_shack", joints: uniform("nail"), slabThickness: 0.2, plateThickness: 0.1, timber: true, wallRole: "partition", wallFill: 1 }],
|
|
16166
16171
|
["canvas", { walls: "", joints: uniform("tie"), slabThickness: 0, plateThickness: 0, timber: false, wallRole: "partition", wallFill: 1 }]
|
|
16167
16172
|
]);
|
|
16173
|
+
var ROOF_COVERINGS = /* @__PURE__ */ new Map([
|
|
16174
|
+
["colonial", { material: "ceramic", joint: "resting" }],
|
|
16175
|
+
["fiber_cement", { material: "concrete", joint: "bolt" }],
|
|
16176
|
+
["slab", { material: "concrete", joint: "rebar" }],
|
|
16177
|
+
["asphalt", { material: "plastic", joint: "nail" }],
|
|
16178
|
+
["zinc", { material: "steel", joint: "nail" }],
|
|
16179
|
+
["wood", { material: "wood_soft", joint: "nail" }],
|
|
16180
|
+
["canvas", { material: "fabric", joint: "tie" }],
|
|
16181
|
+
["thatch", { material: "foliage", joint: "tie" }]
|
|
16182
|
+
]);
|
|
16183
|
+
var WALL_THICKNESS = 0.15;
|
|
16168
16184
|
var round2 = (value) => Math.round(value * 100) / 100;
|
|
16169
16185
|
function touches(a, b, tolerance) {
|
|
16170
16186
|
return a[0] < b[2] + tolerance && a[2] > b[0] - tolerance && a[1] < b[3] + tolerance && a[3] > b[1] - tolerance;
|
|
16171
16187
|
}
|
|
16188
|
+
function distanceBetween(a, b) {
|
|
16189
|
+
return Math.hypot(Math.max(a[0] - b[2], b[0] - a[2], 0), Math.max(a[1] - b[3], b[1] - a[3], 0));
|
|
16190
|
+
}
|
|
16191
|
+
function unionOf(rects) {
|
|
16192
|
+
const out = [1e9, 1e9, -1e9, -1e9];
|
|
16193
|
+
for (const rect of rects) {
|
|
16194
|
+
out[0] = Math.min(out[0], rect[0]);
|
|
16195
|
+
out[1] = Math.min(out[1], rect[1]);
|
|
16196
|
+
out[2] = Math.max(out[2], rect[2]);
|
|
16197
|
+
out[3] = Math.max(out[3], rect[3]);
|
|
16198
|
+
}
|
|
16199
|
+
return out;
|
|
16200
|
+
}
|
|
16201
|
+
function wallBox(wall) {
|
|
16202
|
+
const half = (wall.thickness ?? WALL_THICKNESS) / 2;
|
|
16203
|
+
return [Math.min(wall.u0, wall.u1) - half, Math.min(wall.v0, wall.v1) - half, Math.max(wall.u0, wall.u1) + half, Math.max(wall.v0, wall.v1) + half];
|
|
16204
|
+
}
|
|
16205
|
+
var SLAB_COVERING = "slab";
|
|
16206
|
+
var PLASTERED_FINISHES = ["plaster", "partial_plaster"];
|
|
16207
|
+
function masonryConstruction(source) {
|
|
16208
|
+
const unit = source.floorNumber !== void 0;
|
|
16209
|
+
const covering = unit ? SLAB_COVERING : source.facade.roof ?? "colonial";
|
|
16210
|
+
const finish = source.facade.finish ?? "roughcast";
|
|
16211
|
+
const budget = source.style === "budget";
|
|
16212
|
+
const flat = unit || covering === SLAB_COVERING;
|
|
16213
|
+
return {
|
|
16214
|
+
system: "masonry",
|
|
16215
|
+
walls: { material: "brick", cladding: PLASTERED_FINISHES.includes(finish) ? "plaster" : null, finish, thickness: WALL_THICKNESS, ...finish === "exposed_block" ? { assembly: "concrete_block_wall" } : {} },
|
|
16216
|
+
floor: { material: budget ? "concrete" : "ceramic", finish: budget ? "burnt_cement" : "ceramic_tile" },
|
|
16217
|
+
roof: { material: ROOF_COVERINGS.get(covering)?.material ?? "ceramic", covering, shape: flat ? "slab" : "gable", pitch: flat ? 0 : covering === "colonial" ? 30 : 15, timber: "wood_soft" },
|
|
16218
|
+
frame: { material: "concrete", pillars: "concrete", beams: "concrete", slabs: "concrete", timber: "wood_soft", rebar: "steel" },
|
|
16219
|
+
foundation: { type: unit ? "building" : "strip_footing", material: "concrete", elevation: 0 }
|
|
16220
|
+
};
|
|
16221
|
+
}
|
|
16222
|
+
function resolveConstruction(source) {
|
|
16223
|
+
const extras = source.structureExtras ?? {};
|
|
16224
|
+
return { construction: source.construction ?? masonryConstruction(source), extras };
|
|
16225
|
+
}
|
|
16172
16226
|
var en_default = {
|
|
16173
16227
|
ui: {
|
|
16174
16228
|
structure_layer: "Structure",
|
|
@@ -16239,8 +16293,950 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
16239
16293
|
};
|
|
16240
16294
|
var DEFAULT_DENSITY = 500;
|
|
16241
16295
|
var densityOf = (material) => DENSITY[material] ?? DEFAULT_DENSITY;
|
|
16296
|
+
var StructureBuilder = class {
|
|
16297
|
+
constructor() {
|
|
16298
|
+
__publicField(this, "parts", []);
|
|
16299
|
+
__publicField(this, "supports", []);
|
|
16300
|
+
__publicField(this, "ids", /* @__PURE__ */ new Set());
|
|
16301
|
+
}
|
|
16302
|
+
add(draft, options = {}) {
|
|
16303
|
+
const { id, role, material, aabb, y0, y1 } = draft;
|
|
16304
|
+
if (this.ids.has(id)) throw new Error(`Part repeated in the structure: ${id}`);
|
|
16305
|
+
this.ids.add(id);
|
|
16306
|
+
const { floor, fill: fill2, ...extras } = options;
|
|
16307
|
+
const volume = Math.max(0, (aabb[2] - aabb[0]) * (aabb[3] - aabb[1]) * (y1 - y0)) * (fill2 ?? 1);
|
|
16308
|
+
const part = {
|
|
16309
|
+
id,
|
|
16310
|
+
role,
|
|
16311
|
+
material,
|
|
16312
|
+
aabb: aabb.map(round2),
|
|
16313
|
+
y0: round2(y0),
|
|
16314
|
+
y1: round2(y1),
|
|
16315
|
+
floor: floor ?? 0,
|
|
16316
|
+
mass: Math.max(1, Math.round(volume * densityOf(material)))
|
|
16317
|
+
};
|
|
16318
|
+
for (const [key, value] of Object.entries(extras)) if (value !== void 0) part[key] = value;
|
|
16319
|
+
this.parts.push(part);
|
|
16320
|
+
return part;
|
|
16321
|
+
}
|
|
16322
|
+
rest(part, on, joint) {
|
|
16323
|
+
const id = typeof part === "string" ? part : part.id;
|
|
16324
|
+
const base = typeof on === "string" ? on : on.id;
|
|
16325
|
+
this.supports.push({ part: id, on: base === GROUND ? GROUND : base, joint });
|
|
16326
|
+
}
|
|
16327
|
+
has(id) {
|
|
16328
|
+
return this.ids.has(id);
|
|
16329
|
+
}
|
|
16330
|
+
find(id) {
|
|
16331
|
+
return this.parts.find((part) => part.id === id);
|
|
16332
|
+
}
|
|
16333
|
+
};
|
|
16334
|
+
function hashLegacyKey(key) {
|
|
16335
|
+
let hash = 1779033703 ^ key.length;
|
|
16336
|
+
for (let i = 0; i < key.length; i++) {
|
|
16337
|
+
hash = Math.imul(hash ^ key.charCodeAt(i), 3432918353);
|
|
16338
|
+
hash = hash << 13 | hash >>> 19;
|
|
16339
|
+
}
|
|
16340
|
+
hash = Math.imul(hash ^ hash >>> 16, 2246822507);
|
|
16341
|
+
hash = Math.imul(hash ^ hash >>> 13, 3266489909);
|
|
16342
|
+
return (hash ^ hash >>> 16) >>> 0;
|
|
16343
|
+
}
|
|
16242
16344
|
var OPEN_ROOM_TYPES2 = ["balcony", "terrace", "porch"];
|
|
16345
|
+
var GUARD_HEIGHT = 1.1;
|
|
16346
|
+
function createContext(source, construction, extras, tank, options) {
|
|
16347
|
+
const system = CONSTRUCTION_SYSTEMS.get(construction.system);
|
|
16348
|
+
if (!system) throw new Error(`Unknown construction system "${construction.system}"`);
|
|
16349
|
+
const floorCount2 = source.floors.length;
|
|
16350
|
+
const isUnit = source.floorNumber !== void 0;
|
|
16351
|
+
const elevation = construction.foundation.elevation || 0;
|
|
16352
|
+
const level = (floor) => round2(elevation + (source.floors[floor]?.y0 ?? 0));
|
|
16353
|
+
const ceilingOf = (floor) => source.floors[floor]?.ceiling ?? 0;
|
|
16354
|
+
const topOf = (floor) => floor < floorCount2 - 1 && !isUnit ? level(floor + 1) - system.slabThickness : level(floor) + ceilingOf(floor);
|
|
16355
|
+
const rectsOf2 = (floor, exclude = []) => source.rooms.filter((room) => room.floor === floor && !exclude.includes(room.type)).flatMap((room) => room.parts);
|
|
16356
|
+
const builder = new StructureBuilder();
|
|
16357
|
+
const context = {
|
|
16358
|
+
source,
|
|
16359
|
+
construction,
|
|
16360
|
+
system,
|
|
16361
|
+
extras,
|
|
16362
|
+
tank,
|
|
16363
|
+
builder,
|
|
16364
|
+
porchRoofOnPostsOnly: options.porchRoofOnPostsOnly,
|
|
16365
|
+
rafterRoof: options.rafterRoof,
|
|
16366
|
+
floorCount: floorCount2,
|
|
16367
|
+
isUnit,
|
|
16368
|
+
elevation,
|
|
16369
|
+
isTimber: system.timber,
|
|
16370
|
+
walls: [],
|
|
16371
|
+
wallParts: /* @__PURE__ */ new Map(),
|
|
16372
|
+
carriers: /* @__PURE__ */ new Map(),
|
|
16373
|
+
plates: /* @__PURE__ */ new Map(),
|
|
16374
|
+
pillars: /* @__PURE__ */ new Map(),
|
|
16375
|
+
porches: /* @__PURE__ */ new Map(),
|
|
16376
|
+
base0: GROUND,
|
|
16377
|
+
houseBox: [0, 0, 0, 0],
|
|
16378
|
+
topBox: [0, 0, 0, 0],
|
|
16379
|
+
hasBasement: false,
|
|
16380
|
+
roof: { shape: "slab", covering: "", material: "", pitch: 0, bearingFloor: 0, panes: [], trusses: 0 },
|
|
16381
|
+
level,
|
|
16382
|
+
ceilingOf,
|
|
16383
|
+
topOf,
|
|
16384
|
+
rectsOf: rectsOf2,
|
|
16385
|
+
baseOf: (floor) => floor === 0 ? context.base0 : builder.find(`slab_${floor}`)
|
|
16386
|
+
};
|
|
16387
|
+
const closed = rectsOf2(0, ["balcony", "porch"]);
|
|
16388
|
+
context.houseBox = unionOf(closed.length ? closed : rectsOf2(0));
|
|
16389
|
+
context.walls = classifyWalls(context);
|
|
16390
|
+
return context;
|
|
16391
|
+
}
|
|
16392
|
+
var isBearingOnTop = (wall, walls) => {
|
|
16393
|
+
const along = (w, pick2) => w.axis === "u" ? pick2(w.u0, w.u1) : pick2(w.v0, w.v1);
|
|
16394
|
+
const across = (w) => w.axis === "u" ? w.v0 : w.u0;
|
|
16395
|
+
return walls.some(
|
|
16396
|
+
(other) => other.floor === wall.floor + 1 && other.type === "wall" && other.axis === wall.axis && Math.abs(across(other) - across(wall)) < 0.2 && Math.min(along(wall, Math.max), along(other, Math.max)) - Math.max(along(wall, Math.min), along(other, Math.min)) > 0.3
|
|
16397
|
+
);
|
|
16398
|
+
};
|
|
16399
|
+
function roleOf(context, wall, walls, porchIds) {
|
|
16400
|
+
if (wall.type === "railing") return "partition";
|
|
16401
|
+
const { wallRole } = context.system;
|
|
16402
|
+
if (wallRole === "bearing") return "wall";
|
|
16403
|
+
if (wallRole === "partition") return "partition";
|
|
16404
|
+
const bearingFloor = context.construction.roof.bearingFloor ?? context.floorCount - 1;
|
|
16405
|
+
if (wall.floor > bearingFloor) return "partition";
|
|
16406
|
+
if (wall.exterior || wall.sides.some((id) => porchIds.has(id))) return "wall";
|
|
16407
|
+
return wall.floor < context.floorCount - 1 && isBearingOnTop(wall, walls) ? "wall" : "partition";
|
|
16408
|
+
}
|
|
16409
|
+
function materialOf(context, wall) {
|
|
16410
|
+
const { walls, guard } = context.construction;
|
|
16411
|
+
if (wall.type === "railing") return guard ?? (context.isTimber ? "wood_soft" : "steel");
|
|
16412
|
+
if (walls.mixed?.length) return walls.mixed[hashLegacyKey(wall.legacyKey) % walls.mixed.length];
|
|
16413
|
+
return wall.exterior ? walls.material : walls.interior ?? walls.material;
|
|
16414
|
+
}
|
|
16415
|
+
function classifyWalls(context) {
|
|
16416
|
+
const countByFloor = /* @__PURE__ */ new Map();
|
|
16417
|
+
const all = context.source.walls.map((wall) => {
|
|
16418
|
+
const index = countByFloor.get(wall.floor) ?? 0;
|
|
16419
|
+
countByFloor.set(wall.floor, index + 1);
|
|
16420
|
+
return { ...wall, id: `wall_${wall.floor}_${index}`, legacyKey: `w${wall.floor}_${index}`, role: "wall", material: "", box: wallBox(wall) };
|
|
16421
|
+
});
|
|
16422
|
+
const built = all.filter((wall) => wall.type === "wall" || wall.type === "railing");
|
|
16423
|
+
const porchIds = new Set(context.source.rooms.filter((room) => room.type === "porch").map((room) => room.id));
|
|
16424
|
+
for (const wall of built) {
|
|
16425
|
+
wall.role = roleOf(context, wall, built, porchIds);
|
|
16426
|
+
wall.material = materialOf(context, wall);
|
|
16427
|
+
}
|
|
16428
|
+
return built;
|
|
16429
|
+
}
|
|
16430
|
+
var guardHeightOf = (wall) => wall.h || GUARD_HEIGHT;
|
|
16431
|
+
function addBalconies(context) {
|
|
16432
|
+
const { builder, construction, system } = context;
|
|
16433
|
+
for (const room of context.source.rooms.filter((r) => r.type === "balcony" && r.floor >= 0)) {
|
|
16434
|
+
const floor = room.floor;
|
|
16435
|
+
const box22 = unionOf(room.parts);
|
|
16436
|
+
const base = floor === 0 ? void 0 : context.baseOf(floor);
|
|
16437
|
+
const deck = builder.add({ id: `slab_${floor}_${room.id}`, role: "slab", material: construction.frame.slabs, aabb: box22, y0: context.level(floor) - system.slabThickness, y1: context.level(floor) }, { floor });
|
|
16438
|
+
if (base) {
|
|
16439
|
+
builder.rest(deck, base, system.joints.slab);
|
|
16440
|
+
continue;
|
|
16441
|
+
}
|
|
16442
|
+
const pillar = builder.add({ id: `balcony_column_${room.id}`, role: "column", material: construction.frame.pillars, aabb: [box22[0] - 0.08, box22[1] - 0.08, box22[0] + 0.08, box22[1] + 0.08], y0: 0, y1: context.level(floor) - system.slabThickness }, { floor: 0 });
|
|
16443
|
+
builder.rest(pillar, GROUND, "rebar");
|
|
16444
|
+
builder.rest(deck, pillar, "rebar");
|
|
16445
|
+
}
|
|
16446
|
+
}
|
|
16447
|
+
var GROUNDSHEET = 0.02;
|
|
16448
|
+
function buildCanvasStructure(construction, extras) {
|
|
16449
|
+
const builder = new StructureBuilder();
|
|
16450
|
+
const panes = [];
|
|
16451
|
+
for (const tent of extras.tents ?? []) {
|
|
16452
|
+
const [u0, v0, u1, v1] = tent.aabb;
|
|
16453
|
+
const centreU = (u0 + u1) / 2;
|
|
16454
|
+
const centreV = (v0 + v1) / 2;
|
|
16455
|
+
const sheet = builder.add({ id: `groundsheet_${tent.id}`, role: "slab", material: "plastic", aabb: tent.aabb, y0: 0, y1: GROUNDSHEET }, { floor: 0, tent: tent.id });
|
|
16456
|
+
builder.rest(sheet, GROUND, "resting");
|
|
16457
|
+
const canvas = builder.add({ id: `canvas_${tent.id}`, role: "roof", material: "fabric", aabb: tent.aabb, y0: GROUNDSHEET, y1: tent.height }, { floor: 0, fill: 0.04, tent: tent.id, form: tent.kind });
|
|
16458
|
+
panes.push(canvas.id);
|
|
16459
|
+
const poles = tent.kind === "tunnel" ? [0.25, 0.75].map((fraction, k) => [[u0 + (u1 - u0) * fraction - 0.015, v0 + 0.05, u0 + (u1 - u0) * fraction + 0.015, v1 - 0.05], k]) : [[[u0 + 0.05, centreV - 0.015, u1 - 0.05, centreV + 0.015], 0], [[centreU - 0.015, v0 + 0.05, centreU + 0.015, v1 - 0.05], 1]];
|
|
16460
|
+
for (const [aabb, k] of poles) {
|
|
16461
|
+
const pole = builder.add({ id: `pole_${tent.id}_${k}`, role: "column", material: construction.frame.pillars, aabb, y0: GROUNDSHEET, y1: tent.height - GROUNDSHEET }, { floor: 0, fill: 0.05, tent: tent.id });
|
|
16462
|
+
builder.rest(pole, GROUND, "resting");
|
|
16463
|
+
builder.rest(canvas, pole, "tie");
|
|
16464
|
+
}
|
|
16465
|
+
const corners = [[u0 - 0.2, v0 - 0.2], [u1 + 0.2, v0 - 0.2], [u0 - 0.2, v1 + 0.2], [u1 + 0.2, v1 + 0.2]];
|
|
16466
|
+
corners.forEach(([u, v], k) => {
|
|
16467
|
+
const peg = builder.add({ id: `peg_${tent.id}_${k}`, role: "column", material: "wood_soft", aabb: [u - 0.02, v - 0.02, u + 0.02, v + 0.02], y0: 0, y1: 0.2 }, { floor: 0 });
|
|
16468
|
+
builder.rest(peg, GROUND, "nail");
|
|
16469
|
+
builder.rest(canvas, peg, "tie");
|
|
16470
|
+
});
|
|
16471
|
+
}
|
|
16472
|
+
const roof = { shape: "tent", covering: "canvas", material: "fabric", pitch: 0, bearingFloor: 0, panes, trusses: 0 };
|
|
16473
|
+
return { parts: builder.parts, supports: builder.supports, levels: [0], elevation: 0, roof, construction, framed: false, openings: [] };
|
|
16474
|
+
}
|
|
16475
|
+
var CHIMNEY_CLEARANCE_ABOVE_RIDGE = 0.6;
|
|
16476
|
+
function addChimney(context) {
|
|
16477
|
+
const chimney = context.extras.chimney;
|
|
16478
|
+
if (!chimney) return;
|
|
16479
|
+
const { builder } = context;
|
|
16480
|
+
const top = context.floorCount - 1;
|
|
16481
|
+
const ridge = context.roof.ridge || context.level(top) + context.ceilingOf(top);
|
|
16482
|
+
const height = Math.max(ridge, chimney.top || 0) + CHIMNEY_CLEARANCE_ABOVE_RIDGE;
|
|
16483
|
+
const part = builder.add({ id: "chimney", role: "column", material: chimney.material || "brick", aabb: chimney.aabb, y0: chimney.flue ? context.level(0) : 0, y1: height }, { floor: 0, fill: chimney.flue ? 0.15 : 0.7 });
|
|
16484
|
+
if (chimney.flue) builder.rest(part, context.base0 ?? GROUND, "resting");
|
|
16485
|
+
else builder.rest(part, GROUND, "mortar");
|
|
16486
|
+
const walls = builder.parts.filter((wall) => wall.role === "wall" && wall.floor === 0 && !wall.id.startsWith("basement") && touches(wall.aabb, part.aabb, 0.1));
|
|
16487
|
+
for (const wall of walls) builder.rest(part, wall, "bolt");
|
|
16488
|
+
chimney.height = round2(height);
|
|
16489
|
+
}
|
|
16490
|
+
function addWell(context) {
|
|
16491
|
+
const well = context.extras.well;
|
|
16492
|
+
if (!well) return;
|
|
16493
|
+
const part = context.builder.add({ id: "well", role: "column", material: "stone", aabb: well.aabb, y0: -0.5, y1: well.height || 0.9 }, { floor: 0, fill: 0.5 });
|
|
16494
|
+
context.builder.rest(part, GROUND, "mortar");
|
|
16495
|
+
}
|
|
16496
|
+
var JOIST_PITCH = 0.6;
|
|
16497
|
+
function addJoists(context, options) {
|
|
16498
|
+
const { floor, box: box22, thickness, carriers, material, joint, suffix = "" } = options;
|
|
16499
|
+
const length = box22[2] - box22[0];
|
|
16500
|
+
const depth = box22[3] - box22[1];
|
|
16501
|
+
const alongU = length >= depth;
|
|
16502
|
+
const span = alongU ? length : depth;
|
|
16503
|
+
const count = Math.max(2, Math.round(span / JOIST_PITCH) + 1);
|
|
16504
|
+
const top = context.level(floor) - thickness * 0.15;
|
|
16505
|
+
const out = [];
|
|
16506
|
+
for (let k = 0; k < count; k++) {
|
|
16507
|
+
const centre = (alongU ? box22[0] : box22[1]) + 0.05 + k * (span - 0.1) / (count - 1);
|
|
16508
|
+
const aabb = alongU ? [centre - 0.025, box22[1], centre + 0.025, box22[3]] : [box22[0], centre - 0.025, box22[2], centre + 0.025];
|
|
16509
|
+
const joist = context.builder.add({ id: `joist_${floor}${suffix}_${k}`, role: "beam", material, aabb, y0: context.level(floor) - thickness, y1: top }, { floor, fill: 1, spacing: JOIST_PITCH });
|
|
16510
|
+
out.push(joist);
|
|
16511
|
+
const below = carriers.filter((carrier) => carrier.y0 <= top + 0.05);
|
|
16512
|
+
const touching = below.filter((carrier) => touches(aabb, carrier.aabb, 0.2));
|
|
16513
|
+
const pool = below.length ? below : carriers;
|
|
16514
|
+
const chosen = touching.length ? touching : pool.slice().sort((a, b) => distanceBetween(aabb, a.aabb) - distanceBetween(aabb, b.aabb)).slice(0, 1);
|
|
16515
|
+
for (const carrier of chosen) context.builder.rest(joist, carrier, joint);
|
|
16516
|
+
}
|
|
16517
|
+
return out;
|
|
16518
|
+
}
|
|
16519
|
+
function addDeck(context, id, material, options, joists) {
|
|
16520
|
+
const { floor, box: box22, thickness, joint } = options;
|
|
16521
|
+
const deck = context.builder.add({ id, role: "slab", material, aabb: box22, y0: context.level(floor) - thickness * 0.15, y1: context.level(floor) }, { floor });
|
|
16522
|
+
for (const joist of joists) context.builder.rest(deck, joist, joint);
|
|
16523
|
+
return deck;
|
|
16524
|
+
}
|
|
16525
|
+
var raft = (context, thickness, material) => {
|
|
16526
|
+
const [u0, v0, u1, v1] = context.houseBox;
|
|
16527
|
+
const part = context.builder.add({ id: "foundation_raft", role: "slab", material, aabb: [u0 - 0.1, v0 - 0.1, u1 + 0.1, v1 + 0.1], y0: 0, y1: thickness }, { floor: 0 });
|
|
16528
|
+
context.builder.rest(part, GROUND, "resting");
|
|
16529
|
+
return part;
|
|
16530
|
+
};
|
|
16531
|
+
function addBuildingBase(context) {
|
|
16532
|
+
const { builder, construction, houseBox: box22 } = context;
|
|
16533
|
+
const corners = [[box22[0], box22[1]], [box22[2], box22[1]], [box22[0], box22[3]], [box22[2], box22[3]]];
|
|
16534
|
+
const top = context.level(0) - context.system.slabThickness;
|
|
16535
|
+
const pillars = corners.map(([u, v], k) => {
|
|
16536
|
+
const pillar = builder.add({ id: `building_column_${k}`, role: "column", material: construction.frame.pillars, aabb: [u - 0.15, v - 0.15, u + 0.15, v + 0.15], y0: 0, y1: top }, { floor: 0 });
|
|
16537
|
+
builder.rest(pillar, GROUND, "rebar");
|
|
16538
|
+
return pillar;
|
|
16539
|
+
});
|
|
16540
|
+
const slab = builder.add({ id: "slab_base", role: "slab", material: construction.frame.slabs, aabb: box22, y0: top, y1: context.level(0) }, { floor: 0, footprint: [box22] });
|
|
16541
|
+
for (const pillar of pillars) builder.rest(slab, pillar, "rebar");
|
|
16542
|
+
context.base0 = slab;
|
|
16543
|
+
}
|
|
16544
|
+
function addBasement(context) {
|
|
16545
|
+
const { builder, houseBox: box22, elevation } = context;
|
|
16546
|
+
const depth = context.construction.foundation.depth || 2.4;
|
|
16547
|
+
const floor = builder.add({ id: "basement_slab", role: "slab", material: "concrete", aabb: box22, y0: -depth - 0.15, y1: -depth }, { floor: -1 });
|
|
16548
|
+
builder.rest(floor, GROUND, "resting");
|
|
16549
|
+
const sides = [
|
|
16550
|
+
["front", [box22[0], box22[1] - 0.1, box22[2], box22[1] + 0.1]],
|
|
16551
|
+
["back", [box22[0], box22[3] - 0.1, box22[2], box22[3] + 0.1]],
|
|
16552
|
+
["left", [box22[0] - 0.1, box22[1], box22[0] + 0.1, box22[3]]],
|
|
16553
|
+
["right", [box22[2] - 0.1, box22[1], box22[2] + 0.1, box22[3]]]
|
|
16554
|
+
];
|
|
16555
|
+
const carried = [];
|
|
16556
|
+
for (const [name, aabb] of sides) {
|
|
16557
|
+
const wall = builder.add({ id: `basement_wall_${name}`, role: "wall", material: "concrete", aabb, y0: -depth, y1: elevation }, { floor: -1 });
|
|
16558
|
+
builder.rest(wall, GROUND, "rebar");
|
|
16559
|
+
builder.rest(wall, floor, "rebar");
|
|
16560
|
+
carried.push(wall);
|
|
16561
|
+
}
|
|
16562
|
+
const count = Math.max(1, Math.floor((box22[2] - box22[0]) / 3));
|
|
16563
|
+
for (let k = 0; k < count; k++) {
|
|
16564
|
+
const u = box22[0] + (k + 0.5) * (box22[2] - box22[0]) / count;
|
|
16565
|
+
const v = (box22[1] + box22[3]) / 2;
|
|
16566
|
+
const column = builder.add({ id: `basement_column_${k}`, role: "column", material: "concrete", aabb: [u - 0.15, v - 0.15, u + 0.15, v + 0.15], y0: -depth, y1: elevation - 0.3 }, { floor: -1 });
|
|
16567
|
+
builder.rest(column, floor, "rebar");
|
|
16568
|
+
builder.rest(column, GROUND, "rebar");
|
|
16569
|
+
carried.push(column);
|
|
16570
|
+
}
|
|
16571
|
+
context.hasBasement = true;
|
|
16572
|
+
return carried;
|
|
16573
|
+
}
|
|
16574
|
+
function addPiers(context) {
|
|
16575
|
+
const { builder, houseBox: box22, elevation, construction } = context;
|
|
16576
|
+
const columns = Math.max(2, Math.ceil((box22[2] - box22[0]) / 2) + 1);
|
|
16577
|
+
const rows = Math.max(2, Math.ceil((box22[3] - box22[1]) / 2) + 1);
|
|
16578
|
+
const height = Math.max(0.1, elevation - context.system.slabThickness - 0.15);
|
|
16579
|
+
const piers = [];
|
|
16580
|
+
for (let j = 0; j < rows; j++) {
|
|
16581
|
+
for (let i = 0; i < columns; i++) {
|
|
16582
|
+
const u = box22[0] + i * (box22[2] - box22[0]) / (columns - 1);
|
|
16583
|
+
const v = box22[1] + j * (box22[3] - box22[1]) / (rows - 1);
|
|
16584
|
+
const pier = builder.add({ id: `footing_pier_${j}_${i}`, role: "column", material: construction.foundation.material || "concrete", aabb: [u - 0.12, v - 0.12, u + 0.12, v + 0.12], y0: 0, y1: height }, { floor: 0 });
|
|
16585
|
+
builder.rest(pier, GROUND, "resting");
|
|
16586
|
+
piers.push(pier);
|
|
16587
|
+
}
|
|
16588
|
+
}
|
|
16589
|
+
const alongU = box22[2] - box22[0] >= box22[3] - box22[1];
|
|
16590
|
+
const beams = [];
|
|
16591
|
+
const lines = alongU ? rows : columns;
|
|
16592
|
+
for (let line = 0; line < lines; line++) {
|
|
16593
|
+
const at2 = alongU ? box22[1] + line * (box22[3] - box22[1]) / (rows - 1) : box22[0] + line * (box22[2] - box22[0]) / (columns - 1);
|
|
16594
|
+
const aabb = alongU ? [box22[0], at2 - 0.07, box22[2], at2 + 0.07] : [at2 - 0.07, box22[1], at2 + 0.07, box22[3]];
|
|
16595
|
+
const beam = builder.add({ id: `base_beam_${line}`, role: "beam", material: construction.frame.timber, aabb, y0: height, y1: elevation - context.system.slabThickness }, { floor: 0 });
|
|
16596
|
+
const centre = (q) => alongU ? (q.aabb[1] + q.aabb[3]) / 2 : (q.aabb[0] + q.aabb[2]) / 2;
|
|
16597
|
+
for (const pier of piers.filter((q) => Math.abs(centre(q) - at2) < 0.05)) builder.rest(beam, pier, "bolt");
|
|
16598
|
+
beams.push(beam);
|
|
16599
|
+
}
|
|
16600
|
+
return beams;
|
|
16601
|
+
}
|
|
16602
|
+
function addRaisedFloor(context) {
|
|
16603
|
+
const { construction, system, houseBox: box22 } = context;
|
|
16604
|
+
const carriers = construction.foundation.type === "basement" ? addBasement(context) : addPiers(context);
|
|
16605
|
+
const thickness = system.slabThickness;
|
|
16606
|
+
const joists = addJoists(context, { floor: 0, box: box22, thickness, carriers, material: construction.frame.timber, joint: construction.foundation.type === "basement" ? "bolt" : "nail" });
|
|
16607
|
+
const deckMaterial = context.isTimber ? construction.floor.material === "wood_hard" ? "wood_hard" : "plywood" : construction.frame.slabs;
|
|
16608
|
+
context.base0 = addDeck(context, "slab_0", deckMaterial, { floor: 0, box: box22, thickness, joint: "nail" }, joists);
|
|
16609
|
+
}
|
|
16610
|
+
function addFoundation(context) {
|
|
16611
|
+
const { type, material } = context.construction.foundation;
|
|
16612
|
+
if (context.isUnit) return addBuildingBase(context);
|
|
16613
|
+
if (type === "raft") context.base0 = raft(context, Math.max(0.1, context.elevation), material || "concrete");
|
|
16614
|
+
else if (type === "crawl_space" || type === "piles" || type === "basement") addRaisedFloor(context);
|
|
16615
|
+
else if (context.isTimber && type !== "ground") context.base0 = raft(context, Math.max(0.12, context.elevation), "concrete");
|
|
16616
|
+
}
|
|
16617
|
+
var MAX_GAP_WITHIN_RUN = 3.2;
|
|
16618
|
+
var POST_SPACING = 2.4;
|
|
16619
|
+
var POST_SIDE = 0.05;
|
|
16620
|
+
var alongOf = (wall, pick2) => wall.axis === "u" ? pick2(wall.u0, wall.u1) : pick2(wall.v0, wall.v1);
|
|
16621
|
+
var acrossOf = (wall) => wall.axis === "u" ? wall.v0 : wall.u0;
|
|
16622
|
+
function runsOf(context, walls, floor) {
|
|
16623
|
+
const lines = /* @__PURE__ */ new Map();
|
|
16624
|
+
for (const wall of walls) {
|
|
16625
|
+
if (!wall.exterior || wall.type !== "wall") continue;
|
|
16626
|
+
const top = round2(context.wallParts.get(wall.id).y1);
|
|
16627
|
+
const key = `${floor}|${wall.axis}|${acrossOf(wall).toFixed(2)}|${top.toFixed(2)}`;
|
|
16628
|
+
lines.set(key, [...lines.get(key) ?? [], wall]);
|
|
16629
|
+
}
|
|
16630
|
+
return [...lines.values()].map((line) => {
|
|
16631
|
+
const sorted = line.slice().sort((a, b) => alongOf(a, Math.min) - alongOf(b, Math.min));
|
|
16632
|
+
const runs = [];
|
|
16633
|
+
for (const wall of sorted) {
|
|
16634
|
+
const from = alongOf(wall, Math.min);
|
|
16635
|
+
const to = alongOf(wall, Math.max);
|
|
16636
|
+
const last = runs[runs.length - 1];
|
|
16637
|
+
if (last && from - last.to <= MAX_GAP_WITHIN_RUN) {
|
|
16638
|
+
last.to = Math.max(last.to, to);
|
|
16639
|
+
last.walls.push(wall);
|
|
16640
|
+
} else runs.push({ from, to, walls: [wall] });
|
|
16641
|
+
}
|
|
16642
|
+
return runs;
|
|
16643
|
+
});
|
|
16644
|
+
}
|
|
16645
|
+
function addShackPosts(context, run, plate, floor, index) {
|
|
16646
|
+
const first = run.walls[0];
|
|
16647
|
+
const across = acrossOf(first);
|
|
16648
|
+
const top = context.wallParts.get(first.id).y1;
|
|
16649
|
+
const count = Math.max(1, Math.ceil((run.to - run.from) / POST_SPACING));
|
|
16650
|
+
const posts = [];
|
|
16651
|
+
for (let k = 0; k <= count; k++) {
|
|
16652
|
+
const along = run.from + (run.to - run.from) * k / count;
|
|
16653
|
+
const [u, v] = first.axis === "u" ? [along, across] : [across, along];
|
|
16654
|
+
const half = 0.05 + POST_SIDE / 2;
|
|
16655
|
+
const post = context.builder.add({ id: `post_${floor}_${index}_${k}`, role: "column", material: "wood_soft", aabb: [u - half, v - half, u + half, v + half], y0: context.level(floor), y1: top }, { floor });
|
|
16656
|
+
const base = context.baseOf(floor);
|
|
16657
|
+
if (base === GROUND || !base) context.builder.rest(post, GROUND, "tie");
|
|
16658
|
+
else context.builder.rest(post, base, "nail");
|
|
16659
|
+
context.builder.rest(plate, post, "nail");
|
|
16660
|
+
posts.push(post);
|
|
16661
|
+
}
|
|
16662
|
+
return posts;
|
|
16663
|
+
}
|
|
16664
|
+
function addPlates(context, walls, floor) {
|
|
16665
|
+
const { builder, system, construction } = context;
|
|
16666
|
+
const plates = [];
|
|
16667
|
+
const pillars = [];
|
|
16668
|
+
let counter = 0;
|
|
16669
|
+
for (const runs of runsOf(context, walls, floor)) {
|
|
16670
|
+
for (const run of runs) {
|
|
16671
|
+
const first = run.walls[0];
|
|
16672
|
+
const half = (first.thickness ?? 0.15) / 2;
|
|
16673
|
+
const across = acrossOf(first);
|
|
16674
|
+
const top = context.wallParts.get(first.id).y1;
|
|
16675
|
+
const aabb = first.axis === "u" ? [run.from - half, across - half, run.to + half, across + half] : [across - half, run.from - half, across + half, run.to + half];
|
|
16676
|
+
const material = context.isTimber ? construction.frame.timber : construction.frame.beams;
|
|
16677
|
+
const plate = builder.add({ id: `plate_${floor}_${counter++}`, role: "beam", material, aabb, y0: top, y1: top + system.plateThickness }, { floor, beamKind: context.isTimber ? "plate" : "bond_beam" });
|
|
16678
|
+
if (construction.system === "improvised") pillars.push(...addShackPosts(context, run, plate, floor, counter));
|
|
16679
|
+
else for (const wall of run.walls) builder.rest(plate, context.wallParts.get(wall.id), system.joints.beam);
|
|
16680
|
+
plates.push(plate);
|
|
16681
|
+
}
|
|
16682
|
+
}
|
|
16683
|
+
return { plates, pillars };
|
|
16684
|
+
}
|
|
16685
|
+
function cornerPoints(walls) {
|
|
16686
|
+
const ends = walls.filter((wall) => wall.exterior && wall.type === "wall").flatMap(
|
|
16687
|
+
(wall) => wall.axis === "u" ? [[Math.min(wall.u0, wall.u1), wall.v0, "u"], [Math.max(wall.u0, wall.u1), wall.v0, "u"]] : [[wall.u0, Math.min(wall.v0, wall.v1), "v"], [wall.u0, Math.max(wall.v0, wall.v1), "v"]]
|
|
16688
|
+
);
|
|
16689
|
+
const points = [];
|
|
16690
|
+
for (const a of ends) {
|
|
16691
|
+
const joinsOtherAxis = ends.some((b) => b[2] !== a[2] && Math.hypot(a[0] - b[0], a[1] - b[1]) < 0.12);
|
|
16692
|
+
if (joinsOtherAxis && !points.some((q) => Math.hypot(q[0] - a[0], q[1] - a[1]) < 0.12)) points.push([a[0], a[1]]);
|
|
16693
|
+
}
|
|
16694
|
+
return points;
|
|
16695
|
+
}
|
|
16696
|
+
function addCornerPillars(context, walls, floor, plates) {
|
|
16697
|
+
const { builder } = context;
|
|
16698
|
+
const topOfFloor = context.topOf(floor);
|
|
16699
|
+
return cornerPoints(walls).map(([u, v], k) => {
|
|
16700
|
+
const box22 = [u - 0.1, v - 0.1, u + 0.1, v + 0.1];
|
|
16701
|
+
const top = Math.max(topOfFloor, ...plates.filter((plate) => touches(plate.aabb, box22, 0.05)).map((plate) => plate.y0));
|
|
16702
|
+
const pillar = builder.add({ id: `column_${floor}_${k}`, role: "column", material: context.construction.frame.pillars, aabb: box22, y0: context.level(floor), y1: top }, { floor });
|
|
16703
|
+
const base = context.baseOf(floor);
|
|
16704
|
+
builder.rest(pillar, base === GROUND || !base ? GROUND : base, "rebar");
|
|
16705
|
+
for (const plate of plates.filter((p) => touches(p.aabb, pillar.aabb, 0.05))) builder.rest(plate, pillar, "rebar");
|
|
16706
|
+
return pillar;
|
|
16707
|
+
});
|
|
16708
|
+
}
|
|
16709
|
+
function addPlatesAndPillars(context, floor) {
|
|
16710
|
+
const walls = context.walls.filter((wall) => wall.floor === floor);
|
|
16711
|
+
const { plates, pillars } = addPlates(context, walls, floor);
|
|
16712
|
+
if (context.construction.system === "masonry") pillars.push(...addCornerPillars(context, walls, floor, plates));
|
|
16713
|
+
context.pillars.set(floor, pillars);
|
|
16714
|
+
context.plates.set(floor, plates);
|
|
16715
|
+
const innerBearing = walls.filter((wall) => wall.role === "wall" && !wall.exterior).map((wall) => context.wallParts.get(wall.id));
|
|
16716
|
+
context.carriers.set(floor, [...plates, ...pillars, ...innerBearing]);
|
|
16717
|
+
}
|
|
16718
|
+
var POST_HALF = 0.08;
|
|
16719
|
+
var FOOTING_HALF = 0.12;
|
|
16720
|
+
var BEAM_DEPTH = 0.2;
|
|
16721
|
+
var BEAM_WIDTH = 0.16;
|
|
16722
|
+
function addPosts(context, porchId, rect, deck, floor) {
|
|
16723
|
+
const { builder, construction } = context;
|
|
16724
|
+
const hasUpperFloor = floor < context.floorCount - 1;
|
|
16725
|
+
const ceilingY = hasUpperFloor ? context.level(floor + 1) - context.system.slabThickness : context.level(floor) + context.ceilingOf(floor);
|
|
16726
|
+
const deckDepth = Math.min(0.2, Math.max(0.06, context.elevation * 0.5));
|
|
16727
|
+
const spots = [[rect[0] + 0.1, rect[1] + 0.1], [rect[2] - 0.1, rect[1] + 0.1]];
|
|
16728
|
+
if (rect[2] - rect[0] > 4.5) spots.push([(rect[0] + rect[2]) / 2, rect[1] + 0.1]);
|
|
16729
|
+
const posts = spots.map(([u, v], k) => {
|
|
16730
|
+
const footing = builder.add({ id: `porch_footing_${porchId}_${k}`, role: "column", material: "concrete", aabb: [u - FOOTING_HALF, v - FOOTING_HALF, u + FOOTING_HALF, v + FOOTING_HALF], y0: 0, y1: context.level(floor) - deckDepth }, { floor: 0 });
|
|
16731
|
+
builder.rest(footing, GROUND, "resting");
|
|
16732
|
+
builder.rest(deck, footing, "resting");
|
|
16733
|
+
const material = context.isTimber ? construction.frame.timber : construction.frame.pillars;
|
|
16734
|
+
const post = builder.add({ id: `porch_post_${porchId}_${k}`, role: "column", material, aabb: [u - POST_HALF, v - POST_HALF, u + POST_HALF, v + POST_HALF], y0: context.level(floor), y1: hasUpperFloor ? ceilingY - BEAM_DEPTH : ceilingY }, { floor });
|
|
16735
|
+
builder.rest(post, deck, context.isTimber ? "nail" : "rebar");
|
|
16736
|
+
return post;
|
|
16737
|
+
});
|
|
16738
|
+
context.porches.set(porchId, { posts, ceilingY });
|
|
16739
|
+
return posts;
|
|
16740
|
+
}
|
|
16741
|
+
function addUpperBeams(context, porchId, rect, posts, floor) {
|
|
16742
|
+
const { builder, construction } = context;
|
|
16743
|
+
const material = context.isTimber ? construction.frame.timber : construction.frame.beams;
|
|
16744
|
+
const joint = context.isTimber ? "nail" : "rebar";
|
|
16745
|
+
const ceilingY = context.porches.get(porchId).ceilingY;
|
|
16746
|
+
const y0 = ceilingY - BEAM_DEPTH;
|
|
16747
|
+
const carriers = context.carriers.get(floor);
|
|
16748
|
+
const head = builder.add({ id: `porch_beam_${porchId}`, role: "beam", material, aabb: [rect[0], rect[1], rect[2], rect[1] + BEAM_WIDTH], y0, y1: ceilingY }, { floor });
|
|
16749
|
+
for (const post of posts) builder.rest(head, post, joint);
|
|
16750
|
+
carriers.push(head);
|
|
16751
|
+
const sides = [["e", [rect[0], rect[1], rect[0] + BEAM_WIDTH, rect[3]], posts[0]], ["d", [rect[2] - BEAM_WIDTH, rect[1], rect[2], rect[3]], posts[1]]];
|
|
16752
|
+
for (const [name, aabb, post] of sides) {
|
|
16753
|
+
const side = builder.add({ id: `porch_beam_${porchId}_${name}`, role: "beam", material, aabb, y0, y1: ceilingY }, { floor });
|
|
16754
|
+
builder.rest(side, post, joint);
|
|
16755
|
+
builder.rest(side, head, joint);
|
|
16756
|
+
for (const wall of context.walls.filter((w) => w.floor === floor && w.role === "wall" && touches(w.box, side.aabb, 0.3))) builder.rest(side, context.wallParts.get(wall.id), joint);
|
|
16757
|
+
carriers.push(side);
|
|
16758
|
+
}
|
|
16759
|
+
}
|
|
16760
|
+
function addPorches(context, floor) {
|
|
16761
|
+
const { builder, construction } = context;
|
|
16762
|
+
for (const room of context.source.rooms.filter((r) => r.type === "porch" && r.floor === floor)) {
|
|
16763
|
+
const rect = room.parts[0];
|
|
16764
|
+
const base = context.baseOf(floor);
|
|
16765
|
+
const deckDepth = Math.min(0.2, Math.max(0.06, context.elevation * 0.5));
|
|
16766
|
+
const deck = builder.add({ id: `porch_floor_${room.id}`, role: "slab", material: context.isTimber ? "wood_soft" : construction.frame.slabs, aabb: rect, y0: context.level(floor) - deckDepth, y1: context.level(floor) }, { floor });
|
|
16767
|
+
if (base && base !== GROUND) builder.rest(deck, base, context.isTimber ? "nail" : context.system.joints.slab);
|
|
16768
|
+
const posts = addPosts(context, room.id, rect, deck, floor);
|
|
16769
|
+
if (floor < context.floorCount - 1) addUpperBeams(context, room.id, rect, posts, floor);
|
|
16770
|
+
}
|
|
16771
|
+
}
|
|
16772
|
+
var ROOF_RISE = 0.6;
|
|
16773
|
+
function addPorchRoofs(context) {
|
|
16774
|
+
const { builder, construction } = context;
|
|
16775
|
+
for (const room of context.source.rooms.filter((r) => r.type === "porch")) {
|
|
16776
|
+
const floor = room.floor;
|
|
16777
|
+
const rect = room.parts[0];
|
|
16778
|
+
const posts = context.porches.get(room.id);
|
|
16779
|
+
if (floor !== context.floorCount - 1 || !posts) continue;
|
|
16780
|
+
const material = ROOF_COVERINGS.get(construction.roof.covering)?.material ?? "ceramic";
|
|
16781
|
+
const roof = builder.add({ id: `porch_roof_${room.id}`, role: "roof", material, aabb: [rect[0] - 0.3, rect[1] - 0.5, rect[2] + 0.3, rect[3]], y0: posts.ceilingY, y1: posts.ceilingY + ROOF_RISE }, { floor });
|
|
16782
|
+
for (const post of posts.posts) builder.rest(roof, post, context.isTimber ? "nail" : "bolt");
|
|
16783
|
+
const housewalls = context.walls.filter((w) => w.floor === floor && !w.exterior && w.sides.includes(room.id) && w.type === "wall");
|
|
16784
|
+
for (const wall of housewalls) {
|
|
16785
|
+
if (context.porchRoofOnPostsOnly) builder.supports.push({ part: roof.id, on: wall.id, joint: "nail", bears: false });
|
|
16786
|
+
else builder.rest(roof, context.wallParts.get(wall.id), "nail");
|
|
16787
|
+
}
|
|
16788
|
+
}
|
|
16789
|
+
}
|
|
16790
|
+
var TRUSS_PITCH = 1.2;
|
|
16791
|
+
var DEFAULT_PITCH = 20;
|
|
16792
|
+
var DEFAULT_EAVE = 0.4;
|
|
16243
16793
|
var CLOSED_ONLY = [...OPEN_ROOM_TYPES2, "void"];
|
|
16794
|
+
function roofUnits(context, bearing) {
|
|
16795
|
+
const units = [{ suffix: "", box: context.topBox, floor: bearing, annex: false }];
|
|
16796
|
+
if (context.floorCount <= 1 || context.isUnit || bearing !== context.floorCount - 1) return units;
|
|
16797
|
+
for (let floor = 0; floor < context.floorCount - 1; floor++) {
|
|
16798
|
+
const above = context.source.rooms.filter((room) => room.floor === floor + 1).flatMap((room) => room.parts);
|
|
16799
|
+
const rooms = context.source.rooms.filter((room) => room.floor === floor && !OPEN_ROOM_TYPES2.includes(room.type) && room.type !== "void" && room.type !== "elevator");
|
|
16800
|
+
for (const room of rooms) {
|
|
16801
|
+
const area3 = room.parts.reduce((total, part) => total + (part[2] - part[0]) * (part[3] - part[1]), 0);
|
|
16802
|
+
const covered = room.parts.reduce((total, part) => total + above.reduce((sum, other) => sum + Math.max(0, Math.min(part[2], other[2]) - Math.max(part[0], other[0])) * Math.max(0, Math.min(part[3], other[3]) - Math.max(part[1], other[1])), 0), 0);
|
|
16803
|
+
if (covered < area3 * 0.7) units.push({ suffix: `_${room.id}`, box: unionOf(room.parts), floor, annex: true });
|
|
16804
|
+
}
|
|
16805
|
+
}
|
|
16806
|
+
return units;
|
|
16807
|
+
}
|
|
16808
|
+
function roofCarriers(context, unit) {
|
|
16809
|
+
const platesHere = context.plates.get(unit.floor) ?? [];
|
|
16810
|
+
const allPlates = [...context.plates.values()].flat();
|
|
16811
|
+
const eaveHeight = platesHere.length ? Math.max(...platesHere.map((plate) => plate.y1)) : 0;
|
|
16812
|
+
const plates = allPlates.filter((plate) => Math.abs(plate.y1 - eaveHeight) < 0.4 && touches(plate.aabb, unit.box, 0.3));
|
|
16813
|
+
const pillars = (context.pillars.get(unit.floor) ?? []).filter((pillar) => touches(pillar.aabb, unit.box, 0.3));
|
|
16814
|
+
const walls = context.walls.filter((wall) => wall.floor === unit.floor && wall.role === "wall" && !wall.exterior && touches(wall.box, unit.box, 0.2)).map((wall) => context.wallParts.get(wall.id));
|
|
16815
|
+
return [...plates, ...pillars, ...walls];
|
|
16816
|
+
}
|
|
16817
|
+
function addFlatRoof(context, unit, carriers) {
|
|
16818
|
+
const { builder, construction, system } = context;
|
|
16819
|
+
const top = context.level(unit.floor) + context.ceilingOf(unit.floor);
|
|
16820
|
+
const [u0, v0, u1, v1] = unit.box;
|
|
16821
|
+
const slab = builder.add({ id: `slab_top${unit.suffix}`, role: "slab", material: construction.frame.slabs, aabb: [u0 - 0.15, v0 - 0.15, u1 + 0.15, v1 + 0.15], y0: top, y1: top + 0.12 }, { floor: unit.floor, cover: true, footprint: [unit.box] });
|
|
16822
|
+
for (const carrier of carriers.length ? carriers : context.plates.get(unit.floor) ?? []) builder.rest(slab, carrier, system.joints.slab);
|
|
16823
|
+
if (unit.suffix === "") context.topSlab = slab;
|
|
16824
|
+
return { id: slab.id, aabb: slab.aabb, y0: slab.y0, y1: slab.y1, flat: true };
|
|
16825
|
+
}
|
|
16826
|
+
function addTrusses(context, unit, carriers, geometry) {
|
|
16827
|
+
const { builder, construction, system } = context;
|
|
16828
|
+
const { box: box22 } = unit;
|
|
16829
|
+
const { axis, length, eave, rise, eaveY } = geometry;
|
|
16830
|
+
const count = Math.max(2, Math.ceil(length / TRUSS_PITCH) + 1);
|
|
16831
|
+
const trusses = [];
|
|
16832
|
+
for (let k = 0; k < count; k++) {
|
|
16833
|
+
const at2 = (axis === "u" ? box22[0] : box22[1]) + k * length / (count - 1);
|
|
16834
|
+
const aabb = axis === "u" ? [at2 - 0.04, box22[1] - eave * 0.5, at2 + 0.04, box22[3] + eave * 0.5] : [box22[0] - eave * 0.5, at2 - 0.04, box22[2] + eave * 0.5, at2 + 0.04];
|
|
16835
|
+
const truss = builder.add({ id: `truss${unit.suffix}_${k}`, role: "beam", material: construction.frame.timber, aabb, y0: eaveY, y1: eaveY + rise }, { floor: unit.floor, fill: 0.25 });
|
|
16836
|
+
const touching = carriers.filter((carrier) => touches(aabb, carrier.aabb, 0.2) && carrier.role !== "slab");
|
|
16837
|
+
const chosen = touching.length ? touching : carriers.slice().sort((a, b) => distanceBetween(aabb, a.aabb) - distanceBetween(aabb, b.aabb)).slice(0, 2);
|
|
16838
|
+
for (const carrier of chosen) builder.rest(truss, carrier, system.joints.truss);
|
|
16839
|
+
trusses.push(truss);
|
|
16840
|
+
}
|
|
16841
|
+
return trusses;
|
|
16842
|
+
}
|
|
16843
|
+
function geometryOf(context, unit) {
|
|
16844
|
+
const { box: box22 } = unit;
|
|
16845
|
+
const roof = context.construction.roof;
|
|
16846
|
+
const platesHere = context.plates.get(unit.floor) ?? [];
|
|
16847
|
+
const width = box22[2] - box22[0];
|
|
16848
|
+
const depth = box22[3] - box22[1];
|
|
16849
|
+
const axis = roof.axis ?? (width >= depth ? "u" : "v");
|
|
16850
|
+
const span = axis === "u" ? depth : width;
|
|
16851
|
+
const pitch = unit.annex ? Math.min(roof.pitch || DEFAULT_PITCH, 20) : roof.pitch || DEFAULT_PITCH;
|
|
16852
|
+
const eaveY = platesHere.length ? Math.max(...platesHere.map((plate) => plate.y1)) : context.level(unit.floor) + context.ceilingOf(unit.floor);
|
|
16853
|
+
return { axis, length: axis === "u" ? width : depth, eave: roof.eave ?? DEFAULT_EAVE, rise: round2(span / 2 * Math.tan(pitch * Math.PI / 180)), eaveY };
|
|
16854
|
+
}
|
|
16855
|
+
function addRafters(context, unit, carriers, geometry) {
|
|
16856
|
+
const { builder, construction, system } = context;
|
|
16857
|
+
const { box: box22 } = unit;
|
|
16858
|
+
const { axis, length, eave, rise, eaveY } = geometry;
|
|
16859
|
+
const count = Math.max(2, Math.ceil(length / TRUSS_PITCH) + 1);
|
|
16860
|
+
const middle = axis === "u" ? (box22[1] + box22[3]) / 2 : (box22[0] + box22[2]) / 2;
|
|
16861
|
+
const frames = { all: [], sideA: [], sideB: [] };
|
|
16862
|
+
for (let k = 0; k < count; k++) {
|
|
16863
|
+
const at2 = (axis === "u" ? box22[0] : box22[1]) + k * length / (count - 1);
|
|
16864
|
+
const halves = axis === "u" ? [["a", [at2 - 0.04, box22[1] - eave * 0.5, at2 + 0.04, middle]], ["b", [at2 - 0.04, middle, at2 + 0.04, box22[3] + eave * 0.5]]] : [["a", [box22[0] - eave * 0.5, at2 - 0.04, middle, at2 + 0.04]], ["b", [middle, at2 - 0.04, box22[2] + eave * 0.5, at2 + 0.04]]];
|
|
16865
|
+
for (const [side, aabb] of halves) {
|
|
16866
|
+
const rafter = builder.add({ id: `rafter${unit.suffix}_${side}_${k}`, role: "beam", material: construction.frame.timber, aabb, y0: eaveY, y1: eaveY + rise }, { floor: unit.floor, fill: 0.25 });
|
|
16867
|
+
const touching = carriers.filter((carrier) => touches(aabb, carrier.aabb, 0.2) && carrier.role !== "slab");
|
|
16868
|
+
const chosen = touching.length ? touching : carriers.slice().sort((x, y) => distanceBetween(aabb, x.aabb) - distanceBetween(aabb, y.aabb)).slice(0, 2);
|
|
16869
|
+
for (const carrier of chosen) builder.rest(rafter, carrier, system.joints.truss);
|
|
16870
|
+
frames.all.push(rafter);
|
|
16871
|
+
if (side === "a") frames.sideA.push(rafter);
|
|
16872
|
+
else frames.sideB.push(rafter);
|
|
16873
|
+
}
|
|
16874
|
+
}
|
|
16875
|
+
if (!unit.annex) {
|
|
16876
|
+
const ridgeBox = axis === "u" ? [box22[0] - eave, middle - 0.05, box22[2] + eave, middle + 0.05] : [middle - 0.05, box22[1] - eave, middle + 0.05, box22[3] + eave];
|
|
16877
|
+
const ridge = builder.add({ id: `ridge${unit.suffix}`, role: "beam", material: construction.frame.timber, aabb: ridgeBox, y0: eaveY + rise - 0.12, y1: eaveY + rise }, { floor: unit.floor });
|
|
16878
|
+
for (const rafter of frames.all) builder.rest(ridge, rafter, system.joints.truss);
|
|
16879
|
+
}
|
|
16880
|
+
context.roof.trusses += count;
|
|
16881
|
+
return frames;
|
|
16882
|
+
}
|
|
16883
|
+
function panesOf(unit, geometry) {
|
|
16884
|
+
const [u0, v0, u1, v1] = unit.box;
|
|
16885
|
+
const { eave, axis } = geometry;
|
|
16886
|
+
if (unit.annex) return [[u0 - eave, v0 - eave, u1 + eave, v1 + eave]];
|
|
16887
|
+
const midV = (v0 + v1) / 2;
|
|
16888
|
+
const midU = (u0 + u1) / 2;
|
|
16889
|
+
return axis === "u" ? [[u0 - eave, v0 - eave, u1 + eave, midV], [u0 - eave, midV, u1 + eave, v1 + eave]] : [[u0 - eave, v0 - eave, midU, v1 + eave], [midU, v0 - eave, u1 + eave, v1 + eave]];
|
|
16890
|
+
}
|
|
16891
|
+
function coarseFrames(context, unit, carriers, geometry) {
|
|
16892
|
+
const trusses = addTrusses(context, unit, carriers, geometry);
|
|
16893
|
+
context.roof.trusses += trusses.length;
|
|
16894
|
+
return { all: trusses, sideA: trusses, sideB: trusses };
|
|
16895
|
+
}
|
|
16896
|
+
function addGableRoof(context, unit, carriers, covering) {
|
|
16897
|
+
const { builder, construction } = context;
|
|
16898
|
+
const geometry = geometryOf(context, unit);
|
|
16899
|
+
const frames = context.rafterRoof ? addRafters(context, unit, carriers, geometry) : coarseFrames(context, unit, carriers, geometry);
|
|
16900
|
+
const panes = [];
|
|
16901
|
+
panesOf(unit, geometry).forEach((aabb, k) => {
|
|
16902
|
+
const name = unit.annex ? "annex" : k === 0 ? "a" : "b";
|
|
16903
|
+
const options = { floor: unit.floor, fill: construction.roof.covering === "colonial" ? 0.12 : 0.05, ...construction.roof.pitch === void 0 ? {} : { pitch: construction.roof.pitch } };
|
|
16904
|
+
const pane = builder.add({ id: `roof${unit.suffix}_${name}`, role: "roof", material: construction.roof.material, aabb, y0: geometry.eaveY, y1: geometry.eaveY + geometry.rise + 0.05 }, options);
|
|
16905
|
+
const carried = unit.annex || !context.rafterRoof ? frames.all : k === 0 ? frames.sideA : frames.sideB;
|
|
16906
|
+
for (const frame2 of carried) builder.rest(pane, frame2, covering);
|
|
16907
|
+
panes.push({ id: pane.id, aabb: pane.aabb, y0: pane.y0, y1: pane.y1 });
|
|
16908
|
+
});
|
|
16909
|
+
if (!unit.annex) {
|
|
16910
|
+
const roof = context.roof;
|
|
16911
|
+
roof.axis = geometry.axis;
|
|
16912
|
+
roof.ridge = round2(geometry.eaveY + geometry.rise);
|
|
16913
|
+
roof.eave = geometry.eave;
|
|
16914
|
+
roof.y0 = round2(geometry.eaveY);
|
|
16915
|
+
roof.aabb = [unit.box[0] - geometry.eave, unit.box[1] - geometry.eave, unit.box[2] + geometry.eave, unit.box[3] + geometry.eave].map(round2);
|
|
16916
|
+
}
|
|
16917
|
+
return panes;
|
|
16918
|
+
}
|
|
16919
|
+
function addCeilingJoists(context) {
|
|
16920
|
+
const { builder, construction } = context;
|
|
16921
|
+
const bearing = context.roof.bearingFloor;
|
|
16922
|
+
const rects = context.rectsOf(bearing, CLOSED_ONLY);
|
|
16923
|
+
const box22 = unionOf(rects.length ? rects : [context.topBox]);
|
|
16924
|
+
const carriers = [...context.plates.get(bearing) ?? [], ...context.walls.filter((w) => w.floor === bearing && w.role === "wall" && !w.exterior).map((w) => context.wallParts.get(w.id))];
|
|
16925
|
+
const length = box22[2] - box22[0];
|
|
16926
|
+
const depth = box22[3] - box22[1];
|
|
16927
|
+
const alongU = length >= depth;
|
|
16928
|
+
const span = alongU ? length : depth;
|
|
16929
|
+
const count = Math.max(2, Math.round(span / 0.6) + 1);
|
|
16930
|
+
const beamTops = carriers.filter((carrier) => carrier.role === "beam").map((carrier) => carrier.y0);
|
|
16931
|
+
const y0 = carriers.length ? Math.max(...beamTops, context.level(bearing) + 1) : context.topOf(bearing);
|
|
16932
|
+
const joists = [];
|
|
16933
|
+
for (let k = 0; k < count; k++) {
|
|
16934
|
+
const at2 = (alongU ? box22[0] : box22[1]) + 0.05 + k * (span - 0.1) / (count - 1);
|
|
16935
|
+
const aabb = alongU ? [at2 - 0.025, box22[1], at2 + 0.025, box22[3]] : [box22[0], at2 - 0.025, box22[2], at2 + 0.025];
|
|
16936
|
+
const joist = builder.add({ id: `ceiling_joist_${k}`, role: "beam", material: construction.frame.timber, aabb, y0: y0 - 0.02, y1: y0 + context.system.plateThickness - 0.02 }, { floor: bearing, spacing: 0.6 });
|
|
16937
|
+
const beams = carriers.filter((carrier) => carrier.role === "beam" && touches(aabb, carrier.aabb, 0.2));
|
|
16938
|
+
for (const carrier of beams.length ? beams : carriers.slice(0, 2)) builder.rest(joist, carrier, "nail");
|
|
16939
|
+
joists.push(joist);
|
|
16940
|
+
}
|
|
16941
|
+
context.ceilingJoists = joists;
|
|
16942
|
+
}
|
|
16943
|
+
function addRoof(context) {
|
|
16944
|
+
const { construction } = context;
|
|
16945
|
+
const covering = ROOF_COVERINGS.get(construction.roof.covering);
|
|
16946
|
+
const bearing = construction.roof.bearingFloor ?? context.floorCount - 1;
|
|
16947
|
+
const open = context.rectsOf(context.floorCount - 1, OPEN_ROOM_TYPES2);
|
|
16948
|
+
const topRects = context.rectsOf(context.floorCount - 1, CLOSED_ONLY);
|
|
16949
|
+
const body = unionOf(open.length ? open : topRects);
|
|
16950
|
+
context.topBox = context.floorCount - 1 === bearing ? body : unionOf(context.rectsOf(bearing, OPEN_ROOM_TYPES2));
|
|
16951
|
+
context.roof = { shape: construction.roof.shape, covering: construction.roof.covering, material: construction.roof.material, pitch: construction.roof.pitch || 0, bearingFloor: bearing, panes: [], trusses: 0 };
|
|
16952
|
+
for (const unit of roofUnits(context, bearing)) {
|
|
16953
|
+
const carriers = roofCarriers(context, unit);
|
|
16954
|
+
if (construction.roof.shape === "slab") context.roof.panes.push(addFlatRoof(context, unit, carriers));
|
|
16955
|
+
else context.roof.panes.push(...addGableRoof(context, unit, carriers, covering?.joint ?? "nail"));
|
|
16956
|
+
}
|
|
16957
|
+
if (context.isTimber && construction.roof.shape !== "slab") addCeilingJoists(context);
|
|
16958
|
+
}
|
|
16959
|
+
function flightsOf(items) {
|
|
16960
|
+
const flights = /* @__PURE__ */ new Map();
|
|
16961
|
+
for (const item of items.filter((it) => it.category === "stairs" && it.link)) {
|
|
16962
|
+
const key = `${item.link.from}_${item.link.to}`;
|
|
16963
|
+
if (!flights.has(key) || item.floor === item.link.from) flights.set(key, item);
|
|
16964
|
+
}
|
|
16965
|
+
return flights;
|
|
16966
|
+
}
|
|
16967
|
+
function addStairs(context) {
|
|
16968
|
+
const { builder, construction } = context;
|
|
16969
|
+
const material = context.isTimber ? construction.frame.timber : construction.stairs ?? "concrete";
|
|
16970
|
+
for (const [key, item2] of flightsOf(context.source.items)) {
|
|
16971
|
+
const { from, to } = item2.link;
|
|
16972
|
+
const flight2 = builder.add({ id: `stairs_${key}`, role: "stair", material, aabb: item2.aabb, y0: context.level(from), y1: context.level(to) }, { floor: from, steps: Math.round((context.level(to) - context.level(from)) / 0.18) });
|
|
16973
|
+
const base = context.baseOf(from);
|
|
16974
|
+
builder.rest(flight2, !base || base === GROUND ? GROUND : base, !base || base === GROUND ? "resting" : context.isTimber ? "nail" : "mortar");
|
|
16975
|
+
const upper = context.baseOf(to);
|
|
16976
|
+
if (upper && upper !== GROUND) builder.rest(flight2, upper, context.isTimber ? "nail" : "bolt");
|
|
16977
|
+
}
|
|
16978
|
+
if (!context.hasBasement) return;
|
|
16979
|
+
const item = context.source.items.find((it) => it.type === "basement_stairs");
|
|
16980
|
+
if (!item?.aabb) return;
|
|
16981
|
+
const depth = construction.foundation.depth || 2.4;
|
|
16982
|
+
const flight = builder.add({ id: "basement_stairs", role: "stair", material: "wood_soft", aabb: item.aabb, y0: -depth, y1: context.level(0) }, { floor: -1, steps: Math.round((context.level(0) + depth) / 0.18) });
|
|
16983
|
+
builder.rest(flight, builder.find("basement_slab"), "resting");
|
|
16984
|
+
if (context.base0 && context.base0 !== GROUND) builder.rest(flight, context.base0, "nail");
|
|
16985
|
+
}
|
|
16986
|
+
var TOLERANCE = 0.02;
|
|
16987
|
+
var DOOR_HEIGHT = 2.1;
|
|
16988
|
+
var LINTEL_DEPTH = 0.2;
|
|
16989
|
+
var LINTEL_BEARING = 0.2;
|
|
16990
|
+
var crossOf = (wall) => wall.axis === "u" ? wall.v0 : wall.u0;
|
|
16991
|
+
var alongRange = (wall) => wall.axis === "u" ? [Math.min(wall.u0, wall.u1), Math.max(wall.u0, wall.u1)] : [Math.min(wall.v0, wall.v1), Math.max(wall.v0, wall.v1)];
|
|
16992
|
+
function findOpenings(context) {
|
|
16993
|
+
const openings = [];
|
|
16994
|
+
for (const window of context.source.windows ?? []) {
|
|
16995
|
+
const from = window.at - window.width / 2;
|
|
16996
|
+
const to = window.at + window.width / 2;
|
|
16997
|
+
const wall = context.walls.find((w) => {
|
|
16998
|
+
if (w.floor !== window.floor || w.axis !== window.axis || w.type !== "wall" || Math.abs(crossOf(w) - window.pos) > TOLERANCE) return false;
|
|
16999
|
+
const [low, high] = alongRange(w);
|
|
17000
|
+
return from >= low - TOLERANCE && to <= high + TOLERANCE;
|
|
17001
|
+
});
|
|
17002
|
+
if (!wall) continue;
|
|
17003
|
+
const base = context.level(window.floor);
|
|
17004
|
+
openings.push({ id: window.id, kind: "window", wall: wall.id, from, to, y0: base + window.y0, y1: base + window.y1 });
|
|
17005
|
+
}
|
|
17006
|
+
return openings;
|
|
17007
|
+
}
|
|
17008
|
+
function addDoorLintels(context) {
|
|
17009
|
+
const { builder, construction, system } = context;
|
|
17010
|
+
for (const door of context.source.doors.filter((d) => d.a !== void 0 && d.type !== "zipper")) {
|
|
17011
|
+
const along = door.axis === "u" ? door.u : door.v;
|
|
17012
|
+
const cross = door.axis === "u" ? door.v : door.u;
|
|
17013
|
+
const from = along - door.width / 2;
|
|
17014
|
+
const to = along + door.width / 2;
|
|
17015
|
+
const beside = context.walls.filter((w) => w.floor === door.floor && w.axis === door.axis && w.type === "wall" && Math.abs(crossOf(w) - cross) <= TOLERANCE && (Math.abs(alongRange(w)[1] - from) <= 0.05 || Math.abs(alongRange(w)[0] - to) <= 0.05));
|
|
17016
|
+
if (!beside.length) continue;
|
|
17017
|
+
const half = (beside[0].thickness ?? 0.15) / 2;
|
|
17018
|
+
const lo = from - LINTEL_BEARING;
|
|
17019
|
+
const hi = to + LINTEL_BEARING;
|
|
17020
|
+
const box22 = door.axis === "u" ? [lo, cross - half, hi, cross + half] : [cross - half, lo, cross + half, hi];
|
|
17021
|
+
const y0 = context.level(door.floor) + DOOR_HEIGHT;
|
|
17022
|
+
const lintel = builder.add({ id: `lintel_${door.id}`, role: "beam", material: system.timber ? construction.frame.timber : "concrete", aabb: box22, y0, y1: y0 + LINTEL_DEPTH }, { floor: door.floor, ...system.timber ? {} : { assembly: "reinforced_concrete" } });
|
|
17023
|
+
for (const wall of beside) builder.rest(lintel, context.wallParts.get(wall.id), system.joints.beam);
|
|
17024
|
+
for (const plate of context.plates.get(door.floor) ?? []) if (overlapsInPlan(plate.aabb, box22)) builder.rest(plate, lintel, system.joints.beam);
|
|
17025
|
+
}
|
|
17026
|
+
}
|
|
17027
|
+
var overlapsInPlan = (a, b) => a[0] < b[2] && a[2] > b[0] && a[1] < b[3] && a[3] > b[1];
|
|
17028
|
+
var RISER = 0.18;
|
|
17029
|
+
var TREAD = 0.28;
|
|
17030
|
+
var stepCount = (elevation) => Math.max(1, Math.ceil(elevation / RISER));
|
|
17031
|
+
function addPorchSteps(context) {
|
|
17032
|
+
const { builder } = context;
|
|
17033
|
+
for (const room of context.source.rooms.filter((r) => r.type === "porch")) {
|
|
17034
|
+
const deck = builder.find(`porch_floor_${room.id}`);
|
|
17035
|
+
for (const door of context.source.doors.filter((d) => d.floor === room.floor && d.b === "outside" && d.a === room.id)) {
|
|
17036
|
+
const count = stepCount(context.elevation);
|
|
17037
|
+
const depth = count * TREAD;
|
|
17038
|
+
const aabb = [door.u - door.width / 2, door.v - depth, door.u + door.width / 2, door.v];
|
|
17039
|
+
const flight = builder.add({ id: `steps_${door.id}`, role: "stair", material: context.isTimber ? "wood_soft" : "concrete", aabb, y0: 0, y1: context.level(room.floor) }, { floor: 0, steps: count, door: door.id });
|
|
17040
|
+
builder.rest(flight, GROUND, "resting");
|
|
17041
|
+
if (deck) builder.rest(flight, deck, context.isTimber ? "nail" : "mortar");
|
|
17042
|
+
}
|
|
17043
|
+
}
|
|
17044
|
+
}
|
|
17045
|
+
function boxOfSteps(door, depth) {
|
|
17046
|
+
const direction = door.axis === "u" ? door.side === "front" ? -1 : 1 : door.side === "left" ? -1 : 1;
|
|
17047
|
+
if (door.axis === "u") return [door.u - door.width / 2, Math.min(door.v, door.v + direction * depth), door.u + door.width / 2, Math.max(door.v, door.v + direction * depth)];
|
|
17048
|
+
return [Math.min(door.u, door.u + direction * depth), door.v - door.width / 2, Math.max(door.u, door.u + direction * depth), door.v + door.width / 2];
|
|
17049
|
+
}
|
|
17050
|
+
function addDoorSteps(context) {
|
|
17051
|
+
if (context.elevation <= 0.1) return;
|
|
17052
|
+
const { builder } = context;
|
|
17053
|
+
const doors = context.source.doors.filter((d) => d.floor === 0 && d.exterior && d.model !== "steel" && d.type !== "steps" && d.type !== "zipper");
|
|
17054
|
+
for (const door of doors) {
|
|
17055
|
+
const count = stepCount(context.elevation);
|
|
17056
|
+
const depth = Math.min(TREAD * count, 0.9);
|
|
17057
|
+
const flight = builder.add({ id: `steps_${door.id}`, role: "stair", material: context.isTimber ? "wood_soft" : "concrete", aabb: boxOfSteps(door, depth), y0: 0, y1: context.level(0) }, { floor: 0, steps: count, door: door.id });
|
|
17058
|
+
builder.rest(flight, GROUND, "resting");
|
|
17059
|
+
const base = context.base0;
|
|
17060
|
+
if (base && base !== GROUND) builder.rest(flight, base, context.isTimber ? "nail" : "mortar");
|
|
17061
|
+
}
|
|
17062
|
+
}
|
|
17063
|
+
function addExteriorSteps(context) {
|
|
17064
|
+
addPorchSteps(context);
|
|
17065
|
+
addDoorSteps(context);
|
|
17066
|
+
}
|
|
17067
|
+
var TANK_FILL = 0.08;
|
|
17068
|
+
var squareAround = (u, v, side) => [u - side / 2, v - side / 2, u + side / 2, v + side / 2];
|
|
17069
|
+
function addTank(context, tank, floor, y0) {
|
|
17070
|
+
return context.builder.add({ id: "water_tank", role: "none", material: tank.material ?? "plastic", aabb: tank.aabb, y0, y1: y0 + tank.h }, { floor, fill: TANK_FILL, liters: tank.capacity });
|
|
17071
|
+
}
|
|
17072
|
+
function ensureCeilingSlab(context, y) {
|
|
17073
|
+
const { builder, construction, system } = context;
|
|
17074
|
+
const existing = builder.find("slab_ceiling");
|
|
17075
|
+
if (existing) return existing;
|
|
17076
|
+
const top = context.floorCount - 1;
|
|
17077
|
+
const box22 = context.topBox;
|
|
17078
|
+
const carriers = builder.parts.filter(
|
|
17079
|
+
(part) => (part.role === "beam" && part.id.startsWith(`plate_${top}_`) || part.role === "column" && part.floor === top || part.role === "wall" && part.floor === top && !part.id.startsWith("basement")) && touches(box22, part.aabb, 0.1)
|
|
17080
|
+
);
|
|
17081
|
+
const slab = builder.add({ id: "slab_ceiling", role: "slab", material: construction.frame.slabs, aabb: box22, y0: y - 0.12, y1: y }, { floor: top, footprint: [box22] });
|
|
17082
|
+
for (const carrier of carriers) builder.rest(slab, carrier, system.joints.slab);
|
|
17083
|
+
return slab;
|
|
17084
|
+
}
|
|
17085
|
+
function addRaisedPlatform(context, tank) {
|
|
17086
|
+
const { builder, construction } = context;
|
|
17087
|
+
const platform = tank.platform;
|
|
17088
|
+
const top = context.floorCount - 1;
|
|
17089
|
+
const ceiling = ensureCeilingSlab(context, platform.baseY);
|
|
17090
|
+
const pillars = platform.pillars.map((q, k) => {
|
|
17091
|
+
const pillar = builder.add({ id: `tank_column_${k}`, role: "column", material: construction.frame.pillars, aabb: squareAround(q.u, q.v, q.side), y0: platform.baseY, y1: platform.topY - platform.thickness }, { floor: top });
|
|
17092
|
+
builder.rest(pillar, ceiling, "rebar");
|
|
17093
|
+
return pillar;
|
|
17094
|
+
});
|
|
17095
|
+
const slab = builder.add({ id: "tank_slab", role: "slab", material: construction.frame.slabs, aabb: platform.aabb, y0: platform.topY - platform.thickness, y1: platform.topY }, { floor: top });
|
|
17096
|
+
for (const pillar of pillars) builder.rest(slab, pillar, "rebar");
|
|
17097
|
+
builder.rest(addTank(context, tank, top, tank.y), slab, "resting");
|
|
17098
|
+
}
|
|
17099
|
+
function addAtticTank(context, tank) {
|
|
17100
|
+
const { builder } = context;
|
|
17101
|
+
const top = context.floorCount - 1;
|
|
17102
|
+
if (!context.isTimber) {
|
|
17103
|
+
const ceiling = ensureCeilingSlab(context, tank.y);
|
|
17104
|
+
builder.rest(addTank(context, tank, top, tank.y), ceiling, "resting");
|
|
17105
|
+
return;
|
|
17106
|
+
}
|
|
17107
|
+
const supports = context.topSlab ? [context.topSlab] : context.ceilingJoists ?? builder.parts.filter((part) => part.role === "beam" && part.id.startsWith(`plate_${top}_`));
|
|
17108
|
+
const y0 = supports[0] ? supports[0].y1 : tank.y - 0.03;
|
|
17109
|
+
const floor = builder.add({ id: "attic_floor", role: "slab", material: "plywood", aabb: context.topBox, y0, y1: y0 + 0.03 }, { floor: top });
|
|
17110
|
+
for (const support of supports) if (touches(floor.aabb, support.aabb, 0.1)) builder.rest(floor, support, "nail");
|
|
17111
|
+
builder.rest(addTank(context, tank, top, tank.y), floor, "resting");
|
|
17112
|
+
}
|
|
17113
|
+
function addSlabTank(context, tank) {
|
|
17114
|
+
const { builder } = context;
|
|
17115
|
+
const supports = builder.parts.filter((part2) => part2.role === "slab" && Math.abs(part2.y1 - tank.y) < 0.3 && touches(part2.aabb, tank.aabb, 0.1));
|
|
17116
|
+
const carrier = supports.sort((a, b) => Math.abs(a.y1 - tank.y) - Math.abs(b.y1 - tank.y))[0] ?? context.topSlab;
|
|
17117
|
+
const part = addTank(context, tank, tank.floor, tank.y);
|
|
17118
|
+
builder.rest(part, carrier ?? GROUND, "resting");
|
|
17119
|
+
}
|
|
17120
|
+
function addTrestleTank(context, tank) {
|
|
17121
|
+
const { builder } = context;
|
|
17122
|
+
const stand = tank.stand;
|
|
17123
|
+
const columns = stand.pillars.map((q, k) => {
|
|
17124
|
+
const column = builder.add({ id: `trestle_column_${k}`, role: "column", material: stand.material, aabb: squareAround(q.u, q.v, q.side), y0: 0, y1: stand.height }, { floor: 0 });
|
|
17125
|
+
builder.rest(column, GROUND, stand.baseJoint ?? "resting");
|
|
17126
|
+
return column;
|
|
17127
|
+
});
|
|
17128
|
+
const [u0, v0, u1, v1] = tank.aabb;
|
|
17129
|
+
const beams = [[u0 - 0.1, v0 - 0.1, u1 + 0.1, v0 + 0.05], [u0 - 0.1, v1 - 0.05, u1 + 0.1, v1 + 0.1]].map((aabb, k) => {
|
|
17130
|
+
const beam = builder.add({ id: `trestle_beam_${k}`, role: "beam", material: stand.material, aabb, y0: stand.height - 0.12, y1: stand.height }, { floor: 0 });
|
|
17131
|
+
for (const column of columns.filter((c) => touches(beam.aabb, c.aabb, 0.15))) builder.rest(beam, column, stand.joint ?? "nail");
|
|
17132
|
+
return beam;
|
|
17133
|
+
});
|
|
17134
|
+
const part = addTank(context, tank, 0, stand.height);
|
|
17135
|
+
for (const beam of beams) builder.rest(part, beam, stand.tie ?? "resting");
|
|
17136
|
+
}
|
|
17137
|
+
function addWaterTank(context) {
|
|
17138
|
+
const tank = context.tank;
|
|
17139
|
+
if (!tank) return;
|
|
17140
|
+
switch (tank.place) {
|
|
17141
|
+
case "slab":
|
|
17142
|
+
return addSlabTank(context, tank);
|
|
17143
|
+
case "raised_slab":
|
|
17144
|
+
return addRaisedPlatform(context, tank);
|
|
17145
|
+
case "attic":
|
|
17146
|
+
return addAtticTank(context, tank);
|
|
17147
|
+
case "trestle":
|
|
17148
|
+
return addTrestleTank(context, tank);
|
|
17149
|
+
}
|
|
17150
|
+
}
|
|
17151
|
+
function addUpperFloor(context, floor) {
|
|
17152
|
+
if (floor >= context.floorCount - 1 || context.isUnit) return;
|
|
17153
|
+
const next = floor + 1;
|
|
17154
|
+
const rects = context.rectsOf(next, ["balcony", "porch", "void"]);
|
|
17155
|
+
const box22 = rects.length ? unionOf(rects) : context.houseBox;
|
|
17156
|
+
const carriers = context.carriers.get(floor);
|
|
17157
|
+
const { system, construction, builder } = context;
|
|
17158
|
+
const thickness = system.slabThickness;
|
|
17159
|
+
if (context.isTimber) {
|
|
17160
|
+
const joists = addJoists(context, { floor: next, box: box22, thickness, carriers, material: construction.frame.timber, joint: system.joints.beam });
|
|
17161
|
+
addDeck(context, `slab_${next}`, construction.frame.slabs, { floor: next, box: box22, thickness, joint: system.joints.slab }, joists);
|
|
17162
|
+
return;
|
|
17163
|
+
}
|
|
17164
|
+
const slab = builder.add({ id: `slab_${next}`, role: "slab", material: construction.frame.slabs, aabb: box22, y0: context.level(next) - thickness, y1: context.level(next) }, { floor: next, footprint: rects.length ? rects : [context.houseBox] });
|
|
17165
|
+
const below = carriers.filter((carrier) => carrier.y0 <= slab.y0 + 0.05);
|
|
17166
|
+
const touching = below.filter((carrier) => touches(slab.aabb, carrier.aabb, 0.2));
|
|
17167
|
+
for (const carrier of touching.length ? touching : below) builder.rest(slab, carrier, system.joints.slab);
|
|
17168
|
+
}
|
|
17169
|
+
function wallCeiling(context, wall) {
|
|
17170
|
+
const rooms = wall.sides.map((id) => context.source.rooms.find((room) => room.id === id && room.floor === wall.floor)).filter((room) => room !== void 0);
|
|
17171
|
+
return Math.max(context.ceilingOf(wall.floor), ...rooms.map((room) => room.ceiling || 0));
|
|
17172
|
+
}
|
|
17173
|
+
function wallTop(context, wall, floor) {
|
|
17174
|
+
const y0 = context.level(floor);
|
|
17175
|
+
if (wall.type === "railing") return y0 + guardHeightOf(wall);
|
|
17176
|
+
const ceiling = wallCeiling(context, wall);
|
|
17177
|
+
const height = wall.structureHeight || wall.h || context.ceilingOf(floor);
|
|
17178
|
+
if (wall.exterior && floor < context.floorCount - 1 && !context.isUnit && ceiling > context.ceilingOf(floor) + 0.01) return y0 + ceiling;
|
|
17179
|
+
if (floor === context.floorCount - 1 || context.isUnit) return y0 + Math.max(height, ceiling);
|
|
17180
|
+
const top = context.topOf(floor);
|
|
17181
|
+
return Math.max(y0 + height, y0 + ceiling > top ? top : y0 + ceiling);
|
|
17182
|
+
}
|
|
17183
|
+
function railingBase(context, wall, floor) {
|
|
17184
|
+
const open = wall.sides.map((id) => context.source.rooms.find((room) => room.id === id && room.floor === floor)).find((room) => room && (room.type === "balcony" || room.type === "porch"));
|
|
17185
|
+
if (!open) return context.baseOf(floor);
|
|
17186
|
+
return open.type === "porch" ? `porch_floor_${open.id}` : `slab_${floor}_${open.id}`;
|
|
17187
|
+
}
|
|
17188
|
+
var assemblyOf = (context) => context.construction.walls.assembly ?? (context.system.walls || void 0);
|
|
17189
|
+
function addWallPart(context, wall, floor) {
|
|
17190
|
+
const { system, builder } = context;
|
|
17191
|
+
const isRailing = wall.type === "railing";
|
|
17192
|
+
const y0 = context.level(floor);
|
|
17193
|
+
const top = wallTop(context, wall, floor);
|
|
17194
|
+
const y1 = isRailing ? top : wall.exterior && !wall.gable ? top - system.plateThickness : top;
|
|
17195
|
+
const framed = system.studs !== void 0 && !isRailing;
|
|
17196
|
+
const part = builder.add(
|
|
17197
|
+
{ id: wall.id, role: wall.role, material: wall.material, aabb: wall.box, y0, y1: Math.max(y1, y0 + 0.2) },
|
|
17198
|
+
{ floor, fill: context.isTimber && wall.role === "wall" ? system.wallFill : 1, ...framed ? { studs: system.studs } : {}, ...isRailing ? {} : { assembly: assemblyOf(context) } }
|
|
17199
|
+
);
|
|
17200
|
+
context.wallParts.set(wall.id, part);
|
|
17201
|
+
const base = isRailing ? railingBase(context, wall, floor) : context.baseOf(floor);
|
|
17202
|
+
const joint = isRailing ? "nail" : system.joints.wall;
|
|
17203
|
+
if (base === GROUND || floor === 0 && !base) builder.rest(part, GROUND, joint);
|
|
17204
|
+
else if (base) builder.rest(part, base, joint);
|
|
17205
|
+
}
|
|
17206
|
+
function addWalls(context, floor) {
|
|
17207
|
+
for (const wall of context.walls.filter((w) => w.floor === floor)) addWallPart(context, wall, floor);
|
|
17208
|
+
}
|
|
17209
|
+
function buildFloors(context) {
|
|
17210
|
+
for (let floor = 0; floor < context.floorCount; floor++) {
|
|
17211
|
+
addWalls(context, floor);
|
|
17212
|
+
addPlatesAndPillars(context, floor);
|
|
17213
|
+
addPorches(context, floor);
|
|
17214
|
+
addUpperFloor(context, floor);
|
|
17215
|
+
}
|
|
17216
|
+
}
|
|
17217
|
+
function buildStructure(source, options = {}) {
|
|
17218
|
+
const refined = options.wallDetail !== "coarse";
|
|
17219
|
+
const built = options.construction ? { construction: options.construction, extras: options.extras ?? {} } : resolveConstruction(source);
|
|
17220
|
+
const construction = built.construction;
|
|
17221
|
+
const extras = options.extras ?? built.extras ?? {};
|
|
17222
|
+
if (construction.system === "canvas") return buildCanvasStructure(construction, extras);
|
|
17223
|
+
const tank = options.tank !== void 0 ? options.tank : source.waterTank ?? null;
|
|
17224
|
+
const context = createContext(source, construction, extras, tank, { porchRoofOnPostsOnly: options.porchRoofOnPostsOnly ?? refined, rafterRoof: options.rafterRoof ?? refined });
|
|
17225
|
+
addFoundation(context);
|
|
17226
|
+
buildFloors(context);
|
|
17227
|
+
addBalconies(context);
|
|
17228
|
+
addPorchRoofs(context);
|
|
17229
|
+
addExteriorSteps(context);
|
|
17230
|
+
addStairs(context);
|
|
17231
|
+
if (options.roof !== false) addRoof(context);
|
|
17232
|
+
if (refined) addDoorLintels(context);
|
|
17233
|
+
addWaterTank(context);
|
|
17234
|
+
addChimney(context);
|
|
17235
|
+
addWell(context);
|
|
17236
|
+
const levels = source.floors.map((_, floor) => context.level(floor));
|
|
17237
|
+
const framed = construction.system === "masonry" && (context.isUnit || source.style === "commercial" || context.floorCount >= 3);
|
|
17238
|
+
return { parts: context.builder.parts, supports: context.builder.supports, levels, elevation: context.elevation, roof: context.roof, construction, framed, openings: findOpenings(context) };
|
|
17239
|
+
}
|
|
16244
17240
|
var entry = (itemId, min, max, group, pickable, weight) => ({ itemId, min, max, group, pickable, weight });
|
|
16245
17241
|
var FRIDGE = [
|
|
16246
17242
|
entry("water_bottle", 1, 3, "water", true, 3),
|
|
@@ -20373,10 +21369,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20373
21369
|
}
|
|
20374
21370
|
|
|
20375
21371
|
// ../game-floorplan-residential/dist/index.js
|
|
20376
|
-
var
|
|
21372
|
+
var __defProp3 = Object.defineProperty;
|
|
20377
21373
|
var __export2 = (target, all) => {
|
|
20378
21374
|
for (var name in all)
|
|
20379
|
-
|
|
21375
|
+
__defProp3(target, name, { get: all[name], enumerable: true });
|
|
20380
21376
|
};
|
|
20381
21377
|
var residentialItems = [
|
|
20382
21378
|
{ type: "sofa_3seat", category: "sofa", w: 2.1, d: 0.9, h: 0.85, color: { role: "fabric_main" } },
|
|
@@ -21577,7 +22573,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21577
22573
|
}
|
|
21578
22574
|
function recordSpec(THREE, name, root, run, opts) {
|
|
21579
22575
|
const o = { chairs: opts.chairs };
|
|
21580
|
-
const
|
|
22576
|
+
const materialOf2 = { ...BASE_MATERIAL, ...opts.materials };
|
|
21581
22577
|
const drawn = [];
|
|
21582
22578
|
const counters = /* @__PURE__ */ new Map();
|
|
21583
22579
|
const q = new THREE.Quaternion();
|
|
@@ -21633,7 +22629,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21633
22629
|
if (!drawn.length) throw new Error(`game-floorplan-three: the builder of "${name}" drew no box or cylinder`);
|
|
21634
22630
|
const parts = drawn.map((p) => {
|
|
21635
22631
|
const thin = Math.min(...p.shape.kind === "box" ? p.shape.size : p.shape.kind === "cylinder" ? [p.shape.radius * 2, p.shape.height] : [p.shape.radius * 2]);
|
|
21636
|
-
let material =
|
|
22632
|
+
let material = materialOf2[p.key] ?? "plastic";
|
|
21637
22633
|
if (p.key === "wood" && material === "wood_hard" && thin < WOOD_THIN) material = "wood_soft";
|
|
21638
22634
|
const part = { id: p.id, material, shape: p.shape, position: p.position };
|
|
21639
22635
|
if (p.rotation) part.rotation = p.rotation;
|
|
@@ -21759,6 +22755,66 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21759
22755
|
K.PARTS.length = before;
|
|
21760
22756
|
return { spec: made.spec, build: made.build, spout: [water.pos[0] - root.x, water.pos[1], water.pos[2] - root.z] };
|
|
21761
22757
|
}
|
|
22758
|
+
|
|
22759
|
+
// src/wall.ts
|
|
22760
|
+
var PLASTER = 15262420;
|
|
22761
|
+
var WALL_ID = "wall_0_0";
|
|
22762
|
+
function wallPlan(options) {
|
|
22763
|
+
const { w, h, thickness = 0.15, finish = "plaster", color: color2 = PLASTER } = options;
|
|
22764
|
+
const facade = { finish, roof: "none", floors: 1 };
|
|
22765
|
+
const wall = { id: WALL_ID, floor: 0, axis: "u", u0: -w / 2, v0: 0, u1: w / 2, v1: 0, thickness, sides: ["outside", "outside"], exterior: true, type: "wall", h };
|
|
22766
|
+
const plan = {
|
|
22767
|
+
template: "wall",
|
|
22768
|
+
name: "wall",
|
|
22769
|
+
style: "mid",
|
|
22770
|
+
state: "normal",
|
|
22771
|
+
w,
|
|
22772
|
+
d: thickness,
|
|
22773
|
+
floors: [{ index: 0, y0: 0, ceiling: h }],
|
|
22774
|
+
rooms: [],
|
|
22775
|
+
walls: [wall],
|
|
22776
|
+
doors: [],
|
|
22777
|
+
windows: [],
|
|
22778
|
+
items: [],
|
|
22779
|
+
stateItems: [],
|
|
22780
|
+
openPairs: [],
|
|
22781
|
+
partyWalls: [],
|
|
22782
|
+
missing: [],
|
|
22783
|
+
facade,
|
|
22784
|
+
colors: { facade: color2, wall: color2 },
|
|
22785
|
+
lot: null,
|
|
22786
|
+
building: null,
|
|
22787
|
+
waterTank: null,
|
|
22788
|
+
outbuildings: []
|
|
22789
|
+
};
|
|
22790
|
+
plan.construction = masonryConstruction({ ...plan, facade: { ...facade, roof: "colonial" } });
|
|
22791
|
+
plan.structure = buildStructure(plan, { wallDetail: "coarse", construction: plan.construction, roof: false });
|
|
22792
|
+
return plan;
|
|
22793
|
+
}
|
|
22794
|
+
function draw(THREE, plan, options) {
|
|
22795
|
+
return create3(THREE, { ...options, fleet: null }).build(plan, { quality: "game", terrain: false, noPerimeter: true, pieces: "meshes" });
|
|
22796
|
+
}
|
|
22797
|
+
function label(house) {
|
|
22798
|
+
for (const [id, items] of Object.entries(house.destruction.ranges())) {
|
|
22799
|
+
for (const item of items) {
|
|
22800
|
+
const object2 = item.isObject3D ? item : item.mesh;
|
|
22801
|
+
object2.userData.destructionPart = id;
|
|
22802
|
+
}
|
|
22803
|
+
}
|
|
22804
|
+
return house.group;
|
|
22805
|
+
}
|
|
22806
|
+
function wallPiece(THREE, options) {
|
|
22807
|
+
const plan = wallPlan(options);
|
|
22808
|
+
const houseOptions = options.house ?? {};
|
|
22809
|
+
const probe = draw(THREE, plan, { ...houseOptions, destruction: void 0, destructionRenderer: void 0 });
|
|
22810
|
+
const spec = probe.structure.spec({ wallDetail: "coarse" });
|
|
22811
|
+
probe.dispose();
|
|
22812
|
+
return {
|
|
22813
|
+
plan,
|
|
22814
|
+
spec,
|
|
22815
|
+
build: (T2) => label(draw(T2, plan, houseOptions))
|
|
22816
|
+
};
|
|
22817
|
+
}
|
|
21762
22818
|
return __toCommonJS(index_exports);
|
|
21763
22819
|
})();
|
|
21764
22820
|
//# sourceMappingURL=index.global.js.map
|