flowfig 0.11.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +148 -21
- package/dist/atlas.js +6 -2
- package/dist/browser.d.ts +1 -0
- package/dist/browser.js +9 -4
- package/dist/check.d.ts +2 -2
- package/dist/check.js +135 -5
- package/dist/cli.js +174 -70
- package/dist/diff.d.ts +2 -0
- package/dist/diff.js +79 -24
- package/dist/element-looks.js +4 -0
- package/dist/element-world.js +6 -0
- package/dist/element.d.ts +27 -0
- package/dist/element.js +67 -0
- package/dist/explain.d.ts +45 -0
- package/dist/explain.js +161 -0
- package/dist/frames.d.ts +34 -0
- package/dist/frames.js +117 -0
- package/dist/index.js +283 -131
- package/dist/load.js +9 -4
- package/dist/looks.d.ts +15 -0
- package/dist/looks.js +32 -0
- package/dist/mcp.d.ts +4 -0
- package/dist/mcp.js +14 -6
- package/dist/model.d.ts +97 -0
- package/dist/model.js +182 -1
- package/dist/scene.d.ts +2 -0
- package/dist/source.d.ts +4 -2
- package/dist/source.js +15 -9
- package/dist/svg.d.ts +12 -0
- package/dist/svg.js +235 -75
- package/dist/verify.d.ts +6 -0
- package/dist/verify.js +104 -56
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/world-art.d.ts +59 -0
- package/dist/world-art.js +854 -0
- package/dist/world.d.ts +233 -0
- package/dist/world.js +1577 -0
- package/package.json +9 -3
|
@@ -0,0 +1,854 @@
|
|
|
1
|
+
export const U = 40, C = U * Math.cos(Math.PI / 6), S = U / 2;
|
|
2
|
+
export const P = (x, y, z = 0) => [(x - y) * C, (x + y) * S - z * U];
|
|
3
|
+
const f = (n) => Math.round(n * 10) / 10;
|
|
4
|
+
const pts = (a) => a.map(([x, y]) => `${f(x)},${f(y)}`).join(' ');
|
|
5
|
+
const poly = (a, fill, ex = '') => `<polygon points="${pts(a)}" fill="${fill}" ${ex}/>`;
|
|
6
|
+
const FRONT = 4.6, WALK0 = 5.4, ROAD0 = 6.0, ROAD1 = 8.0, WALK1 = 8.6;
|
|
7
|
+
export const BY = 1.6;
|
|
8
|
+
const K = {
|
|
9
|
+
ground: '#E8ECE3',
|
|
10
|
+
lawn: '#DDE6D4',
|
|
11
|
+
yard: '#D3DFC8',
|
|
12
|
+
walk: '#F4F5F0',
|
|
13
|
+
seam: '#E2E5DC',
|
|
14
|
+
curb: '#C3C8CE',
|
|
15
|
+
road: '#8A919B',
|
|
16
|
+
dash: '#EEF0F2',
|
|
17
|
+
glass: '#2a3446',
|
|
18
|
+
glassR: '#222a39',
|
|
19
|
+
light: '#f2b544',
|
|
20
|
+
lightR: '#d99a2b',
|
|
21
|
+
leaf: '#7DB27A',
|
|
22
|
+
leafD: '#5E9660',
|
|
23
|
+
trunk: '#6b5a49',
|
|
24
|
+
ink: '#141A22',
|
|
25
|
+
post: '#3b4252',
|
|
26
|
+
ao: 'rgba(20,26,34,.11)',
|
|
27
|
+
};
|
|
28
|
+
const M = {
|
|
29
|
+
brick: {
|
|
30
|
+
l: '#c96a4b',
|
|
31
|
+
r: '#a4513a',
|
|
32
|
+
t: '#d6c0ab',
|
|
33
|
+
e: '#6e3424',
|
|
34
|
+
tex: '#b65d41',
|
|
35
|
+
texR: '#934733',
|
|
36
|
+
cap: '#f6ecdb',
|
|
37
|
+
capR: '#dccdb4',
|
|
38
|
+
fr: '#f3e8d6',
|
|
39
|
+
frR: '#d9cbb3',
|
|
40
|
+
},
|
|
41
|
+
stone: {
|
|
42
|
+
l: '#e9dcc0',
|
|
43
|
+
r: '#cbbd9f',
|
|
44
|
+
t: '#d9cfb8',
|
|
45
|
+
e: '#8f8064',
|
|
46
|
+
tex: '#d6c8a8',
|
|
47
|
+
texR: '#b6a888',
|
|
48
|
+
cap: '#fbf7ee',
|
|
49
|
+
capR: '#ddd3bf',
|
|
50
|
+
fr: '#7d7058',
|
|
51
|
+
frR: '#6a5e48',
|
|
52
|
+
},
|
|
53
|
+
green: {
|
|
54
|
+
l: '#86a581',
|
|
55
|
+
r: '#678663',
|
|
56
|
+
t: '#c3cac1',
|
|
57
|
+
e: '#3c533d',
|
|
58
|
+
tex: '#76946f',
|
|
59
|
+
texR: '#587553',
|
|
60
|
+
cap: '#eef0ea',
|
|
61
|
+
capR: '#cdd3ca',
|
|
62
|
+
fr: '#eef0ea',
|
|
63
|
+
frR: '#cdd3ca',
|
|
64
|
+
},
|
|
65
|
+
slate: {
|
|
66
|
+
l: '#434b5a',
|
|
67
|
+
r: '#2e3440',
|
|
68
|
+
t: '#5a6372',
|
|
69
|
+
e: '#14181e',
|
|
70
|
+
tex: '#515a6a',
|
|
71
|
+
texR: '#3a414d',
|
|
72
|
+
cap: '#717a8a',
|
|
73
|
+
capR: '#5a6271',
|
|
74
|
+
fr: '#6b7484',
|
|
75
|
+
frR: '#555d6b',
|
|
76
|
+
},
|
|
77
|
+
pale: {
|
|
78
|
+
l: '#e3e8ef',
|
|
79
|
+
r: '#c3ccd8',
|
|
80
|
+
t: '#d3dae4',
|
|
81
|
+
e: '#5d6878',
|
|
82
|
+
tex: '#d2d9e3',
|
|
83
|
+
texR: '#b3bdcb',
|
|
84
|
+
cap: '#f5f7fa',
|
|
85
|
+
capR: '#dce2ea',
|
|
86
|
+
fr: '#9aa5b5',
|
|
87
|
+
frR: '#818c9c',
|
|
88
|
+
},
|
|
89
|
+
clay: {
|
|
90
|
+
l: '#e7d3b4',
|
|
91
|
+
r: '#c9b292',
|
|
92
|
+
t: '#d9c8ad',
|
|
93
|
+
e: '#7f6a4c',
|
|
94
|
+
tex: '#dbc5a3',
|
|
95
|
+
texR: '#b9a282',
|
|
96
|
+
cap: '#f8f0e1',
|
|
97
|
+
capR: '#ddd0b9',
|
|
98
|
+
fr: '#f8f0e1',
|
|
99
|
+
frR: '#ddd0b9',
|
|
100
|
+
roof: '#7a4f3a',
|
|
101
|
+
roofB: '#5f3c2c',
|
|
102
|
+
},
|
|
103
|
+
sand: {
|
|
104
|
+
l: '#d8c49a',
|
|
105
|
+
r: '#b9a57c',
|
|
106
|
+
t: '#ccbf9f',
|
|
107
|
+
e: '#6f6043',
|
|
108
|
+
tex: '#cab68c',
|
|
109
|
+
texR: '#a9966e',
|
|
110
|
+
cap: '#f3ead6',
|
|
111
|
+
capR: '#d6cbb2',
|
|
112
|
+
fr: '#f3ead6',
|
|
113
|
+
frR: '#d6cbb2',
|
|
114
|
+
},
|
|
115
|
+
marble: {
|
|
116
|
+
l: '#ece8df',
|
|
117
|
+
r: '#cfc9bc',
|
|
118
|
+
t: '#dfdacf',
|
|
119
|
+
e: '#7e776a',
|
|
120
|
+
tex: '#e0dbd0',
|
|
121
|
+
texR: '#bdb6a8',
|
|
122
|
+
cap: '#faf8f3',
|
|
123
|
+
capR: '#ddd8cc',
|
|
124
|
+
fr: '#5e584d',
|
|
125
|
+
frR: '#4e493f',
|
|
126
|
+
},
|
|
127
|
+
concrete: {
|
|
128
|
+
l: '#cfd2cc',
|
|
129
|
+
r: '#b0b4ad',
|
|
130
|
+
t: '#c3c7c0',
|
|
131
|
+
e: '#5b6058',
|
|
132
|
+
tex: '#c2c6bf',
|
|
133
|
+
texR: '#a2a69f',
|
|
134
|
+
cap: '#eef0ec',
|
|
135
|
+
capR: '#d1d4ce',
|
|
136
|
+
fr: '#eef0ec',
|
|
137
|
+
frR: '#d1d4ce',
|
|
138
|
+
},
|
|
139
|
+
plain: {
|
|
140
|
+
l: '#dcd8cf',
|
|
141
|
+
r: '#bfbab0',
|
|
142
|
+
t: '#d0ccc3',
|
|
143
|
+
e: '#716b60',
|
|
144
|
+
tex: '#cfcbc1',
|
|
145
|
+
texR: '#b0aba1',
|
|
146
|
+
cap: '#f6f4ef',
|
|
147
|
+
capR: '#d9d5cd',
|
|
148
|
+
fr: '#f6f4ef',
|
|
149
|
+
frR: '#d9d5cd',
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
const quadT = (x0, x1, y0, y1, z, fill, ex = '') => poly([P(x0, y0, z), P(x1, y0, z), P(x1, y1, z), P(x0, y1, z)], fill, ex);
|
|
153
|
+
const quadL = (y, x0, x1, z0, z1, fill, ex = '') => poly([P(x0, y, z0), P(x1, y, z0), P(x1, y, z1), P(x0, y, z1)], fill, ex);
|
|
154
|
+
const quadR = (x, y0, y1, z0, z1, fill, ex = '') => poly([P(x, y0, z0), P(x, y1, z0), P(x, y1, z1), P(x, y0, z1)], fill, ex);
|
|
155
|
+
const edge = (c) => `stroke="${c}" stroke-opacity=".55" stroke-width="1" stroke-linejoin="round"`;
|
|
156
|
+
const box = (x, y, z, w, d, h, t, l, r, e) => {
|
|
157
|
+
const ex = e ? edge(e) : '';
|
|
158
|
+
return quadL(y + d, x, x + w, z, z + h, l, ex) + quadR(x + w, y, y + d, z, z + h, r, ex) + quadT(x, x + w, y, y + d, z + h, t, ex);
|
|
159
|
+
};
|
|
160
|
+
const mbox = (x, y, z, w, d, h, m) => box(x, y, z, w, d, h, m.t, m.l, m.r, m.e);
|
|
161
|
+
const line = (a, b, stroke, w = 1, ex = '') => `<line x1="${f(a[0])}" y1="${f(a[1])}" x2="${f(b[0])}" y2="${f(b[1])}" stroke="${stroke}" stroke-width="${w}" ${ex}/>`;
|
|
162
|
+
const ring = (fn, n = 28) => Array.from({ length: n }, (_, i) => fn((i / n) * Math.PI * 2));
|
|
163
|
+
const ellT = (cx, cy, z, r, fill, ex = '') => poly(ring((t) => P(cx + r * Math.cos(t), cy + r * Math.sin(t), z)), fill, ex);
|
|
164
|
+
const ao = (x, y, w, d) => quadT(x - 0.05, x + w + 0.45, y - 0.05, y + d + 0.22, 0, K.ao);
|
|
165
|
+
const coursesL = (Y, x0, x1, z0, z1, step, c) => {
|
|
166
|
+
let o = '';
|
|
167
|
+
for (let z = z0 + step; z < z1 - 0.02; z += step)
|
|
168
|
+
o += line(P(x0, Y, z), P(x1, Y, z), c, 1);
|
|
169
|
+
return o;
|
|
170
|
+
};
|
|
171
|
+
const coursesR = (X, y0, y1, z0, z1, step, c) => {
|
|
172
|
+
let o = '';
|
|
173
|
+
for (let z = z0 + step; z < z1 - 0.02; z += step)
|
|
174
|
+
o += line(P(X, y0, z), P(X, y1, z), c, 1);
|
|
175
|
+
return o;
|
|
176
|
+
};
|
|
177
|
+
const seamsL = (Y, x0, x1, z0, z1, step, c) => {
|
|
178
|
+
let o = '';
|
|
179
|
+
for (let x = x0 + step; x < x1 - 0.02; x += step)
|
|
180
|
+
o += line(P(x, Y, z0), P(x, Y, z1), c, 1);
|
|
181
|
+
return o;
|
|
182
|
+
};
|
|
183
|
+
const seamsR = (X, y0, y1, z0, z1, step, c) => {
|
|
184
|
+
let o = '';
|
|
185
|
+
for (let y = y0 + step; y < y1 - 0.02; y += step)
|
|
186
|
+
o += line(P(X, y, z0), P(X, y, z1), c, 1);
|
|
187
|
+
return o;
|
|
188
|
+
};
|
|
189
|
+
const cube = (x, y, z, w, d, h) => [
|
|
190
|
+
[x, y, z],
|
|
191
|
+
[x + w, y, z],
|
|
192
|
+
[x, y + d, z],
|
|
193
|
+
[x + w, y + d, z],
|
|
194
|
+
].flatMap(([u, v]) => [
|
|
195
|
+
[u, v, z],
|
|
196
|
+
[u, v, z + h],
|
|
197
|
+
]);
|
|
198
|
+
function winL(m, Y, a, b, z0, z1, lit, cols = 2, transom = true) {
|
|
199
|
+
const k = 0.05;
|
|
200
|
+
let o = quadL(Y, a, b, z0, z1, m.fr) + quadL(Y, a + k, b - k, z0 + k, z1 - k, lit ? K.light : K.glass);
|
|
201
|
+
for (let i = 1; i < cols; i++) {
|
|
202
|
+
const x = a + ((b - a) * i) / cols;
|
|
203
|
+
o += line(P(x, Y, z0 + k), P(x, Y, z1 - k), m.fr, 1.5);
|
|
204
|
+
}
|
|
205
|
+
if (transom) {
|
|
206
|
+
const z = z0 + (z1 - z0) * 0.68;
|
|
207
|
+
o += line(P(a + k, Y, z), P(b - k, Y, z), m.fr, 1.5);
|
|
208
|
+
}
|
|
209
|
+
return o + quadL(Y, a - 0.03, b + 0.03, z0 - 0.06, z0, m.cap);
|
|
210
|
+
}
|
|
211
|
+
function winR(m, X, a, b, z0, z1, lit, cols = 2, transom = true) {
|
|
212
|
+
const k = 0.05;
|
|
213
|
+
let o = quadR(X, a, b, z0, z1, m.frR) + quadR(X, a + k, b - k, z0 + k, z1 - k, lit ? K.lightR : K.glassR);
|
|
214
|
+
for (let i = 1; i < cols; i++) {
|
|
215
|
+
const y = a + ((b - a) * i) / cols;
|
|
216
|
+
o += line(P(X, y, z0 + k), P(X, y, z1 - k), m.frR, 1.5);
|
|
217
|
+
}
|
|
218
|
+
if (transom) {
|
|
219
|
+
const z = z0 + (z1 - z0) * 0.68;
|
|
220
|
+
o += line(P(X, a + k, z), P(X, b - k, z), m.frR, 1.5);
|
|
221
|
+
}
|
|
222
|
+
return o + quadR(X, a - 0.03, b + 0.03, z0 - 0.06, z0, m.capR);
|
|
223
|
+
}
|
|
224
|
+
function roofWell(x, y, w, d, h, m, k = 0.12) {
|
|
225
|
+
let o = quadT(x, x + w, y, y + d, h, m.cap, edge(m.e));
|
|
226
|
+
o += quadT(x + k, x + w - k, y + k, y + d - k, h - 0.1, m.t);
|
|
227
|
+
o += quadL(y + k, x + k, x + w - k, h - 0.1, h, m.tex) + quadR(x + k, y + k, y + d - k, h - 0.1, h, m.texR);
|
|
228
|
+
o += quadT(x, x + w, y + d - k, y + d, h, m.cap) + quadT(x + w - k, x + w, y, y + d, h, m.cap);
|
|
229
|
+
return o;
|
|
230
|
+
}
|
|
231
|
+
const hvac = (x, y, z, w = 0.8, d = 0.7, h = 0.35) => box(x, y, z, w, d, h, '#e4e6e9', '#cfd3d8', '#aeb4bc', '#6b717a');
|
|
232
|
+
const door2 = (m, Y, a, b, h) => quadL(Y, a, b, 0, h, m.fr) +
|
|
233
|
+
quadL(Y, a + 0.06, b - 0.06, 0, h - 0.05, K.glass) +
|
|
234
|
+
quadL(Y, (a + b) / 2 - 0.02, (a + b) / 2 + 0.02, 0, h - 0.05, m.fr);
|
|
235
|
+
const rollerL = (Y, a, b, h, frame, slat, slat2) => {
|
|
236
|
+
let o = quadL(Y, a - 0.05, b + 0.05, 0, h + 0.05, frame) + quadL(Y, a, b, 0, h, slat);
|
|
237
|
+
for (let z = 0.1; z < h - 0.05; z += 0.105)
|
|
238
|
+
o += quadL(Y, a, b, z, z + 0.035, slat2);
|
|
239
|
+
return o;
|
|
240
|
+
};
|
|
241
|
+
function house(x, y) {
|
|
242
|
+
const m = M.clay, w = 3, d = 3, h = 1.15, rz = 0.95, o0 = 0.16, Y = y + d, X = x + w, ym = y + d / 2;
|
|
243
|
+
let o = ao(x, y, w, d) + mbox(x, y, 0, w, d, h, m);
|
|
244
|
+
o += coursesL(Y, x, X, 0, h, 0.13, m.tex) + coursesR(X, y, Y, 0, h, 0.13, m.texR);
|
|
245
|
+
o += quadL(Y, x, X, 0, 0.1, m.texR) + quadR(X, y, Y, 0, 0.1, m.e, 'fill-opacity=".35"');
|
|
246
|
+
o +=
|
|
247
|
+
quadL(Y, x + 0.3, x + 0.9, 0, 0.92, '#5b3a2a') +
|
|
248
|
+
quadL(Y, x + 0.36, x + 0.84, 0, 0.86, '#6f4733') +
|
|
249
|
+
`<circle cx="${f(P(x + 0.76, Y, 0.45)[0])}" cy="${f(P(x + 0.76, Y, 0.45)[1])}" r="1.6" fill="${K.light}"/>`;
|
|
250
|
+
o += quadL(Y, x + 0.22, x + 0.98, 0.92, 0.98, m.cap);
|
|
251
|
+
o += winL(m, Y, x + 1.3, x + 2.0, 0.32, 0.86, true, 2, false) + winL(m, Y, x + 2.2, x + 2.8, 0.32, 0.86, false, 2, false);
|
|
252
|
+
o += winR(m, X, y + 0.45, y + 1.15, 0.32, 0.86, true, 2, false) + winR(m, X, y + 1.85, y + 2.55, 0.32, 0.86, false, 2, false);
|
|
253
|
+
o += poly([P(x - o0, y - o0, h), P(X + o0, y - o0, h), P(X + o0, ym, h + rz), P(x - o0, ym, h + rz)], m.roofB);
|
|
254
|
+
o += poly([P(X, y, h), P(X, Y, h), P(X, ym, h + rz)], m.r, edge(m.e)) + coursesR(X, y + 0.5, Y - 0.5, h, h + rz * 0.5, 0.13, m.texR);
|
|
255
|
+
o += winR(m, X, ym - 0.22, ym + 0.22, h + 0.18, h + 0.55, true, 1, false);
|
|
256
|
+
o += poly([P(x - o0, Y + o0, h), P(X + o0, Y + o0, h), P(X + o0, ym, h + rz), P(x - o0, ym, h + rz)], m.roof, edge(m.e));
|
|
257
|
+
for (let k = 1; k < 6; k++) {
|
|
258
|
+
const t = k / 6;
|
|
259
|
+
o += line(P(x - o0, Y + o0 - (Y + o0 - ym) * t, h + rz * t), P(X + o0, Y + o0 - (Y + o0 - ym) * t, h + rz * t), m.roofB, 1);
|
|
260
|
+
}
|
|
261
|
+
o += line(P(x - o0, ym, h + rz), P(X + o0, ym, h + rz), '#3e271c', 2);
|
|
262
|
+
o +=
|
|
263
|
+
box(x + 0.55, ym + 0.25, h + rz * 0.62, 0.36, 0.36, rz * 0.38 + 0.25, '#9c4f3a', '#8a4433', '#6f3628', '#4a241a') +
|
|
264
|
+
box(x + 0.5, ym + 0.2, h + rz + 0.5, 0.46, 0.46, 0.08, '#b9b0a2', '#a39a8c', '#8a8274');
|
|
265
|
+
return {
|
|
266
|
+
svg: o,
|
|
267
|
+
ant: [x + 2.5, ym, h + rz],
|
|
268
|
+
pts: [
|
|
269
|
+
...cube(x - o0, y - o0, 0, w + 2 * o0, d + 2 * o0, h),
|
|
270
|
+
[x - o0, ym, h + rz],
|
|
271
|
+
[X + o0, ym, h + rz],
|
|
272
|
+
[x + 0.5, ym + 0.2, h + rz + 0.6],
|
|
273
|
+
[x + 0.96, ym + 0.66, h + rz + 0.6],
|
|
274
|
+
],
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
function shop(x, y) {
|
|
278
|
+
const m = M.brick, w = 3, d = 3, h = 1.5, Y = y + d, X = x + w;
|
|
279
|
+
let o = ao(x, y, w, d) + mbox(x, y, 0, w, d, h, m);
|
|
280
|
+
o += coursesL(Y, x, X, 0, h, 0.12, m.tex) + coursesR(X, y, Y, 0, h, 0.12, m.texR);
|
|
281
|
+
o += quadL(Y, x, X, 0, 0.12, m.r) + quadR(X, y, Y, 0, 0.12, m.e, 'fill-opacity=".5"');
|
|
282
|
+
o +=
|
|
283
|
+
quadL(Y, x + 1.05, x + 1.95, 0, 1.0, m.fr) +
|
|
284
|
+
quadL(Y, x + 1.11, x + 1.89, 0, 0.94, K.glass) +
|
|
285
|
+
quadL(Y, x + 1.49, x + 1.51, 0, 0.94, m.fr) +
|
|
286
|
+
quadL(Y, x + 1.17, x + 1.83, 0.72, 0.88, K.light);
|
|
287
|
+
o += winL(m, Y, x + 0.2, x + 0.85, 0.3, 0.95, true, 2, false) + winL(m, Y, x + 2.15, x + 2.8, 0.3, 0.95, true, 2, false);
|
|
288
|
+
for (let i = 0; i < 7; i++) {
|
|
289
|
+
const a = x + 0.12 + i * 0.395, b = a + 0.395;
|
|
290
|
+
o += poly([P(a, Y, 1.14), P(b, Y, 1.14), P(b, Y + 0.38, 1.0), P(a, Y + 0.38, 1.0)], i % 2 ? '#9c4632' : '#f6ecdb', edge(m.e));
|
|
291
|
+
}
|
|
292
|
+
o += poly([P(x + 0.12, Y + 0.38, 1.0), P(x + 2.89, Y + 0.38, 1.0), P(x + 2.89, Y + 0.38, 0.94), P(x + 0.12, Y + 0.38, 0.94)], '#7c3626');
|
|
293
|
+
o += winR(m, X, y + 0.4, y + 1.1, 0.45, 1.0, false) + winR(m, X, y + 1.5, y + 2.2, 0.45, 1.0, true);
|
|
294
|
+
o += roofWell(x, y, w, d, h + 0.12, m);
|
|
295
|
+
o += hvac(x + 0.4, y + 0.5, h + 0.02) + hvac(x + 1.95, y + 1.75, h + 0.02, 0.45, 0.45, 0.24);
|
|
296
|
+
return { svg: o, ant: [x + 2.5, y + 0.7, h + 0.12], pts: cube(x, y, 0, w, d, h + 0.4) };
|
|
297
|
+
}
|
|
298
|
+
function office(x, y, floors) {
|
|
299
|
+
const m = M.stone, w = 3, d = 3, h = 0.04 + 1.38 * floors, Y = y + d, X = x + w;
|
|
300
|
+
let o = ao(x, y, w, d) + mbox(x, y, 0, w, d, h, m);
|
|
301
|
+
o += coursesL(Y, x, X, 0, h, 0.2, m.tex) + coursesR(X, y, Y, 0, h, 0.2, m.texR);
|
|
302
|
+
for (let fl = 1; fl < floors; fl++)
|
|
303
|
+
o += quadL(Y, x, X, fl * 1.38 - 0.04, fl * 1.38 + 0.06, m.cap) + quadR(X, y, Y, fl * 1.38 - 0.04, fl * 1.38 + 0.06, m.capR);
|
|
304
|
+
o += quadL(Y, x, X, 0, 0.15, m.tex) + quadR(X, y, Y, 0, 0.15, m.texR);
|
|
305
|
+
const lit = (k) => (k * 7) % 5 < 2;
|
|
306
|
+
for (let fl = 0; fl < floors; fl++)
|
|
307
|
+
for (let i = 0; i < 4; i++) {
|
|
308
|
+
const z0 = 0.38 + fl * 1.38, z1 = z0 + 0.74, a = x + 0.22 + i * 0.68;
|
|
309
|
+
if (!(fl === 0 && (i === 1 || i === 2)))
|
|
310
|
+
o += winL(m, Y, a, a + 0.48, z0, z1, lit(fl * 4 + i), 2);
|
|
311
|
+
const b = y + 0.22 + i * 0.68;
|
|
312
|
+
o += winR(m, X, b, b + 0.48, z0, z1, lit(fl * 4 + i + 3), 2);
|
|
313
|
+
}
|
|
314
|
+
o +=
|
|
315
|
+
quadL(Y, x + 1.0, x + 2.0, 0, 1.05, m.fr) + quadL(Y, x + 1.05, x + 1.95, 0, 1.0, K.glass) + quadL(Y, x + 1.48, x + 1.52, 0, 1.0, m.fr);
|
|
316
|
+
o += quadL(Y, x + 1.1, x + 1.9, 0.75, 0.95, K.light);
|
|
317
|
+
o += box(x + 0.85, Y, 1.08, 1.3, 0.45, 0.1, m.cap, m.cap, m.capR, m.e);
|
|
318
|
+
o += roofWell(x, y, w, d, h + 0.12, m);
|
|
319
|
+
o += hvac(x + 1.7, y + 0.4, h + 0.02, 0.9, 0.7, 0.45);
|
|
320
|
+
for (let i = 0; i < 3; i++)
|
|
321
|
+
o += quadL(y + 1.1, x + 1.8 + i * 0.25, x + 1.95 + i * 0.25, h + 0.12, h + 0.37, '#8b939f');
|
|
322
|
+
o += box(x + 0.4, y + 1.6, h + 0.02, 0.5, 0.5, 0.3, m.cap, m.cap, m.capR, m.e);
|
|
323
|
+
return { svg: o, ant: [x + 2.4, y + 2.3, h + 0.04], pts: cube(x, y, 0, w, d, h + 0.5) };
|
|
324
|
+
}
|
|
325
|
+
function depot(x, y) {
|
|
326
|
+
const m = M.green, w = 3, d = 2, h = 1.4, Y = y + d, X = x + w;
|
|
327
|
+
let o = ao(x, y, w, d) + mbox(x, y, 0, w, d, h, m);
|
|
328
|
+
o += seamsL(Y, x, X, 0, h, 0.12, m.tex) + seamsR(X, y, Y, 0, h, 0.12, m.texR);
|
|
329
|
+
o += quadL(Y, x + 0.25, x + 1.85, 0, 1.08, m.fr) + quadL(Y, x + 0.3, x + 1.8, 0, 1.03, '#1d222b');
|
|
330
|
+
o +=
|
|
331
|
+
quadL(Y, x + 2.15, x + 2.6, 0, 0.88, m.fr) +
|
|
332
|
+
quadL(Y, x + 2.2, x + 2.55, 0, 0.83, K.glass) +
|
|
333
|
+
quadL(Y, x + 2.25, x + 2.5, 0.6, 0.78, K.light);
|
|
334
|
+
o += winR(m, X, y + 0.35, y + 1.65, 0.55, 1.0, true, 3, false);
|
|
335
|
+
o += quadT(x - 0.05, X + 0.05, y - 0.05, Y + 0.05, h, m.t, edge(m.e));
|
|
336
|
+
for (let k = y + 0.1; k < Y; k += 0.16)
|
|
337
|
+
o += line(P(x - 0.05, k, h), P(X + 0.05, k, h), '#a7b0a5', 1);
|
|
338
|
+
o += quadL(Y + 0.05, x - 0.05, X + 0.05, h - 0.06, h, '#a7b0a5') + quadR(X + 0.05, y - 0.05, Y + 0.05, h - 0.06, h, '#8e978c');
|
|
339
|
+
for (let i = 0; i < 3; i++)
|
|
340
|
+
o += box(x + 0.4 + i * 0.85, y + 0.6, h, 0.5, 0.8, 0.14, '#e9eee8', '#dfe5dc', '#c3cbc0', m.e);
|
|
341
|
+
return { svg: o, ant: [x + 2.6, y + 1.7, h], pts: cube(x, y, 0, w, d, h + 0.14), depot: { x, y: Y } };
|
|
342
|
+
}
|
|
343
|
+
function shed(x, y) {
|
|
344
|
+
const m = M.sand, w = 3, d = 3, h = 1.35, Y = y + d, X = x + w;
|
|
345
|
+
let o = ao(x, y, w, d) + mbox(x, y, 0, w, d, h, m);
|
|
346
|
+
o += seamsL(Y, x, X, 0, h, 0.15, m.tex) + seamsR(X, y, Y, 0, h, 0.15, m.texR);
|
|
347
|
+
for (let i = 0; i < 3; i++) {
|
|
348
|
+
const a = x + 0.2 + i * 0.95;
|
|
349
|
+
o += box(a - 0.04, Y, 0, 0.75, 0.28, 0.32, '#8b8f96', '#9aa0a8', '#767b83', '#3b4252');
|
|
350
|
+
o += rollerL(Y, a, a + 0.68, 0.86, m.fr, '#4f5866', '#6a7482');
|
|
351
|
+
o += quadL(Y + 0.29, a + 0.02, a + 0.12, 0.12, 0.3, '#1d222b') + quadL(Y + 0.29, a + 0.56, a + 0.66, 0.12, 0.3, '#1d222b');
|
|
352
|
+
}
|
|
353
|
+
o += poly([P(x - 0.05, Y, 1.12), P(X + 0.05, Y, 1.12), P(X + 0.05, Y + 0.3, 1.06), P(x - 0.05, Y + 0.3, 1.06)], '#aab3be', edge('#5b636f'));
|
|
354
|
+
o += quadL(Y + 0.3, x - 0.05, X + 0.05, 1.01, 1.06, '#7d8794');
|
|
355
|
+
o += winR(m, X, y + 0.4, y + 2.6, 0.62, 1.05, true, 4, false);
|
|
356
|
+
o += roofWell(x, y, w, d, h + 0.1, m);
|
|
357
|
+
o += box(x + 0.35, y + 0.35, h + 0.02, 2.3, 0.5, 0.18, '#e9e4d6', '#d8d1bf', '#bdb5a2', m.e);
|
|
358
|
+
o += box(x + 0.35, y + 1.25, h + 0.02, 2.3, 0.5, 0.18, '#e9e4d6', '#d8d1bf', '#bdb5a2', m.e);
|
|
359
|
+
return { svg: o, ant: [x + 2.6, y + 2.4, h + 0.02], pts: cube(x, y, 0, w, d + 0.3, h + 0.3) };
|
|
360
|
+
}
|
|
361
|
+
function hall(x, y, m, led) {
|
|
362
|
+
const w = 3, d = 3, h = 1.9, Y = y + d, X = x + w;
|
|
363
|
+
let o = ao(x, y, w, d) + mbox(x, y, 0, w, d, h, m);
|
|
364
|
+
o += seamsL(Y, x, X, 0, h, 0.5, m.tex) + seamsR(X, y, Y, 0, h, 0.5, m.texR);
|
|
365
|
+
o += coursesL(Y, x, X, 0, h, 0.63, m.tex) + coursesR(X, y, Y, 0, h, 0.63, m.texR);
|
|
366
|
+
o +=
|
|
367
|
+
quadL(Y, x + 1.15, x + 1.85, 0, 1.15, m.fr) +
|
|
368
|
+
quadL(Y, x + 1.2, x + 1.8, 0, 1.1, '#1d222b') +
|
|
369
|
+
quadL(Y, x + 1.49, x + 1.51, 0, 1.1, m.fr);
|
|
370
|
+
o += quadL(Y, x + 1.92, x + 2.04, 0.5, 0.68, '#1d222b') + quadL(Y, x + 1.95, x + 2.01, 0.6, 0.65, K.light);
|
|
371
|
+
for (let i = 0; i < 6; i++) {
|
|
372
|
+
o += quadL(Y, x + 0.25, x + 0.95, 0.3 + i * 0.17, 0.37 + i * 0.17, m.e, 'fill-opacity=".7"');
|
|
373
|
+
o += quadL(Y, x + 2.2, x + 2.8, 0.3 + i * 0.17, 0.37 + i * 0.17, m.e, 'fill-opacity=".7"');
|
|
374
|
+
}
|
|
375
|
+
for (let i = 0; i < 4; i++) {
|
|
376
|
+
const b = y + 0.25 + i * 0.68;
|
|
377
|
+
o += quadR(X, b, b + 0.42, 0.3, 1.5, m.frR) + quadR(X, b + 0.04, b + 0.38, 0.34, 1.46, '#1a1e26');
|
|
378
|
+
for (let j = 0; j < 5; j++)
|
|
379
|
+
o += quadR(X, b + 0.08, b + 0.14, 0.45 + j * 0.22, 0.5 + j * 0.22, j === 2 && i === 1 ? K.light : led);
|
|
380
|
+
}
|
|
381
|
+
o += roofWell(x, y, w, d, h + 0.12, m);
|
|
382
|
+
o += box(x + 0.25, y + 0.3, h + 0.02, 0.25, 2.4, 0.08, m.cap, m.capR, m.texR);
|
|
383
|
+
for (const [cx, cy] of [
|
|
384
|
+
[x + 0.95, y + 0.55],
|
|
385
|
+
[x + 0.95, y + 1.65],
|
|
386
|
+
]) {
|
|
387
|
+
o += box(cx, cy, h + 0.02, 0.95, 0.9, 0.32, '#c9ced6', '#dfe3e9', '#a9b0bb', '#3d4659');
|
|
388
|
+
const c = [cx + 0.475, cy + 0.45], zt = h + 0.35;
|
|
389
|
+
o += ellT(c[0], c[1], zt, 0.33, '#2a3142') + ellT(c[0], c[1], zt + 0.01, 0.08, '#8b9099');
|
|
390
|
+
for (let k = 0; k < 3; k++) {
|
|
391
|
+
const a = (k * 2 * Math.PI) / 3 + 0.4;
|
|
392
|
+
o += line(P(c[0], c[1], zt + 0.01), P(c[0] + 0.3 * Math.cos(a), c[1] + 0.3 * Math.sin(a), zt + 0.01), '#8b9099', 1.5);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
return { svg: o, ant: [x + 2.5, y + 2.4, h + 0.04], pts: cube(x, y, 0, w, d, h + 0.4) };
|
|
396
|
+
}
|
|
397
|
+
function archive(x, y) {
|
|
398
|
+
const m = M.marble, w = 3, d = 3, h = 1.55, Y = y + d, X = x + w;
|
|
399
|
+
let o = ao(x, y, w, d + 0.5);
|
|
400
|
+
o +=
|
|
401
|
+
box(x - 0.1, y - 0.1, 0, w + 0.2, d + 0.6, 0.08, m.cap, m.tex, m.texR, m.e) +
|
|
402
|
+
box(x - 0.05, y - 0.05, 0.08, w + 0.1, d + 0.35, 0.08, m.cap, m.tex, m.texR, m.e);
|
|
403
|
+
o += mbox(x, y, 0.16, w, d, h - 0.16, m);
|
|
404
|
+
o += coursesR(X, y, Y, 0.16, h, 0.24, m.texR);
|
|
405
|
+
o +=
|
|
406
|
+
quadL(Y, x + 1.15, x + 1.85, 0.16, 1.1, m.fr) +
|
|
407
|
+
quadL(Y, x + 1.2, x + 1.8, 0.16, 1.05, '#3a352d') +
|
|
408
|
+
quadL(Y, x + 1.49, x + 1.51, 0.16, 1.05, m.fr);
|
|
409
|
+
for (const a of [x + 0.18, x + 0.68, x + 2.08, x + 2.58]) {
|
|
410
|
+
o += quadL(Y + 0.25, a, a + 0.26, 0.16, h - 0.1, '#f7f4ee') + quadL(Y + 0.25, a + 0.18, a + 0.26, 0.16, h - 0.1, '#d8d2c5');
|
|
411
|
+
o +=
|
|
412
|
+
box(a - 0.03, Y + 0.12, 0.16, 0.32, 0.16, 0.06, m.cap, m.tex, m.texR) +
|
|
413
|
+
box(a - 0.03, Y + 0.12, h - 0.14, 0.32, 0.16, 0.06, m.cap, m.tex, m.texR);
|
|
414
|
+
}
|
|
415
|
+
for (let i = 0; i < 4; i++) {
|
|
416
|
+
const b = y + 0.35 + i * 0.62;
|
|
417
|
+
o += quadR(X, b, b + 0.16, 0.45, 1.25, m.frR);
|
|
418
|
+
}
|
|
419
|
+
o += poly([P(x - 0.05, Y + 0.3, h), P(X + 0.05, Y + 0.3, h), P(X + 0.05, y, h), P(x - 0.05, y, h)], m.cap, edge(m.e));
|
|
420
|
+
o += box(x - 0.05, y, h - 0.1, w + 0.1, d + 0.3, 0.12, m.cap, m.tex, m.texR, m.e);
|
|
421
|
+
const pz = h + 0.02;
|
|
422
|
+
o +=
|
|
423
|
+
poly([P(x, Y + 0.3, pz), P(X, Y + 0.3, pz), P(x + w / 2, Y + 0.3, pz + 0.52)], m.l, edge(m.e)) +
|
|
424
|
+
poly([P(x + 0.3, Y + 0.3, pz + 0.06), P(X - 0.3, Y + 0.3, pz + 0.06), P(x + w / 2, Y + 0.3, pz + 0.4)], m.tex);
|
|
425
|
+
o += poly([P(X, Y + 0.3, pz), P(x + w / 2, Y + 0.3, pz + 0.52), P(x + w / 2, y + 0.2, pz + 0.52), P(X, y + 0.2, pz)], m.r, edge(m.e));
|
|
426
|
+
o += quadT(x + 0.15, x + w / 2 - 0.1, y + 0.4, y + 1.2, pz, m.t);
|
|
427
|
+
return {
|
|
428
|
+
svg: o,
|
|
429
|
+
ant: [x + 2.3, y + 0.7, h + 0.02],
|
|
430
|
+
pts: [...cube(x - 0.1, y - 0.1, 0, w + 0.2, d + 0.6, h + 0.1), [x + w / 2, Y + 0.3, pz + 0.52], [x + w / 2, y + 0.2, pz + 0.52]],
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
function works(x, y) {
|
|
434
|
+
const m = M.concrete, w = 3, d = 3, h = 1.25, Y = y + d, X = x + w, tz = 0.55;
|
|
435
|
+
let o = ao(x, y, w, d) + mbox(x, y, 0, w, d, h, m);
|
|
436
|
+
o += seamsL(Y, x, X, 0, h, 0.5, m.tex) + seamsR(X, y, Y, 0, h, 0.5, m.texR);
|
|
437
|
+
o += rollerL(Y, x + 0.3, x + 1.3, 0.95, m.fr, '#5a6b5f', '#71837a');
|
|
438
|
+
o += winL(m, Y, x + 1.65, x + 2.75, 0.55, 0.98, true, 3, false) + winR(m, X, y + 0.3, y + 2.7, 0.55, 0.98, true, 4, false);
|
|
439
|
+
const stack = (zTop) => box(x + 2.35, y + 0.25, 0, 0.36, 0.36, zTop, '#a5503b', '#93463a', '#743628', '#4a241a') +
|
|
440
|
+
box(x + 2.31, y + 0.21, zTop, 0.44, 0.44, 0.08, '#6b717a', '#5a6170', '#454b57');
|
|
441
|
+
o += quadT(x, X, y, Y, h, m.t, edge(m.e));
|
|
442
|
+
for (let k = 0; k < 3; k++) {
|
|
443
|
+
const y0 = y + k, y1 = y0 + 1;
|
|
444
|
+
o += poly([P(x, y0, h), P(X, y0, h), P(X, y1, h + tz), P(x, y1, h + tz)], '#8f97a1', edge('#3b4252'));
|
|
445
|
+
o += quadL(y1, x, X, h, h + tz, '#2a3446') + seamsL(y1, x, X, h, h + tz, 0.3, '#5d6b80');
|
|
446
|
+
o += poly([P(X, y0, h), P(X, y1, h), P(X, y1, h + tz)], m.r, edge(m.e));
|
|
447
|
+
if (k === 0)
|
|
448
|
+
o += stack(h + 1.75);
|
|
449
|
+
}
|
|
450
|
+
return {
|
|
451
|
+
svg: o,
|
|
452
|
+
ant: [x + 2.75, y + 2.95, h + tz],
|
|
453
|
+
pts: [...cube(x, y, 0, w, d, h + tz), [x + 2.31, y + 0.21, h + 1.83], [x + 2.75, y + 0.65, h + 1.83]],
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
function mast(x, y) {
|
|
457
|
+
const m = M.concrete, Y = y + 3;
|
|
458
|
+
let o = ao(x + 0.2, y + 1.3, 2.0, 1.7) + mbox(x + 0.2, y + 1.3, 0, 2.0, 1.7, 1.05, m);
|
|
459
|
+
o +=
|
|
460
|
+
quadL(Y, x + 0.9, x + 1.5, 0, 0.85, m.fr) +
|
|
461
|
+
quadL(Y, x + 0.95, x + 1.45, 0, 0.8, '#5b636f') +
|
|
462
|
+
quadL(Y, x + 0.4, x + 0.7, 0.5, 0.75, '#2e3440') +
|
|
463
|
+
seamsL(Y, x + 0.4, x + 0.7, 0.5, 0.75, 0.06, '#5b636f');
|
|
464
|
+
o += quadR(x + 2.2, y + 1.6, y + 2.6, 0.55, 0.8, '#2e3440') + seamsR(x + 2.2, y + 1.6, y + 2.6, 0.55, 0.8, 0.08, '#5b636f');
|
|
465
|
+
o += roofWell(x + 0.2, y + 1.3, 2.0, 1.7, 1.12, m, 0.08);
|
|
466
|
+
const b0 = [x + 1.6, y + 0.15], s0 = 1.1, top = 4.6, s1 = 0.24, c0 = b0[0] + s0 / 2, c1 = b0[1] + s0 / 2;
|
|
467
|
+
const leg = (sx, sy, z) => {
|
|
468
|
+
const s = s0 + (s1 - s0) * (z / top);
|
|
469
|
+
return [c0 + (sx * s) / 2, c1 + (sy * s) / 2, z];
|
|
470
|
+
};
|
|
471
|
+
const st = '#4d5666', W = (p) => P(...p);
|
|
472
|
+
let mo = '';
|
|
473
|
+
for (const [sx, sy] of [
|
|
474
|
+
[-1, -1],
|
|
475
|
+
[1, -1],
|
|
476
|
+
[-1, 1],
|
|
477
|
+
[1, 1],
|
|
478
|
+
])
|
|
479
|
+
mo += line(W(leg(sx, sy, 0)), W(leg(sx, sy, top)), st, 2.2);
|
|
480
|
+
const zs = [0, 0.75, 1.5, 2.25, 3.0, 3.7, top];
|
|
481
|
+
for (let i = 0; i < zs.length - 1; i++) {
|
|
482
|
+
mo += line(W(leg(-1, 1, zs[i])), W(leg(1, 1, zs[i + 1])), st, 1.2) + line(W(leg(1, 1, zs[i])), W(leg(-1, 1, zs[i + 1])), st, 1.2);
|
|
483
|
+
mo += line(W(leg(1, -1, zs[i])), W(leg(1, 1, zs[i + 1])), st, 1.2) + line(W(leg(1, 1, zs[i])), W(leg(1, -1, zs[i + 1])), st, 1.2);
|
|
484
|
+
mo +=
|
|
485
|
+
line(W(leg(-1, 1, zs[i + 1])), W(leg(1, 1, zs[i + 1])), st, 1.4) + line(W(leg(1, -1, zs[i + 1])), W(leg(1, 1, zs[i + 1])), st, 1.4);
|
|
486
|
+
}
|
|
487
|
+
for (const [dx, dy] of [
|
|
488
|
+
[0, 0.17],
|
|
489
|
+
[0.17, 0],
|
|
490
|
+
[0.12, 0.12],
|
|
491
|
+
])
|
|
492
|
+
mo += box(c0 + dx - 0.05, c1 + dy - 0.05, 3.55, 0.1, 0.1, 0.65, '#eef0f2', '#dfe3e8', '#b9c0ca', '#5b636f');
|
|
493
|
+
const dc = P(c0 + 0.15, c1 + 0.35, 2.7);
|
|
494
|
+
mo += `<ellipse cx="${f(dc[0] + 3)}" cy="${f(dc[1])}" rx="7" ry="10" fill="#c9ced6" stroke="#5b636f" stroke-width="1"/><ellipse cx="${f(dc[0] + 4)}" cy="${f(dc[1])}" rx="2" ry="3" fill="#5b636f"/>`;
|
|
495
|
+
const tp = W(leg(0, 0, top));
|
|
496
|
+
mo += line(tp, [tp[0], tp[1] - 14], st, 1.6) + `<circle cx="${f(tp[0])}" cy="${f(tp[1] - 15)}" r="3" fill="#D63B2F"/>`;
|
|
497
|
+
o = `<ellipse cx="${f(P(c0, c1)[0] + 6)}" cy="${f(P(c0, c1)[1] + 2)}" rx="34" ry="12" fill="${K.ao}"/>` + mo + o;
|
|
498
|
+
return {
|
|
499
|
+
svg: o,
|
|
500
|
+
ant: [c0, c1, top + 0.45],
|
|
501
|
+
own: true,
|
|
502
|
+
pts: [...cube(x + 0.2, y + 1.3, 0, 2.0, 1.7, 1.12), leg(-1, -1, 0), leg(1, 1, 0), leg(1, -1, 0), [c0, c1, top + 0.45]],
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
function plain(x, y) {
|
|
506
|
+
const m = M.plain, w = 3, d = 3, h = 1.6, Y = y + d, X = x + w;
|
|
507
|
+
let o = ao(x, y, w, d) + mbox(x, y, 0, w, d, h, m);
|
|
508
|
+
o += coursesL(Y, x, X, 0, h, 0.4, m.tex) + coursesR(X, y, Y, 0, h, 0.4, m.texR);
|
|
509
|
+
o += door2(m, Y, x + 1.15, x + 1.85, 0.95) + quadL(Y, x + 1.05, x + 1.95, 0.95, 1.02, '#9a9488');
|
|
510
|
+
o += winL(m, Y, x + 0.3, x + 0.9, 0.35, 0.85, true, 2, false) + winL(m, Y, x + 2.1, x + 2.7, 0.35, 0.85, false, 2, false);
|
|
511
|
+
o +=
|
|
512
|
+
winL(m, Y, x + 0.3, x + 0.9, 1.05, 1.42, false, 2, false) +
|
|
513
|
+
winL(m, Y, x + 1.2, x + 1.8, 1.05, 1.42, true, 2, false) +
|
|
514
|
+
winL(m, Y, x + 2.1, x + 2.7, 1.05, 1.42, false, 2, false);
|
|
515
|
+
for (let i = 0; i < 3; i++) {
|
|
516
|
+
const b = y + 0.3 + i * 0.9;
|
|
517
|
+
o += winR(m, X, b, b + 0.55, 0.35, 0.85, i === 1, 2, false) + winR(m, X, b, b + 0.55, 1.05, 1.42, i === 2, 2, false);
|
|
518
|
+
}
|
|
519
|
+
o += roofWell(x, y, w, d, h + 0.1, m);
|
|
520
|
+
o += hvac(x + 1.6, y + 0.5, h + 0.02, 0.7, 0.6, 0.3);
|
|
521
|
+
return { svg: o, ant: [x + 2.4, y + 2.3, h + 0.02], pts: cube(x, y, 0, w, d, h + 0.35) };
|
|
522
|
+
}
|
|
523
|
+
export const antenna = ([x, y, z]) => {
|
|
524
|
+
const b = P(x, y, z), t = P(x, y, z + 0.8), c = '#3b4252';
|
|
525
|
+
let o = `<ellipse cx="${f(b[0])}" cy="${f(b[1])}" rx="4" ry="2" fill="${c}"/>` + line(b, t, c, 2);
|
|
526
|
+
o += line(P(x - 0.16, y, z + 0.6), P(x + 0.16, y, z + 0.6), c, 1.6) + line(P(x, y - 0.16, z + 0.45), P(x, y + 0.16, z + 0.45), c, 1.6);
|
|
527
|
+
return o + `<circle cx="${f(t[0])}" cy="${f(t[1])}" r="3.4" fill="#ffffff" stroke="#3B4252" stroke-width="2"/>`;
|
|
528
|
+
};
|
|
529
|
+
const BUILD = {
|
|
530
|
+
person: house,
|
|
531
|
+
phone: house,
|
|
532
|
+
shop,
|
|
533
|
+
desk: (x, y) => office(x, y, 2),
|
|
534
|
+
team: (x, y) => office(x, y, 3),
|
|
535
|
+
truck: depot,
|
|
536
|
+
queue: shed,
|
|
537
|
+
server: (x, y) => hall(x, y, M.slate, '#6f95e3'),
|
|
538
|
+
cloud: (x, y) => hall(x, y, M.pale, '#3d7be0'),
|
|
539
|
+
cabinet: archive,
|
|
540
|
+
gear: works,
|
|
541
|
+
tower: mast,
|
|
542
|
+
};
|
|
543
|
+
function tree(x, y, s = 1, kind = 0) {
|
|
544
|
+
const [gx, gy] = P(x, y, 0);
|
|
545
|
+
let o = `<ellipse cx="${f(gx + 6 * s)}" cy="${f(gy + 2)}" rx="${f(13 * s)}" ry="${f(6 * s)}" fill="${K.ao}"/>`;
|
|
546
|
+
o += box(x - 0.06, y - 0.06, 0, 0.12, 0.12, 0.4 * s, K.trunk, K.trunk, '#574837');
|
|
547
|
+
const [cx, cy] = P(x, y, 0.4 * s);
|
|
548
|
+
if (kind === 0) {
|
|
549
|
+
const r = 15 * s;
|
|
550
|
+
o += `<circle cx="${f(cx)}" cy="${f(cy - r + 4)}" r="${f(r)}" fill="${K.leafD}"/>`;
|
|
551
|
+
o += `<circle cx="${f(cx - r * 0.2)}" cy="${f(cy - r + 4 - r * 0.2)}" r="${f(r * 0.78)}" fill="${K.leaf}"/>`;
|
|
552
|
+
}
|
|
553
|
+
else {
|
|
554
|
+
const h = 44 * s, w = 14 * s;
|
|
555
|
+
o += poly([
|
|
556
|
+
[cx, cy - h],
|
|
557
|
+
[cx + w, cy + 2],
|
|
558
|
+
[cx, cy + 6 * s],
|
|
559
|
+
], K.leafD);
|
|
560
|
+
o += poly([
|
|
561
|
+
[cx, cy - h],
|
|
562
|
+
[cx, cy + 6 * s],
|
|
563
|
+
[cx - w, cy + 2],
|
|
564
|
+
], K.leaf);
|
|
565
|
+
}
|
|
566
|
+
return o;
|
|
567
|
+
}
|
|
568
|
+
const shrub = (x, y, r) => {
|
|
569
|
+
const [gx, gy] = P(x, y, 0), R = r * U;
|
|
570
|
+
return `<ellipse cx="${f(gx + 3)}" cy="${f(gy + 1)}" rx="${f(R * 1.15)}" ry="${f(R * 0.5)}" fill="${K.ao}"/><circle cx="${f(gx)}" cy="${f(gy - R * 0.62)}" r="${f(R * 0.72)}" fill="${K.leafD}"/><circle cx="${f(gx - R * 0.16)}" cy="${f(gy - R * 0.74)}" r="${f(R * 0.52)}" fill="${K.leaf}"/>`;
|
|
571
|
+
};
|
|
572
|
+
export function hull(points) {
|
|
573
|
+
const p = points.slice().sort((a, b) => a[0] - b[0] || a[1] - b[1]);
|
|
574
|
+
const cross = (o, a, b) => (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0]);
|
|
575
|
+
const lo = [], up = [];
|
|
576
|
+
for (const q of p) {
|
|
577
|
+
while (lo.length >= 2 && cross(lo[lo.length - 2], lo[lo.length - 1], q) <= 0)
|
|
578
|
+
lo.pop();
|
|
579
|
+
lo.push(q);
|
|
580
|
+
}
|
|
581
|
+
for (const q of p.slice().reverse()) {
|
|
582
|
+
while (up.length >= 2 && cross(up[up.length - 2], up[up.length - 1], q) <= 0)
|
|
583
|
+
up.pop();
|
|
584
|
+
up.push(q);
|
|
585
|
+
}
|
|
586
|
+
return lo.slice(0, -1).concat(up.slice(0, -1));
|
|
587
|
+
}
|
|
588
|
+
export function street(looks, withAntenna, pitch, step = 0) {
|
|
589
|
+
const n = looks.length, X0 = -40, X1 = (n - 1) * pitch + 44;
|
|
590
|
+
const bends = [];
|
|
591
|
+
for (let i = 0, x = 0, y = 0; step && i < n; i++) {
|
|
592
|
+
bends.push([x, y + 7]);
|
|
593
|
+
if (i % 2)
|
|
594
|
+
x += step;
|
|
595
|
+
else
|
|
596
|
+
y += step;
|
|
597
|
+
}
|
|
598
|
+
const stack = step > 0, xs = looks.map((_, i) => (stack ? bends[i][0] - 5.4 : i * pitch)), ys = looks.map((_, i) => (stack ? bends[i][1] - 7 : 0));
|
|
599
|
+
let g = '';
|
|
600
|
+
const objs = [], lots = [];
|
|
601
|
+
if (stack) {
|
|
602
|
+
const e = bends[n - 1], roads = [[e[0], e[0] + (n % 2 ? 0 : 40), e[1], e[1] + (n % 2 ? 40 : 0)]];
|
|
603
|
+
bends.forEach(([x, y], i) => {
|
|
604
|
+
const [u, v] = bends[i + 1] ?? [x, y];
|
|
605
|
+
if (i < n - 1)
|
|
606
|
+
roads.push([x, u, y, v]);
|
|
607
|
+
if (!i || i % 2)
|
|
608
|
+
roads.push([xs[i] - 2, x, y, y]);
|
|
609
|
+
});
|
|
610
|
+
const lo = Math.min(...xs) - 40, hi = Math.max(...xs) + 44;
|
|
611
|
+
g = quadT(lo, hi, -40, Math.max(...ys) + 60, 0, K.lawn);
|
|
612
|
+
for (const [h, fill] of [
|
|
613
|
+
[1.6, K.walk],
|
|
614
|
+
[1.05, K.curb],
|
|
615
|
+
[1, K.road],
|
|
616
|
+
])
|
|
617
|
+
for (const [x0, x1, y0, y1] of roads)
|
|
618
|
+
g += quadT(x0 - h, x1 + h, y0 - h, y1 + h, 0, fill);
|
|
619
|
+
for (const [x0, x1, y0, y1] of roads)
|
|
620
|
+
for (let u = 1.6; u < Math.max(x1 - x0, y1 - y0) - 1.6; u += 1.2) {
|
|
621
|
+
const v = Math.min(u + 0.6, Math.max(x1 - x0, y1 - y0) - 1.6);
|
|
622
|
+
g += y0 === y1 ? quadT(x0 + u, x0 + v, y0 - 0.03, y0 + 0.03, 0, K.dash) : quadT(x0 - 0.03, x0 + 0.03, y0 + u, y0 + v, 0, K.dash);
|
|
623
|
+
}
|
|
624
|
+
const clear = (x, y) => roads.every(([x0, x1, y0, y1]) => x < x0 - 2.5 || x > x1 + 2.5 || y < y0 - 2.5 || y > y1 + 2.5) &&
|
|
625
|
+
xs.every((lx, i) => x < lx - 1.4 || x > lx + 4.4 || y < ys[i] + BY - 1.4 || y > ys[i] + FRONT + 1.4);
|
|
626
|
+
xs.forEach((x, i) => {
|
|
627
|
+
for (const [dx, dy] of [
|
|
628
|
+
[-4.6, -1.6],
|
|
629
|
+
[7.4, -1.6],
|
|
630
|
+
[4.6, 4],
|
|
631
|
+
[-3, 9],
|
|
632
|
+
])
|
|
633
|
+
if (clear(x + dx, ys[i] + dy))
|
|
634
|
+
objs.push([x + dx + ys[i] + dy, tree(x + dx, ys[i] + dy)]);
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
else {
|
|
638
|
+
g = quadT(X0, X1, -40, FRONT - 0.15, 0, K.lawn) + quadT(X0, X1, WALK1, 60, 0, K.lawn);
|
|
639
|
+
for (const x of xs)
|
|
640
|
+
for (const [a, b, c, d] of [
|
|
641
|
+
[-7.5, -2.5, 10.5, 15],
|
|
642
|
+
[3, 8, 10.8, 14.6],
|
|
643
|
+
[-6, -1.5, -6, 0.6],
|
|
644
|
+
])
|
|
645
|
+
g += quadT(x + a, x + b, c, d, 0, K.yard);
|
|
646
|
+
}
|
|
647
|
+
xs.forEach((x, i) => (g += quadT(x - 0.3, x + 3.3, FRONT - 0.15 + ys[i], WALK0 + ys[i], 0, K.yard)));
|
|
648
|
+
const seamX = (x0, x1, y0, y1) => {
|
|
649
|
+
let o = '';
|
|
650
|
+
for (let x = Math.ceil(x0 * 2) / 2; x < x1; x += 0.5)
|
|
651
|
+
o += line(P(x, y0), P(x, y1), K.seam, 1);
|
|
652
|
+
return o;
|
|
653
|
+
};
|
|
654
|
+
if (!stack) {
|
|
655
|
+
g += quadT(X0, X1, WALK0, ROAD0, 0, K.walk) + seamX(X0, X1, WALK0, ROAD0);
|
|
656
|
+
g += quadT(X0, X1, ROAD1, WALK1, 0, K.walk) + seamX(X0, X1, ROAD1, WALK1);
|
|
657
|
+
g += quadT(X0, X1, ROAD0, ROAD1, 0, K.road);
|
|
658
|
+
g += quadT(X0, X1, ROAD0, ROAD0 + 0.05, 0, K.curb) + quadT(X0, X1, ROAD1 - 0.05, ROAD1, 0, K.curb);
|
|
659
|
+
for (let x = X0; x < X1; x += 1.2)
|
|
660
|
+
g += quadT(x, x + 0.6, 7.18, 7.24, 0, K.dash);
|
|
661
|
+
}
|
|
662
|
+
xs.forEach((x, i) => (g += quadT(x + 1.05, x + 1.95, FRONT + ys[i], WALK0 + ys[i], 0, K.walk) + seamX(x + 1.05, x + 1.95, FRONT + ys[i], WALK0 + ys[i])));
|
|
663
|
+
looks.forEach((look, i) => {
|
|
664
|
+
const x = xs[i], y = ys[i] + BY, b = ((look && BUILD[look]) || plain)(x, y), tip = [b.ant[0], b.ant[1], b.ant[2] + (b.own ? 0 : 0.8)];
|
|
665
|
+
if (withAntenna[i] && !b.own)
|
|
666
|
+
b.svg += antenna(b.ant);
|
|
667
|
+
const hl = hull((withAntenna[i] ? [...b.pts, tip] : b.pts).map((p) => P(...p))).map(([u, v]) => [f(u), f(v)]);
|
|
668
|
+
const top = hl.reduce((q, p) => (p[1] < q[1] ? p : q));
|
|
669
|
+
const v = P(x, y, 1.5);
|
|
670
|
+
const [rx, ry] = P(...tip);
|
|
671
|
+
lots.push({
|
|
672
|
+
x,
|
|
673
|
+
y: ys[i],
|
|
674
|
+
hull: hl,
|
|
675
|
+
tag: [f(v[0]), f(top[1])],
|
|
676
|
+
door: x + 1.5,
|
|
677
|
+
depot: b.depot ?? null,
|
|
678
|
+
roof: withAntenna[i] ? [f(rx), f(ry)] : null,
|
|
679
|
+
});
|
|
680
|
+
objs.push([x + 1.5 + y + 1.5, `<g class="bld" id="b-${i}">${b.svg}</g>`]);
|
|
681
|
+
});
|
|
682
|
+
for (const x of stack ? [] : xs) {
|
|
683
|
+
for (const [dx, y, s, k] of [
|
|
684
|
+
[-4.6, -1.6, 1, 0],
|
|
685
|
+
[7.4, -1.6, 1, 0],
|
|
686
|
+
[4.6, 13.2, 1, 0],
|
|
687
|
+
])
|
|
688
|
+
objs.push([x + dx + y, tree(x + dx, y, s, k)]);
|
|
689
|
+
for (const [dx, r] of [
|
|
690
|
+
[-4.2, 0.34],
|
|
691
|
+
[4.2, 0.36],
|
|
692
|
+
])
|
|
693
|
+
objs.push([x + dx + 9.2, shrub(x + dx, 9.15, r)]);
|
|
694
|
+
}
|
|
695
|
+
const pads = xs
|
|
696
|
+
.map((x, i) => `<g class="pad" id="pad-${i}">${quadT(x - 0.55, x + 3.55, BY - 0.55 + ys[i], BY + 3.5 + ys[i], 0, '#FBFAF3')}</g>`)
|
|
697
|
+
.join('');
|
|
698
|
+
return {
|
|
699
|
+
svg: g +
|
|
700
|
+
pads +
|
|
701
|
+
objs
|
|
702
|
+
.sort((p, q) => p[0] - q[0])
|
|
703
|
+
.map((o) => o[1])
|
|
704
|
+
.join(''),
|
|
705
|
+
lots,
|
|
706
|
+
bends,
|
|
707
|
+
};
|
|
708
|
+
}
|
|
709
|
+
export const LANE = 6.6, TD = 0.78, BAR_Y = 5.7, GZ = 0.8, GL = 1.2;
|
|
710
|
+
const BH = 0.46;
|
|
711
|
+
export const BED_ROWS = [LANE - 0.19, LANE + 0.19];
|
|
712
|
+
export const INK = { ink: '#141A22', data: '#2456D6', fail: '#B8322A', muted: '#646C79' };
|
|
713
|
+
const BARREL = { side: '#D9822B', shade: '#B4661D', top: '#EDAA5E', rim: '#6E3E10' };
|
|
714
|
+
const at = (p, inner, id = '') => `<g${id ? ` id="${id}"` : ''} transform="translate(${f(p[0])} ${f(p[1])})">${inner}</g>`;
|
|
715
|
+
function barrel() {
|
|
716
|
+
const BR = 0.17, rx = BR * Math.SQRT2 * C, ry = BR * Math.SQRT2 * S, h = BH * U, k = 0.35, sk = Math.sqrt(1 - k * k);
|
|
717
|
+
const T = BARREL;
|
|
718
|
+
let o = `<path d="M${f(-rx)},${f(-h)} L${f(-rx)},0 A${f(rx)} ${f(ry)} 0 0 0 ${f(rx)},0 L${f(rx)},${f(-h)} Z" fill="${T.side}"/>`;
|
|
719
|
+
o += `<path d="M${f(k * rx)},${f(-h + ry * sk)} L${f(k * rx)},${f(ry * sk)} A${f(rx)} ${f(ry)} 0 0 0 ${f(rx)},0 L${f(rx)},${f(-h)} A${f(rx)} ${f(ry)} 0 0 1 ${f(k * rx)},${f(-h + ry * sk)} Z" fill="${T.shade}"/>`;
|
|
720
|
+
for (const q of [0.3, 0.68])
|
|
721
|
+
o += `<path d="M${f(-rx)},${f(-h * q)} A${f(rx)} ${f(ry)} 0 0 0 ${f(rx)},${f(-h * q)}" fill="none" stroke="${T.rim}" stroke-opacity=".7" stroke-width="1"/>`;
|
|
722
|
+
o += `<path d="M${f(-rx)},${f(-h)} L${f(-rx)},0 A${f(rx)} ${f(ry)} 0 0 0 ${f(rx)},0 L${f(rx)},${f(-h)}" fill="none" stroke="${T.rim}" stroke-opacity=".8" stroke-width="1"/>`;
|
|
723
|
+
o += `<ellipse cx="0" cy="${f(-h)}" rx="${f(rx)}" ry="${f(ry)}" fill="${T.top}" stroke="${T.rim}" stroke-width="1"/>`;
|
|
724
|
+
o += `<ellipse cx="0" cy="${f(-h)}" rx="${f(rx * 0.74)}" ry="${f(ry * 0.74)}" fill="none" stroke="${T.rim}" stroke-opacity=".55" stroke-width=".8"/>`;
|
|
725
|
+
return o + `<ellipse cx="${f(rx * 0.38)}" cy="${f(-h - ry * 0.1)}" rx="1.6" ry="1" fill="${T.rim}"/>`;
|
|
726
|
+
}
|
|
727
|
+
function carton() {
|
|
728
|
+
const w = 0.48, d = 0.48, h = 0.38, x = -w / 2, y = -d / 2;
|
|
729
|
+
let o = box(x, y, 0, w, d, h, '#e3c48f', '#c99a5b', '#ad8046', '#6b4a22');
|
|
730
|
+
o +=
|
|
731
|
+
quadT(x + w / 2 - 0.035, x + w / 2 + 0.035, y, y + d, h, '#a07a45') +
|
|
732
|
+
quadL(y + d, x + w / 2 - 0.035, x + w / 2 + 0.035, h - 0.12, h, '#a07a45');
|
|
733
|
+
o += quadL(y + d, x + 0.06, x + 0.2, 0.08, 0.16, '#f4ecdc') + quadL(y + d, x + 0.06, x + 0.17, 0.2, 0.23, '#f4ecdc');
|
|
734
|
+
return o;
|
|
735
|
+
}
|
|
736
|
+
function notes() {
|
|
737
|
+
const w = 0.44, d = 0.28, h = 0.16, x = -w / 2, y = -d / 2;
|
|
738
|
+
let o = box(x, y, 0, w, d, h, '#cfe3c9', '#7fb07a', '#5f9160', '#2f5a33');
|
|
739
|
+
o += quadL(y + d, -0.04, 0.04, 0, h, '#f4f6fb') + quadT(-0.04, 0.04, y, y + d, h, '#f4f6fb');
|
|
740
|
+
for (const k of [0.05, 0.1])
|
|
741
|
+
o += quadL(y + d, x + 0.02, x + w - 0.02, k, k + 0.012, '#5f9160');
|
|
742
|
+
return o;
|
|
743
|
+
}
|
|
744
|
+
export const UNIT = { barrel: barrel(), box: carton(), notes: notes() };
|
|
745
|
+
export function truckArt(depot) {
|
|
746
|
+
const ty = LANE - TD / 2, TY = ty + TD, bedL = 1.78, bedX = 0.68, m = M.green;
|
|
747
|
+
const steel = ['#9aa2ae', '#7d8592', '#646c79', '#2a3142'];
|
|
748
|
+
const rail = (x, y, w, d, z, h) => box(x, y, z, w, d, h, steel[0], steel[1], steel[2], steel[3]);
|
|
749
|
+
const wheelAt = (wx) => poly(Array.from({ length: 20 }, (_, i) => {
|
|
750
|
+
const a = (i / 20) * Math.PI * 2;
|
|
751
|
+
return P(wx + 0.17 * Math.cos(a), TY + 0.01, 0.2 + 0.17 * Math.sin(a));
|
|
752
|
+
}), '#1b2130') +
|
|
753
|
+
poly(Array.from({ length: 14 }, (_, i) => {
|
|
754
|
+
const a = (i / 14) * Math.PI * 2;
|
|
755
|
+
return P(wx + 0.07 * Math.cos(a), TY + 0.02, 0.2 + 0.07 * Math.sin(a));
|
|
756
|
+
}), '#8b9099');
|
|
757
|
+
let tBack = quadT(-0.05, 2.6, ty, TY + 0.25, 0, K.ao) + box(0, ty, 0.2, 2.5, TD, 0.16, '#3a4458', '#2a3142', '#222838', '#11151c');
|
|
758
|
+
tBack +=
|
|
759
|
+
box(0, ty, 0.36, 0.64, TD, 0.72, '#a9c2a4', m.l, m.r, m.e) +
|
|
760
|
+
box(0.06, ty + 0.06, 1.08, 0.54, TD - 0.12, 0.05, '#c3d2bf', '#8fac8a', '#6f8c6b');
|
|
761
|
+
tBack +=
|
|
762
|
+
quadL(TY, 0.1, 0.52, 0.72, 0.98, K.glass) +
|
|
763
|
+
quadR(0.64, ty + 0.08, TY - 0.08, 0.5, 0.98, '#587553') +
|
|
764
|
+
quadL(TY, 0.08, 0.58, 0.42, 0.48, m.cap) +
|
|
765
|
+
quadL(TY, 0.04, 0.14, 0.52, 0.6, K.light);
|
|
766
|
+
tBack +=
|
|
767
|
+
rail(bedX, ty, bedL, 0.05, 0.43, 0.36) +
|
|
768
|
+
box(bedX, ty, 0.36, bedL, TD, 0.07, '#8b929d', '#6b7280', '#5a6170', '#2a3142') +
|
|
769
|
+
rail(bedX, ty, 0.07, TD, 0.43, 0.5);
|
|
770
|
+
const tailX = bedX + bedL - 0.05;
|
|
771
|
+
let tFront = rail(bedX, TY - 0.05, bedL, 0.05, 0.43, 0.13) + rail(tailX, ty, 0.05, TD, 0.43, 0.2);
|
|
772
|
+
tFront +=
|
|
773
|
+
quadR(tailX + 0.05, ty + 0.05, ty + 0.15, 0.48, 0.56, INK.fail) + quadR(tailX + 0.05, TY - 0.15, TY - 0.05, 0.48, 0.56, INK.fail);
|
|
774
|
+
tFront += [0.36, 1.64, 2.14].map(wheelAt).join('');
|
|
775
|
+
const rBed = 0.04, rCab = 1.86;
|
|
776
|
+
let rBack = quadT(-0.05, 2.6, ty, TY + 0.25, 0, K.ao) + box(0, ty, 0.2, 2.5, TD, 0.16, '#3a4458', '#2a3142', '#222838', '#11151c');
|
|
777
|
+
rBack +=
|
|
778
|
+
rail(rBed, ty, bedL, 0.05, 0.43, 0.36) +
|
|
779
|
+
box(rBed, ty, 0.36, bedL, TD, 0.07, '#8b929d', '#6b7280', '#5a6170', '#2a3142') +
|
|
780
|
+
rail(rBed, ty, 0.05, TD, 0.43, 0.2);
|
|
781
|
+
let rFront = rail(rBed, TY - 0.05, bedL, 0.05, 0.43, 0.13) + rail(rBed + bedL - 0.07, ty, 0.07, TD, 0.43, 0.5);
|
|
782
|
+
rFront +=
|
|
783
|
+
box(rCab, ty, 0.36, 0.64, TD, 0.72, '#a9c2a4', m.l, m.r, m.e) +
|
|
784
|
+
box(rCab + 0.04, ty + 0.06, 1.08, 0.54, TD - 0.12, 0.05, '#c3d2bf', '#8fac8a', '#6f8c6b');
|
|
785
|
+
rFront +=
|
|
786
|
+
quadR(rCab + 0.64, ty + 0.1, TY - 0.1, 0.72, 1.0, K.glassR) +
|
|
787
|
+
quadL(TY, rCab + 0.12, rCab + 0.54, 0.72, 0.98, K.glass) +
|
|
788
|
+
quadL(TY, rCab + 0.08, rCab + 0.58, 0.42, 0.48, m.cap) +
|
|
789
|
+
quadL(TY, rCab + 0.5, rCab + 0.6, 0.52, 0.6, K.light);
|
|
790
|
+
rFront += [0.36, 0.86, 2.14].map(wheelAt).join('');
|
|
791
|
+
const slotsL = [0.27, 0.69, 1.11, 1.53].map((d) => bedX + d + 0.06), slotsR = [0.27, 0.69, 1.11, 1.53].map((d) => rBed + d - 0.04);
|
|
792
|
+
const loadL = BED_ROWS.flatMap((y, r) => slotsL.map((x, i) => at(P(x, y, 0.43), '', 'tl' + (r * 4 + i)))).join(''), loadR = BED_ROWS.flatMap((y, r) => slotsR.map((x, i) => at(P(x, y, 0.43), '', 'tr' + (r * 4 + i)))).join('');
|
|
793
|
+
const outDoor = hull([depot.x + 0.2, depot.x + 1.9].flatMap((x) => [depot.y, depot.y + 6].flatMap((y) => [0, 2.5].map((z) => P(x, y, z)))))
|
|
794
|
+
.map((p) => p.map((v) => f(v)).join(','))
|
|
795
|
+
.join(' ');
|
|
796
|
+
const wheelY = (wy) => poly(Array.from({ length: 20 }, (_, i) => {
|
|
797
|
+
const a = (i / 20) * Math.PI * 2;
|
|
798
|
+
return P(TD + 0.01, wy + 0.17 * Math.cos(a), 0.2 + 0.17 * Math.sin(a));
|
|
799
|
+
}), '#1b2130') +
|
|
800
|
+
poly(Array.from({ length: 14 }, (_, i) => {
|
|
801
|
+
const a = (i / 14) * Math.PI * 2;
|
|
802
|
+
return P(TD + 0.02, wy + 0.07 * Math.cos(a), 0.2 + 0.07 * Math.sin(a));
|
|
803
|
+
}), '#8b9099');
|
|
804
|
+
const chassis = quadT(-0.05, TD + 0.25, -0.05, 2.6, 0, K.ao) + box(0, 0, 0.2, TD, 2.5, 0.16, '#3a4458', '#2a3142', '#222838', '#11151c');
|
|
805
|
+
const yBack = chassis +
|
|
806
|
+
rail(0, 0.04, 0.05, 1.78, 0.43, 0.36) +
|
|
807
|
+
box(0, 0.04, 0.36, TD, 1.78, 0.07, '#8b929d', '#6b7280', '#5a6170', '#2a3142') +
|
|
808
|
+
rail(0, 0.04, TD, 0.05, 0.43, 0.2);
|
|
809
|
+
let yFront = rail(TD - 0.05, 0.04, 0.05, 1.78, 0.43, 0.13) + rail(0, 1.75, TD, 0.07, 0.43, 0.5);
|
|
810
|
+
yFront +=
|
|
811
|
+
box(0, 1.86, 0.36, TD, 0.64, 0.72, '#a9c2a4', m.l, m.r, m.e) +
|
|
812
|
+
box(0.06, 1.92, 1.08, TD - 0.12, 0.52, 0.05, '#c3d2bf', '#8fac8a', '#6f8c6b');
|
|
813
|
+
yFront +=
|
|
814
|
+
quadL(2.5, 0.1, TD - 0.1, 0.72, 1.0, K.glass) +
|
|
815
|
+
quadR(TD, 1.95, 2.4, 0.72, 0.98, K.glassR) +
|
|
816
|
+
quadL(2.5, 0.08, TD - 0.08, 0.42, 0.48, m.cap);
|
|
817
|
+
yFront += quadL(2.5, 0.05, 0.16, 0.52, 0.6, K.light) + quadL(2.5, TD - 0.16, TD - 0.05, 0.52, 0.6, K.light);
|
|
818
|
+
yFront += [0.36, 0.86, 2.14].map(wheelY).join('');
|
|
819
|
+
let uBack = chassis + box(0, 0, 0.36, TD, 0.64, 0.72, '#a9c2a4', m.l, m.r, m.e) + quadR(TD, 0.1, 0.5, 0.72, 0.98, K.glassR);
|
|
820
|
+
uBack +=
|
|
821
|
+
rail(0, 0.68, 0.05, 1.78, 0.43, 0.36) +
|
|
822
|
+
box(0, 0.68, 0.36, TD, 1.78, 0.07, '#8b929d', '#6b7280', '#5a6170', '#2a3142') +
|
|
823
|
+
rail(0, 0.68, TD, 0.07, 0.43, 0.5);
|
|
824
|
+
let uFront = rail(TD - 0.05, 0.68, 0.05, 1.78, 0.43, 0.13) + rail(0, 2.41, TD, 0.05, 0.43, 0.2);
|
|
825
|
+
uFront += quadL(2.46, 0.05, 0.16, 0.46, 0.56, INK.fail) + quadL(2.46, TD - 0.16, TD - 0.05, 0.46, 0.56, INK.fail);
|
|
826
|
+
uFront += [0.36, 1.64, 2.14].map(wheelY).join('');
|
|
827
|
+
const loadY = (k, y0) => [0, 1]
|
|
828
|
+
.flatMap((r) => [0.27, 0.69, 1.11, 1.53].map((d, i) => at(P(TD / 2 - 0.19 + 0.38 * r, y0 + d, 0.43), '', k + (r * 4 + i))))
|
|
829
|
+
.join('');
|
|
830
|
+
return {
|
|
831
|
+
door: `<g id="depotDoor">${quadL(depot.y + 0.002, depot.x + 0.3, depot.x + 1.8, 0, 1.03, '#1d222b')}<g id="doorPanel"></g></g>`,
|
|
832
|
+
yard: `<clipPath id="outDoor"><polygon points="${outDoor}"/></clipPath><g clip-path="url(#outDoor)"><g id="truckY">${yBack + yFront}</g></g>`,
|
|
833
|
+
road: `<g id="truck" display="none"><g>${tBack}</g><g>${loadL}</g><g>${tFront}</g></g><g id="truckR" display="none"><g>${rBack}</g><g>${loadR}</g><g>${rFront}</g></g><g id="truckD" display="none">${yBack + loadY('td', 0.1) + yFront}</g><g id="truckU" display="none">${uBack + loadY('tu', 0.74) + uFront}</g>`,
|
|
834
|
+
slots: { L: slotsL, R: slotsR },
|
|
835
|
+
};
|
|
836
|
+
}
|
|
837
|
+
const screens = `<g class="scr" data-s="idle"><path d="M-6,-5 h12 M-6,0 h9 M-6,5 h7" stroke="${INK.ink}" stroke-opacity=".4" stroke-width="1.6" stroke-linecap="round"/></g>
|
|
838
|
+
<g class="scr" data-s="tx" display="none"><circle r="8" fill="${INK.data}"/><path d="M0,4V-4M-3.5,-.5L0,-4L3.5,-.5" stroke="#fff" stroke-width="1.8" fill="none" stroke-linecap="round" stroke-linejoin="round"/></g>
|
|
839
|
+
<g class="scr" data-s="in" display="none"><rect x="-7" y="-9" width="14" height="9" rx="2" fill="${INK.data}"/><path d="M-6,4 h12 M-6,8 h8" stroke="${INK.ink}" stroke-opacity=".4" stroke-width="1.6" stroke-linecap="round"/></g>`;
|
|
840
|
+
function phone(w, h) {
|
|
841
|
+
let o = `<rect x="${-w / 2}" y="${-h}" width="${w}" height="${h}" rx="${f(w * 0.2)}" fill="${INK.ink}"/>`;
|
|
842
|
+
o += `<rect x="${f(-w / 2 + w * 0.09)}" y="${f(-h + h * 0.12)}" width="${f(w * 0.82)}" height="${f(h * 0.76)}" rx="${f(w * 0.08)}" fill="#F4F5F0"/>`;
|
|
843
|
+
o += `<rect x="${f(-w * 0.12)}" y="${f(-h + h * 0.045)}" width="${f(w * 0.24)}" height="${f(h * 0.03)}" rx="1" fill="#3b4252"/>`;
|
|
844
|
+
return `${o}<g transform="translate(0 ${f(-h / 2)})">${screens}</g>`;
|
|
845
|
+
}
|
|
846
|
+
export const PHONE = { svg: phone(26, 46), w: 26, h: 46 };
|
|
847
|
+
export function gateArt(g) {
|
|
848
|
+
const post = (x, h) => box(x - 0.09, g.y - 0.09, 0, 0.18, 0.18, h, '#5a6372', '#434b5a', '#2e3440', '#14181e');
|
|
849
|
+
const b = P(g.px, g.y);
|
|
850
|
+
return `<g class="gt"><ellipse cx="${f(b[0] + 4)}" cy="${f(b[1] + 1)}" rx="12" ry="5" fill="${K.ao}"/>
|
|
851
|
+
${post(g.ex, GZ - 0.1)}${box(g.ex - 0.13, g.y - 0.13, GZ - 0.1, 0.26, 0.26, 0.05, '#2e3440', '#2e3440', '#1d222b')}
|
|
852
|
+
${post(g.px, GZ + 0.12)}${box(g.px - 0.32, g.y - 0.11, GZ - 0.14, 0.24, 0.22, 0.22, '#5a6372', '#434b5a', '#2e3440', '#14181e')}
|
|
853
|
+
<line class="arm" stroke-width="5" stroke-linecap="round"/><line class="armW" stroke="#ffffff" stroke-width="5" stroke-dasharray="6 6"/><circle class="hub" r="3.5" fill="#2e3440"/></g>`;
|
|
854
|
+
}
|