@a2f0/skyline 0.2.56 → 0.2.57
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/lib/models/borg-warner-geographic.js +2 -5
- package/lib/models/colour-materials.d.ts +2 -2
- package/lib/models/colour-materials.js +1 -10
- package/lib/models/colour-palette.d.ts +1 -1
- package/lib/models/facade-grid.d.ts +7 -0
- package/lib/models/facade-grid.js +17 -0
- package/lib/models/gage-geographic.js +2 -12
- package/lib/models/lake-view-geographic.js +2 -10
- package/lib/models/maclean-center-geographic.js +2 -12
- package/lib/models/material-names.d.ts +2 -0
- package/lib/models/material-names.js +13 -0
- package/lib/models/michigan-boulevard-geographic.js +2 -12
- package/lib/models/monroe-geographic.js +2 -12
- package/lib/models/night-windows.d.ts +1 -1
- package/lib/models/north-michigan-180-geographic.js +2 -10
- package/lib/models/peoples-gas-geographic.js +2 -11
- package/lib/models/railway-exchange-geographic.js +2 -9
- package/lib/models/six-north-michigan-geographic.js +3 -12
- package/lib/models/university-club-geographic.js +2 -12
- package/lib/models/willoughby-tower-geographic.js +3 -12
- package/package.json +1 -1
- package/site/models/borg-warner-geographic.js +2 -5
- package/site/models/colour-materials.js +1 -10
- package/site/models/facade-grid.js +17 -0
- package/site/models/gage-geographic.js +2 -12
- package/site/models/lake-view-geographic.js +2 -10
- package/site/models/maclean-center-geographic.js +2 -12
- package/site/models/material-names.js +13 -0
- package/site/models/michigan-boulevard-geographic.js +2 -12
- package/site/models/monroe-geographic.js +2 -12
- package/site/models/north-michigan-180-geographic.js +2 -10
- package/site/models/peoples-gas-geographic.js +2 -11
- package/site/models/railway-exchange-geographic.js +2 -9
- package/site/models/six-north-michigan-geographic.js +3 -12
- package/site/models/university-club-geographic.js +2 -12
- package/site/models/willoughby-tower-geographic.js +3 -12
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as THREE from "../vendor/three-r186.js";
|
|
2
2
|
import { createBuilder, polygonOf } from "./building-kit.js";
|
|
3
|
-
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt } from "./facade-grid.js";
|
|
3
|
+
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt, lotFrame } from "./facade-grid.js";
|
|
4
4
|
// The Borg-Warner Building, 200 South Michigan Avenue (A. Epstein & Sons with William
|
|
5
5
|
// Lescaze, 1958): the geographic layout's model, on the mapped outline 124873918. The
|
|
6
6
|
// original layout has no model of it; the drawing shows it across Adams from Peoples Gas.
|
|
@@ -69,10 +69,7 @@ export function createBorgWarnerGeographicBuilding(record, projectPlan, offset)
|
|
|
69
69
|
const corner = lot.reduce((best, p) => (p[0] + p[1] > best[0] + best[1] ? p : best));
|
|
70
70
|
const northEast = lot.reduce((best, p) => (p[0] - p[1] > best[0] - best[1] ? p : best));
|
|
71
71
|
const southWest = lot.reduce((best, p) => (p[1] - p[0] > best[1] - best[0] ? p : best));
|
|
72
|
-
const
|
|
73
|
-
const west = unit(southWest), north = unit(northEast);
|
|
74
|
-
const at = (a, b) => [corner[0] + west[0] * a + north[0] * b, corner[1] + west[1] * a + north[1] * b];
|
|
75
|
-
const rect = (a0, a1, b0, b1) => orient([at(a0, b0), at(a1, b0), at(a1, b1), at(a0, b1)]);
|
|
72
|
+
const { rect } = lotFrame(corner, southWest, northEast);
|
|
76
73
|
planOf(lot).forEach((run) => {
|
|
77
74
|
const a = run.at(0), b = run.at(run.length), n = run.normal(0);
|
|
78
75
|
kit.quad(shell, [[a[0], 0, a[1]], [b[0], 0, b[1]], [b[0], h.roof, b[1]], [a[0], h.roof, a[1]]], [[n[0], 0, n[1]]], core);
|
|
@@ -2,8 +2,8 @@ import type { BuildingModel } from "./building-kit.js";
|
|
|
2
2
|
import type { Daylight } from "../study-types.js";
|
|
3
3
|
import { type ReflectionColours } from "./colour-reflections.js";
|
|
4
4
|
import { type NightLighting } from "./night-windows.js";
|
|
5
|
-
|
|
6
|
-
export type MaterialName
|
|
5
|
+
import type { MaterialName } from "./material-names.js";
|
|
6
|
+
export { materialNames, type MaterialName } from "./material-names.js";
|
|
7
7
|
export type Tones = Readonly<Record<number, MaterialName>>;
|
|
8
8
|
export type Batch = readonly [material: MaterialName, tones?: Tones];
|
|
9
9
|
export type BuildingMaterials = Readonly<Record<string, Batch>>;
|
|
@@ -9,16 +9,7 @@ import { nightWindowMask } from "./night-windows.js";
|
|
|
9
9
|
// and each mesh's batch, the part of its name after the last " · ", or that without a trailing
|
|
10
10
|
// number, so "glazing 3" reads as "glazing". A surface is its batch's material unless its grey
|
|
11
11
|
// names another.
|
|
12
|
-
export
|
|
13
|
-
"neutral", "glass", "green glass", "blue-green glass", "bronze glass", "lit window", "dim window", "lamp",
|
|
14
|
-
"limestone", "marble", "white granite", "granite", "dark granite", "slate",
|
|
15
|
-
"white terracotta", "pink terracotta", "green tile", "brick", "common brick", "orange brick", "brown brick", "buff brick", "glazed brick",
|
|
16
|
-
"concrete", "precast", "copper", "maroon", "blue enamel", "bronze", "dark metal", "aluminium", "stainless", "opaque spandrel",
|
|
17
|
-
// Parts the photographs show on their own, named as the night first showed them: crown glass
|
|
18
|
-
// and crown lights, an emblem screen and the lights in its bands, a sign's board and letters,
|
|
19
|
-
// and a lit cap.
|
|
20
|
-
"crown glass", "crown lights", "screen", "band lights", "sign board", "sign letters", "cap lights",
|
|
21
|
-
];
|
|
12
|
+
export { materialNames } from "./material-names.js";
|
|
22
13
|
// A batch's lit and dim office windows.
|
|
23
14
|
const windows = (lit, dim) => ({ [lit]: "lit window", [dim]: "dim window" });
|
|
24
15
|
export const colourMaterials = {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { MaterialName } from "./
|
|
1
|
+
import type { MaterialName } from "./material-names.js";
|
|
2
2
|
export type Measurement = number | MaterialName | null;
|
|
3
3
|
export declare const measuredColours: Readonly<Record<string, Readonly<Partial<Record<MaterialName, Measurement>>>>>;
|
|
4
4
|
export declare const daylightColours: {
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import * as THREE from "../vendor/three-r186.js";
|
|
2
2
|
import type { BatchData, Builder, Plan, Run, Vec2 } from "./building-kit.js";
|
|
3
3
|
export declare const orient: (corners: Vec2[]) => Vec2[];
|
|
4
|
+
export declare function lotFrame(corner: Vec2, toWest: Vec2, toNorth: Vec2): {
|
|
5
|
+
west: Vec2;
|
|
6
|
+
north: Vec2;
|
|
7
|
+
at: (a: number, b: number) => Vec2;
|
|
8
|
+
inLot: (p: Vec2) => Vec2;
|
|
9
|
+
rect: (a0: number, a1: number, b0: number, b1: number) => Vec2[];
|
|
10
|
+
};
|
|
4
11
|
export declare const planOf: (corners: Vec2[]) => Plan;
|
|
5
12
|
export declare const turnAt: (a: Run, b: Run) => number;
|
|
6
13
|
export interface Chain {
|
|
@@ -4,6 +4,23 @@ export const orient = (corners) => {
|
|
|
4
4
|
const area = corners.reduce((sum, [x, z], i) => { const [x2, z2] = corners[(i + 1) % corners.length]; return sum + x * z2 - x2 * z; }, 0);
|
|
5
5
|
return area < 0 ? corners : [...corners].reverse();
|
|
6
6
|
};
|
|
7
|
+
// A lot's frame from the corner its fronts run from: `west` and `north` are the unit
|
|
8
|
+
// directions from `corner` toward two other points, `at(a, b)` is the point `a` along `west`
|
|
9
|
+
// and `b` along `north`, `inLot` is its inverse, a point's distances along the two fronts,
|
|
10
|
+
// which can meet a little off square, and `rect` is the oriented outline from a0 to a1 along
|
|
11
|
+
// `west` and b0 to b1 along `north`.
|
|
12
|
+
export function lotFrame(corner, toWest, toNorth) {
|
|
13
|
+
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]; };
|
|
14
|
+
const west = unit(toWest), north = unit(toNorth);
|
|
15
|
+
const at = (a, b) => [corner[0] + west[0] * a + north[0] * b, corner[1] + west[1] * a + north[1] * b];
|
|
16
|
+
const skew = west[0] * north[1] - west[1] * north[0];
|
|
17
|
+
const inLot = (p) => {
|
|
18
|
+
const [x, z] = [p[0] - corner[0], p[1] - corner[1]];
|
|
19
|
+
return [(x * north[1] - z * north[0]) / skew, (west[0] * z - west[1] * x) / skew];
|
|
20
|
+
};
|
|
21
|
+
const rect = (a0, a1, b0, b1) => orient([at(a0, b0), at(a1, b0), at(a1, b1), at(a0, b1)]);
|
|
22
|
+
return { west, north, at, inLot, rect };
|
|
23
|
+
}
|
|
7
24
|
export const planOf = (corners) => corners.map((corner, i) => line(corner, corners[(i + 1) % corners.length]));
|
|
8
25
|
// The turn from run a into run b at their shared corner; negative where the outline turns
|
|
9
26
|
// out (a convex corner) and positive where it turns in.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as THREE from "../vendor/three-r186.js";
|
|
2
2
|
import { createBuilder, polygonOf } from "./building-kit.js";
|
|
3
|
-
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt } from "./facade-grid.js";
|
|
3
|
+
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt, lotFrame } from "./facade-grid.js";
|
|
4
4
|
// The Gage Building, 18 South Michigan Avenue (Holabird & Roche, with a front by Louis
|
|
5
5
|
// Sullivan, 1899; four storeys added in 1902): the geographic layout's model, on the mapped
|
|
6
6
|
// outline 124865450. The original layout has no model of it; the drawing shows its Michigan
|
|
@@ -65,17 +65,7 @@ export function createGageGeographicBuilding(record, projectPlan, offset) {
|
|
|
65
65
|
const corner = lot.reduce((best, p) => (p[0] + p[1] > best[0] + best[1] ? p : best));
|
|
66
66
|
const northEast = lot.reduce((best, p) => (p[0] - p[1] > best[0] - best[1] ? p : best));
|
|
67
67
|
const southWest = lot.reduce((best, p) => (p[1] - p[0] > best[1] - best[0] ? p : best));
|
|
68
|
-
const
|
|
69
|
-
const west = unit(southWest), north = unit(northEast);
|
|
70
|
-
const at = (a, b) => [corner[0] + west[0] * a + north[0] * b, corner[1] + west[1] * a + north[1] * b];
|
|
71
|
-
// The inverse of `at`: a point's distances along the south wall and the Michigan front,
|
|
72
|
-
// which meet a little off square.
|
|
73
|
-
const skew = west[0] * north[1] - west[1] * north[0];
|
|
74
|
-
const inLot = (p) => {
|
|
75
|
-
const [x, z] = [p[0] - corner[0], p[1] - corner[1]];
|
|
76
|
-
return [(x * north[1] - z * north[0]) / skew, (west[0] * z - west[1] * x) / skew];
|
|
77
|
-
};
|
|
78
|
-
const rect = (a0, a1, b0, b1) => orient([at(a0, b0), at(a1, b0), at(a1, b1), at(a0, b1)]);
|
|
68
|
+
const { inLot, rect } = lotFrame(corner, southWest, northEast);
|
|
79
69
|
planOf(lot).forEach((run) => {
|
|
80
70
|
const a = run.at(0), b = run.at(run.length), n = run.normal(0);
|
|
81
71
|
kit.quad(shell, [[a[0], 0, a[1]], [b[0], 0, b[1]], [b[0], h.top, b[1]], [a[0], h.top, a[1]]], [[n[0], 0, n[1]]], core);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as THREE from "../vendor/three-r186.js";
|
|
2
2
|
import { createBuilder, polygonOf } from "./building-kit.js";
|
|
3
|
-
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt } from "./facade-grid.js";
|
|
3
|
+
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt, lotFrame } from "./facade-grid.js";
|
|
4
4
|
// The Lake View Building, 116 South Michigan Avenue (Jenney, Mundie & Jensen; its top five
|
|
5
5
|
// storeys added by them in 1912): the geographic layout's model, on the mapped outline
|
|
6
6
|
// 145498711. The original layout has no model of it; the drawing shows it between Peoples
|
|
@@ -62,15 +62,7 @@ export function createLakeViewGeographicBuilding(record, projectPlan, offset) {
|
|
|
62
62
|
const corner = lot.reduce((best, p) => (p[0] + p[1] > best[0] + best[1] ? p : best));
|
|
63
63
|
const northEast = lot.reduce((best, p) => (p[0] - p[1] > best[0] - best[1] ? p : best));
|
|
64
64
|
const neighbours = [lot[(lot.indexOf(corner) + 1) % lot.length], lot[(lot.indexOf(corner) + lot.length - 1) % lot.length]];
|
|
65
|
-
const
|
|
66
|
-
const west = unit(neighbours[0][0] < neighbours[1][0] ? neighbours[0] : neighbours[1]), north = unit(northEast);
|
|
67
|
-
// A point's distances along the south wall and the Michigan front, which meet a little
|
|
68
|
-
// off square.
|
|
69
|
-
const skew = west[0] * north[1] - west[1] * north[0];
|
|
70
|
-
const inLot = (p) => {
|
|
71
|
-
const [x, z] = [p[0] - corner[0], p[1] - corner[1]];
|
|
72
|
-
return [(x * north[1] - z * north[0]) / skew, (west[0] * z - west[1] * x) / skew];
|
|
73
|
-
};
|
|
65
|
+
const { inLot } = lotFrame(corner, neighbours[0][0] < neighbours[1][0] ? neighbours[0] : neighbours[1], northEast);
|
|
74
66
|
const front = inLot(northEast)[1];
|
|
75
67
|
planOf(lot).forEach((run) => {
|
|
76
68
|
const a = run.at(0), b = run.at(run.length), n = run.normal(0);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as THREE from "../vendor/three-r186.js";
|
|
2
2
|
import { createBuilder, polygonOf } from "./building-kit.js";
|
|
3
|
-
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt } from "./facade-grid.js";
|
|
3
|
+
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt, lotFrame } from "./facade-grid.js";
|
|
4
4
|
// The MacLean Center, 112 South Michigan Avenue, built as the Illinois Athletic Club
|
|
5
5
|
// (Barnett, Haynes & Barnett, 1908) and raised six floors by Swann & Weiskopf in 1985: the
|
|
6
6
|
// geographic layout's model, on the mapped outline 145498712. The original layout has no
|
|
@@ -78,18 +78,8 @@ export function createMacleanCenterGeographicBuilding(record, projectPlan, offse
|
|
|
78
78
|
const corner = lot.reduce((best, p) => (p[0] + p[1] > best[0] + best[1] ? p : best));
|
|
79
79
|
const northEast = lot.reduce((best, p) => (p[0] - p[1] > best[0] - best[1] ? p : best));
|
|
80
80
|
const neighbours = [lot[(lot.indexOf(corner) + 1) % lot.length], lot[(lot.indexOf(corner) + lot.length - 1) % lot.length]];
|
|
81
|
-
const
|
|
82
|
-
const west = unit(neighbours[0][0] < neighbours[1][0] ? neighbours[0] : neighbours[1]), north = unit(northEast);
|
|
83
|
-
const at = (a, b) => [corner[0] + west[0] * a + north[0] * b, corner[1] + west[1] * a + north[1] * b];
|
|
84
|
-
// The inverse of `at`: a point's distances along the south wall and the Michigan front,
|
|
85
|
-
// which meet a little off square.
|
|
86
|
-
const skew = west[0] * north[1] - west[1] * north[0];
|
|
87
|
-
const inLot = (p) => {
|
|
88
|
-
const [x, z] = [p[0] - corner[0], p[1] - corner[1]];
|
|
89
|
-
return [(x * north[1] - z * north[0]) / skew, (west[0] * z - west[1] * x) / skew];
|
|
90
|
-
};
|
|
81
|
+
const { inLot, rect } = lotFrame(corner, neighbours[0][0] < neighbours[1][0] ? neighbours[0] : neighbours[1], northEast);
|
|
91
82
|
const front = inLot(northEast)[1];
|
|
92
|
-
const rect = (a0, a1, b0, b1) => orient([at(a0, b0), at(a1, b0), at(a1, b1), at(a0, b1)]);
|
|
93
83
|
planOf(lot).forEach((run) => {
|
|
94
84
|
const a = run.at(0), b = run.at(run.length), n = run.normal(0);
|
|
95
85
|
kit.quad(shell, [[a[0], 0, a[1]], [b[0], 0, b[1]], [b[0], h.top, b[1]], [a[0], h.top, a[1]]], [[n[0], 0, n[1]]], core);
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const materialNames: readonly ["neutral", "glass", "green glass", "blue-green glass", "bronze glass", "lit window", "dim window", "lamp", "limestone", "marble", "white granite", "granite", "dark granite", "slate", "white terracotta", "pink terracotta", "green tile", "brick", "common brick", "orange brick", "brown brick", "buff brick", "glazed brick", "concrete", "precast", "copper", "maroon", "blue enamel", "bronze", "dark metal", "aluminium", "stainless", "opaque spandrel", "crown glass", "crown lights", "screen", "band lights", "sign board", "sign letters", "cap lights"];
|
|
2
|
+
export type MaterialName = (typeof materialNames)[number];
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// The colour trial's named materials (https://github.com/a2f0/skyline/issues/115), which
|
|
2
|
+
// colour-materials.ts assigns to every surface, colour-palette.ts measures and night-windows.ts
|
|
3
|
+
// lights. They live apart from all three so that each can name them without importing another.
|
|
4
|
+
export const materialNames = [
|
|
5
|
+
"neutral", "glass", "green glass", "blue-green glass", "bronze glass", "lit window", "dim window", "lamp",
|
|
6
|
+
"limestone", "marble", "white granite", "granite", "dark granite", "slate",
|
|
7
|
+
"white terracotta", "pink terracotta", "green tile", "brick", "common brick", "orange brick", "brown brick", "buff brick", "glazed brick",
|
|
8
|
+
"concrete", "precast", "copper", "maroon", "blue enamel", "bronze", "dark metal", "aluminium", "stainless", "opaque spandrel",
|
|
9
|
+
// Parts the photographs show on their own, named as the night first showed them: crown glass
|
|
10
|
+
// and crown lights, an emblem screen and the lights in its bands, a sign's board and letters,
|
|
11
|
+
// and a lit cap.
|
|
12
|
+
"crown glass", "crown lights", "screen", "band lights", "sign board", "sign letters", "cap lights",
|
|
13
|
+
];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as THREE from "../vendor/three-r186.js";
|
|
2
2
|
import { createBuilder, polygonOf } from "./building-kit.js";
|
|
3
|
-
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt } from "./facade-grid.js";
|
|
3
|
+
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt, lotFrame } from "./facade-grid.js";
|
|
4
4
|
// The Michigan Boulevard Building, 30 North Michigan Avenue (Jarvis Hunt, 1914, fifteen
|
|
5
5
|
// storeys; six added by Hunt in 1923): the geographic layout's model, on the mapped outline
|
|
6
6
|
// 126982630. The original layout has no model of it; the drawing shows its Michigan front
|
|
@@ -68,18 +68,8 @@ export function createMichiganBoulevardGeographicBuilding(record, projectPlan, o
|
|
|
68
68
|
const corner = lot.reduce((best, p) => (p[0] + p[1] > best[0] + best[1] ? p : best));
|
|
69
69
|
const northEast = lot.reduce((best, p) => (p[0] - p[1] > best[0] - best[1] ? p : best));
|
|
70
70
|
const neighbours = [lot[(lot.indexOf(corner) + 1) % lot.length], lot[(lot.indexOf(corner) + lot.length - 1) % lot.length]];
|
|
71
|
-
const
|
|
72
|
-
const west = unit(neighbours[0][0] < neighbours[1][0] ? neighbours[0] : neighbours[1]), north = unit(northEast);
|
|
73
|
-
const at = (a, b) => [corner[0] + west[0] * a + north[0] * b, corner[1] + west[1] * a + north[1] * b];
|
|
74
|
-
// The inverse of `at`: a point's distances along the south wall and the Michigan front,
|
|
75
|
-
// which meet a little off square.
|
|
76
|
-
const skew = west[0] * north[1] - west[1] * north[0];
|
|
77
|
-
const inLot = (p) => {
|
|
78
|
-
const [x, z] = [p[0] - corner[0], p[1] - corner[1]];
|
|
79
|
-
return [(x * north[1] - z * north[0]) / skew, (west[0] * z - west[1] * x) / skew];
|
|
80
|
-
};
|
|
71
|
+
const { inLot, rect } = lotFrame(corner, neighbours[0][0] < neighbours[1][0] ? neighbours[0] : neighbours[1], northEast);
|
|
81
72
|
const front = inLot(northEast)[1];
|
|
82
|
-
const rect = (a0, a1, b0, b1) => orient([at(a0, b0), at(a1, b0), at(a1, b1), at(a0, b1)]);
|
|
83
73
|
planOf(lot).forEach((run) => {
|
|
84
74
|
const a = run.at(0), b = run.at(run.length), n = run.normal(0);
|
|
85
75
|
kit.quad(shell, [[a[0], 0, a[1]], [b[0], 0, b[1]], [b[0], h.top, b[1]], [a[0], h.top, a[1]]], [[n[0], 0, n[1]]], core);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as THREE from "../vendor/three-r186.js";
|
|
2
2
|
import { createBuilder, polygonOf } from "./building-kit.js";
|
|
3
|
-
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt } from "./facade-grid.js";
|
|
3
|
+
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt, lotFrame } from "./facade-grid.js";
|
|
4
4
|
// The Monroe Building, 104 South Michigan Avenue (Holabird & Roche, 1912): the geographic
|
|
5
5
|
// layout's model, on the mapped outline 145498713. The original layout has no model of it;
|
|
6
6
|
// the drawing shows it left of the University Club, across Monroe Street.
|
|
@@ -71,17 +71,7 @@ export function createMonroeGeographicBuilding(record, projectPlan, offset) {
|
|
|
71
71
|
const corner = lot.reduce((best, p) => (p[0] + p[1] > best[0] + best[1] ? p : best));
|
|
72
72
|
const northEast = lot.reduce((best, p) => (p[0] - p[1] > best[0] - best[1] ? p : best));
|
|
73
73
|
const neighbours = [lot[(lot.indexOf(corner) + 1) % lot.length], lot[(lot.indexOf(corner) + lot.length - 1) % lot.length]];
|
|
74
|
-
const
|
|
75
|
-
const west = unit(neighbours[0][0] < neighbours[1][0] ? neighbours[0] : neighbours[1]), north = unit(northEast);
|
|
76
|
-
const at = (a, b) => [corner[0] + west[0] * a + north[0] * b, corner[1] + west[1] * a + north[1] * b];
|
|
77
|
-
// The inverse of `at`: a point's distances along the south wall and the Michigan front,
|
|
78
|
-
// which meet a little off square.
|
|
79
|
-
const skew = west[0] * north[1] - west[1] * north[0];
|
|
80
|
-
const inLot = (p) => {
|
|
81
|
-
const [x, z] = [p[0] - corner[0], p[1] - corner[1]];
|
|
82
|
-
return [(x * north[1] - z * north[0]) / skew, (west[0] * z - west[1] * x) / skew];
|
|
83
|
-
};
|
|
84
|
-
const rect = (a0, a1, b0, b1) => orient([at(a0, b0), at(a1, b0), at(a1, b1), at(a0, b1)]);
|
|
74
|
+
const { at, inLot, rect } = lotFrame(corner, neighbours[0][0] < neighbours[1][0] ? neighbours[0] : neighbours[1], northEast);
|
|
85
75
|
const lift = ([x, z], y) => [x, y, z];
|
|
86
76
|
// The lot's four corners, in lot coordinates: its north and south walls are a little out
|
|
87
77
|
// of parallel.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type * as THREE from "../vendor/three-r186.js";
|
|
2
|
-
import type { MaterialName } from "./
|
|
2
|
+
import type { MaterialName } from "./material-names.js";
|
|
3
3
|
export interface NightLighting {
|
|
4
4
|
/** Sunset/dawn transition, from daylight (0) to full darkness (1). */
|
|
5
5
|
darkness: number;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as THREE from "../vendor/three-r186.js";
|
|
2
2
|
import { createBuilder, polygonOf } from "./building-kit.js";
|
|
3
|
-
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt } from "./facade-grid.js";
|
|
3
|
+
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt, lotFrame } from "./facade-grid.js";
|
|
4
4
|
// 180 North Michigan Avenue, the Harvester Building (1927): the geographic layout's model,
|
|
5
5
|
// on the mapped outline 210671714. The original layout has no model of it; the drawing
|
|
6
6
|
// shows its south wall behind Millennium Park Plaza, which hides its Michigan front.
|
|
@@ -59,15 +59,7 @@ export function createNorthMichigan180GeographicBuilding(record, projectPlan, of
|
|
|
59
59
|
const corner = lot.reduce((best, p) => (p[0] + p[1] > best[0] + best[1] ? p : best));
|
|
60
60
|
const northEast = lot.reduce((best, p) => (p[0] - p[1] > best[0] - best[1] ? p : best));
|
|
61
61
|
const neighbours = [lot[(lot.indexOf(corner) + 1) % lot.length], lot[(lot.indexOf(corner) + lot.length - 1) % lot.length]];
|
|
62
|
-
const
|
|
63
|
-
const west = unit(neighbours[0][0] < neighbours[1][0] ? neighbours[0] : neighbours[1]), north = unit(northEast);
|
|
64
|
-
// A point's distances along the south wall and the Michigan front, which meet a little off
|
|
65
|
-
// square.
|
|
66
|
-
const skew = west[0] * north[1] - west[1] * north[0];
|
|
67
|
-
const inLot = (p) => {
|
|
68
|
-
const [x, z] = [p[0] - corner[0], p[1] - corner[1]];
|
|
69
|
-
return [(x * north[1] - z * north[0]) / skew, (west[0] * z - west[1] * x) / skew];
|
|
70
|
-
};
|
|
62
|
+
const { inLot } = lotFrame(corner, neighbours[0][0] < neighbours[1][0] ? neighbours[0] : neighbours[1], northEast);
|
|
71
63
|
planOf(lot).forEach((run) => {
|
|
72
64
|
const a = run.at(0), b = run.at(run.length), n = run.normal(0);
|
|
73
65
|
kit.quad(shell, [[a[0], 0, a[1]], [b[0], 0, b[1]], [b[0], h.top, b[1]], [a[0], h.top, a[1]]], [[n[0], 0, n[1]]], core);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as THREE from "../vendor/three-r186.js";
|
|
2
2
|
import { createBuilder, polygonOf } from "./building-kit.js";
|
|
3
|
-
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt } from "./facade-grid.js";
|
|
3
|
+
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt, lotFrame } from "./facade-grid.js";
|
|
4
4
|
// The Peoples Gas Building, 122 South Michigan Avenue (D. H. Burnham & Co., 1911): the
|
|
5
5
|
// geographic layout's model, on the mapped outline 145498710 and its parts. The original
|
|
6
6
|
// layout has no model of it; the drawing shows it between the Lake View Building and Adams
|
|
@@ -90,16 +90,7 @@ export function createPeoplesGasGeographicBuilding(record, projectPlan, offset)
|
|
|
90
90
|
const corner = lot.reduce((best, p) => (p[0] + p[1] > best[0] + best[1] ? p : best));
|
|
91
91
|
const northEast = lot.reduce((best, p) => (p[0] - p[1] > best[0] - best[1] ? p : best));
|
|
92
92
|
const southWest = lot.reduce((best, p) => (p[1] - p[0] > best[1] - best[0] ? p : best));
|
|
93
|
-
const
|
|
94
|
-
const west = unit(southWest), north = unit(northEast);
|
|
95
|
-
const at = (a, b) => [corner[0] + west[0] * a + north[0] * b, corner[1] + west[1] * a + north[1] * b];
|
|
96
|
-
// The inverse of `at`: a point's distances along the Adams and Michigan fronts, which
|
|
97
|
-
// meet a little off square.
|
|
98
|
-
const skew = west[0] * north[1] - west[1] * north[0];
|
|
99
|
-
const inLot = (p) => {
|
|
100
|
-
const [x, z] = [p[0] - corner[0], p[1] - corner[1]];
|
|
101
|
-
return [(x * north[1] - z * north[0]) / skew, (west[0] * z - west[1] * x) / skew];
|
|
102
|
-
};
|
|
93
|
+
const { west, north, at, inLot } = lotFrame(corner, southWest, northEast);
|
|
103
94
|
const [adams, michigan] = [inLot(southWest)[0], inLot(northEast)[1]];
|
|
104
95
|
// Corners and edges by value, since parts share the outline's nodes.
|
|
105
96
|
const key = (p) => `${p[0].toFixed(3)},${p[1].toFixed(3)}`;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as THREE from "../vendor/three-r186.js";
|
|
2
2
|
import { createBuilder, polygonOf } from "./building-kit.js";
|
|
3
|
-
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt } from "./facade-grid.js";
|
|
3
|
+
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt, lotFrame } from "./facade-grid.js";
|
|
4
4
|
// The Railway Exchange Building, 224 South Michigan Avenue (Frederick P. Dinkelberg of D. H.
|
|
5
5
|
// Burnham & Co., 1904): the geographic layout's model, on the mapped outline 124873931. The
|
|
6
6
|
// original layout has no model of it; the drawing shows it at Michigan and Jackson, left of
|
|
@@ -71,14 +71,7 @@ export function createRailwayExchangeGeographicBuilding(record, projectPlan, off
|
|
|
71
71
|
const northEast = lot.reduce((best, p) => (p[0] - p[1] > best[0] - best[1] ? p : best));
|
|
72
72
|
const southWest = lot.reduce((best, p) => (p[1] - p[0] > best[1] - best[0] ? p : best));
|
|
73
73
|
const northWest = lot.reduce((best, p) => (-p[0] - p[1] > -best[0] - best[1] ? p : best));
|
|
74
|
-
const
|
|
75
|
-
const west = unit(southWest), north = unit(northEast);
|
|
76
|
-
const at = (a, b) => [corner[0] + west[0] * a + north[0] * b, corner[1] + west[1] * a + north[1] * b];
|
|
77
|
-
const skew = west[0] * north[1] - west[1] * north[0];
|
|
78
|
-
const inLot = (p) => {
|
|
79
|
-
const [x, z] = [p[0] - corner[0], p[1] - corner[1]];
|
|
80
|
-
return [(x * north[1] - z * north[0]) / skew, (west[0] * z - west[1] * x) / skew];
|
|
81
|
-
};
|
|
74
|
+
const { at, inLot } = lotFrame(corner, southWest, northEast);
|
|
82
75
|
const [jackson, michigan] = [inLot(southWest)[0], inLot(northEast)[1]];
|
|
83
76
|
const lift = ([x, z], y) => [x, y, z];
|
|
84
77
|
// The walls to the roof's foot.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as THREE from "../vendor/three-r186.js";
|
|
2
2
|
import { createBuilder, polygonOf } from "./building-kit.js";
|
|
3
|
-
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt } from "./facade-grid.js";
|
|
3
|
+
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt, lotFrame } from "./facade-grid.js";
|
|
4
4
|
// Six North Michigan, the Montgomery Ward Building (Schmidt, Garden & Martin, 1899; four
|
|
5
5
|
// floors added by Holabird & Roche, 1923): the geographic layout's model, on the mapped
|
|
6
6
|
// outline 126982631. The original layout has no model of it; the drawing shows it right of
|
|
@@ -79,17 +79,8 @@ export function createSixNorthMichiganGeographicBuilding(record, projectPlan, of
|
|
|
79
79
|
// The lot's south-east corner, and its Madison and Michigan fronts running from it.
|
|
80
80
|
const corner = lot.reduce((best, p) => (p[0] + p[1] > best[0] + best[1] ? p : best));
|
|
81
81
|
const neighbours = [lot[(lot.indexOf(corner) + 1) % lot.length], lot[(lot.indexOf(corner) + lot.length - 1) % lot.length]];
|
|
82
|
-
const
|
|
83
|
-
const
|
|
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)]);
|
|
82
|
+
const [westward, northward] = neighbours[0][0] < neighbours[1][0] ? [neighbours[0], neighbours[1]] : [neighbours[1], neighbours[0]];
|
|
83
|
+
const { at, inLot, rect } = lotFrame(corner, westward, northward);
|
|
93
84
|
const [depth, front] = [Math.max(...lot.map((p) => inLot(p)[0])), Math.max(...lot.map((p) => inLot(p)[1]))];
|
|
94
85
|
const tower = (grow) => rect(-grow, h.towerDepth + grow, h.towerSouth - grow, h.towerNorth + grow);
|
|
95
86
|
// A solid on an outline between two heights.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as THREE from "../vendor/three-r186.js";
|
|
2
2
|
import { createBuilder, polygonOf } from "./building-kit.js";
|
|
3
|
-
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt } from "./facade-grid.js";
|
|
3
|
+
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt, lotFrame } from "./facade-grid.js";
|
|
4
4
|
// The University Club of Chicago, 76 East Monroe Street (Holabird & Roche, 1909): the
|
|
5
5
|
// geographic layout's model, on the mapped outline 126982632. The original layout has no
|
|
6
6
|
// model of it; the drawing shows it left of Willoughby Tower, behind the Monroe Building.
|
|
@@ -81,18 +81,8 @@ export function createUniversityClubGeographicBuilding(record, projectPlan, offs
|
|
|
81
81
|
const corner = lot.reduce((best, p) => (p[0] + p[1] > best[0] + best[1] ? p : best));
|
|
82
82
|
const northEast = lot.reduce((best, p) => (p[0] - p[1] > best[0] - best[1] ? p : best));
|
|
83
83
|
const neighbours = [lot[(lot.indexOf(corner) + 1) % lot.length], lot[(lot.indexOf(corner) + lot.length - 1) % lot.length]];
|
|
84
|
-
const
|
|
85
|
-
const west = unit(neighbours[0][0] < neighbours[1][0] ? neighbours[0] : neighbours[1]), north = unit(northEast);
|
|
86
|
-
const at = (a, b) => [corner[0] + west[0] * a + north[0] * b, corner[1] + west[1] * a + north[1] * b];
|
|
87
|
-
// The inverse of `at`: a point's distances along Monroe and Michigan, whose fronts meet a
|
|
88
|
-
// little off square.
|
|
89
|
-
const skew = west[0] * north[1] - west[1] * north[0];
|
|
90
|
-
const inLot = (p) => {
|
|
91
|
-
const [x, z] = [p[0] - corner[0], p[1] - corner[1]];
|
|
92
|
-
return [(x * north[1] - z * north[0]) / skew, (west[0] * z - west[1] * x) / skew];
|
|
93
|
-
};
|
|
84
|
+
const { at, inLot, rect } = lotFrame(corner, neighbours[0][0] < neighbours[1][0] ? neighbours[0] : neighbours[1], northEast);
|
|
94
85
|
const [length, depth] = [Math.max(...lot.map((p) => inLot(p)[0])), inLot(northEast)[1]];
|
|
95
|
-
const rect = (a0, a1, b0, b1) => orient([at(a0, b0), at(a1, b0), at(a1, b1), at(a0, b1)]);
|
|
96
86
|
const lift = ([x, z], y) => [x, y, z];
|
|
97
87
|
// The main block, to the parapet's top.
|
|
98
88
|
planOf(lot).forEach((run) => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as THREE from "../vendor/three-r186.js";
|
|
2
2
|
import { createBuilder, inside, polygonOf } from "./building-kit.js";
|
|
3
|
-
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt } from "./facade-grid.js";
|
|
3
|
+
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt, lotFrame } from "./facade-grid.js";
|
|
4
4
|
// Willoughby Tower, 8 South Michigan Avenue (Samuel N. Crowen, 1929): the geographic
|
|
5
5
|
// layout's model, on the mapped outline 124873939. The original layout has no model of it;
|
|
6
6
|
// the drawing shows it left of Six North Michigan, outside the excerpt it is fitted to.
|
|
@@ -64,10 +64,8 @@ export function createWilloughbyTowerGeographicBuilding(record, projectPlan, off
|
|
|
64
64
|
// The lot's south-east corner, and its south wall and Michigan front running from it.
|
|
65
65
|
const corner = lot.reduce((best, p) => (p[0] + p[1] > best[0] + best[1] ? p : best));
|
|
66
66
|
const neighbours = [lot[(lot.indexOf(corner) + 1) % lot.length], lot[(lot.indexOf(corner) + lot.length - 1) % lot.length]];
|
|
67
|
-
const
|
|
68
|
-
const
|
|
69
|
-
const at = (a, b) => [corner[0] + west[0] * a + north[0] * b, corner[1] + west[1] * a + north[1] * b];
|
|
70
|
-
const rect = (a0, a1, b0, b1) => orient([at(a0, b0), at(a1, b0), at(a1, b1), at(a0, b1)]);
|
|
67
|
+
const [westward, northward] = neighbours[0][0] < neighbours[1][0] ? [neighbours[0], neighbours[1]] : [neighbours[1], neighbours[0]];
|
|
68
|
+
const { west, at, inLot, rect } = lotFrame(corner, westward, northward);
|
|
71
69
|
// The south wall's length: the farthest lot corner on its line.
|
|
72
70
|
const southWall = Math.max(...lot.filter((p) => Math.abs((p[0] - corner[0]) * west[1] - (p[1] - corner[1]) * west[0]) < 0.5).map((p) => (p[0] - corner[0]) * west[0] + (p[1] - corner[1]) * west[1]));
|
|
73
71
|
const shaft = rect(0, h.shaftWidth, 0, h.shaftDepth), shoulder = rect(h.shaftWidth, southWall, 0, h.shaftDepth), crown = rect(h.crownEnds, h.shaftWidth - h.crownEnds, h.crownSides, h.shaftDepth - h.crownSides);
|
|
@@ -131,13 +129,6 @@ export function createWilloughbyTowerGeographicBuilding(record, projectPlan, off
|
|
|
131
129
|
const columns = [0, at(0.15), at(0.25), at(0.315), at(0.385), at(0.465), at(0.535), at(0.615), at(0.685), at(0.75), at(0.85), length];
|
|
132
130
|
return [columns, (bay) => (bay === 2 || bay === 10 ? "window" : bay === 4 || bay === 6 || bay === 8 ? "strip" : "stone")];
|
|
133
131
|
};
|
|
134
|
-
// The inverse of `at`: a point's distances along the south wall and the Michigan front,
|
|
135
|
-
// which meet a degree off square.
|
|
136
|
-
const skew = west[0] * north[1] - west[1] * north[0];
|
|
137
|
-
const inLot = (p) => {
|
|
138
|
-
const [x, z] = [p[0] - corner[0], p[1] - corner[1]];
|
|
139
|
-
return [(x * north[1] - z * north[0]) / skew, (west[0] * z - west[1] * x) / skew];
|
|
140
|
-
};
|
|
141
132
|
// The crown: three arched windows to a face, 0.9 m wide and 1.7 m apart, their heads
|
|
142
133
|
// narrowing to the middle 0.45 m. A short face's are tall and centred on it; a long
|
|
143
134
|
// face's are short, centred crownWindows west of Michigan, as the drawing has them.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as THREE from "../vendor/three-r186.js";
|
|
2
2
|
import { createBuilder, polygonOf } from "./building-kit.js";
|
|
3
|
-
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt } from "./facade-grid.js";
|
|
3
|
+
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt, lotFrame } from "./facade-grid.js";
|
|
4
4
|
// The Borg-Warner Building, 200 South Michigan Avenue (A. Epstein & Sons with William
|
|
5
5
|
// Lescaze, 1958): the geographic layout's model, on the mapped outline 124873918. The
|
|
6
6
|
// original layout has no model of it; the drawing shows it across Adams from Peoples Gas.
|
|
@@ -69,10 +69,7 @@ export function createBorgWarnerGeographicBuilding(record, projectPlan, offset)
|
|
|
69
69
|
const corner = lot.reduce((best, p) => (p[0] + p[1] > best[0] + best[1] ? p : best));
|
|
70
70
|
const northEast = lot.reduce((best, p) => (p[0] - p[1] > best[0] - best[1] ? p : best));
|
|
71
71
|
const southWest = lot.reduce((best, p) => (p[1] - p[0] > best[1] - best[0] ? p : best));
|
|
72
|
-
const
|
|
73
|
-
const west = unit(southWest), north = unit(northEast);
|
|
74
|
-
const at = (a, b) => [corner[0] + west[0] * a + north[0] * b, corner[1] + west[1] * a + north[1] * b];
|
|
75
|
-
const rect = (a0, a1, b0, b1) => orient([at(a0, b0), at(a1, b0), at(a1, b1), at(a0, b1)]);
|
|
72
|
+
const { rect } = lotFrame(corner, southWest, northEast);
|
|
76
73
|
planOf(lot).forEach((run) => {
|
|
77
74
|
const a = run.at(0), b = run.at(run.length), n = run.normal(0);
|
|
78
75
|
kit.quad(shell, [[a[0], 0, a[1]], [b[0], 0, b[1]], [b[0], h.roof, b[1]], [a[0], h.roof, a[1]]], [[n[0], 0, n[1]]], core);
|
|
@@ -9,16 +9,7 @@ import { nightWindowMask } from "./night-windows.js";
|
|
|
9
9
|
// and each mesh's batch, the part of its name after the last " · ", or that without a trailing
|
|
10
10
|
// number, so "glazing 3" reads as "glazing". A surface is its batch's material unless its grey
|
|
11
11
|
// names another.
|
|
12
|
-
export
|
|
13
|
-
"neutral", "glass", "green glass", "blue-green glass", "bronze glass", "lit window", "dim window", "lamp",
|
|
14
|
-
"limestone", "marble", "white granite", "granite", "dark granite", "slate",
|
|
15
|
-
"white terracotta", "pink terracotta", "green tile", "brick", "common brick", "orange brick", "brown brick", "buff brick", "glazed brick",
|
|
16
|
-
"concrete", "precast", "copper", "maroon", "blue enamel", "bronze", "dark metal", "aluminium", "stainless", "opaque spandrel",
|
|
17
|
-
// Parts the photographs show on their own, named as the night first showed them: crown glass
|
|
18
|
-
// and crown lights, an emblem screen and the lights in its bands, a sign's board and letters,
|
|
19
|
-
// and a lit cap.
|
|
20
|
-
"crown glass", "crown lights", "screen", "band lights", "sign board", "sign letters", "cap lights",
|
|
21
|
-
];
|
|
12
|
+
export { materialNames } from "./material-names.js";
|
|
22
13
|
// A batch's lit and dim office windows.
|
|
23
14
|
const windows = (lit, dim) => ({ [lit]: "lit window", [dim]: "dim window" });
|
|
24
15
|
export const colourMaterials = {
|
|
@@ -4,6 +4,23 @@ export const orient = (corners) => {
|
|
|
4
4
|
const area = corners.reduce((sum, [x, z], i) => { const [x2, z2] = corners[(i + 1) % corners.length]; return sum + x * z2 - x2 * z; }, 0);
|
|
5
5
|
return area < 0 ? corners : [...corners].reverse();
|
|
6
6
|
};
|
|
7
|
+
// A lot's frame from the corner its fronts run from: `west` and `north` are the unit
|
|
8
|
+
// directions from `corner` toward two other points, `at(a, b)` is the point `a` along `west`
|
|
9
|
+
// and `b` along `north`, `inLot` is its inverse, a point's distances along the two fronts,
|
|
10
|
+
// which can meet a little off square, and `rect` is the oriented outline from a0 to a1 along
|
|
11
|
+
// `west` and b0 to b1 along `north`.
|
|
12
|
+
export function lotFrame(corner, toWest, toNorth) {
|
|
13
|
+
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]; };
|
|
14
|
+
const west = unit(toWest), north = unit(toNorth);
|
|
15
|
+
const at = (a, b) => [corner[0] + west[0] * a + north[0] * b, corner[1] + west[1] * a + north[1] * b];
|
|
16
|
+
const skew = west[0] * north[1] - west[1] * north[0];
|
|
17
|
+
const inLot = (p) => {
|
|
18
|
+
const [x, z] = [p[0] - corner[0], p[1] - corner[1]];
|
|
19
|
+
return [(x * north[1] - z * north[0]) / skew, (west[0] * z - west[1] * x) / skew];
|
|
20
|
+
};
|
|
21
|
+
const rect = (a0, a1, b0, b1) => orient([at(a0, b0), at(a1, b0), at(a1, b1), at(a0, b1)]);
|
|
22
|
+
return { west, north, at, inLot, rect };
|
|
23
|
+
}
|
|
7
24
|
export const planOf = (corners) => corners.map((corner, i) => line(corner, corners[(i + 1) % corners.length]));
|
|
8
25
|
// The turn from run a into run b at their shared corner; negative where the outline turns
|
|
9
26
|
// out (a convex corner) and positive where it turns in.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as THREE from "../vendor/three-r186.js";
|
|
2
2
|
import { createBuilder, polygonOf } from "./building-kit.js";
|
|
3
|
-
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt } from "./facade-grid.js";
|
|
3
|
+
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt, lotFrame } from "./facade-grid.js";
|
|
4
4
|
// The Gage Building, 18 South Michigan Avenue (Holabird & Roche, with a front by Louis
|
|
5
5
|
// Sullivan, 1899; four storeys added in 1902): the geographic layout's model, on the mapped
|
|
6
6
|
// outline 124865450. The original layout has no model of it; the drawing shows its Michigan
|
|
@@ -65,17 +65,7 @@ export function createGageGeographicBuilding(record, projectPlan, offset) {
|
|
|
65
65
|
const corner = lot.reduce((best, p) => (p[0] + p[1] > best[0] + best[1] ? p : best));
|
|
66
66
|
const northEast = lot.reduce((best, p) => (p[0] - p[1] > best[0] - best[1] ? p : best));
|
|
67
67
|
const southWest = lot.reduce((best, p) => (p[1] - p[0] > best[1] - best[0] ? p : best));
|
|
68
|
-
const
|
|
69
|
-
const west = unit(southWest), north = unit(northEast);
|
|
70
|
-
const at = (a, b) => [corner[0] + west[0] * a + north[0] * b, corner[1] + west[1] * a + north[1] * b];
|
|
71
|
-
// The inverse of `at`: a point's distances along the south wall and the Michigan front,
|
|
72
|
-
// which meet a little off square.
|
|
73
|
-
const skew = west[0] * north[1] - west[1] * north[0];
|
|
74
|
-
const inLot = (p) => {
|
|
75
|
-
const [x, z] = [p[0] - corner[0], p[1] - corner[1]];
|
|
76
|
-
return [(x * north[1] - z * north[0]) / skew, (west[0] * z - west[1] * x) / skew];
|
|
77
|
-
};
|
|
78
|
-
const rect = (a0, a1, b0, b1) => orient([at(a0, b0), at(a1, b0), at(a1, b1), at(a0, b1)]);
|
|
68
|
+
const { inLot, rect } = lotFrame(corner, southWest, northEast);
|
|
79
69
|
planOf(lot).forEach((run) => {
|
|
80
70
|
const a = run.at(0), b = run.at(run.length), n = run.normal(0);
|
|
81
71
|
kit.quad(shell, [[a[0], 0, a[1]], [b[0], 0, b[1]], [b[0], h.top, b[1]], [a[0], h.top, a[1]]], [[n[0], 0, n[1]]], core);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as THREE from "../vendor/three-r186.js";
|
|
2
2
|
import { createBuilder, polygonOf } from "./building-kit.js";
|
|
3
|
-
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt } from "./facade-grid.js";
|
|
3
|
+
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt, lotFrame } from "./facade-grid.js";
|
|
4
4
|
// The Lake View Building, 116 South Michigan Avenue (Jenney, Mundie & Jensen; its top five
|
|
5
5
|
// storeys added by them in 1912): the geographic layout's model, on the mapped outline
|
|
6
6
|
// 145498711. The original layout has no model of it; the drawing shows it between Peoples
|
|
@@ -62,15 +62,7 @@ export function createLakeViewGeographicBuilding(record, projectPlan, offset) {
|
|
|
62
62
|
const corner = lot.reduce((best, p) => (p[0] + p[1] > best[0] + best[1] ? p : best));
|
|
63
63
|
const northEast = lot.reduce((best, p) => (p[0] - p[1] > best[0] - best[1] ? p : best));
|
|
64
64
|
const neighbours = [lot[(lot.indexOf(corner) + 1) % lot.length], lot[(lot.indexOf(corner) + lot.length - 1) % lot.length]];
|
|
65
|
-
const
|
|
66
|
-
const west = unit(neighbours[0][0] < neighbours[1][0] ? neighbours[0] : neighbours[1]), north = unit(northEast);
|
|
67
|
-
// A point's distances along the south wall and the Michigan front, which meet a little
|
|
68
|
-
// off square.
|
|
69
|
-
const skew = west[0] * north[1] - west[1] * north[0];
|
|
70
|
-
const inLot = (p) => {
|
|
71
|
-
const [x, z] = [p[0] - corner[0], p[1] - corner[1]];
|
|
72
|
-
return [(x * north[1] - z * north[0]) / skew, (west[0] * z - west[1] * x) / skew];
|
|
73
|
-
};
|
|
65
|
+
const { inLot } = lotFrame(corner, neighbours[0][0] < neighbours[1][0] ? neighbours[0] : neighbours[1], northEast);
|
|
74
66
|
const front = inLot(northEast)[1];
|
|
75
67
|
planOf(lot).forEach((run) => {
|
|
76
68
|
const a = run.at(0), b = run.at(run.length), n = run.normal(0);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as THREE from "../vendor/three-r186.js";
|
|
2
2
|
import { createBuilder, polygonOf } from "./building-kit.js";
|
|
3
|
-
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt } from "./facade-grid.js";
|
|
3
|
+
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt, lotFrame } from "./facade-grid.js";
|
|
4
4
|
// The MacLean Center, 112 South Michigan Avenue, built as the Illinois Athletic Club
|
|
5
5
|
// (Barnett, Haynes & Barnett, 1908) and raised six floors by Swann & Weiskopf in 1985: the
|
|
6
6
|
// geographic layout's model, on the mapped outline 145498712. The original layout has no
|
|
@@ -78,18 +78,8 @@ export function createMacleanCenterGeographicBuilding(record, projectPlan, offse
|
|
|
78
78
|
const corner = lot.reduce((best, p) => (p[0] + p[1] > best[0] + best[1] ? p : best));
|
|
79
79
|
const northEast = lot.reduce((best, p) => (p[0] - p[1] > best[0] - best[1] ? p : best));
|
|
80
80
|
const neighbours = [lot[(lot.indexOf(corner) + 1) % lot.length], lot[(lot.indexOf(corner) + lot.length - 1) % lot.length]];
|
|
81
|
-
const
|
|
82
|
-
const west = unit(neighbours[0][0] < neighbours[1][0] ? neighbours[0] : neighbours[1]), north = unit(northEast);
|
|
83
|
-
const at = (a, b) => [corner[0] + west[0] * a + north[0] * b, corner[1] + west[1] * a + north[1] * b];
|
|
84
|
-
// The inverse of `at`: a point's distances along the south wall and the Michigan front,
|
|
85
|
-
// which meet a little off square.
|
|
86
|
-
const skew = west[0] * north[1] - west[1] * north[0];
|
|
87
|
-
const inLot = (p) => {
|
|
88
|
-
const [x, z] = [p[0] - corner[0], p[1] - corner[1]];
|
|
89
|
-
return [(x * north[1] - z * north[0]) / skew, (west[0] * z - west[1] * x) / skew];
|
|
90
|
-
};
|
|
81
|
+
const { inLot, rect } = lotFrame(corner, neighbours[0][0] < neighbours[1][0] ? neighbours[0] : neighbours[1], northEast);
|
|
91
82
|
const front = inLot(northEast)[1];
|
|
92
|
-
const rect = (a0, a1, b0, b1) => orient([at(a0, b0), at(a1, b0), at(a1, b1), at(a0, b1)]);
|
|
93
83
|
planOf(lot).forEach((run) => {
|
|
94
84
|
const a = run.at(0), b = run.at(run.length), n = run.normal(0);
|
|
95
85
|
kit.quad(shell, [[a[0], 0, a[1]], [b[0], 0, b[1]], [b[0], h.top, b[1]], [a[0], h.top, a[1]]], [[n[0], 0, n[1]]], core);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// The colour trial's named materials (https://github.com/a2f0/skyline/issues/115), which
|
|
2
|
+
// colour-materials.ts assigns to every surface, colour-palette.ts measures and night-windows.ts
|
|
3
|
+
// lights. They live apart from all three so that each can name them without importing another.
|
|
4
|
+
export const materialNames = [
|
|
5
|
+
"neutral", "glass", "green glass", "blue-green glass", "bronze glass", "lit window", "dim window", "lamp",
|
|
6
|
+
"limestone", "marble", "white granite", "granite", "dark granite", "slate",
|
|
7
|
+
"white terracotta", "pink terracotta", "green tile", "brick", "common brick", "orange brick", "brown brick", "buff brick", "glazed brick",
|
|
8
|
+
"concrete", "precast", "copper", "maroon", "blue enamel", "bronze", "dark metal", "aluminium", "stainless", "opaque spandrel",
|
|
9
|
+
// Parts the photographs show on their own, named as the night first showed them: crown glass
|
|
10
|
+
// and crown lights, an emblem screen and the lights in its bands, a sign's board and letters,
|
|
11
|
+
// and a lit cap.
|
|
12
|
+
"crown glass", "crown lights", "screen", "band lights", "sign board", "sign letters", "cap lights",
|
|
13
|
+
];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as THREE from "../vendor/three-r186.js";
|
|
2
2
|
import { createBuilder, polygonOf } from "./building-kit.js";
|
|
3
|
-
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt } from "./facade-grid.js";
|
|
3
|
+
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt, lotFrame } from "./facade-grid.js";
|
|
4
4
|
// The Michigan Boulevard Building, 30 North Michigan Avenue (Jarvis Hunt, 1914, fifteen
|
|
5
5
|
// storeys; six added by Hunt in 1923): the geographic layout's model, on the mapped outline
|
|
6
6
|
// 126982630. The original layout has no model of it; the drawing shows its Michigan front
|
|
@@ -68,18 +68,8 @@ export function createMichiganBoulevardGeographicBuilding(record, projectPlan, o
|
|
|
68
68
|
const corner = lot.reduce((best, p) => (p[0] + p[1] > best[0] + best[1] ? p : best));
|
|
69
69
|
const northEast = lot.reduce((best, p) => (p[0] - p[1] > best[0] - best[1] ? p : best));
|
|
70
70
|
const neighbours = [lot[(lot.indexOf(corner) + 1) % lot.length], lot[(lot.indexOf(corner) + lot.length - 1) % lot.length]];
|
|
71
|
-
const
|
|
72
|
-
const west = unit(neighbours[0][0] < neighbours[1][0] ? neighbours[0] : neighbours[1]), north = unit(northEast);
|
|
73
|
-
const at = (a, b) => [corner[0] + west[0] * a + north[0] * b, corner[1] + west[1] * a + north[1] * b];
|
|
74
|
-
// The inverse of `at`: a point's distances along the south wall and the Michigan front,
|
|
75
|
-
// which meet a little off square.
|
|
76
|
-
const skew = west[0] * north[1] - west[1] * north[0];
|
|
77
|
-
const inLot = (p) => {
|
|
78
|
-
const [x, z] = [p[0] - corner[0], p[1] - corner[1]];
|
|
79
|
-
return [(x * north[1] - z * north[0]) / skew, (west[0] * z - west[1] * x) / skew];
|
|
80
|
-
};
|
|
71
|
+
const { inLot, rect } = lotFrame(corner, neighbours[0][0] < neighbours[1][0] ? neighbours[0] : neighbours[1], northEast);
|
|
81
72
|
const front = inLot(northEast)[1];
|
|
82
|
-
const rect = (a0, a1, b0, b1) => orient([at(a0, b0), at(a1, b0), at(a1, b1), at(a0, b1)]);
|
|
83
73
|
planOf(lot).forEach((run) => {
|
|
84
74
|
const a = run.at(0), b = run.at(run.length), n = run.normal(0);
|
|
85
75
|
kit.quad(shell, [[a[0], 0, a[1]], [b[0], 0, b[1]], [b[0], h.top, b[1]], [a[0], h.top, a[1]]], [[n[0], 0, n[1]]], core);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as THREE from "../vendor/three-r186.js";
|
|
2
2
|
import { createBuilder, polygonOf } from "./building-kit.js";
|
|
3
|
-
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt } from "./facade-grid.js";
|
|
3
|
+
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt, lotFrame } from "./facade-grid.js";
|
|
4
4
|
// The Monroe Building, 104 South Michigan Avenue (Holabird & Roche, 1912): the geographic
|
|
5
5
|
// layout's model, on the mapped outline 145498713. The original layout has no model of it;
|
|
6
6
|
// the drawing shows it left of the University Club, across Monroe Street.
|
|
@@ -71,17 +71,7 @@ export function createMonroeGeographicBuilding(record, projectPlan, offset) {
|
|
|
71
71
|
const corner = lot.reduce((best, p) => (p[0] + p[1] > best[0] + best[1] ? p : best));
|
|
72
72
|
const northEast = lot.reduce((best, p) => (p[0] - p[1] > best[0] - best[1] ? p : best));
|
|
73
73
|
const neighbours = [lot[(lot.indexOf(corner) + 1) % lot.length], lot[(lot.indexOf(corner) + lot.length - 1) % lot.length]];
|
|
74
|
-
const
|
|
75
|
-
const west = unit(neighbours[0][0] < neighbours[1][0] ? neighbours[0] : neighbours[1]), north = unit(northEast);
|
|
76
|
-
const at = (a, b) => [corner[0] + west[0] * a + north[0] * b, corner[1] + west[1] * a + north[1] * b];
|
|
77
|
-
// The inverse of `at`: a point's distances along the south wall and the Michigan front,
|
|
78
|
-
// which meet a little off square.
|
|
79
|
-
const skew = west[0] * north[1] - west[1] * north[0];
|
|
80
|
-
const inLot = (p) => {
|
|
81
|
-
const [x, z] = [p[0] - corner[0], p[1] - corner[1]];
|
|
82
|
-
return [(x * north[1] - z * north[0]) / skew, (west[0] * z - west[1] * x) / skew];
|
|
83
|
-
};
|
|
84
|
-
const rect = (a0, a1, b0, b1) => orient([at(a0, b0), at(a1, b0), at(a1, b1), at(a0, b1)]);
|
|
74
|
+
const { at, inLot, rect } = lotFrame(corner, neighbours[0][0] < neighbours[1][0] ? neighbours[0] : neighbours[1], northEast);
|
|
85
75
|
const lift = ([x, z], y) => [x, y, z];
|
|
86
76
|
// The lot's four corners, in lot coordinates: its north and south walls are a little out
|
|
87
77
|
// of parallel.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as THREE from "../vendor/three-r186.js";
|
|
2
2
|
import { createBuilder, polygonOf } from "./building-kit.js";
|
|
3
|
-
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt } from "./facade-grid.js";
|
|
3
|
+
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt, lotFrame } from "./facade-grid.js";
|
|
4
4
|
// 180 North Michigan Avenue, the Harvester Building (1927): the geographic layout's model,
|
|
5
5
|
// on the mapped outline 210671714. The original layout has no model of it; the drawing
|
|
6
6
|
// shows its south wall behind Millennium Park Plaza, which hides its Michigan front.
|
|
@@ -59,15 +59,7 @@ export function createNorthMichigan180GeographicBuilding(record, projectPlan, of
|
|
|
59
59
|
const corner = lot.reduce((best, p) => (p[0] + p[1] > best[0] + best[1] ? p : best));
|
|
60
60
|
const northEast = lot.reduce((best, p) => (p[0] - p[1] > best[0] - best[1] ? p : best));
|
|
61
61
|
const neighbours = [lot[(lot.indexOf(corner) + 1) % lot.length], lot[(lot.indexOf(corner) + lot.length - 1) % lot.length]];
|
|
62
|
-
const
|
|
63
|
-
const west = unit(neighbours[0][0] < neighbours[1][0] ? neighbours[0] : neighbours[1]), north = unit(northEast);
|
|
64
|
-
// A point's distances along the south wall and the Michigan front, which meet a little off
|
|
65
|
-
// square.
|
|
66
|
-
const skew = west[0] * north[1] - west[1] * north[0];
|
|
67
|
-
const inLot = (p) => {
|
|
68
|
-
const [x, z] = [p[0] - corner[0], p[1] - corner[1]];
|
|
69
|
-
return [(x * north[1] - z * north[0]) / skew, (west[0] * z - west[1] * x) / skew];
|
|
70
|
-
};
|
|
62
|
+
const { inLot } = lotFrame(corner, neighbours[0][0] < neighbours[1][0] ? neighbours[0] : neighbours[1], northEast);
|
|
71
63
|
planOf(lot).forEach((run) => {
|
|
72
64
|
const a = run.at(0), b = run.at(run.length), n = run.normal(0);
|
|
73
65
|
kit.quad(shell, [[a[0], 0, a[1]], [b[0], 0, b[1]], [b[0], h.top, b[1]], [a[0], h.top, a[1]]], [[n[0], 0, n[1]]], core);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as THREE from "../vendor/three-r186.js";
|
|
2
2
|
import { createBuilder, polygonOf } from "./building-kit.js";
|
|
3
|
-
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt } from "./facade-grid.js";
|
|
3
|
+
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt, lotFrame } from "./facade-grid.js";
|
|
4
4
|
// The Peoples Gas Building, 122 South Michigan Avenue (D. H. Burnham & Co., 1911): the
|
|
5
5
|
// geographic layout's model, on the mapped outline 145498710 and its parts. The original
|
|
6
6
|
// layout has no model of it; the drawing shows it between the Lake View Building and Adams
|
|
@@ -90,16 +90,7 @@ export function createPeoplesGasGeographicBuilding(record, projectPlan, offset)
|
|
|
90
90
|
const corner = lot.reduce((best, p) => (p[0] + p[1] > best[0] + best[1] ? p : best));
|
|
91
91
|
const northEast = lot.reduce((best, p) => (p[0] - p[1] > best[0] - best[1] ? p : best));
|
|
92
92
|
const southWest = lot.reduce((best, p) => (p[1] - p[0] > best[1] - best[0] ? p : best));
|
|
93
|
-
const
|
|
94
|
-
const west = unit(southWest), north = unit(northEast);
|
|
95
|
-
const at = (a, b) => [corner[0] + west[0] * a + north[0] * b, corner[1] + west[1] * a + north[1] * b];
|
|
96
|
-
// The inverse of `at`: a point's distances along the Adams and Michigan fronts, which
|
|
97
|
-
// meet a little off square.
|
|
98
|
-
const skew = west[0] * north[1] - west[1] * north[0];
|
|
99
|
-
const inLot = (p) => {
|
|
100
|
-
const [x, z] = [p[0] - corner[0], p[1] - corner[1]];
|
|
101
|
-
return [(x * north[1] - z * north[0]) / skew, (west[0] * z - west[1] * x) / skew];
|
|
102
|
-
};
|
|
93
|
+
const { west, north, at, inLot } = lotFrame(corner, southWest, northEast);
|
|
103
94
|
const [adams, michigan] = [inLot(southWest)[0], inLot(northEast)[1]];
|
|
104
95
|
// Corners and edges by value, since parts share the outline's nodes.
|
|
105
96
|
const key = (p) => `${p[0].toFixed(3)},${p[1].toFixed(3)}`;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as THREE from "../vendor/three-r186.js";
|
|
2
2
|
import { createBuilder, polygonOf } from "./building-kit.js";
|
|
3
|
-
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt } from "./facade-grid.js";
|
|
3
|
+
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt, lotFrame } from "./facade-grid.js";
|
|
4
4
|
// The Railway Exchange Building, 224 South Michigan Avenue (Frederick P. Dinkelberg of D. H.
|
|
5
5
|
// Burnham & Co., 1904): the geographic layout's model, on the mapped outline 124873931. The
|
|
6
6
|
// original layout has no model of it; the drawing shows it at Michigan and Jackson, left of
|
|
@@ -71,14 +71,7 @@ export function createRailwayExchangeGeographicBuilding(record, projectPlan, off
|
|
|
71
71
|
const northEast = lot.reduce((best, p) => (p[0] - p[1] > best[0] - best[1] ? p : best));
|
|
72
72
|
const southWest = lot.reduce((best, p) => (p[1] - p[0] > best[1] - best[0] ? p : best));
|
|
73
73
|
const northWest = lot.reduce((best, p) => (-p[0] - p[1] > -best[0] - best[1] ? p : best));
|
|
74
|
-
const
|
|
75
|
-
const west = unit(southWest), north = unit(northEast);
|
|
76
|
-
const at = (a, b) => [corner[0] + west[0] * a + north[0] * b, corner[1] + west[1] * a + north[1] * b];
|
|
77
|
-
const skew = west[0] * north[1] - west[1] * north[0];
|
|
78
|
-
const inLot = (p) => {
|
|
79
|
-
const [x, z] = [p[0] - corner[0], p[1] - corner[1]];
|
|
80
|
-
return [(x * north[1] - z * north[0]) / skew, (west[0] * z - west[1] * x) / skew];
|
|
81
|
-
};
|
|
74
|
+
const { at, inLot } = lotFrame(corner, southWest, northEast);
|
|
82
75
|
const [jackson, michigan] = [inLot(southWest)[0], inLot(northEast)[1]];
|
|
83
76
|
const lift = ([x, z], y) => [x, y, z];
|
|
84
77
|
// The walls to the roof's foot.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as THREE from "../vendor/three-r186.js";
|
|
2
2
|
import { createBuilder, polygonOf } from "./building-kit.js";
|
|
3
|
-
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt } from "./facade-grid.js";
|
|
3
|
+
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt, lotFrame } from "./facade-grid.js";
|
|
4
4
|
// Six North Michigan, the Montgomery Ward Building (Schmidt, Garden & Martin, 1899; four
|
|
5
5
|
// floors added by Holabird & Roche, 1923): the geographic layout's model, on the mapped
|
|
6
6
|
// outline 126982631. The original layout has no model of it; the drawing shows it right of
|
|
@@ -79,17 +79,8 @@ export function createSixNorthMichiganGeographicBuilding(record, projectPlan, of
|
|
|
79
79
|
// The lot's south-east corner, and its Madison and Michigan fronts running from it.
|
|
80
80
|
const corner = lot.reduce((best, p) => (p[0] + p[1] > best[0] + best[1] ? p : best));
|
|
81
81
|
const neighbours = [lot[(lot.indexOf(corner) + 1) % lot.length], lot[(lot.indexOf(corner) + lot.length - 1) % lot.length]];
|
|
82
|
-
const
|
|
83
|
-
const
|
|
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)]);
|
|
82
|
+
const [westward, northward] = neighbours[0][0] < neighbours[1][0] ? [neighbours[0], neighbours[1]] : [neighbours[1], neighbours[0]];
|
|
83
|
+
const { at, inLot, rect } = lotFrame(corner, westward, northward);
|
|
93
84
|
const [depth, front] = [Math.max(...lot.map((p) => inLot(p)[0])), Math.max(...lot.map((p) => inLot(p)[1]))];
|
|
94
85
|
const tower = (grow) => rect(-grow, h.towerDepth + grow, h.towerSouth - grow, h.towerNorth + grow);
|
|
95
86
|
// A solid on an outline between two heights.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as THREE from "../vendor/three-r186.js";
|
|
2
2
|
import { createBuilder, polygonOf } from "./building-kit.js";
|
|
3
|
-
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt } from "./facade-grid.js";
|
|
3
|
+
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt, lotFrame } from "./facade-grid.js";
|
|
4
4
|
// The University Club of Chicago, 76 East Monroe Street (Holabird & Roche, 1909): the
|
|
5
5
|
// geographic layout's model, on the mapped outline 126982632. The original layout has no
|
|
6
6
|
// model of it; the drawing shows it left of Willoughby Tower, behind the Monroe Building.
|
|
@@ -81,18 +81,8 @@ export function createUniversityClubGeographicBuilding(record, projectPlan, offs
|
|
|
81
81
|
const corner = lot.reduce((best, p) => (p[0] + p[1] > best[0] + best[1] ? p : best));
|
|
82
82
|
const northEast = lot.reduce((best, p) => (p[0] - p[1] > best[0] - best[1] ? p : best));
|
|
83
83
|
const neighbours = [lot[(lot.indexOf(corner) + 1) % lot.length], lot[(lot.indexOf(corner) + lot.length - 1) % lot.length]];
|
|
84
|
-
const
|
|
85
|
-
const west = unit(neighbours[0][0] < neighbours[1][0] ? neighbours[0] : neighbours[1]), north = unit(northEast);
|
|
86
|
-
const at = (a, b) => [corner[0] + west[0] * a + north[0] * b, corner[1] + west[1] * a + north[1] * b];
|
|
87
|
-
// The inverse of `at`: a point's distances along Monroe and Michigan, whose fronts meet a
|
|
88
|
-
// little off square.
|
|
89
|
-
const skew = west[0] * north[1] - west[1] * north[0];
|
|
90
|
-
const inLot = (p) => {
|
|
91
|
-
const [x, z] = [p[0] - corner[0], p[1] - corner[1]];
|
|
92
|
-
return [(x * north[1] - z * north[0]) / skew, (west[0] * z - west[1] * x) / skew];
|
|
93
|
-
};
|
|
84
|
+
const { at, inLot, rect } = lotFrame(corner, neighbours[0][0] < neighbours[1][0] ? neighbours[0] : neighbours[1], northEast);
|
|
94
85
|
const [length, depth] = [Math.max(...lot.map((p) => inLot(p)[0])), inLot(northEast)[1]];
|
|
95
|
-
const rect = (a0, a1, b0, b1) => orient([at(a0, b0), at(a1, b0), at(a1, b1), at(a0, b1)]);
|
|
96
86
|
const lift = ([x, z], y) => [x, y, z];
|
|
97
87
|
// The main block, to the parapet's top.
|
|
98
88
|
planOf(lot).forEach((run) => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as THREE from "../vendor/three-r186.js";
|
|
2
2
|
import { createBuilder, inside, polygonOf } from "./building-kit.js";
|
|
3
|
-
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt } from "./facade-grid.js";
|
|
3
|
+
import { chainSkin, chainsOf, orient, paintedSlab, planOf, turnsAt, lotFrame } from "./facade-grid.js";
|
|
4
4
|
// Willoughby Tower, 8 South Michigan Avenue (Samuel N. Crowen, 1929): the geographic
|
|
5
5
|
// layout's model, on the mapped outline 124873939. The original layout has no model of it;
|
|
6
6
|
// the drawing shows it left of Six North Michigan, outside the excerpt it is fitted to.
|
|
@@ -64,10 +64,8 @@ export function createWilloughbyTowerGeographicBuilding(record, projectPlan, off
|
|
|
64
64
|
// The lot's south-east corner, and its south wall and Michigan front running from it.
|
|
65
65
|
const corner = lot.reduce((best, p) => (p[0] + p[1] > best[0] + best[1] ? p : best));
|
|
66
66
|
const neighbours = [lot[(lot.indexOf(corner) + 1) % lot.length], lot[(lot.indexOf(corner) + lot.length - 1) % lot.length]];
|
|
67
|
-
const
|
|
68
|
-
const
|
|
69
|
-
const at = (a, b) => [corner[0] + west[0] * a + north[0] * b, corner[1] + west[1] * a + north[1] * b];
|
|
70
|
-
const rect = (a0, a1, b0, b1) => orient([at(a0, b0), at(a1, b0), at(a1, b1), at(a0, b1)]);
|
|
67
|
+
const [westward, northward] = neighbours[0][0] < neighbours[1][0] ? [neighbours[0], neighbours[1]] : [neighbours[1], neighbours[0]];
|
|
68
|
+
const { west, at, inLot, rect } = lotFrame(corner, westward, northward);
|
|
71
69
|
// The south wall's length: the farthest lot corner on its line.
|
|
72
70
|
const southWall = Math.max(...lot.filter((p) => Math.abs((p[0] - corner[0]) * west[1] - (p[1] - corner[1]) * west[0]) < 0.5).map((p) => (p[0] - corner[0]) * west[0] + (p[1] - corner[1]) * west[1]));
|
|
73
71
|
const shaft = rect(0, h.shaftWidth, 0, h.shaftDepth), shoulder = rect(h.shaftWidth, southWall, 0, h.shaftDepth), crown = rect(h.crownEnds, h.shaftWidth - h.crownEnds, h.crownSides, h.shaftDepth - h.crownSides);
|
|
@@ -131,13 +129,6 @@ export function createWilloughbyTowerGeographicBuilding(record, projectPlan, off
|
|
|
131
129
|
const columns = [0, at(0.15), at(0.25), at(0.315), at(0.385), at(0.465), at(0.535), at(0.615), at(0.685), at(0.75), at(0.85), length];
|
|
132
130
|
return [columns, (bay) => (bay === 2 || bay === 10 ? "window" : bay === 4 || bay === 6 || bay === 8 ? "strip" : "stone")];
|
|
133
131
|
};
|
|
134
|
-
// The inverse of `at`: a point's distances along the south wall and the Michigan front,
|
|
135
|
-
// which meet a degree off square.
|
|
136
|
-
const skew = west[0] * north[1] - west[1] * north[0];
|
|
137
|
-
const inLot = (p) => {
|
|
138
|
-
const [x, z] = [p[0] - corner[0], p[1] - corner[1]];
|
|
139
|
-
return [(x * north[1] - z * north[0]) / skew, (west[0] * z - west[1] * x) / skew];
|
|
140
|
-
};
|
|
141
132
|
// The crown: three arched windows to a face, 0.9 m wide and 1.7 m apart, their heads
|
|
142
133
|
// narrowing to the middle 0.45 m. A short face's are tall and centred on it; a long
|
|
143
134
|
// face's are short, centred crownWindows west of Michigan, as the drawing has them.
|