fix: a building glyph's pane and door are true metres, not scene units
0.012 and 0.028 were scene-unit thicknesses chosen against the Bay Area board, so a pane stood 1.13 m proud and a door 2.64 m. On the merged board that is 23 m of glass and a 54 m door — measured on the HQ glyph at Salesforce Tower while naming the 700 m FiDi slab. Same class as the pin, the aeroplane, and the freeway ribbon. The Bay Area appearance does not move; the test is the two-board property.
This commit is contained in:
@@ -49,6 +49,18 @@ interface WindowPlacement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_BODY = 0x8d9aa4;
|
const DEFAULT_BODY = 0x8d9aa4;
|
||||||
|
/**
|
||||||
|
* Pane and door thickness, in true metres.
|
||||||
|
*
|
||||||
|
* These were 0.012 and 0.028 **scene units**, chosen against the Bay Area
|
||||||
|
* board (94.3 m to the unit) so a pane stood 1.13 m proud and a door 2.64 m.
|
||||||
|
* On the merged board that is 23 m of glass and a 54 m door — measured on the
|
||||||
|
* HQ glyph at Salesforce Tower while hunting the 700 m FiDi slab. Same class
|
||||||
|
* of bug as the pin, the aeroplane, and the freeway ribbon: a constant in
|
||||||
|
* scene units is a constant that assumes one board.
|
||||||
|
*/
|
||||||
|
const PANE_DEPTH_M = 1.13;
|
||||||
|
const DOOR_DEPTH_M = 2.64;
|
||||||
const WINDOW_DAY = new THREE.Color(0x334c5d);
|
const WINDOW_DAY = new THREE.Color(0x334c5d);
|
||||||
const WINDOW_LIT = new THREE.Color(0xd7c68d);
|
const WINDOW_LIT = new THREE.Color(0xd7c68d);
|
||||||
|
|
||||||
@@ -203,7 +215,7 @@ export function createBuildingGlyph(
|
|||||||
windows.forEach((window, i) => {
|
windows.forEach((window, i) => {
|
||||||
position.set(window.x, window.y, window.z);
|
position.set(window.x, window.y, window.z);
|
||||||
quaternion.setFromAxisAngle(up, window.yaw);
|
quaternion.setFromAxisAngle(up, window.yaw);
|
||||||
scale.set(window.width, window.height, 0.012);
|
scale.set(window.width, window.height, PANE_DEPTH_M * horizontal);
|
||||||
matrix.compose(position, quaternion, scale);
|
matrix.compose(position, quaternion, scale);
|
||||||
windowMesh.setMatrixAt(i, matrix);
|
windowMesh.setMatrixAt(i, matrix);
|
||||||
// A few warm panes stop the repeated grid reading as graph paper. The
|
// A few warm panes stop the repeated grid reading as graph paper. The
|
||||||
@@ -248,7 +260,7 @@ export function createBuildingGlyph(
|
|||||||
vertical(first.base),
|
vertical(first.base),
|
||||||
(first.z + first.depth / 2 + 0.18) * horizontal,
|
(first.z + first.depth / 2 + 0.18) * horizontal,
|
||||||
);
|
);
|
||||||
door.scale.set(doorWidth * horizontal, vertical(doorHeight), 0.028);
|
door.scale.set(doorWidth * horizontal, vertical(doorHeight), DOOR_DEPTH_M * horizontal);
|
||||||
door.castShadow = false;
|
door.castShadow = false;
|
||||||
group.add(door);
|
group.add(door);
|
||||||
pickables.push(door);
|
pickables.push(door);
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
import assert from "node:assert/strict";
|
import assert from "node:assert/strict";
|
||||||
import { describe, it } from "node:test";
|
import { describe, it } from "node:test";
|
||||||
import { layoutBuildingGlyph } from "../engine/buildingGlyph.ts";
|
import * as THREE from "three";
|
||||||
import type { BuildingGlyph } from "../engine/types.ts";
|
import { createBuildingGlyph, layoutBuildingGlyph } from "../engine/buildingGlyph.ts";
|
||||||
|
import type { BuildingGlyph, City } from "../engine/types.ts";
|
||||||
|
import { World } from "../engine/world.ts";
|
||||||
|
import { setReconcile } from "../cities/reconcile.ts";
|
||||||
|
|
||||||
|
setReconcile(false);
|
||||||
|
|
||||||
function glyph(overrides: Partial<BuildingGlyph> = {}): BuildingGlyph {
|
function glyph(overrides: Partial<BuildingGlyph> = {}): BuildingGlyph {
|
||||||
return {
|
return {
|
||||||
@@ -57,3 +62,72 @@ describe("map building glyph layouts", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/** The same square of ground at two scales; see `markerScale.test.ts`. */
|
||||||
|
function board(latScale: number): City {
|
||||||
|
return {
|
||||||
|
id: `glyph-scale-${latScale}`,
|
||||||
|
name: "Glyph Scale Board",
|
||||||
|
center: { lat: 37.78, lng: -122.42 },
|
||||||
|
bounds: { minLat: 37.7, maxLat: 37.86, minLng: -122.5, maxLng: -122.34 },
|
||||||
|
latScale,
|
||||||
|
verticalExaggeration: 3.6,
|
||||||
|
cellLat: 0.01,
|
||||||
|
cellLng: 0.01,
|
||||||
|
coastFalloff: 0.02,
|
||||||
|
landmasses: [
|
||||||
|
[
|
||||||
|
[37.71, -122.49],
|
||||||
|
[37.85, -122.49],
|
||||||
|
[37.85, -122.35],
|
||||||
|
[37.71, -122.35],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
parks: [],
|
||||||
|
inlandWater: [],
|
||||||
|
districts: [],
|
||||||
|
landmarks: [],
|
||||||
|
bridges: [],
|
||||||
|
roads: [],
|
||||||
|
chapters: [],
|
||||||
|
hills: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const HQ: BuildingGlyph = {
|
||||||
|
kind: "building",
|
||||||
|
width: 48,
|
||||||
|
depth: 42,
|
||||||
|
height: 326,
|
||||||
|
storeys: 61,
|
||||||
|
heading: 205,
|
||||||
|
profile: "tower",
|
||||||
|
seed: 115,
|
||||||
|
bodyColor: 0x8799a8,
|
||||||
|
};
|
||||||
|
|
||||||
|
function doorDepthM(latScale: number): number {
|
||||||
|
const world = new World(board(latScale));
|
||||||
|
const built = createBuildingGlyph(world, HQ, 0xf5b53f);
|
||||||
|
let depthM = 0;
|
||||||
|
built.group.traverse((node) => {
|
||||||
|
if (!(node instanceof THREE.Mesh) || node.name !== "building entrance") return;
|
||||||
|
node.updateWorldMatrix(true, false);
|
||||||
|
depthM = Math.abs(node.scale.z) * world.metresPerUnit;
|
||||||
|
});
|
||||||
|
built.dispose();
|
||||||
|
return depthM;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("a building glyph is a true-metre object", () => {
|
||||||
|
it("draws the same door thickness on a 94 m board and a 1,919 m one", () => {
|
||||||
|
const metro = doorDepthM(1180);
|
||||||
|
const state = doorDepthM(58);
|
||||||
|
assert.ok(metro > 1 && metro < 6, `a door ${metro.toFixed(2)} m thick is not a door`);
|
||||||
|
assert.ok(
|
||||||
|
Math.abs(metro - state) < 0.05,
|
||||||
|
`a door is ${metro.toFixed(2)} m thick on a 94 m/unit board and ` +
|
||||||
|
`${state.toFixed(2)} m on a 1,919 m/unit one`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user