fix: update building dimensions and descriptions in README, model.json, and klabava.js
continuous-integration/drone/push Build is passing

This commit is contained in:
martin.fencl
2026-10-31 18:00:33 +01:00
parent b08f70d18e
commit 4596a28aed
4 changed files with 58 additions and 55 deletions
+47 -45
View File
@@ -90,7 +90,7 @@ sunLight.target = sunTarget;
const modelRoot = new THREE.Group();
modelRoot.name = 'Klabava – dům a pozemek';
scene.add(modelRoot);
const groundGroup = new THREE.Group(); groundGroup.name = 'Terén a zahrada'; modelRoot.add(groundGroup);
const groundGroup = new THREE.Group(); groundGroup.name = 'Interpolovaný terén'; modelRoot.add(groundGroup);
const boundaryGroup = new THREE.Group(); boundaryGroup.name = 'Orientační hranice parcely'; modelRoot.add(boundaryGroup);
const parkingGroup = new THREE.Group(); parkingGroup.name = 'Příjezd a parkování'; modelRoot.add(parkingGroup);
const houseGroup = new THREE.Group(); houseGroup.name = 'Rodinný dům – pracovní hmota'; houseGroup.position.set(0, 0, 8.4); modelRoot.add(houseGroup);
@@ -108,13 +108,9 @@ const mats = {
door: new THREE.MeshStandardMaterial({ color: 0x958d7d, roughness: 0.8 }),
terrace: new THREE.MeshStandardMaterial({ color: 0xaaa492, roughness: 0.88 }),
metal: new THREE.MeshStandardMaterial({ color: 0x545b58, roughness: 0.6, metalness: 0.18 }),
trunk: new THREE.MeshStandardMaterial({ color: 0x735d46, roughness: 1 }),
leaf: new THREE.MeshStandardMaterial({ color: 0x657c5c, roughness: 1 }),
leaf2: new THREE.MeshStandardMaterial({ color: 0x839273, roughness: 1 }),
car1: new THREE.MeshStandardMaterial({ color: 0x777e7b, roughness: 0.45, metalness: 0.08 }),
car2: new THREE.MeshStandardMaterial({ color: 0xa59f91, roughness: 0.45, metalness: 0.08 }),
tire: new THREE.MeshStandardMaterial({ color: 0x333635, roughness: 0.95 }),
pavingLine: new THREE.MeshStandardMaterial({ color: 0xe4e0d2, roughness: 0.9 })
tire: new THREE.MeshStandardMaterial({ color: 0x333635, roughness: 0.95 })
};
function mesh(geometry, material, parent, name = '') {
@@ -194,7 +190,7 @@ function buildGround() {
// Parcel outline is intentionally thin and diagrammatic; the supplied survey has no parcel staking coordinates.
const border = [nw, ne, se, sw].map(([x, z]) => [x, groundHeight(x, z) + 0.045, z]);
line(boundaryGroup, 'Grafická hranice parcely 66/17', [...border, border[0]], 0x4f694f, 0.95);
borderGroup.add(line(boundaryGroup, 'Grafická hranice parcely 66/17', [...border, border[0]], 0x4f694f, 0.95));
for (let i = 0; i < border.length; i++) {
const [x, y, z] = border[i];
const post = mesh(new THREE.CylinderGeometry(0.035, 0.035, 0.12, 6), mats.frame, boundaryGroup, `Orientační lom hranice ${i + 1}`);
@@ -203,20 +199,20 @@ function buildGround() {
}
buildParking(roadY);
buildGarden();
}
function buildParking(roadY) {
const y = (x, z) => groundHeight(x, z) + 0.035;
const drivewayPts = [[-9.2, y(-9.2, 20.2), 20.2], [-5.3, y(-5.3, 20.2), 20.2], [-5.3, y(-5.3, 17.8), 17.8], [-9.2, y(-9.2, 17.8), 17.8]];
poly(parkingGroup, 'Příjezd na pozemek', drivewayPts, mats.gravel);
const pad = [[-10.3, y(-10.3, 17.7), 17.7], [-3.7, y(-3.7, 17.7), 17.7], [-3.7, y(-3.7, 14.9), 14.9], [-10.3, y(-10.3, 14.9), 14.9]];
// Situace places the two-car apron on the road side; the 6.625 × 5.0 m pad is at the right of this view.
const drivewayPts = [[5.0, y(5.0, 20.45), 20.45], [8.9, y(8.9, 20.45), 20.45], [8.9, y(8.9, 19.85), 19.85], [5.0, y(5.0, 19.85), 19.85]];
poly(parkingGroup, 'Příjezd z komunikace', drivewayPts, mats.gravel);
const pad = [[3.7, y(3.7, 20.0), 20.0], [10.325, y(10.325, 20.0), 20.0], [10.325, y(10.325, 15.0), 15.0], [3.7, y(3.7, 15.0), 15.0]];
poly(parkingGroup, 'Orientační parkovací plocha', pad, mats.gravel);
line(parkingGroup, 'Osa příjezdu', [[-7.25, roadY(20) + 0.03, 20], [-7.25, y(-7.25, 17.8) + 0.04, 17.8]], 0x8f958b, 0.65);
line(parkingGroup, 'Napojení na komunikaci', [[6.95, roadY(20.3) + 0.04, 20.3], [6.95, y(6.95, 19.85) + 0.04, 19.85]], 0x8f958b, 0.65);
function addCar(cx, cz, material, label) {
const car = group(parkingGroup, label);
car.position.set(cx, groundHeight(cx, cz) + 0.12, cz);
car.position.set(cx, groundHeight(cx, cz) + 0.035, cz);
box(car, `${label} karoserie`, 0, 0.42, 0, 2.05, 0.72, 4.35, material);
box(car, `${label} kabina`, 0, 0.93, -0.1, 1.55, 0.62, 2.45, mats.glass);
for (const x of [-1.02, 1.02]) for (const z of [-1.42, 1.42]) {
@@ -226,34 +222,13 @@ function buildParking(roadY) {
}
box(car, `${label} přední sklo`, 0, 0.95, 1.12, 1.38, 0.43, 0.08, mats.glass, 0.18);
}
addCar(-8.15, 16.35, mats.car1, 'Orientační automobil 1');
addCar(-5.75, 16.35, mats.car2, 'Orientační automobil 2');
// A short walk connects the front door and the gravel parking area.
const walkway = [[-0.9, y(-0.9, 16.5), 16.5], [0.55, y(0.55, 16.5), 16.5], [0.55, y(0.55, 14.7), 14.7], [-0.9, y(-0.9, 14.7), 14.7]];
poly(parkingGroup, 'Pěší vstup', walkway, mats.path);
}
function addTree(x, z, height, variant = 0) {
const g = group(groundGroup, 'Orientační strom');
g.position.set(x, groundHeight(x, z), z);
const trunkHeight = height * 0.42;
const trunk = mesh(new THREE.CylinderGeometry(0.11, 0.17, trunkHeight, 7), mats.trunk, g, 'Kmen');
trunk.position.y = trunkHeight / 2;
const material = variant % 2 ? mats.leaf2 : mats.leaf;
for (let i = 0; i < 3; i++) {
const radius = height * (0.27 - i * 0.04);
const cone = mesh(new THREE.ConeGeometry(radius, height * 0.42, 8), material, g, 'Koruna');
cone.position.set(0, trunkHeight + height * (0.17 + i * 0.18), 0);
}
}
function buildGarden() {
const trees = [[-10.7, -3.7, 3.7], [10.7, -3.4, 3.4], [-10.1, -10.2, 3.6], [11.0, -11.3, 4.1], [-7.4, -16.9, 3.4], [3.5, -17.1, 3.8], [9.6, 4.3, 3.1]];
trees.forEach(([x, z, h], i) => addTree(x, z, h, i));
for (const [x, z] of [[-9.5, -6.5], [10.3, -6.4], [-5.9, -18.1], [6.1, -18.2]]) {
const shrub = mesh(new THREE.SphereGeometry(0.65, 10, 8), mats.leaf2, groundGroup, 'Orientační keř');
shrub.scale.set(1.2, 0.8, 0.9);
shrub.position.set(x, groundHeight(x, z) + 0.44, z);
}
addCar(5.55, 17.5, mats.car1, 'Orientační automobil 1');
addCar(8.45, 17.5, mats.car2, 'Orientační automobil 2');
// The front walk runs from the entrance to the right-hand parking apron.
const walkToDoor = [[-0.3, y(-0.3, 16.4), 16.4], [1.15, y(1.15, 16.4), 16.4], [1.15, y(1.15, 14.7), 14.7], [-0.3, y(-0.3, 14.7), 14.7]];
const walkToParking = [[0.8, y(0.8, 14.7), 14.7], [4.0, y(4.0, 14.7), 14.7], [4.0, y(4.0, 15.35), 15.35], [0.8, y(0.8, 15.35), 15.35]];
poly(parkingGroup, 'Pěší vstup od domu', walkToDoor, mats.path);
poly(parkingGroup, 'Pěší napojení parkování', walkToParking, mats.path);
}
const footprint = [
@@ -311,8 +286,8 @@ function makeWallEdge(p1, p2, openings = []) {
wallSegment(cursor, length, 0, height);
}
function hipRoof(x0, x1, z0, z1, name, ridgeHeight = 5.832) {
const overhang = 0.38, eave = 3.06;
function hipRoof(x0, x1, z0, z1, name, ridgeHeight) {
const overhang = 0.38, eave = 3.046;
x0 -= overhang; x1 += overhang; z0 -= overhang; z1 += overhang;
const xm = (x0 + x1) / 2, zm = (z0 + z1) / 2;
const width = x1 - x0, depth = z1 - z0;
@@ -341,6 +316,32 @@ function hipRoof(x0, x1, z0, z1, name, ridgeHeight = 5.832) {
box(houseGroup, `${name} – okap východ`, x1, eave - 0.04, zm, 0.12, 0.12, depth, mats.frame);
}
// The higher roof crosses the deeper wing. Its 13.05 m roof span and +5.832 m
// ridge follow the 23° section/elevation; the wing walls themselves are 11.67 m deep.
function hipRoofAcrossDepth(x0, x1, z0, z1, name, ridgeHeight) {
const eave = 3.046, overhangX = 0.38, overhangZ = 0.69;
x0 -= overhangX; x1 += overhangX; z0 -= overhangZ; z1 += overhangZ;
const zm = (z0 + z1) / 2;
const v = (x, y, z) => [x, y, z];
poly(houseGroup, `${name} – severní střešní rovina`, [
v(x0, eave, z1), v(x1, eave, z1), v(x1, ridgeHeight, zm), v(x0, ridgeHeight, zm)
], mats.roof);
poly(houseGroup, `${name} – jižní střešní rovina`, [
v(x1, eave, z0), v(x0, eave, z0), v(x0, ridgeHeight, zm), v(x1, ridgeHeight, zm)
], mats.roof);
poly(houseGroup, `${name} – západní valba`, [
v(x0, eave, z0), v(x0, eave, z1), v(x0, ridgeHeight, zm)
], mats.roof);
poly(houseGroup, `${name} – východní valba`, [
v(x1, eave, z1), v(x1, eave, z0), v(x1, ridgeHeight, zm)
], mats.roof);
box(houseGroup, `${name} – hřeben`, (x0 + x1) / 2, ridgeHeight, zm, x1 - x0, 0.12, 0.12, mats.roof);
box(houseGroup, `${name} – okap sever`, (x0 + x1) / 2, eave - 0.04, z1, x1 - x0, 0.12, 0.12, mats.frame);
box(houseGroup, `${name} – okap jih`, (x0 + x1) / 2, eave - 0.04, z0, x1 - x0, 0.12, 0.12, mats.frame);
box(houseGroup, `${name} – okap západ`, x0, eave - 0.04, zm, 0.12, 0.12, z1 - z0, mats.frame);
box(houseGroup, `${name} – okap východ`, x1, eave - 0.04, zm, 0.12, 0.12, z1 - z0, mats.frame);
}
function buildHouse() {
makeFootprintSlab();
const openings = [
@@ -354,8 +355,9 @@ function buildHouse() {
[]
];
for (let i = 0; i < footprint.length; i++) makeWallEdge(footprint[i], footprint[(i + 1) % footprint.length], openings[i]);
hipRoof(-1.575, 8.7, -2.775, 6.525, 'Hlavní valbová střecha');
hipRoof(-8.7, -1.575, -6.525, 5.145, 'Střecha západního křídla');
// The section shows the 23° lower roof ridge (+5.275 m); the elevations show the deeper wing ridge (+5.832 m).
hipRoof(-1.575, 8.7, -2.775, 6.525, 'Nižší valbová střecha', 5.275);
hipRoofAcrossDepth(-8.7, -1.575, -6.525, 5.145, 'Vyšší valbová střecha', 5.832);
// Chimney shown in the elevations, with a simple cap.
box(houseGroup, 'Komín', 5.7, 5.78, 1.8, 0.64, 1.25, 0.64, mats.foundation);