@a2f0/skyline 0.0.0-stage → 0.1.1
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/NOTICE.md +20 -0
- package/README.md +52 -2
- package/docs/package.md +222 -0
- package/docs/skyline-geography.md +503 -0
- package/lib/models/aon-center.d.ts +4 -0
- package/lib/models/aon-center.js +60 -0
- package/lib/models/aon-geographic.d.ts +9 -0
- package/lib/models/aon-geographic.js +35 -0
- package/lib/models/aon-tower.d.ts +23 -0
- package/lib/models/aon-tower.js +130 -0
- package/lib/models/blue-cross-geographic.d.ts +14 -0
- package/lib/models/blue-cross-geographic.js +248 -0
- package/lib/models/borg-warner-geographic.d.ts +20 -0
- package/lib/models/borg-warner-geographic.js +143 -0
- package/lib/models/buckingham-geographic.d.ts +10 -0
- package/lib/models/buckingham-geographic.js +121 -0
- package/lib/models/building-kit.d.ts +84 -0
- package/lib/models/building-kit.js +358 -0
- package/lib/models/celebrations.d.ts +39 -0
- package/lib/models/celebrations.js +44 -0
- package/lib/models/chicago-athletic-association-geographic.d.ts +32 -0
- package/lib/models/chicago-athletic-association-geographic.js +173 -0
- package/lib/models/crain-communications.d.ts +5 -0
- package/lib/models/crain-communications.js +75 -0
- package/lib/models/crain-geographic.d.ts +10 -0
- package/lib/models/crain-geographic.js +69 -0
- package/lib/models/crain-tower.d.ts +32 -0
- package/lib/models/crain-tower.js +378 -0
- package/lib/models/facade-grid.d.ts +18 -0
- package/lib/models/facade-grid.js +176 -0
- package/lib/models/gage-geographic.d.ts +19 -0
- package/lib/models/gage-geographic.js +154 -0
- package/lib/models/heritage-at-millennium-park.d.ts +3 -0
- package/lib/models/heritage-at-millennium-park.js +284 -0
- package/lib/models/heritage-geographic.d.ts +11 -0
- package/lib/models/heritage-geographic.js +208 -0
- package/lib/models/hyatt-west-tower-geographic.d.ts +26 -0
- package/lib/models/hyatt-west-tower-geographic.js +86 -0
- package/lib/models/keith-ascher-geographic.d.ts +29 -0
- package/lib/models/keith-ascher-geographic.js +110 -0
- package/lib/models/kemper-geographic.d.ts +8 -0
- package/lib/models/kemper-geographic.js +153 -0
- package/lib/models/kemper.d.ts +2 -0
- package/lib/models/kemper.js +78 -0
- package/lib/models/lake-view-geographic.d.ts +15 -0
- package/lib/models/lake-view-geographic.js +134 -0
- package/lib/models/maclean-center-geographic.d.ts +20 -0
- package/lib/models/maclean-center-geographic.js +162 -0
- package/lib/models/michigan-boulevard-geographic.d.ts +12 -0
- package/lib/models/michigan-boulevard-geographic.js +157 -0
- package/lib/models/michigan-plaza-south-geographic.d.ts +7 -0
- package/lib/models/michigan-plaza-south-geographic.js +84 -0
- package/lib/models/michigan-plaza-south.d.ts +2 -0
- package/lib/models/michigan-plaza-south.js +68 -0
- package/lib/models/millennium-park-plaza-geographic.d.ts +9 -0
- package/lib/models/millennium-park-plaza-geographic.js +103 -0
- package/lib/models/monroe-geographic.d.ts +19 -0
- package/lib/models/monroe-geographic.js +177 -0
- package/lib/models/north-michigan-180-geographic.d.ts +14 -0
- package/lib/models/north-michigan-180-geographic.js +117 -0
- package/lib/models/north-wabash-geographic.d.ts +14 -0
- package/lib/models/north-wabash-geographic.js +122 -0
- package/lib/models/on-the-park-geographic.d.ts +11 -0
- package/lib/models/on-the-park-geographic.js +245 -0
- package/lib/models/one-prudential-geographic.d.ts +12 -0
- package/lib/models/one-prudential-geographic.js +55 -0
- package/lib/models/one-prudential-plaza.d.ts +5 -0
- package/lib/models/one-prudential-plaza.js +72 -0
- package/lib/models/one-prudential-tower.d.ts +45 -0
- package/lib/models/one-prudential-tower.js +246 -0
- package/lib/models/peoples-gas-geographic.d.ts +23 -0
- package/lib/models/peoples-gas-geographic.js +250 -0
- package/lib/models/railway-exchange-geographic.d.ts +18 -0
- package/lib/models/railway-exchange-geographic.js +176 -0
- package/lib/models/river-plaza-geographic.d.ts +16 -0
- package/lib/models/river-plaza-geographic.js +104 -0
- package/lib/models/sheraton-grand-geographic.d.ts +24 -0
- package/lib/models/sheraton-grand-geographic.js +112 -0
- package/lib/models/six-north-michigan-geographic.d.ts +16 -0
- package/lib/models/six-north-michigan-geographic.js +180 -0
- package/lib/models/skyline-geography-data.d.ts +44 -0
- package/lib/models/skyline-geography-data.js +607 -0
- package/lib/models/skyline-geography.d.ts +23 -0
- package/lib/models/skyline-geography.js +322 -0
- package/lib/models/swissotel-geographic.d.ts +24 -0
- package/lib/models/swissotel-geographic.js +79 -0
- package/lib/models/three-illinois-center-geographic.d.ts +26 -0
- package/lib/models/three-illinois-center-geographic.js +86 -0
- package/lib/models/trump-geographic.d.ts +14 -0
- package/lib/models/trump-geographic.js +51 -0
- package/lib/models/trump-international-tower.d.ts +4 -0
- package/lib/models/trump-international-tower.js +84 -0
- package/lib/models/trump-tower.d.ts +43 -0
- package/lib/models/trump-tower.js +229 -0
- package/lib/models/two-illinois-center-geographic.d.ts +26 -0
- package/lib/models/two-illinois-center-geographic.js +85 -0
- package/lib/models/two-prudential-geographic.d.ts +25 -0
- package/lib/models/two-prudential-geographic.js +47 -0
- package/lib/models/two-prudential-plaza.d.ts +8 -0
- package/lib/models/two-prudential-plaza.js +55 -0
- package/lib/models/two-prudential-tower.d.ts +53 -0
- package/lib/models/two-prudential-tower.js +441 -0
- package/lib/models/university-club-geographic.d.ts +24 -0
- package/lib/models/university-club-geographic.js +217 -0
- package/lib/models/willoughby-tower-geographic.d.ts +17 -0
- package/lib/models/willoughby-tower-geographic.js +195 -0
- package/lib/models/window-illumination.d.ts +14 -0
- package/lib/models/window-illumination.js +64 -0
- package/lib/package-assets.d.ts +5 -0
- package/lib/package-assets.js +9 -0
- package/lib/skyline-package.d.ts +23 -0
- package/lib/skyline-package.js +25 -0
- package/lib/skyline-scene.d.ts +25 -0
- package/lib/skyline-scene.js +86 -0
- package/lib/study-types.d.ts +49 -0
- package/lib/study-types.js +1 -0
- package/lib/vendor/three-r186.d.ts +1 -0
- package/lib/vendor/three-r186.js +1 -0
- package/package.json +64 -4
- package/site/building-detail.html +54 -0
- package/site/building-detail.js +84 -0
- package/site/building-study.html +58 -0
- package/site/building-study.js +3 -0
- package/site/index.html +407 -0
- package/site/models/aon-center.js +60 -0
- package/site/models/aon-geographic.js +35 -0
- package/site/models/aon-tower.js +130 -0
- package/site/models/blue-cross-geographic.js +248 -0
- package/site/models/borg-warner-geographic.js +143 -0
- package/site/models/buckingham-geographic.js +121 -0
- package/site/models/building-kit.js +358 -0
- package/site/models/celebrations.js +44 -0
- package/site/models/chicago-athletic-association-geographic.js +173 -0
- package/site/models/crain-communications.js +75 -0
- package/site/models/crain-geographic.js +69 -0
- package/site/models/crain-reference.svg +10 -0
- package/site/models/crain-tower.js +378 -0
- package/site/models/facade-grid.js +176 -0
- package/site/models/gage-geographic.js +154 -0
- package/site/models/heritage-at-millennium-park.js +284 -0
- package/site/models/heritage-geographic.js +208 -0
- package/site/models/hyatt-west-tower-geographic.js +86 -0
- package/site/models/keith-ascher-geographic.js +110 -0
- package/site/models/kemper-geographic.js +153 -0
- package/site/models/kemper.js +78 -0
- package/site/models/lake-view-geographic.js +134 -0
- package/site/models/maclean-center-geographic.js +162 -0
- package/site/models/michigan-boulevard-geographic.js +157 -0
- package/site/models/michigan-plaza-south-geographic.js +84 -0
- package/site/models/michigan-plaza-south.js +68 -0
- package/site/models/millennium-park-plaza-geographic.js +103 -0
- package/site/models/monroe-geographic.js +177 -0
- package/site/models/north-michigan-180-geographic.js +117 -0
- package/site/models/north-wabash-geographic.js +122 -0
- package/site/models/on-the-park-geographic.js +245 -0
- package/site/models/one-prudential-geographic.js +55 -0
- package/site/models/one-prudential-plaza.js +72 -0
- package/site/models/one-prudential-tower.js +246 -0
- package/site/models/peoples-gas-geographic.js +250 -0
- package/site/models/railway-exchange-geographic.js +176 -0
- package/site/models/river-plaza-geographic.js +104 -0
- package/site/models/sheraton-grand-geographic.js +112 -0
- package/site/models/six-north-michigan-geographic.js +180 -0
- package/site/models/skyline-geography-data.js +607 -0
- package/site/models/skyline-geography.js +322 -0
- package/site/models/skyline-panorama.svg +3491 -0
- package/site/models/skyline-reference.svg +3090 -0
- package/site/models/swissotel-geographic.js +79 -0
- package/site/models/three-illinois-center-geographic.js +86 -0
- package/site/models/trump-geographic.js +51 -0
- package/site/models/trump-international-tower.js +84 -0
- package/site/models/trump-tower.js +229 -0
- package/site/models/two-illinois-center-geographic.js +85 -0
- package/site/models/two-prudential-geographic.js +47 -0
- package/site/models/two-prudential-plaza.js +55 -0
- package/site/models/two-prudential-tower.js +441 -0
- package/site/models/university-club-geographic.js +217 -0
- package/site/models/willoughby-tower-geographic.js +195 -0
- package/site/models/window-illumination.js +64 -0
- package/site/skyline-3d.html +92 -0
- package/site/skyline-3d.js +333 -0
- package/site/skyline-animated.svg +18795 -0
- package/site/skyline-comparison.js +97 -0
- package/site/skyline-original-fit.svg +18312 -0
- package/site/skyline-scene.js +86 -0
- package/site/skyline-study.html +83 -0
- package/site/skyline-study.js +109 -0
- package/site/skyline-webgl.html +667 -0
- package/site/stars.svg +176 -0
- package/site/study-loader.js +20 -0
- package/site/study-types.js +1 -0
- package/site/study-viewer.js +605 -0
- package/site/study.css +204 -0
- package/site/vendor/THREE-LICENSE.txt +21 -0
- package/site/vendor/three-r186.js +4228 -0
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import * as THREE from "../vendor/three-r186.js";
|
|
2
|
+
import { createBuilder, polygonOf } from "./building-kit.js";
|
|
3
|
+
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt } from "./facade-grid.js";
|
|
4
|
+
// Six North Michigan, the Montgomery Ward Building (Schmidt, Garden & Martin, 1899; four
|
|
5
|
+
// floors added by Holabird & Roche, 1923): the geographic layout's model, on the mapped
|
|
6
|
+
// outline 126982631. The original layout has no model of it; the drawing shows it right of
|
|
7
|
+
// Willoughby Tower, outside the excerpt it is fitted to.
|
|
8
|
+
//
|
|
9
|
+
// A sixteen-storey block, 27.5 m on Michigan by 49.6 m on Madison, under a projecting
|
|
10
|
+
// cornice. The tower, built in the middle of the Michigan front rather than on the corner
|
|
11
|
+
// first planned, rises flush with it: a floor above the block, a band, an arched stage of
|
|
12
|
+
// three tall windows to a face under a cornice, and a top stage of panels under a cap at
|
|
13
|
+
// 86 m, where the pyramid and statue came off in 1947. Heights are measured on the drawing
|
|
14
|
+
// down from that top; see docs/six-north-michigan-reference.md. Units are meters; +x is
|
|
15
|
+
// east, +z is south.
|
|
16
|
+
export const sixNorthLevels = Object.freeze({
|
|
17
|
+
block: 62.1, // the block's walls, under its cornice
|
|
18
|
+
cornice: 63.6, // the block's cornice and roof
|
|
19
|
+
band: 65, // the tower's band, over the floor above the block
|
|
20
|
+
bandTop: 66.9,
|
|
21
|
+
arches: 75.6, // the arched stage, under the tower's cornice
|
|
22
|
+
towerCornice: 78, // the tower's cornice, under the top stage
|
|
23
|
+
stage: 84.5, // the top stage, under its cap
|
|
24
|
+
top: 86, // the cap, the published height
|
|
25
|
+
towerSouth: 7.5, // the tower's south wall, north of Madison
|
|
26
|
+
towerNorth: 20, // its north wall
|
|
27
|
+
towerDepth: 12, // west of the Michigan front
|
|
28
|
+
});
|
|
29
|
+
const h = sixNorthLevels;
|
|
30
|
+
// Each floor's level: a 6 m ground floor, then 3.74 m floors to the block's cornice.
|
|
31
|
+
const floor = (n) => (n < 2 ? 0 : 6 + (n - 2) * 3.74);
|
|
32
|
+
const color = (hex) => new THREE.Color(hex);
|
|
33
|
+
const glassTones = [0x4c4c4c, 0x505050, 0x545454, 0x585858].map(color);
|
|
34
|
+
const litGlass = color(0x8a8a8a), dimGlass = color(0x5e5e5e);
|
|
35
|
+
const brick = color(0x6e6e6e), panel = color(0x9c9c9c), core = color(0x2e2e2e), roofing = color(0x484848);
|
|
36
|
+
function paneColor(row, bay, wall) {
|
|
37
|
+
const hash = (Math.imul(row + 31, 0x9e3779b1) ^ Math.imul(bay + 57, 0x85ebca77) ^ Math.imul(wall + 43, 0xc2b2ae3d)) >>> 0;
|
|
38
|
+
const value = hash % 101;
|
|
39
|
+
if (value < 4)
|
|
40
|
+
return litGlass;
|
|
41
|
+
if (value < 8)
|
|
42
|
+
return dimGlass;
|
|
43
|
+
return glassTones[value % glassTones.length];
|
|
44
|
+
}
|
|
45
|
+
const blockRows = [
|
|
46
|
+
{ lo: 0.25, hi: 1, kind: "brick", floor: 1 },
|
|
47
|
+
{ lo: 1, hi: 5.2, kind: "glass", floor: 1 },
|
|
48
|
+
{ lo: 5.2, hi: floor(2) - 0.35, kind: "brick", floor: 1 },
|
|
49
|
+
];
|
|
50
|
+
for (let n = 2; n <= 16; n += 1) {
|
|
51
|
+
blockRows.push({ lo: floor(n) - 0.35, hi: floor(n) + 1.25, kind: "brick", floor: n });
|
|
52
|
+
blockRows.push({ lo: floor(n) + 1.25, hi: floor(n + 1) - 0.35, kind: "glass", floor: n });
|
|
53
|
+
}
|
|
54
|
+
blockRows.push({ lo: floor(17) - 0.35, hi: h.block, kind: "brick", floor: 17 });
|
|
55
|
+
// The tower's rows over the block: the seventeenth floor's windows under the band; then the
|
|
56
|
+
// arched stage's small windows over the band and its tall windows, their heads narrowing
|
|
57
|
+
// for the last half-metre; then the top stage's panel.
|
|
58
|
+
const towerRows = [
|
|
59
|
+
{ lo: h.block, hi: 62.95, kind: "brick", floor: 17 },
|
|
60
|
+
{ lo: 62.95, hi: 64.77, kind: "floor17", floor: 17 },
|
|
61
|
+
{ lo: 64.77, hi: h.band, kind: "brick", floor: 17 },
|
|
62
|
+
{ lo: h.bandTop, hi: 68.2, kind: "small", floor: 18 },
|
|
63
|
+
{ lo: 68.2, hi: 70.7, kind: "brick", floor: 18 },
|
|
64
|
+
{ lo: 70.7, hi: 73.7, kind: "arch", floor: 19 },
|
|
65
|
+
{ lo: 73.7, hi: 74.2, kind: "head", floor: 19 },
|
|
66
|
+
{ lo: 74.2, hi: h.arches, kind: "brick", floor: 20 },
|
|
67
|
+
{ lo: h.towerCornice, hi: 83.2, kind: "panel", floor: 21 },
|
|
68
|
+
{ lo: 83.2, hi: h.stage, kind: "brick", floor: 21 },
|
|
69
|
+
];
|
|
70
|
+
const rowsBetween = (rows, lo, hi) => rows
|
|
71
|
+
.map((row) => ({ ...row, lo: Math.max(row.lo, lo), hi: Math.min(row.hi, hi) }))
|
|
72
|
+
.filter((row) => row.hi - row.lo > 0.05);
|
|
73
|
+
export function createSixNorthMichiganGeographicBuilding(record, projectPlan, offset) {
|
|
74
|
+
const kit = createBuilder(record.name, record.id);
|
|
75
|
+
const shell = kit.batch("Six North Michigan · shell", kit.material(0xffffff, { vertexColors: true }));
|
|
76
|
+
const wall = kit.batch("Six North Michigan · brick and windows", kit.material(0xffffff, { vertexColors: true }));
|
|
77
|
+
const cornices = kit.batch("Six North Michigan · cornices", kit.material(0x747474));
|
|
78
|
+
const lot = orient(polygonOf(projectPlan(record.footprint.coordinates)));
|
|
79
|
+
// The lot's south-east corner, and its Madison and Michigan fronts running from it.
|
|
80
|
+
const corner = lot.reduce((best, p) => (p[0] + p[1] > best[0] + best[1] ? p : best));
|
|
81
|
+
const neighbours = [lot[(lot.indexOf(corner) + 1) % lot.length], lot[(lot.indexOf(corner) + lot.length - 1) % lot.length]];
|
|
82
|
+
const unit = (p) => { const d = Math.hypot(p[0] - corner[0], p[1] - corner[1]); return [(p[0] - corner[0]) / d, (p[1] - corner[1]) / d]; };
|
|
83
|
+
const [west, north] = neighbours[0][0] < neighbours[1][0] ? [unit(neighbours[0]), unit(neighbours[1])] : [unit(neighbours[1]), unit(neighbours[0])];
|
|
84
|
+
const at = (a, b) => [corner[0] + west[0] * a + north[0] * b, corner[1] + west[1] * a + north[1] * b];
|
|
85
|
+
// The inverse of `at`: a point's distances along Madison and Michigan, whose fronts meet
|
|
86
|
+
// a little off square.
|
|
87
|
+
const skew = west[0] * north[1] - west[1] * north[0];
|
|
88
|
+
const inLot = (p) => {
|
|
89
|
+
const [x, z] = [p[0] - corner[0], p[1] - corner[1]];
|
|
90
|
+
return [(x * north[1] - z * north[0]) / skew, (west[0] * z - west[1] * x) / skew];
|
|
91
|
+
};
|
|
92
|
+
const rect = (a0, a1, b0, b1) => orient([at(a0, b0), at(a1, b0), at(a1, b1), at(a0, b1)]);
|
|
93
|
+
const [depth, front] = [Math.max(...lot.map((p) => inLot(p)[0])), Math.max(...lot.map((p) => inLot(p)[1]))];
|
|
94
|
+
const tower = (grow) => rect(-grow, h.towerDepth + grow, h.towerSouth - grow, h.towerNorth + grow);
|
|
95
|
+
// A solid on an outline between two heights.
|
|
96
|
+
const solid = (corners, lo, hi) => {
|
|
97
|
+
planOf(corners).forEach((run) => {
|
|
98
|
+
const a = run.at(0), b = run.at(run.length), n = run.normal(0);
|
|
99
|
+
kit.quad(shell, [[a[0], lo, a[1]], [b[0], lo, b[1]], [b[0], hi, b[1]], [a[0], hi, a[1]]], [[n[0], 0, n[1]]], core);
|
|
100
|
+
});
|
|
101
|
+
paintedSlab(kit, shell, corners, lo, false, roofing);
|
|
102
|
+
paintedSlab(kit, shell, corners, hi, true, roofing);
|
|
103
|
+
};
|
|
104
|
+
solid(lot, 0, h.block);
|
|
105
|
+
solid(tower(0), h.block, h.arches);
|
|
106
|
+
solid(tower(-0.8), h.towerCornice, h.stage);
|
|
107
|
+
// The block's cornice overhangs its walls by a metre, stopping either side of the tower,
|
|
108
|
+
// which rises through it, 2 cm clear of its walls so that the two undersides do not share
|
|
109
|
+
// an edge; the tower's band, cornice and cap are its outline grown or shrunk.
|
|
110
|
+
const [notchNorth, notchSouth, notchBack] = [h.towerNorth + 0.02, h.towerSouth - 0.02, h.towerDepth + 0.02];
|
|
111
|
+
const corniceOutline = orient([at(-1, -1), at(depth + 1, -1), at(depth + 1, front + 1), at(-1, front + 1), at(-1, notchNorth), at(notchBack, notchNorth), at(notchBack, notchSouth), at(-1, notchSouth)]);
|
|
112
|
+
kit.prism(cornices, planOf(corniceOutline), [h.block, h.cornice]);
|
|
113
|
+
kit.prism(cornices, planOf(tower(0.5)), [h.band, h.bandTop]);
|
|
114
|
+
kit.prism(cornices, planOf(tower(1.2)), [h.arches, h.towerCornice]);
|
|
115
|
+
kit.prism(cornices, planOf(tower(-0.3)), [h.stage, h.top]);
|
|
116
|
+
// A wall's skin, one box to a chain the `keep` test accepts, held 2 cm clear of its ends
|
|
117
|
+
// or 9 cm where the outline turns in. `openings` lays a wall's columns out across it,
|
|
118
|
+
// from its start to its end, and says how far each reaches into a window: 0 is brick; a
|
|
119
|
+
// floor's window takes any other; the tower's tall windows 1 and over, its seventeenth
|
|
120
|
+
// floor's 2, its small windows 3, and their heads and the top stage's panel 4. Floors
|
|
121
|
+
// below `fromFloor` stay brick.
|
|
122
|
+
const glassFrom = { brick: 99, glass: 1, floor17: 2, small: 3, arch: 1, head: 4, panel: 4 };
|
|
123
|
+
const skin = (corners, rows, lo, hi, seed, keep, openings, fromFloor = 1) => {
|
|
124
|
+
const plan = planOf(corners), cut = rowsBetween(rows, lo, hi), heights = [cut[0].lo, ...cut.map((row) => row.hi)];
|
|
125
|
+
chainsOf(plan).forEach((chain, index) => {
|
|
126
|
+
if (!chain.runs.every((run) => keep(plan[run])))
|
|
127
|
+
return;
|
|
128
|
+
const first = chain.runs[0], last = chain.runs.at(-1);
|
|
129
|
+
const s0 = turnsAt(plan, first)[0] > 0 ? 0.09 : 0.02, s1 = chain.length - (turnsAt(plan, last)[1] > 0 ? 0.09 : 0.02);
|
|
130
|
+
const [columns, reach] = openings(chain.length, plan[first].at(0), plan[last].at(plan[last].length));
|
|
131
|
+
chainSkin(kit, wall, plan, chain, 0, chain.runs.length - 1, s0, s1, columns, heights, 0.02, 0.07, (bay, r) => {
|
|
132
|
+
const row = cut[r], into = reach(bay);
|
|
133
|
+
if (row.kind === "panel")
|
|
134
|
+
return into >= 4 ? panel : brick;
|
|
135
|
+
if (row.floor < fromFloor)
|
|
136
|
+
return brick;
|
|
137
|
+
return into >= glassFrom[row.kind] ? paneColor(row.floor, bay, seed * 8 + index) : brick;
|
|
138
|
+
}, brick);
|
|
139
|
+
});
|
|
140
|
+
};
|
|
141
|
+
// Windows centred at `centres`, `width` wide, along a wall from its start.
|
|
142
|
+
const windows = (length, centres, width) => {
|
|
143
|
+
const inside = centres.filter((c) => c - width / 2 > 0.1 && c + width / 2 < length - 0.1);
|
|
144
|
+
return [[0, ...inside.flatMap((c) => [c - width / 2, c + width / 2]), length], (bay) => (bay % 2 === 0 && bay <= 2 * inside.length ? 1 : 0)];
|
|
145
|
+
};
|
|
146
|
+
// A position along a wall from its start, given in lot coordinates across it.
|
|
147
|
+
const along = (length, start, end, target, axis) => length * (target - inLot(start)[axis]) / (inLot(end)[axis] - inLot(start)[axis]);
|
|
148
|
+
const michigan = (run) => run.normal(0)[0] > 0.9, party = (run) => run.normal(0)[1] < -0.9;
|
|
149
|
+
// The Michigan front: three windows to each wing either side of the tower, and three to
|
|
150
|
+
// the tower between them, 3 m apart on the centres of the windows above.
|
|
151
|
+
const michiganFront = (length, start, end) => windows(length, [1.6, 3.75, 5.9, 10.75, 13.75, 16.75, 21.6, 23.75, 25.9].map((b) => along(length, start, end, b, 1)), 1.3);
|
|
152
|
+
// Madison, the alley and the north wall: a window every 2.75 m. The north wall is shared
|
|
153
|
+
// with 20 North Michigan, eight storeys high, and stays blank below its ninth floor.
|
|
154
|
+
const punched = (length) => { const bays = Math.round(length / 2.75); return windows(length, Array.from({ length: bays }, (_, i) => length * (i + 0.5) / bays), 1.1); };
|
|
155
|
+
skin(lot, blockRows, 0.25, h.block, 0, michigan, michiganFront);
|
|
156
|
+
skin(lot, blockRows, 0.25, h.block, 1, (run) => !michigan(run) && !party(run), punched);
|
|
157
|
+
skin(lot, blockRows, 0.25, h.block, 6, party, punched, 9);
|
|
158
|
+
// The tower's faces: three windows to a face, centred 3 m apart. A tall window is 2 m
|
|
159
|
+
// wide, its head the middle metre; the seventeenth floor's are 1.3 m and the small ones
|
|
160
|
+
// 1.1 m, all on the same centres.
|
|
161
|
+
const towerFace = (length) => {
|
|
162
|
+
const steps = [-1, -0.65, -0.55, -0.5, 0.5, 0.55, 0.65, 1];
|
|
163
|
+
const columns = [0, ...[-3, 0, 3].flatMap((d) => steps.map((s) => length / 2 + d + s)), length];
|
|
164
|
+
// Bays count from one: a pier, then 1, 2, 3, 4, 3, 2, 1 across each window.
|
|
165
|
+
return [columns, (bay) => (bay > 24 || (bay - 1) % 8 === 0 ? 0 : [0, 1, 2, 3, 4, 3, 2, 1][(bay - 1) % 8])];
|
|
166
|
+
};
|
|
167
|
+
// The top stage's panel, 7.2 m wide in the middle of each face.
|
|
168
|
+
const panelled = (length) => [[0, length / 2 - 3.6, length / 2 + 3.6, length], (bay) => (bay === 2 ? 4 : 0)];
|
|
169
|
+
// Over the block, the tower's Michigan face shows from the block's walls; the cornice
|
|
170
|
+
// hides its other faces' foot.
|
|
171
|
+
skin(tower(0), towerRows, h.block, h.band, 2, michigan, towerFace);
|
|
172
|
+
skin(tower(0), towerRows, h.cornice, h.band, 3, (run) => !michigan(run), towerFace);
|
|
173
|
+
skin(tower(0), towerRows, h.bandTop, h.arches, 4, () => true, towerFace);
|
|
174
|
+
skin(tower(-0.8), towerRows, h.towerCornice, h.stage, 5, () => true, panelled);
|
|
175
|
+
const model = kit.finish({ height: h.top, outlines: [shell, cornices], opacity: 0.16 });
|
|
176
|
+
model.building.position.set(offset[0], 0, offset[1]);
|
|
177
|
+
model.building.userData["geography"] = record;
|
|
178
|
+
model.building.userData["geographicDetail"] = { levels: h, source: "docs/six-north-michigan-reference.md" };
|
|
179
|
+
return model;
|
|
180
|
+
}
|