@tileflow/core 0.1.0-alpha.42 → 0.1.0-alpha.44
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 +56 -69
- package/THIRD_PARTY_NOTICES.md +3 -3
- package/dist/{3d-CzLTD0RK.d.ts → 3d-CW5Ls0An.d.ts} +32 -2
- package/dist/3d.d.ts +1 -1
- package/dist/3d.js +425 -50
- package/dist/browser.d.ts +95 -5
- package/dist/browser.js +866 -101
- package/dist/build.d.ts +8 -4
- package/dist/build.js +250 -3
- package/dist/config-reference.json +3395 -2140
- package/dist/{icon-composition-B1A2udKb.d.ts → icon-composition-Bbw9umUA.d.ts} +37 -2
- package/dist/index.d.ts +13 -4
- package/dist/index.js +193 -3
- package/dist/{manifest-types-B0lQjabX.d.ts → manifest-types-CwjHd4qc.d.ts} +8 -0
- package/dist/manifest.d.ts +2 -2
- package/dist/native-profile.d.ts +4 -0
- package/dist/native-profile.js +2 -0
- package/dist/native.js +789 -462
- package/dist/runtime.d.ts +1 -1
- package/dist/worker/camera-tile-worker.global.js +2 -2
- package/package.json +5 -6
- package/docs/application-tile-reading.md +0 -86
- package/docs/authoring-model.md +0 -269
- package/docs/boundary-areas-and-choropleths.md +0 -230
- package/docs/buildings-3d.md +0 -624
- package/docs/camera-moves-and-tile-cache.md +0 -112
- package/docs/capture-scenes.md +0 -40
- package/docs/capture-shots.md +0 -173
- package/docs/cartographic-defaults.md +0 -214
- package/docs/compiled-style-performance.md +0 -286
- package/docs/data-is-separate-from-design.md +0 -610
- package/docs/depth-markers.md +0 -65
- package/docs/dynamic-style-images.md +0 -100
- package/docs/globe-atmosphere.md +0 -113
- package/docs/hosted-session-authorization.md +0 -106
- package/docs/map-and-terrain-examples.md +0 -156
- package/docs/map-emphasis.md +0 -89
- package/docs/native-artifact-profile.md +0 -152
- package/docs/native-resource-urls.md +0 -369
- package/docs/nautical-marks.md +0 -308
- package/docs/public-api-and-browser-subpath.md +0 -101
- package/docs/route-drawing.md +0 -191
- package/docs/shared-visual-primitives.md +0 -101
- package/docs/street-lights.md +0 -127
- package/docs/street-sky.md +0 -156
- package/docs/style-states.md +0 -73
- package/docs/sun-and-light.md +0 -167
- package/docs/theme-transitions-and-blends.md +0 -317
- package/docs/themes-and-module-styles.md +0 -156
- package/docs/trees-3d.md +0 -295
package/dist/browser.js
CHANGED
|
@@ -1224,7 +1224,7 @@ var init_meshopt_decoder = __esm({
|
|
|
1224
1224
|
}
|
|
1225
1225
|
});
|
|
1226
1226
|
|
|
1227
|
-
// ../../node_modules/.pnpm/maplibre-contour@0.1.
|
|
1227
|
+
// ../../node_modules/.pnpm/maplibre-contour@0.1.1/node_modules/maplibre-contour/dist/index.mjs
|
|
1228
1228
|
var dist_exports = {};
|
|
1229
1229
|
__export(dist_exports, {
|
|
1230
1230
|
default: () => mlcontour$1
|
|
@@ -1248,7 +1248,7 @@ function define(_2, chunk) {
|
|
|
1248
1248
|
}
|
|
1249
1249
|
var shared3, worker, mlcontour, mlcontour$1;
|
|
1250
1250
|
var init_dist = __esm({
|
|
1251
|
-
"../../node_modules/.pnpm/maplibre-contour@0.1.
|
|
1251
|
+
"../../node_modules/.pnpm/maplibre-contour@0.1.1/node_modules/maplibre-contour/dist/index.mjs"() {
|
|
1252
1252
|
"use strict";
|
|
1253
1253
|
define(["exports"], (function(exports) {
|
|
1254
1254
|
"use strict";
|
|
@@ -1596,13 +1596,10 @@ var init_dist = __esm({
|
|
|
1596
1596
|
});
|
|
1597
1597
|
}
|
|
1598
1598
|
function prepareContourTile(promise) {
|
|
1599
|
-
return promise.then(({ arrayBuffer }) => {
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
transferrables: [clone]
|
|
1604
|
-
};
|
|
1605
|
-
});
|
|
1599
|
+
return promise.then(({ arrayBuffer }) => ({
|
|
1600
|
+
arrayBuffer,
|
|
1601
|
+
transferrables: [arrayBuffer]
|
|
1602
|
+
}));
|
|
1606
1603
|
}
|
|
1607
1604
|
let supportsOffscreenCanvas = null;
|
|
1608
1605
|
function offscreenCanvasSupported() {
|
|
@@ -1665,6 +1662,10 @@ var init_dist = __esm({
|
|
|
1665
1662
|
var _a2;
|
|
1666
1663
|
return Boolean((_a2 = abortController === null || abortController === void 0 ? void 0 : abortController.signal) === null || _a2 === void 0 ? void 0 : _a2.aborted);
|
|
1667
1664
|
}
|
|
1665
|
+
function parseUrl(url) {
|
|
1666
|
+
const [, z2, x3, y2] = /\/\/(\d+)\/(\d+)\/(\d+)/.exec(url) || [];
|
|
1667
|
+
return [Number(z2), Number(x3), Number(y2)];
|
|
1668
|
+
}
|
|
1668
1669
|
let num = 0;
|
|
1669
1670
|
class AsyncCache {
|
|
1670
1671
|
constructor(maxSize = 100) {
|
|
@@ -2644,9 +2645,7 @@ var init_dist = __esm({
|
|
|
2644
2645
|
function writeLayer(layer, pbf) {
|
|
2645
2646
|
if (!pbf)
|
|
2646
2647
|
throw new Error("pbf undefined");
|
|
2647
|
-
pbf.writeVarintField(15, 2);
|
|
2648
2648
|
pbf.writeStringField(1, layer.id || "");
|
|
2649
|
-
pbf.writeVarintField(5, layer.extent || 4096);
|
|
2650
2649
|
const context = {
|
|
2651
2650
|
keys: [],
|
|
2652
2651
|
values: [],
|
|
@@ -2663,6 +2662,8 @@ var init_dist = __esm({
|
|
|
2663
2662
|
for (const value of context.values) {
|
|
2664
2663
|
pbf.writeMessage(4, writeValue, value);
|
|
2665
2664
|
}
|
|
2665
|
+
pbf.writeVarintField(5, layer.extent || 4096);
|
|
2666
|
+
pbf.writeVarintField(15, 2);
|
|
2666
2667
|
}
|
|
2667
2668
|
function writeFeature(context, pbf) {
|
|
2668
2669
|
const feature = context.feature;
|
|
@@ -2708,7 +2709,7 @@ var init_dist = __esm({
|
|
|
2708
2709
|
function command(cmd, length) {
|
|
2709
2710
|
return (length << 3) + (cmd & 7);
|
|
2710
2711
|
}
|
|
2711
|
-
function
|
|
2712
|
+
function zigzag3(num2) {
|
|
2712
2713
|
return num2 << 1 ^ num2 >> 31;
|
|
2713
2714
|
}
|
|
2714
2715
|
function writeGeometry(feature, pbf) {
|
|
@@ -2732,8 +2733,8 @@ var init_dist = __esm({
|
|
|
2732
2733
|
}
|
|
2733
2734
|
const dx = ring[i2 * 2] - x3;
|
|
2734
2735
|
const dy = ring[i2 * 2 + 1] - y2;
|
|
2735
|
-
pbf.writeVarint(
|
|
2736
|
-
pbf.writeVarint(
|
|
2736
|
+
pbf.writeVarint(zigzag3(dx));
|
|
2737
|
+
pbf.writeVarint(zigzag3(dy));
|
|
2737
2738
|
x3 += dx;
|
|
2738
2739
|
y2 += dy;
|
|
2739
2740
|
}
|
|
@@ -2911,7 +2912,7 @@ var init_dist = __esm({
|
|
|
2911
2912
|
}
|
|
2912
2913
|
fetchDem(z2, x3, y2, options, abortController, timer) {
|
|
2913
2914
|
return __awaiter(this, void 0, void 0, function* () {
|
|
2914
|
-
const zoom = Math.min(z2 - (options.overzoom || 0), this.maxzoom);
|
|
2915
|
+
const zoom = Math.max(0, Math.min(z2 - (options.overzoom || 0), this.maxzoom));
|
|
2915
2916
|
const subZ = z2 - zoom;
|
|
2916
2917
|
const div = 1 << subZ;
|
|
2917
2918
|
const newX = Math.floor(x3 / div);
|
|
@@ -2926,7 +2927,7 @@ var init_dist = __esm({
|
|
|
2926
2927
|
return Promise.resolve({ arrayBuffer: new ArrayBuffer(0) });
|
|
2927
2928
|
}
|
|
2928
2929
|
const key = [z2, x3, y2, encodeIndividualOptions(options)].join("/");
|
|
2929
|
-
|
|
2930
|
+
const cached = this.contourCache.get(key, (_2, childAbortController) => __awaiter(this, void 0, void 0, function* () {
|
|
2930
2931
|
const max2 = 1 << z2;
|
|
2931
2932
|
const neighborPromises = [];
|
|
2932
2933
|
for (let iy = y2 - 1; iy <= y2 + 1; iy++) {
|
|
@@ -2969,8 +2970,11 @@ var init_dist = __esm({
|
|
|
2969
2970
|
}
|
|
2970
2971
|
});
|
|
2971
2972
|
mark === null || mark === void 0 ? void 0 : mark();
|
|
2972
|
-
return { arrayBuffer: result.buffer };
|
|
2973
|
+
return { arrayBuffer: result.slice().buffer };
|
|
2973
2974
|
}), parentAbortController);
|
|
2975
|
+
return cached.then(({ arrayBuffer }) => ({
|
|
2976
|
+
arrayBuffer: copy(arrayBuffer)
|
|
2977
|
+
}));
|
|
2974
2978
|
}
|
|
2975
2979
|
}
|
|
2976
2980
|
let id = 0;
|
|
@@ -3054,13 +3058,14 @@ var init_dist = __esm({
|
|
|
3054
3058
|
exports.L = LocalDemManager;
|
|
3055
3059
|
exports.T = Timer;
|
|
3056
3060
|
exports._ = __awaiter;
|
|
3057
|
-
exports.a =
|
|
3058
|
-
exports.b =
|
|
3061
|
+
exports.a = parseUrl;
|
|
3062
|
+
exports.b = decodeOptions;
|
|
3059
3063
|
exports.c = decodeParsedImage;
|
|
3060
3064
|
exports.d = defaultDecoder;
|
|
3061
3065
|
exports.e = encodeOptions;
|
|
3062
|
-
exports.f =
|
|
3066
|
+
exports.f = generateIsolines;
|
|
3063
3067
|
exports.g = getOptionsForZoom;
|
|
3068
|
+
exports.h = prepareContourTile;
|
|
3064
3069
|
exports.p = prepareDemTile;
|
|
3065
3070
|
}));
|
|
3066
3071
|
define(["./shared"], (function(actor) {
|
|
@@ -3083,7 +3088,7 @@ var init_dist = __esm({
|
|
|
3083
3088
|
};
|
|
3084
3089
|
this.fetchContourTile = (managerId, z2, x3, y2, options, abortController, timer) => {
|
|
3085
3090
|
var _a2;
|
|
3086
|
-
return actor.
|
|
3091
|
+
return actor.h(((_a2 = this.managers[managerId]) === null || _a2 === void 0 ? void 0 : _a2.fetchContourTile(z2, x3, y2, options, abortController, timer)) || noManager(managerId));
|
|
3087
3092
|
};
|
|
3088
3093
|
}
|
|
3089
3094
|
}
|
|
@@ -3152,7 +3157,7 @@ var init_dist = __esm({
|
|
|
3152
3157
|
maplibre.addProtocol(this.contourProtocolId, this.contourProtocol);
|
|
3153
3158
|
};
|
|
3154
3159
|
this.sharedDemProtocolV4 = (request, abortController) => actor._(this, void 0, void 0, function* () {
|
|
3155
|
-
const [z2, x3, y2] =
|
|
3160
|
+
const [z2, x3, y2] = actor.a(request.url);
|
|
3156
3161
|
const timer = new actor.T("main");
|
|
3157
3162
|
let timing;
|
|
3158
3163
|
try {
|
|
@@ -3175,8 +3180,8 @@ var init_dist = __esm({
|
|
|
3175
3180
|
const timer = new actor.T("main");
|
|
3176
3181
|
let timing;
|
|
3177
3182
|
try {
|
|
3178
|
-
const [z2, x3, y2] =
|
|
3179
|
-
const options = actor.
|
|
3183
|
+
const [z2, x3, y2] = actor.a(request.url);
|
|
3184
|
+
const options = actor.b(request.url);
|
|
3180
3185
|
const data = yield this.manager.fetchContourTile(z2, x3, y2, actor.g(options, z2), abortController, timer);
|
|
3181
3186
|
timing = timer.finish(request.url);
|
|
3182
3187
|
return { data: data.arrayBuffer };
|
|
@@ -3213,13 +3218,9 @@ var init_dist = __esm({
|
|
|
3213
3218
|
getDemTile(z2, x3, y2, abortController) {
|
|
3214
3219
|
return this.manager.fetchAndParseTile(z2, x3, y2, abortController || new AbortController());
|
|
3215
3220
|
}
|
|
3216
|
-
parseUrl(url) {
|
|
3217
|
-
const [, z2, x3, y2] = /\/\/(\d+)\/(\d+)\/(\d+)/.exec(url) || [];
|
|
3218
|
-
return [Number(z2), Number(x3), Number(y2)];
|
|
3219
|
-
}
|
|
3220
3221
|
}
|
|
3221
3222
|
const exported = {
|
|
3222
|
-
generateIsolines: actor.
|
|
3223
|
+
generateIsolines: actor.f,
|
|
3223
3224
|
DemSource,
|
|
3224
3225
|
HeightTile: actor.H,
|
|
3225
3226
|
LocalDemManager: actor.L,
|
|
@@ -3304,7 +3305,11 @@ function createTileflowDynamicImageRegistry(input, context, beforeRestore) {
|
|
|
3304
3305
|
if (existing && existing !== entry.installed && !isRestoredCopy(existing, entry.recoveryImage)) {
|
|
3305
3306
|
throw new Error(`Dynamic image "${entry.name}" conflicts with an existing image owner.`);
|
|
3306
3307
|
}
|
|
3307
|
-
if (!existing)
|
|
3308
|
+
if (!existing)
|
|
3309
|
+
map.addImage(entry.name, entry.pixels, {
|
|
3310
|
+
pixelRatio: entry.pixelRatio,
|
|
3311
|
+
...entry.definition.sdf ? { sdf: true } : {}
|
|
3312
|
+
});
|
|
3308
3313
|
else if (changed) map.updateImage(entry.name, entry.pixels);
|
|
3309
3314
|
entry.installed = map.getImage(entry.name);
|
|
3310
3315
|
entry.recoveryImage = void 0;
|
|
@@ -5320,6 +5325,7 @@ var tileflowSkyHazeReachFloor = 3;
|
|
|
5320
5325
|
var nineTenths = 0.8042;
|
|
5321
5326
|
function tileflowSkyReachDepth(view, reach) {
|
|
5322
5327
|
const sin = Math.sin(radians(view.pitch));
|
|
5328
|
+
if (reach.forward !== void 0) return 1 + reach.forward * sin;
|
|
5323
5329
|
const cos = Math.cos(radians(view.pitch));
|
|
5324
5330
|
const back = -sin;
|
|
5325
5331
|
const across = Math.atan(view.aspect * Math.tan(view.fov / 2));
|
|
@@ -5393,7 +5399,8 @@ function reachOf(map, distance) {
|
|
|
5393
5399
|
return {
|
|
5394
5400
|
ahead: (east * Math.sin(bearing) + north * Math.cos(bearing)) / metres,
|
|
5395
5401
|
across: (east * Math.cos(bearing) - north * Math.sin(bearing)) / metres,
|
|
5396
|
-
radius: reach.radius / metres
|
|
5402
|
+
radius: reach.radius / metres,
|
|
5403
|
+
...reach.forward === void 0 ? {} : { forward: reach.forward / metres }
|
|
5397
5404
|
};
|
|
5398
5405
|
}
|
|
5399
5406
|
function fovOf(map, args) {
|
|
@@ -5737,6 +5744,59 @@ function withAlpha(color, alpha) {
|
|
|
5737
5744
|
// src/browser.ts
|
|
5738
5745
|
init_camera_limits();
|
|
5739
5746
|
|
|
5747
|
+
// src/horizon-queries-browser.ts
|
|
5748
|
+
var horizonShare2 = 0.85;
|
|
5749
|
+
var maximumHorizonAngle = 89.25 * Math.PI / 180;
|
|
5750
|
+
function tileflowHorizonScaleFactor(view) {
|
|
5751
|
+
const pitch = view.pitch * Math.PI / 180;
|
|
5752
|
+
const horizon = Math.min(
|
|
5753
|
+
Math.tan(Math.PI / 2 - pitch) * horizonShare2,
|
|
5754
|
+
Math.tan(maximumHorizonAngle - pitch)
|
|
5755
|
+
);
|
|
5756
|
+
const top = Math.min(view.centerY / view.cameraToCenterDistance, horizon);
|
|
5757
|
+
return 1 / (1 - Math.tan(pitch) * top);
|
|
5758
|
+
}
|
|
5759
|
+
function attachTileflowHorizonQueries(map) {
|
|
5760
|
+
const target = map;
|
|
5761
|
+
const query = target.queryRenderedFeatures;
|
|
5762
|
+
if (typeof query !== "function") return () => {
|
|
5763
|
+
};
|
|
5764
|
+
const own = Object.prototype.hasOwnProperty.call(target, "queryRenderedFeatures");
|
|
5765
|
+
const corrected = /* @__PURE__ */ new Map();
|
|
5766
|
+
const correct = (transform) => {
|
|
5767
|
+
const original = transform?.maxPitchScaleFactor;
|
|
5768
|
+
if (!transform || typeof original !== "function" || corrected.has(transform)) return;
|
|
5769
|
+
const own2 = Object.prototype.hasOwnProperty.call(transform, "maxPitchScaleFactor");
|
|
5770
|
+
corrected.set(transform, own2 ? original : void 0);
|
|
5771
|
+
transform.maxPitchScaleFactor = function() {
|
|
5772
|
+
const value = original.call(this);
|
|
5773
|
+
if (value > 0 && Number.isFinite(value)) return value;
|
|
5774
|
+
const fallback = tileflowHorizonScaleFactor({
|
|
5775
|
+
pitch: this.pitch,
|
|
5776
|
+
centerY: this.centerPoint.y,
|
|
5777
|
+
cameraToCenterDistance: this.cameraToCenterDistance
|
|
5778
|
+
});
|
|
5779
|
+
return fallback > 0 && Number.isFinite(fallback) ? fallback : value;
|
|
5780
|
+
};
|
|
5781
|
+
};
|
|
5782
|
+
const wrapped = function(...args) {
|
|
5783
|
+
correct(target._camera?.transform ?? target.transform);
|
|
5784
|
+
return query.apply(this, args);
|
|
5785
|
+
};
|
|
5786
|
+
target.queryRenderedFeatures = wrapped;
|
|
5787
|
+
return () => {
|
|
5788
|
+
if (target.queryRenderedFeatures === wrapped) {
|
|
5789
|
+
if (own) target.queryRenderedFeatures = query;
|
|
5790
|
+
else delete target.queryRenderedFeatures;
|
|
5791
|
+
}
|
|
5792
|
+
for (const [transform, original] of corrected) {
|
|
5793
|
+
if (original) transform.maxPitchScaleFactor = original;
|
|
5794
|
+
else delete transform.maxPitchScaleFactor;
|
|
5795
|
+
}
|
|
5796
|
+
corrected.clear();
|
|
5797
|
+
};
|
|
5798
|
+
}
|
|
5799
|
+
|
|
5740
5800
|
// src/canvas-context-browser.ts
|
|
5741
5801
|
function tileflowCanvasContextAttributes(attributes4) {
|
|
5742
5802
|
return { antialias: true, ...attributes4 };
|
|
@@ -6384,6 +6444,7 @@ function readModelRoleLighting(value) {
|
|
|
6384
6444
|
...typeof entry.emissiveColor === "string" ? { emissiveColor: entry.emissiveColor } : {},
|
|
6385
6445
|
...typeof entry.color === "string" ? { color: entry.color } : {},
|
|
6386
6446
|
...entry.colorMix === void 0 ? {} : { colorMix: bounded(entry.colorMix, 0, 1, 1) },
|
|
6447
|
+
...entry.colorScale === void 0 ? {} : { colorScale: bounded(entry.colorScale, 0, 1, 1) },
|
|
6387
6448
|
...entry.metallic === void 0 ? {} : { metallic: bounded(entry.metallic, 0, 1, 0) },
|
|
6388
6449
|
...entry.roughness === void 0 ? {} : { roughness: bounded(entry.roughness, 0, 1, 1) },
|
|
6389
6450
|
...entry.shading === "map" || entry.shading === "physical" ? { shading: entry.shading } : {},
|
|
@@ -6486,6 +6547,7 @@ var tileflowDefaultBuildings3DDesign = Object.freeze({
|
|
|
6486
6547
|
shadows: true,
|
|
6487
6548
|
occlusion: true,
|
|
6488
6549
|
groundOcclusion: 0.16,
|
|
6550
|
+
groundOcclusionRadius: 3,
|
|
6489
6551
|
modelOcclusion: 0.75
|
|
6490
6552
|
});
|
|
6491
6553
|
function readTileflowBuildings3D(metadata) {
|
|
@@ -6523,7 +6585,11 @@ function readTileflowBuildings3D(metadata) {
|
|
|
6523
6585
|
shadows: typeof value.shadows === "boolean" ? value.shadows : defaults.shadows,
|
|
6524
6586
|
occlusion: typeof value.occlusion === "boolean" ? value.occlusion : defaults.occlusion,
|
|
6525
6587
|
groundOcclusion: within(value.groundOcclusion, 1, defaults.groundOcclusion),
|
|
6588
|
+
groundOcclusionRadius: within(value.groundOcclusionRadius, 20, defaults.groundOcclusionRadius),
|
|
6526
6589
|
modelOcclusion: within(value.modelOcclusion, 1, defaults.modelOcclusion),
|
|
6590
|
+
...Array.isArray(value.flatLayers) && value.flatLayers.length <= 128 && value.flatLayers.every(
|
|
6591
|
+
(entry) => isRecord6(entry) && typeof entry.id === "string" && typeof entry.visible === "boolean"
|
|
6592
|
+
) ? { flatLayers: value.flatLayers } : {},
|
|
6527
6593
|
...modelsOf(value.models),
|
|
6528
6594
|
...modelColorsOf(value.modelColors),
|
|
6529
6595
|
...landmarksOf(value.landmarks)
|
|
@@ -8364,11 +8430,11 @@ var growth = `
|
|
|
8364
8430
|
uniform float u_scale;
|
|
8365
8431
|
uniform vec2 u_offset; // this tile's corner from the scene's origin, in tile units
|
|
8366
8432
|
uniform float u_metres; // metres per tile unit
|
|
8367
|
-
//
|
|
8368
|
-
//
|
|
8369
|
-
// ground, in this tile's axes.
|
|
8433
|
+
// In this tile's units: origin and start/end of the fade along the view, or centre and radii of the
|
|
8434
|
+
// fallback covered disc. The direction is along the ground in this tile's axes.
|
|
8370
8435
|
uniform vec4 u_ring;
|
|
8371
8436
|
uniform vec2 u_ring_ahead;
|
|
8437
|
+
uniform bool u_ring_directional;
|
|
8372
8438
|
|
|
8373
8439
|
float progressOf() {
|
|
8374
8440
|
return clamp(u_scale * 1.25 - a_wave.x * 0.25, 0.0, 1.0);
|
|
@@ -8380,9 +8446,11 @@ float elevationOf(float own, float top, float p) {
|
|
|
8380
8446
|
}
|
|
8381
8447
|
|
|
8382
8448
|
// Buildings sink into the ground over the last stretch of the city's reach, so it ends without an
|
|
8383
|
-
// edge of cut-off blocks.
|
|
8384
|
-
//
|
|
8449
|
+
// edge of cut-off blocks. The view-aligned fade leaves the entire near width standing; the legacy
|
|
8450
|
+
// disc fallback also exempts its near side.
|
|
8385
8451
|
float reachOf(vec2 position) {
|
|
8452
|
+
if (u_ring_directional)
|
|
8453
|
+
return 1.0 - smoothstep(u_ring.z, u_ring.w, dot(position - u_ring.xy, u_ring_ahead));
|
|
8386
8454
|
if (u_ring.w <= 0.0) return 1.0;
|
|
8387
8455
|
vec2 from = position - u_ring.xy;
|
|
8388
8456
|
float far = smoothstep(0.0, u_ring.w - u_ring.z, dot(from, u_ring_ahead));
|
|
@@ -9750,6 +9818,9 @@ function readTileflowVegetation3D(metadata) {
|
|
|
9750
9818
|
{
|
|
9751
9819
|
heightScale: scale(own.heightScale),
|
|
9752
9820
|
crownScale: scale(own.crownScale),
|
|
9821
|
+
...typeof own.sizeAnchor === "number" && Number.isFinite(own.sizeAnchor) ? { sizeAnchor: clamp(own.sizeAnchor, [1, 45]) } : {},
|
|
9822
|
+
...typeof own.crownAnchor === "number" && Number.isFinite(own.crownAnchor) ? { crownAnchor: clamp(own.crownAnchor, [1, 25]) } : {},
|
|
9823
|
+
...typeof own.sizeCompression === "number" && Number.isFinite(own.sizeCompression) ? { sizeCompression: clamp(own.sizeCompression, [0, 1]) } : {},
|
|
9753
9824
|
...drawn.length > 0 ? { models: drawn } : {}
|
|
9754
9825
|
}
|
|
9755
9826
|
]
|
|
@@ -10069,7 +10140,7 @@ function browserWorker() {
|
|
|
10069
10140
|
if (typeof Worker === "undefined" || false)
|
|
10070
10141
|
return;
|
|
10071
10142
|
const url = URL.createObjectURL(
|
|
10072
|
-
new Blob(['"use strict";(()=>{var Be=new Set,ln=!1;function Pe(e,n,t=2){let i=n&&n.length,o=i?n[0]*t:e.length;Be.size&&Be.clear();let r=zn(e,0,o,t,!0),s=[];if(!r||r.next===r.prev)return s;let a=0,l=0,u=0;if(i&&(r=xt(e,n,r,t)),e.length>80*t){a=e[0],l=e[1];let c=a,f=l;for(let d=t;d<o;d+=t){let g=e[d],m=e[d+1];g<a&&(a=g),m<l&&(l=m),g>c&&(c=g),m>f&&(f=m)}u=Math.max(c-a,f-l),u=u!==0?32767/u:0}return un(r,s,a,l,u),s}function zn(e,n,t,i,o){let r=null;if(o===Ut(e,n,t,i)>0)for(let s=n;s<t;s+=i)r=In(s/i|0,e[s],e[s+1],r);else for(let s=t-i;s>=n;s-=i)r=In(s/i|0,e[s],e[s+1],r);return r&&Oe(r,r.next)&&(Ce(r),r=r.next),r}function ge(e,n=e){let t=n===e,i=e,o;do o=!1,i!==i.next&&(Be.size===0||!Be.has(i))&&(Oe(i,i.next)||Q(i.prev,i,i.next)===0)?((t||i===n)&&(n=i.prev),ln=!0,Ce(i),i=i.prev,o=!0):(t||i!==n)&&(i=i.next,o=!t);while(o||i!==n);return n}function un(e,n,t,i,o){o&&Ft(e,t,i,o);let r=e,s=!1;for(;e.prev!==e.next;){let a=e.prev,l=e.next;if(Q(a,e,l)<0&&(o?bt(e,t,i,o):yt(e))){n.push(a.i,e.i,l.i),Ce(e),e=l,r=l;continue}if(e=l,e===r){if(ln=!1,e=ge(e),ln){r=e;continue}if(!s){e=gt(e,n),r=e,s=!0;continue}wt(e,n,t,i,o);break}}}function yt(e){let n=e.prev,t=e,i=e.next,o=n.x,r=t.x,s=i.x,a=n.y,l=t.y,u=i.y,c=Math.min(o,r,s),f=Math.min(a,l,u),d=Math.max(o,r,s),g=Math.max(a,l,u),m=i.next;for(;m!==n;){if(m.x>=c&&m.x<=d&&m.y>=f&&m.y<=g&&!(o===m.x&&a===m.y)&&Ke(o,a,r,l,s,u,m.x,m.y)&&Q(m.prev,m,m.next)>=0)return!1;m=m.next}return!0}function bt(e,n,t,i){let o=e.prev,r=e,s=e.next,a=o.x,l=r.x,u=s.x,c=o.y,f=r.y,d=s.y,g=Math.min(a,l,u),m=Math.min(c,f,d),p=Math.max(a,l,u),h=Math.max(c,f,d),_=mn(g,m,n,t,i),F=mn(p,h,n,t,i),k=e.prevZ;for(;k&&k.z>=_;){if(k.x>=g&&k.x<=p&&k.y>=m&&k.y<=h&&k!==s&&!(a===k.x&&c===k.y)&&Ke(a,c,l,f,u,d,k.x,k.y)&&Q(k.prev,k,k.next)>=0)return!1;k=k.prevZ}let M=e.nextZ;for(;M&&M.z<=F;){if(M.x>=g&&M.x<=p&&M.y>=m&&M.y<=h&&M!==s&&!(a===M.x&&c===M.y)&&Ke(a,c,l,f,u,d,M.x,M.y)&&Q(M.prev,M,M.next)>=0)return!1;M=M.nextZ}return!0}function gt(e,n){let t=e,i=!1;do{let o=t.prev,r=t.next.next;Dn(o,t,t.next,r,!1)&&Ue(o,r)&&Ue(r,o)&&(n.push(o.i,t.i,r.i),Ce(t),Ce(t.next),t=e=r,i=!0),t=t.next}while(t!==e);return i?ge(t):t}function wt(e,n,t,i,o){let r=e;do{let s=r.next.next;for(;s!==r.prev;){if(r.i!==s.i&&Lt(r,s)){let a=Vn(r,s);r=ge(r,r.next),a=ge(a,a.next),un(r,n,t,i,o),un(a,n,t,i,o);return}s=s.next}r=r.next}while(r!==e)}var cn=!1;function xt(e,n,t,i){let o=[];for(let r=0,s=n.length;r<s;r++){let a=n[r]*i,l=r<s-1?n[r+1]*i:e.length,u=zn(e,a,l,i,!1);u===u.next&&Be.add(u),o.push(St(u))}o.sort(Tt),kt(e.length/i,n.length),Nn(t,t),cn=!0;for(let r=0;r<o.length;r++)t=Mt(o[r],t);return cn=!1,ge(t)}function Tt(e,n){return e.x-n.x||e.y-n.y||(e.next.y-e.y)/(e.next.x-e.x)-(n.next.y-n.y)/(n.next.x-n.x)}function Mt(e,n){let t=Rt(e,n);if(!t)return n;let i=Vn(t,e),o=i.next;return Nn(t,o.next),ge(i,i.next),ge(t,t.next)}var jn=16,X=new Float64Array(0),Je=0,fn=[],dn=[];function kt(e,n){let t=Math.ceil((e+2*n)/jn)+n+2;X.length<t*4&&(X=new Float64Array(t*4)),Je=0}function Nn(e,n){let t=e;do{let i=Je++;fn[i]=t;let o=t.x,r=t.y,s=t.x,a=t.y,l=0;do{let c=t.next;t.z=i,c.x<o&&(o=c.x),c.x>s&&(s=c.x),c.y<r&&(r=c.y),c.y>a&&(a=c.y),t=c}while(++l<jn&&t!==n);dn[i]=t;let u=i*4;X[u]=o,X[u+1]=r,X[u+2]=s,X[u+3]=a}while(t!==n)}function vt(e,n){let t=e.z*4;n.x<X[t]&&(X[t]=n.x),n.y<X[t+1]&&(X[t+1]=n.y),n.x>X[t+2]&&(X[t+2]=n.x),n.y>X[t+3]&&(X[t+3]=n.y)}function Pn(e){let n=dn[e];for(;n.prev.next!==n;)n=n.next;return dn[e]=n,n}function En(e){let n=fn[e];for(;n.prev.next!==n;)n=n.next;return fn[e]=n,n}function Rt(e,n){let t=n,i=e.x,o=e.y,r=-1/0,s;if(Oe(e,t))return t;for(let d=0,g=0;d<Je;d++,g+=4){if(o<X[g+1]||o>X[g+3]||X[g]>i||X[g+2]<=r)continue;let m=Pn(d);t=En(d);do{if(t.prev.next===t){if(Oe(e,t.next))return t.next;if(o<=t.y&&o>=t.next.y&&t.next.y!==t.y){let p=t.x+(o-t.y)*(t.next.x-t.x)/(t.next.y-t.y);if(p<=i&&p>r&&(r=p,s=t.x<t.next.x?t:t.next,p===i))return s}}t=t.next}while(t!==m)}if(!s)return null;let a=s.x,l=s.y,u=Math.min(o,l),c=Math.max(o,l),f=1/0;for(let d=0,g=0;d<Je;d++,g+=4){if(X[g+2]<a||X[g]>i||X[g+3]<u||X[g+1]>c)continue;let m=Pn(d);t=En(d);do{if(t.prev.next===t&&i>=t.x&&t.x>=a&&i!==t.x&&Ke(o<l?i:r,o,a,l,o<l?r:i,o,t.x,t.y)){let p=Math.abs(o-t.y)/(i-t.x);(Ue(t,e)||t.y===o&&t.next.y===o&&t.next.x>i)&&(p<f||p===f&&(t.x>s.x||t.x===s.x&&_t(s,t)))&&(s=t,f=p)}t=t.next}while(t!==m)}return s}function _t(e,n){return Q(e.prev,e,n.prev)<0&&Q(n.next,e,e.next)<0}var ie=[],ve=[],be=new Uint32Array(0),Se=new Uint32Array(0),Le=new Uint32Array(256);function Ft(e,n,t,i){let o=e,r=0;do o.z=mn(o.x,o.y,n,t,i),ie[r++]=o,o=o.next;while(o!==e);At(r);let s=null;for(let a=0;a<r;a++){let l=ie[a];l.prevZ=s,s&&(s.nextZ=l),s=l}s.nextZ=null,ie.fill(null,0,r),ve.fill(null,0,r)}function At(e){if(e<=32){for(let n=1;n<e;n++){let t=ie[n],i=t.z,o=n-1;for(;o>=0&&ie[o].z>i;)ie[o+1]=ie[o],o--;ie[o+1]=t}return}be.length<e&&(be=new Uint32Array(e),Se=new Uint32Array(e),ve=new Array(e));for(let n=0;n<e;n++)be[n]=ie[n].z;Xe(e,ie,be,ve,Se,0),Xe(e,ve,Se,ie,be,8),Xe(e,ie,be,ve,Se,16),Xe(e,ve,Se,ie,be,24)}function Xe(e,n,t,i,o,r){Le.fill(0);for(let a=0;a<e;a++)Le[t[a]>>>r&255]++;let s=0;for(let a=0;a<256;a++){let l=Le[a];Le[a]=s,s+=l}for(let a=0;a<e;a++){let l=t[a],u=Le[l>>>r&255]++;i[u]=n[a],o[u]=l}}function mn(e,n,t,i,o){return e=(e-t)*o|0,n=(n-i)*o|0,e=(e|e<<8)&16711935,e=(e|e<<4)&252645135,e=(e|e<<2)&858993459,e=(e|e<<1)&1431655765,n=(n|n<<8)&16711935,n=(n|n<<4)&252645135,n=(n|n<<2)&858993459,n=(n|n<<1)&1431655765,e|n<<1}function St(e){let n=e,t=e;do(n.x<t.x||n.x===t.x&&n.y<t.y)&&(t=n),n=n.next;while(n!==e);return t}function Ke(e,n,t,i,o,r,s,a){return(o-s)*(n-a)>=(e-s)*(r-a)&&(e-s)*(i-a)>=(t-s)*(n-a)&&(t-s)*(r-a)>=(o-s)*(i-a)}function Lt(e,n){let t=Oe(e,n)&&Q(e.prev,e,e.next)>0&&Q(n.prev,n,n.next)>0;return e.next.i!==n.i&&(t||Ue(e,n)&&Ue(n,e)&&(Q(e.prev,e,n.prev)!==0||Q(e,n.prev,n)!==0))&&!Bt(e,n)&&(t||Ot(e,n))}function Q(e,n,t){return(n.y-e.y)*(t.x-n.x)-(n.x-e.x)*(t.y-n.y)}function Oe(e,n){return e.x===n.x&&e.y===n.y}function Dn(e,n,t,i,o=!0){let r=Q(e,n,t),s=Q(e,n,i),a=Q(t,i,e),l=Q(t,i,n);return(r>0&&s<0||r<0&&s>0)&&(a>0&&l<0||a<0&&l>0)?!0:o?!!(r===0&&Ye(e,t,n)||s===0&&Ye(e,i,n)||a===0&&Ye(t,e,i)||l===0&&Ye(t,n,i)):!1}function Ye(e,n,t){return n.x<=Math.max(e.x,t.x)&&n.x>=Math.min(e.x,t.x)&&n.y<=Math.max(e.y,t.y)&&n.y>=Math.min(e.y,t.y)}function Bt(e,n){let t=Math.min(e.x,n.x),i=Math.max(e.x,n.x),o=Math.min(e.y,n.y),r=Math.max(e.y,n.y),s=e;do{let a=s.next;if(s.x>i&&a.x>i||s.x<t&&a.x<t||s.y>r&&a.y>r||s.y<o&&a.y<o){s=a;continue}if(s.i!==e.i&&a.i!==e.i&&s.i!==n.i&&a.i!==n.i&&Dn(s,a,e,n))return!0;s=a}while(s!==e);return!1}function Ue(e,n){return Q(e.prev,e,e.next)<0?Q(e,n,e.next)>=0&&Q(e,e.prev,n)>=0:Q(e,n,e.prev)<0||Q(e,e.next,n)<0}function Ot(e,n){let t=e,i=!1,o=(e.x+n.x)/2,r=(e.y+n.y)/2;do{let s=t.next;t.y>r!=s.y>r&&o<(s.x-t.x)*(r-t.y)/(s.y-t.y)+t.x&&(i=!i),t=s}while(t!==e);return i}function Vn(e,n){let t=hn(e.i,e.x,e.y),i=hn(n.i,n.x,n.y),o=e.next,r=n.prev;return e.next=n,n.prev=e,t.next=o,o.prev=t,i.next=t,t.prev=i,r.next=i,i.prev=r,i}function In(e,n,t,i){let o=hn(e,n,t);return i?(o.next=i.next,o.prev=i,i.next.prev=o,i.next=o):(o.prev=o,o.next=o),o}function Ce(e){e.next.prev=e.prev,e.prev.next=e.next,e.prevZ&&(e.prevZ.nextZ=e.nextZ),e.nextZ&&(e.nextZ.prevZ=e.prevZ),cn&&vt(e.prev,e.next)}function hn(e,n,t){return{i:e,x:n,y:t,prev:null,next:null,z:0,prevZ:null,nextZ:null}}function Ut(e,n,t,i){let o=0;for(let r=n,s=t-i;r<t;r+=i)o+=(e[s]-e[r])*(e[r+1]+e[s+1]),s=r;return o}var Ct=.7,Pt=Math.tan(Math.PI/6),Et=Math.tan(35*Math.PI/180),It=Math.tan(Math.PI/18),Ee=.65,Ie=.4;function Zn(e,n,t,i,o,r,s){let a=String(t.roof_shape??"");if(!a||a==="flat"||a==="sawtooth"||Vt(e,s))return;let l=Nt(e);if(!l||Math.abs(pn(e))<Ct*4*l.halfU*l.halfV)return;let u=l.u,c=l.v,f=l.halfU*r,d=l.halfV*r;f<d&&([u,c,f,d]=[c,u,d,f]);let g=Gn(t.roof_direction),m=g===void 0?void 0:[Math.sin(g*Math.PI/180),-Math.cos(g*Math.PI/180)];(m!==void 0?Math.abs(m[0]*u[0]+m[1]*u[1])>Math.abs(m[0]*c[0]+m[1]*c[1]):t.roof_orientation==="across")&&a!=="skillion"&&([u,c,f,d]=[c,u,d,f]);let h=jt(a,f,d,m&&[$n(m,u),$n(m,c)]);if(!h)return;let _=Math.max(0,o-i),F=Gn(t.roof_height),k,M;if(F!==void 0&&F>0)M=o,k=Math.max(i+Math.min(2,_/2),o-F);else{let y=Math.min(zt(a,d),_*.6,30);t.height_source==="height"?(M=o,k=o-y):(k=o,M=o+y)}let B=M-k;if(!(B>=.3))return;let[U,E]=l.centre,C=(y,b)=>{let x=(y-U)*r,T=(b-E)*r;return[x*u[0]+T*u[1],x*c[0]+T*c[1]]},I=(y,b)=>[U+(y*u[0]+b*c[0])/r,E+(y*u[1]+b*c[1])/r],D=(y,b)=>{let x=1/0;for(let[T,A,v]of h)x=Math.min(x,T*y+A*b+v);return Math.max(0,x)},K=(y,b)=>k+B*D(...C(y,b)),$=[];for(let y=0;y+1<n.length;y+=2)$.push(...C(n[y],n[y+1]));pn($)<0&&Ht($);let N=1.01,Y=[-f*N,-d*N,f*N,-d*N,f*N,d*N,-f*N,d*N],w=[];for(let[y,b]of h.entries()){let x=Y;for(let[P,Z]of h.entries()){if(P===y)continue;let j=b[0]-Z[0],G=b[1]-Z[1],W=b[2]-Z[2];if(Math.abs(j)+Math.abs(G)+Math.abs(W)<1e-9){P<y&&(x=[]);continue}if(x=Hn(x,j,G,W),x.length<6)break}if(x.length<6)continue;let T=$,A=x.length/2;for(let P=0;P<A&&T.length>=6;P+=1){let[Z,j]=[x[P*2],x[P*2+1]],[G,W]=[x[(P+1)%A*2],x[(P+1)%A*2+1]];T=Hn(T,W-j,Z-G,-(W-j)*Z-(Z-G)*j)}if(T.length<6||Math.abs(pn(T))<1e-6)continue;let v=[];for(let P=0;P<T.length;P+=2)v.push(...I(T[P],T[P+1]));let L=Pe(v);if(L.length===0)continue;let O=B*b[0],V=B*b[1],R=O*u[0]+V*c[0],S=O*u[1]+V*c[1],z=Math.hypot(R,S,1);w.push({ring:v,triangles:L,normal:[-R/z,-S/z]})}if(w.length!==0)return{eaves:k,ridge:M,faces:w,heightAt:K,breaks(y,b,x,T){let[A,v]=C(y,b),[L,O]=C(x,T),V=[];for(let R=0;R<h.length;R+=1)for(let S=R+1;S<h.length;S+=1){let z=(ae,H)=>(h[R][0]-h[S][0])*ae+(h[R][1]-h[S][1])*H+(h[R][2]-h[S][2]),P=z(A,v),Z=z(L,O);if(P===Z||P*Z>0)continue;let j=P/(P-Z);if(j<=1e-4||j>=1-1e-4)continue;let G=A+(L-A)*j,W=v+(O-v)*j;h[R][0]*G+h[R][1]*W+h[R][2]<=D(G,W)+1e-6&&V.push(j)}return[...new Set(V.map(R=>Math.round(R*1e6)/1e6))].sort((R,S)=>R-S)}}}function zt(e,n){switch(e){case"skillion":return 2*n*It;case"pyramidal":return n*Et;case"gambrel":case"mansard":return n*.8;case"dome":case"onion":case"round":return n;default:return n*Pt}}function jt(e,n,t,i){let o=n,r=t,s=[[0,-1/r,1],[0,1/r,1]],a=u=>u.flatMap(c=>[1,-1].flatMap(f=>{let d=c==="v"?r:o,g=Ee/(Ie*r)*f,m=(1-Ee)/((1-Ie)*r)*f,p=h=>c==="v"?[0,-h]:[-h,0];return[[...p(g),Ee/(Ie*r)*d],[...p(m),Ee+(1-Ee)/((1-Ie)*r)*(d-Ie*r)]]})),l=[.99,.8,.5,.2];switch(e){case"gabled":return s;case"saltbox":{let u=r/3;return[[0,-1/(r-u),1+u/(r-u)],[0,1/(r+u),1-u/(r+u)]]}case"hipped":return[...s,[-1/r,0,o/r],[1/r,0,o/r]];case"half_hipped":return[...s,[-1/r,0,.5+o/r],[1/r,0,.5+o/r]];case"pyramidal":return[...s,[-1/o,0,1],[1/o,0,1]];case"gambrel":return a(["v"]);case"mansard":return a(["v","u"]);case"skillion":{let[u,c]=i??[0,1],f=Math.abs(u)*o+Math.abs(c)*r;return f>0?[[-u/(2*f),-c/(2*f),.5]]:void 0}case"round":return[[0,0,1],...l.flatMap(u=>{let c=Math.sqrt(1-u*u);return[1,-1].map(f=>[0,-f*u/(r*c),1/c])})];case"dome":case"onion":return[[0,0,1],...l.flatMap(u=>{let c=Math.sqrt(1-u*u);return Array.from({length:12},(f,d)=>{let g=d*Math.PI/6;return[-u*Math.cos(g)/(o*c),-u*Math.sin(g)/(r*c),1/c]})})];default:return}}function Hn(e,n,t,i){let o=e.length/2,r=[];for(let s=0;s<o;s+=1){let a=e[s*2],l=e[s*2+1],u=e[(s+1)%o*2],c=e[(s+1)%o*2+1],f=n*a+t*l+i,d=n*u+t*c+i;if(f<=0&&r.push(a,l),f<0&&d>0||f>0&&d<0){let g=f/(f-d);r.push(a+(u-a)*g,l+(c-l)*g)}}return r}function Nt(e){let n=Dt(e);if(n.length<3)return;let t,i=1/0;for(let o=0;o<n.length;o+=1){let[r,s]=n[o],[a,l]=n[(o+1)%n.length],u=Math.hypot(a-r,l-s);if(u===0)continue;let c=[(a-r)/u,(l-s)/u],f=[-c[1],c[0]],[d,g,m,p]=[1/0,-1/0,1/0,-1/0];for(let[_,F]of n){let k=_*c[0]+F*c[1],M=_*f[0]+F*f[1];d=Math.min(d,k),g=Math.max(g,k),m=Math.min(m,M),p=Math.max(p,M)}let h=(g-d)*(p-m);if(h<i){i=h;let _=(d+g)/2,F=(m+p)/2;t={centre:[_*c[0]+F*f[0],_*c[1]+F*f[1]],u:c,v:f,halfU:(g-d)/2,halfV:(p-m)/2}}}return t&&t.halfU>0&&t.halfV>0?t:void 0}function Dt(e){let n=[];for(let r=0;r+1<e.length;r+=2)n.push([e[r],e[r+1]]);n.sort((r,s)=>r[0]-s[0]||r[1]-s[1]);let t=(r,s,a)=>(s[0]-r[0])*(a[1]-r[1])-(s[1]-r[1])*(a[0]-r[0]),i=[];for(let r of n){for(;i.length>=2&&t(i.at(-2),i.at(-1),r)<=0;)i.pop();i.push(r)}let o=[];for(let r of n.reverse()){for(;o.length>=2&&t(o.at(-2),o.at(-1),r)<=0;)o.pop();o.push(r)}return[...i.slice(0,-1),...o.slice(0,-1)]}function Vt(e,n){let[t,i,o,r]=[1/0,-1/0,1/0,-1/0];for(let a=0;a+1<e.length;a+=2)t=Math.min(t,e[a]),i=Math.max(i,e[a]),o=Math.min(o,e[a+1]),r=Math.max(r,e[a+1]);let s=e.length/2;for(let a=0;a<s;a+=1){let l=e[a*2],u=e[a*2+1],c=e[(a+1)%s*2],f=e[(a+1)%s*2+1];if(t<0&&l===t&&c===t||i>n&&l===i&&c===i||o<0&&u===o&&f===o||r>n&&u===r&&f===r)return!0}return!1}function pn(e){let n=0,t=e.length/2;for(let i=0;i<t;i+=1){let o=(i+1)%t;n+=e[i*2]*e[o*2+1]-e[o*2]*e[i*2+1]}return n/2}function Ht(e){let n=[];for(let t=0;t<e.length;t+=2)n.push([e[t],e[t+1]]);n.reverse(),e.splice(0,e.length,...n.flat())}function $n(e,n){return e[0]*n[0]+e[1]*n[1]}function Gn(e){let n=typeof e=="string"?Number(e):e;return typeof n=="number"&&Number.isFinite(n)?n:void 0}var $t=Object.freeze({surface:0,secondary:1,glass:2,accent:3,roof:4}),Nr=Object.freeze(Object.keys($t));var Dr=Object.freeze({unclassified:0,wall:1,door:2,roof:3,window:4,lamp:5,logo:6});var Vr=Object.freeze({levels:3,vertices:2e5,triangles:2e5,footprintPoints:4096,radius:2e3,height:1e3,models:512,bytes:16*1024*1024,parts:16});function yn(e,n,t){for(let i of e){let o=!1;for(let r=0,s=i.length-2;r<i.length;s=r,r+=2){let a=i[r],l=i[r+1],u=i[s],c=i[s+1];l>t!=c>t&&n<(u-a)*(t-l)/(c-l)+a&&(o=!o)}if(o)return!0}return!1}function Yn(e,n,t){for(let i of n){let[o,r,s,a]=Xn(i);for(let l of e){let[u,c,f,d]=Xn(l);if(!(u>s-t||f<o+t||c>a-t||d<r+t)&&(Wn(l,i,t)||Wn(i,l,t)))return!0}}return!1}function Wn(e,n,t){let i=(o,r)=>yn([n],o,r)&&Zt(n,o,r)>t;for(let o=0;o+1<e.length;o+=2)if(i(e[o],e[o+1]))return!0;for(let o=0,r=e.length-2;o<e.length;r=o,o+=2){let[s,a,l,u]=[e[r],e[r+1],e[o],e[o+1]],c=[0,1];for(let f=0,d=n.length-2;f<n.length;d=f,f+=2){let g=Gt(s,a,l,u,n[d],n[d+1],n[f],n[f+1]);g!==void 0&&c.push(g)}if(c.length!==2){c.sort((f,d)=>f-d);for(let f=1;f<c.length;f+=1){let d=(c[f-1]+c[f])/2;if(i(s+(l-s)*d,a+(u-a)*d))return!0}}}return!1}function Gt(e,n,t,i,o,r,s,a){let l=t-e,u=i-n,c=s-o,f=a-r,d=l*f-u*c;if(d===0)return;let g=((o-e)*f-(r-n)*c)/d,m=((o-e)*u-(r-n)*l)/d;return g>0&&g<1&&m>=0&&m<=1?g:void 0}function Zt(e,n,t){let i=1/0;for(let o=0,r=e.length-2;o<e.length;r=o,o+=2){let[s,a,l,u]=[e[r],e[r+1],e[o],e[o+1]],c=(l-s)**2+(u-a)**2,f=c>0?Math.max(0,Math.min(1,((n-s)*(l-s)+(t-a)*(u-a))/c)):0;i=Math.min(i,Math.hypot(n-(s+(l-s)*f),t-(a+(u-a)*f)))}return i}function Xn(e){let[n,t,i,o]=[1/0,1/0,-1/0,-1/0];for(let r=0;r+1<e.length;r+=2)n=Math.min(n,e[r]),i=Math.max(i,e[r]),t=Math.min(t,e[r+1]),o=Math.max(o,e[r+1]);return[n,t,i,o]}var ue=8192,pe=28,Wt={commercial:1,active:2,destination:3},Xt={residential:1,...Object.fromEntries(["civic","commercial","education","entertainment","medical","transportation"].map(e=>[e,2])),...Object.fromEntries(["agricultural","industrial","military","outbuilding","religious","service"].map(e=>[e,3]))},Yt={dining:1,entertainment:2,nightlife:3},bn={...Object.fromEntries(["alcoholic_beverage_venue","bar","beer","biergarten","brewery","casino","cocktail_bar","dance_club","karaoke","lounge","music_venue","night_club","nightclub","pub","wine_bar"].map(e=>[e,3])),...Object.fromEntries(["arts_centre","bowling_alley","cinema","comedy_club","concert_hall","movie_theater","opera","performing_arts_venue","theater","theatre","theatre_venue"].map(e=>[e,2])),...Object.fromEntries(["casual_eatery","fast_food","fast_food_restaurant","food_court","restaurant"].map(e=>[e,1]))},Jt=6,Kt=.5,Qt=.5;function Kn(e,n){let t=ue/e.extent,i=n.tileMetres/ue,o=n.defaultHeight??5,r=Number.isFinite(n.edgeRadius)?Math.max(0,Math.min(1.5,n.edgeRadius))/i:0,s=new wn,a=new Qe,l=new Qe,u=[],c=[],f=0,d=tr(e,n);for(let[M,B]of e.features.entries()){if(B.type!=="Polygon"||u.length>=65535)continue;let U=B.properties,E=U.hide_3d;if(E===!0||E===1||E==="1"||E==="true")continue;let C=Math.min(6e3,Jn(U.render_height)??o),I=Math.min(C,Jn(U.render_min_height)??0),D=Wt[String(U.building_tone??"")]??0,K=Xt[String(U.class??"")]??0,$=d.get(M)??0,N=u.length,Y=!1;for(let w of rr(B.geometry,t)){let y=w.map(ir).filter(S=>S.length>=6);if(y.length===0||qe(y[0])===0)continue;let[b,x]=or(y[0]);if(n.masks?.length&&(yn(n.masks,b,x)||Yn(y,n.masks,Qt/i)))continue;let T={cell:Math.min(7,Math.max(0,Math.floor(x/1024)))*8+Math.min(7,Math.max(0,Math.floor(b/1024))),bounds:[1/0,1/0,-1/0,-1/0,C+.1],roofsFrom:a.length,roofsCount:0,wallsFrom:l.length,wallsCount:0};for(let S of y)for(let z=0;z<S.length;z+=2)T.bounds[0]=Math.min(T.bounds[0],S[z]-1),T.bounds[1]=Math.min(T.bounds[1],S[z+1]-1),T.bounds[2]=Math.max(T.bounds[2],S[z]+1),T.bounds[3]=Math.max(T.bounds[3],S[z+1]+1);Y=!0,f=Math.max(f,C);let A=Number.isSafeInteger(B.id),v=gn(A?B.id*.0731:b*.0731+x*.19137+N*1.618),L=!A&&y[0].some(S=>S<=0||S>=ue)?gn(C*7.31+I*3.17+D):v,O={base:I,top:C,jitter:L,seed:v,tone:D,group:K,use:$,cx:b,cy:x,index:N},V=y.map((S,z)=>nr(S,z,r,n.cornerAngle));y=V.map(({ring:S})=>S);let R=w.length===1&&y.length===1?Zn(w[0],y[0],U,I,C,i,ue):void 0;R?(f=Math.max(f,R.ridge),T.bounds[4]=Math.max(T.bounds[4],R.ridge+.1),er(R,O,s,a)):qt(y,O,s,a);for(let[S,z]of y.entries()){let P=qe(z)>0,Z=S===0?P?-1:1:P?1:-1,j=z.length/2,G=H=>{let J=(H%j+j)%j;return[z[J*2],z[J*2+1]]},W=H=>{let[J,re]=G(H-1),[ne,te]=G(H),[le,de]=G(H+1);if(we(J,re,ne,te)||we(ne,te,le,de))return!1;let me=Math.hypot(ne-J,te-re),ce=Math.hypot(le-ne,de-te);if(!me||!ce)return!1;let je=-(te-re)/me*Z,Ne=(ne-J)/me*Z;return(je*(le-ne)+Ne*(de-te))/ce>Kt},se=(H,J)=>R?R.heightAt(H,J):C,ae=0;for(let H=0;H<j;H+=1){let[J,re]=G(H),[ne,te]=G(H+1),le=Math.hypot(ne-J,te-re);if(le===0||we(J,re,ne,te))continue;let de=-(te-re)/le*Z,me=(ne-J)/le*Z,ce=V[S].normals[H]??[de,me],je=V[S].normals[(H+1)%j]??[de,me],Ne=oe=>{let _e=ce[0]+(je[0]-ce[0])*oe,Fe=ce[1]+(je[1]-ce[1])*oe,ye=Math.hypot(_e,Fe)||1;return[_e/ye,Fe/ye]},he=[0,...R?R.breaks(J,re,ne,te):[],1];for(let oe=0;oe+1<he.length;oe+=1){let _e=oe===0,Fe=oe+2===he.length,ye=J+(ne-J)*he[oe],De=re+(te-re)*he[oe],Ve=J+(ne-J)*he[oe+1],He=re+(te-re)*he[oe+1],Ae=Math.hypot(Ve-ye,He-De)/ue*n.tileMetres,$e=(_e&&W(H)?1:0)|(Fe&&W(H+1)?2:0)|(S>0?4:0),Ge=(_e&&xn(J,re)?1:0)|(Fe&&xn(ne,te)?2:0),an=ae+Ae,Ze=Ne(he[oe]),We=Ne(he[oe+1]),Un=se(ye,De),Cn=se(Ve,He),ke=s.write(O,ye,De,0,Ze[0],Ze[1],1,ae,$e,Ae,0,Ge,Un);s.write(O,Ve,He,0,We[0],We[1],1,an,$e,Ae,1,Ge,Cn),s.write(O,ye,De,1,Ze[0],Ze[1],1,ae,$e,Ae,0,Ge,Un),s.write(O,Ve,He,1,We[0],We[1],1,an,$e,Ae,1,Ge,Cn),l.push(ke,ke+1,ke+2,ke+1,ke+3,ke+2),ae=an}}}T.roofsCount=a.length-T.roofsFrom,T.wallsCount=l.length-T.wallsFrom,c.push(T)}Y&&u.push(U)}if(s.count===0)return;let g=new Uint32Array(a.length+l.length),m=[],p=0,h=a.length,_=a.values(),F=l.values();c.sort((M,B)=>M.cell-B.cell);let k=-1;for(let M of c){M.cell!==k&&(k=M.cell,m.push({bounds:[...M.bounds],roofsFrom:p,roofsCount:0,wallsFrom:h,wallsCount:0}));let B=m.at(-1);for(let U=0;U<5;U+=1)B.bounds[U]=U<2?Math.min(B.bounds[U],M.bounds[U]):Math.max(B.bounds[U],M.bounds[U]);g.set(_.subarray(M.roofsFrom,M.roofsFrom+M.roofsCount),p),g.set(F.subarray(M.wallsFrom,M.wallsFrom+M.wallsCount),h),p+=M.roofsCount,h+=M.wallsCount,B.roofsCount+=M.roofsCount,B.wallsCount+=M.wallsCount}return{groups:m,vertices:s.bytes(),indices:g,wallsFrom:a.length,top:f,features:u}}function qt(e,n,t,i){let o=[],r=[];for(let l of e)r.push(o.length/2),o.push(...l);r.push(o.length/2);let s=(l,u)=>{let c=r.findIndex((p,h)=>l>=p&&l<r[h+1]),[f,d]=[r[c],r[c+1]-1];if(u<f||u>d)return!1;let[g,m]=l<u?[l,u]:[u,l];return m-g!==1&&!(g===f&&m===d)?!1:!we(o[l*2],o[l*2+1],o[u*2],o[u*2+1])},a=Pe(o,r.slice(1,-1),2);for(let l=0;l+2<a.length;l+=3){let u=[a[l],a[l+1],a[l+2]],c=0;for(let f=0;f<3;f+=1)s(u[(f+1)%3],u[(f+2)%3])&&(c|=1<<f);for(let[f,d]of u.entries())i.push(t.write(n,o[d*2],o[d*2+1],1,0,0,0,0,0,0,f,c))}}function er(e,n,t,i){for(let o of e.faces){let r=o.ring,s=r.length/2,a=(l,u)=>{let[c,f]=l<u?[l,u]:[u,l];return f-c!==1&&!(c===0&&f===s-1)?!1:!we(r[l*2],r[l*2+1],r[u*2],r[u*2+1])};for(let l=0;l+2<o.triangles.length;l+=3){let u=[o.triangles[l],o.triangles[l+1],o.triangles[l+2]],c=0;for(let f=0;f<3;f+=1)a(u[(f+1)%3],u[(f+2)%3])&&(c|=1<<f);for(let[f,d]of u.entries()){let g=r[d*2],m=r[d*2+1];i.push(t.write(n,g,m,1,o.normal[0],o.normal[1],0,0,0,0,f,c,e.heightAt(g,m)))}}}}function nr(e,n,t,i=Math.PI/6){if(t<1)return{ring:e,normals:[]};let o=e.length/2,r=qe(e)>0,s=n===0?r?-1:1:r?1:-1,a=[],l=[],u=(c,f,d)=>{c=Re(c),f=Re(f),!(a.at(-2)===c&&a.at(-1)===f)&&(a.push(c,f),l.push(d))};for(let c=0;c<o;c+=1){let f=(c+o-1)%o,d=(c+1)%o,[g,m]=[e[f*2],e[f*2+1]],[p,h]=[e[c*2],e[c*2+1]],[_,F]=[e[d*2],e[d*2+1]],k=Math.hypot(p-g,h-m),M=Math.hypot(_-p,F-h);if(!k||!M||xn(p,h)||we(g,m,p,h)||we(p,h,_,F)){u(p,h);continue}let[B,U]=[(p-g)/k,(h-m)/k],[E,C]=[(_-p)/M,(F-h)/M],I=Math.atan2(B*C-U*E,B*E+U*C);if(I*s>=-.08||Math.abs(I)>Math.PI*.85){u(p,h);continue}let D=Math.tan(Math.abs(I)/2),K=Math.min(t*D,k*.2,M*.2),$=K/D;if($<1){u(p,h);continue}let[N,Y]=[-U*s,B*s],[w,y]=[p-B*K-N*$,h-U*K-Y*$],b=Math.atan2(Y,N),x=Math.max(i<=Math.PI/6?2:1,Math.ceil(Math.abs(I)/Math.max(Math.PI/6,Math.min(Math.PI/3,i))));for(let T=0;T<=x;T+=1){let A=b+I*T/x,v=[Math.cos(A),Math.sin(A)];u(w+v[0]*$,y+v[1]*$,v)}}return a[0]===a.at(-2)&&a[1]===a.at(-1)&&(a.splice(-2),l.pop()),a.length>=6?{ring:a,normals:l}:{ring:e,normals:[]}}var wn=class{#e=new ArrayBuffer(4096*pe);#n=new DataView(this.#e);count=0;write(n,t,i,o,r,s,a,l,u,c,f=0,d=0,g=n.top){let m=pe;if((this.count+1)*m>this.#e.byteLength){let _=new ArrayBuffer(this.#e.byteLength*2);new Uint8Array(_).set(new Uint8Array(this.#e)),this.#e=_,this.#n=new DataView(_)}let p=this.#n,h=this.count*m;return p.setUint16(h,Re(t),!0),p.setUint16(h+2,Re(i),!0),p.setUint16(h+4,Math.min(65535,Math.round(n.base*10)),!0),p.setUint16(h+6,Math.min(65535,Math.max(0,Math.round(g*10))),!0),p.setInt8(h+8,Math.round(r*127)),p.setInt8(h+9,Math.round(s*127)),p.setUint8(h+10,o),p.setUint8(h+11,a),p.setUint16(h+12,Math.round(l*10)%65536,!0),p.setUint8(h+14,Math.round(n.jitter*255)),p.setUint8(h+15,Math.round(n.seed*255)),p.setUint16(h+16,Re(n.cx),!0),p.setUint16(h+18,Re(n.cy),!0),p.setUint8(h+20,n.tone+4*n.group),p.setUint8(h+21,n.use),p.setUint8(h+22,u),p.setUint8(h+23,Math.min(255,Math.round(c))),p.setUint16(h+24,n.index,!0),p.setUint8(h+26,f),p.setUint8(h+27,d),this.count+=1,this.count-1}bytes(){return new Uint8Array(this.#e.slice(0,this.count*pe))}},Qe=class{#e=new Uint32Array(8192);length=0;push(...n){if(this.length+n.length>this.#e.length){let t=new Uint32Array(Math.max(this.length+n.length,this.#e.length*2));t.set(this.#e),this.#e=t}for(let t of n)this.#e[this.length++]=t}values(){return this.#e.subarray(0,this.length)}};function tr(e,n){let t=new Map;if(e.features.some(a=>a.properties.night_use!==void 0)){for(let[a,l]of e.features.entries()){let u=Yt[String(l.properties.night_use??"")];u&&t.set(a,u)}return t}let i=n.places;if(!i||i.features.length===0)return t;let o=Jt/n.tileMetres*e.extent,r=[];for(let[a,l]of e.features.entries()){if(l.type!=="Polygon")continue;let u=l.properties.hide_3d;if(u===!0||u===1||u==="1"||u==="true")continue;let c=[1/0,1/0,-1/0,-1/0];for(let f of l.geometry)for(let d=0;d+1<f.length;d+=2)c[0]=Math.min(c[0],f[d]),c[1]=Math.min(c[1],f[d+1]),c[2]=Math.max(c[2],f[d]),c[3]=Math.max(c[3],f[d+1]);r.push({index:a,rings:l.geometry,box:c})}let s=e.extent/i.extent;for(let a of i.features){if(a.type!=="Point")continue;let l=a.properties,u=bn[String(l.type??"")]??bn[String(l.subclass??"")]??bn[String(l.class??"")];if(u)for(let c of a.geometry)for(let f=0;f+1<c.length;f+=2){let d=c[f]*s,g=c[f+1]*s,m,p,h=o;for(let F of r){let[k,M,B,U]=F.box;if(d<k-o||d>B+o||g<M-o||g>U+o)continue;let E=!1;for(let C of F.rings)for(let I=0,D=C.length-2;I+1<C.length;D=I,I+=2){let K=C[D],$=C[D+1],N=C[I],Y=C[I+1];Y>g!=$>g&&d<(K-N)*(g-Y)/($-Y)+N&&(E=!E);let w=N-K,y=Y-$,b=w*w+y*y,x=b?Math.min(1,Math.max(0,((d-K)*w+(g-$)*y)/b)):0,T=Math.hypot(d-K-x*w,g-$-x*y);T<h&&(h=T,p=F.index)}if(E){m=F.index;break}}let _=m??p;_!==void 0&&t.set(_,Math.max(t.get(_)??0,u))}}return t}function Re(e){return Math.min(ue,Math.max(0,Math.round(e)))}function Jn(e){let n=Number(e);return Number.isFinite(n)&&n>0?n:void 0}function rr(e,n){let t=[],i;for(let o of e){let r=[];for(let a=0;a+1<o.length;a+=2){let l=o[a]*n,u=o[a+1]*n;r.length&&l===r.at(-2)&&u===r.at(-1)||r.push(l,u)}if(r.length>=6&&r[0]===r.at(-2)&&r[1]===r.at(-1)&&(r.length-=2),r.length<6)continue;let s=Math.sign(qe(r));s&&(i??=s,s===i||t.length===0?t.push([r]):t.at(-1).push(r))}return t}function qe(e){let n=0,t=e.length/2;for(let i=0;i<t;i+=1){let o=(i+1)%t;n+=e[i*2]*e[o*2+1]-e[o*2]*e[i*2+1]}return n}function or(e){let n=0,t=0,i=e.length/2;for(let o=0;o<i;o+=1)n+=e[o*2],t+=e[o*2+1];return[n/i,t/i]}function xn(e,n){return e<=0||n<=0||e>=ue||n>=ue}function we(e,n,t,i){let o=ue;return e<=0&&t<=0||e>=o&&t>=o||n<=0&&i<=0||n>=o&&i>=o}function ir(e){let n=ue,t=[...e],i=[[0,0,o=>o>=0],[0,n,o=>o<=n],[1,0,o=>o>=0],[1,n,o=>o<=n]];for(let[o,r,s]of i){let a=[],l=t.length/2;for(let u=0;u<l;u+=1){let c=[t[u*2],t[u*2+1]],f=[t[(u+1)%l*2],t[(u+1)%l*2+1]],d=s(c[o]),g=s(f[o]);if(d&&a.push(c[0],c[1]),d!==g){let m=(r-c[o])/(f[o]-c[o]);a.push(c[0]+(f[0]-c[0])*m,c[1]+(f[1]-c[1])*m)}}if(t=a,t.length<6)return[]}return t}function gn(e){let n=Math.sin(e*12.9898+78.233)*43758.5453;return n-Math.floor(n)}var Qn=`\nin float v_haze_depth;\nuniform vec3 u_haze_colour;\nuniform vec3 u_haze; // strength; the view depths where the haze starts and is complete\n\nfloat hazeOf() {\n return u_haze.x > 0.0 ? u_haze.x * smoothstep(u_haze.y, u_haze.z, v_haze_depth) : 0.0;\n}\n\nvec3 hazed(vec3 colour) {\n return mix(colour, u_haze_colour, hazeOf());\n}`;function qn(e){let n=(e.indices.length-e.wallsFrom)/6,t=new Uint8Array(n*16);for(let i=0;i<n;i+=1){let o=e.wallsFrom+i*6,r=e.indices[o]*pe,s=e.indices[o+1]*pe;t.set(e.vertices.subarray(r,r+4),i*16),t.set(e.vertices.subarray(s,s+4),i*16+4),t.set(e.vertices.subarray(r+4,r+8),i*16+8),t[i*16+12]=e.vertices[r+14],t[i*16+13]=e.vertices[r+27]}return t}var Kr=`#version 300 es\nprecision highp float;\nuniform highp sampler2D u_contact;\n${Qn}\nout vec4 fragColor;\nvoid main() {\n float shade = mix(texelFetch(u_contact, ivec2(gl_FragCoord.xy), 0).r, 1.0, hazeOf());\n fragColor = vec4(vec3(shade), 1.0);\n}`;function et(e){let n=e.vertices.length/pe;return{mesh:{...e.groups?{groups:e.groups}:{},wallsFrom:e.wallsFrom,top:e.top,features:e.features,vertexCount:n,indexCount:e.indices.length},data:{vertices:e.vertices,indices:n<=65536?Uint16Array.from(e.indices):e.indices,contact:qn(e)}}}function nt({data:e}){return[e.vertices.buffer,e.indices.buffer,e.contact.buffer]}function Tn(e){let n=sr(e);return n?[Math.min(1,Math.max(0,n[0]/255)),Math.min(1,Math.max(0,n[1]/255)),Math.min(1,Math.max(0,n[2]/255)),Math.min(1,Math.max(0,n[3]))]:null}function sr(e){let n=e.trim().toLowerCase(),t=/^#([\\da-f]{3,8})$/u.exec(n)?.[1];if(t&&[3,4,6,8].includes(t.length)){let _=(t.length<=4?[...t].map(F=>F+F).join(""):t).match(/../gu).map(F=>Number.parseInt(F,16));return[_[0],_[1],_[2],_.length>3?_[3]/255:1]}let i=/^(rgba?|hsla?)\\(([^)]+)\\)$/u.exec(n);if(!i)return null;let o=i[2].split(/[\\s,/]+/u).filter(Boolean);if(o.length<3||o.length>4)return null;let r=o[3]===void 0?1:en(o[3],1);if(i[1].startsWith("rgb")){let[h,_,F]=o.slice(0,3).map(k=>en(k,255));return[h,_,F,r].some(k=>k===null)?null:[h,_,F,r]}let s=Number.parseFloat(o[0]),a=en(o[1],1),l=en(o[2],1);if(!Number.isFinite(s)||a===null||l===null||r===null)return null;let u=(1-Math.abs(2*l-1))*a,c=(s%360+360)%360/60,f=u*(1-Math.abs(c%2-1)),[d,g,m]=c<1?[u,f,0]:c<2?[f,u,0]:c<3?[0,u,f]:c<4?[0,f,u]:c<5?[f,0,u]:[u,0,f],p=l-u/2;return[(d+p)*255,(g+p)*255,(m+p)*255,r]}function en(e,n){let t=e.endsWith("%"),i=Number.parseFloat(e);return Number.isFinite(i)?t?i/100*n:i:null}var fe=8192,Mn=12,ar={primary:{spacing:30,kerb:10},secondary:{spacing:32,kerb:8.5},tertiary:{spacing:34,kerb:7},minor:{spacing:36,kerb:5.5},pedestrian:{spacing:26,kerb:3}},lr={motorway:{spacing:45,kerb:14},trunk:{spacing:40,kerb:12},service:{spacing:38,kerb:4},path:{spacing:28,kerb:1.5},track:{spacing:40,kerb:2.5}},ur={spacing:30,kerb:0},cr=12,fr=18,dr=9,mr={sodium:"#ffa64d",high_pressure_sodium:"#ffa64d",low_pressure_sodium:"#ff9326",led:"#fff1db",mercury:"#e3ecff",metal_halide:"#f4f4ff",fluorescent:"#eef9ff",electric:"#ffd59a",incandescent:"#ffd59a",halogen:"#ffe3b0",gas:"#ffd28a",gaslight:"#ffd28a"},hr={orange:"#ffa64d",yellow:"#ffd27a",warm_white:"#ffe2b8",white:"#fff4e6",cool_white:"#eef4ff",neutral_white:"#fff8f0",blue:"#b8d0ff",green:"#c4ffd0",red:"#ff9a8a"},pr=new Set(["wall","wall_mounted","wall_bracket"]),yr=new Set(["suspended","cable","catenary","wire"]);function it(e,n){let t=n.estimate??"lit",i=new vn,o=new nn(fr),r=new nn(dr),s=e.streetFurniture;if(s){let m=fe/s.extent;for(let p of s.features){let h=p.properties;if(p.type!=="Point"||h.subclass!=="street_lamp")continue;let _=br(h),F=gr(h),k=Math.max(1,Math.min(4,Number(h.light_count)||1)),M=Math.min(24,Math.max(5,_*1.7*(k>1?1.15:1)));for(let B of p.geometry)for(let U=0;U+1<B.length;U+=2){let E=B[U]*m,C=B[U+1]*m;if(!rt(E,C))continue;i.write(E,C,_,M,!0,F);let I=ot(E,C,n.tileMetres);o.add(...I),r.add(...I)}}}let a=i.count;if(t==="none")return i.done(a);let l=e.transportation,u=0;if(l){let m=n.tileMetres/l.extent;for(let p of l.features)if(!(p.type!=="LineString"||!tt(p.properties,"streets")))for(let h of p.geometry)u+=wr(h,l.extent)*m}let c=u>0&&a/(u/1e3)>=cr,f=t==="streets"&&!c?"streets":"lit",d=(m,p,h,_)=>{let F=fe/m.extent,k=[];for(let D=0;D+1<p.length;D+=2)k.push(p[D]*F,p[D+1]*F);let M=n.tileMetres/fe,B=h.kerb*.45/M,U=Rn(k[0]*.013+k[1]*.029+_)*h.spacing,E=0,C=U,I=Rn(k[0]+k[1]*3.1)<.5?1:-1;for(let D=2;D<k.length;D+=2){let K=k[D-2],$=k[D-1],N=k[D],Y=k[D+1],w=Math.hypot(N-K,Y-$)*M;if(w!==0){for(;C<=E+w;){let y=(C-E)/w,b=-(Y-$)/(w/M)*I,x=(N-K)/(w/M)*I,T=K+(N-K)*y+b*B,A=$+(Y-$)*y+x*B;if(C+=h.kerb>0?h.spacing/2:h.spacing,h.kerb>0&&(I=-I),!rt(T,A))continue;let v=ot(T,A,n.tileMetres);o.near(...v)||r.near(...v)||(r.add(...v),i.write(T,A,7,15,!1))}E+=w}}};if(l)for(let m of l.features){if(m.type!=="LineString")continue;let p=tt(m.properties,f);if(p)for(let h of m.geometry)d(l,h,p,1)}let g=e.sidewalks;if(g){for(let m of g.features)if(!(m.type==="Point"||!kn(m.properties.lit)))for(let p of m.geometry)d(g,p,ur,2)}return i.done(a)}function tt(e,n){if(e.brunnel==="tunnel"||e.covered===!0)return;let t=e.lit;if(t===!1||t==="no")return;let i=String(e.class??""),o=String(e.subclass??""),r=i==="path"&&(o==="pedestrian"||o==="living_street")?"pedestrian":i,s=ar[r];if(s&&(n==="streets"||kn(t)))return s;let a=lr[r];if(a&&kn(t))return a}function kn(e){return e===!0||e==="yes"||e===1||e==="1"||e==="true"}function br(e){let n=Number(e.height);if(Number.isFinite(n)&&n>=.5&&n<=40)return n;let t=String(e.lamp_mount??"").toLowerCase();return pr.has(t)?4.5:yr.has(t)?7.5:7}function gr(e){let n=e.light_colour??e["light:colour"];if(typeof n=="string"&&n){let r=n.toLowerCase().replaceAll(" ","_"),s=Tn(hr[r]??n);if(s)return[s[0],s[1],s[2]]}let t=String(e.lamp_type??"").toLowerCase().replaceAll("-","_").replaceAll(" ","_"),i=mr[t];if(!i)return;let o=Tn(i);return[o[0],o[1],o[2]]}function rt(e,n){return e>=0&&n>=0&&e<fe&&n<fe}function ot(e,n,t){return[e/fe*t,n/fe*t]}function wr(e,n){let t=0;for(let i=2;i+1<e.length;i+=2){let o=(e[i-2]+e[i])/2,r=(e[i-1]+e[i+1])/2;o<0||r<0||o>=n||r>=n||(t+=Math.hypot(e[i]-e[i-2],e[i+1]-e[i-1]))}return t}var nn=class{constructor(n){this.size=n}size;#e=new Map;add(n,t){let i=`${Math.floor(n/this.size)}/${Math.floor(t/this.size)}`,o=this.#e.get(i);o?o.push([n,t]):this.#e.set(i,[[n,t]])}near(n,t){let i=Math.floor(n/this.size),o=Math.floor(t/this.size);for(let r=-1;r<=1;r+=1)for(let s=-1;s<=1;s+=1)for(let[a,l]of this.#e.get(`${i+r}/${o+s}`)??[])if(Math.hypot(a-n,l-t)<this.size)return!0;return!1}},vn=class{#e=new ArrayBuffer(256*Mn);#n=new DataView(this.#e);count=0;write(n,t,i,o,r,s){let a=Mn;if((this.count+1)*a>this.#e.byteLength){let c=new ArrayBuffer(this.#e.byteLength*2);new Uint8Array(c).set(new Uint8Array(this.#e)),this.#e=c,this.#n=new DataView(c)}let l=this.#n,u=this.count*a;l.setUint16(u,Math.min(fe,Math.max(0,Math.round(n))),!0),l.setUint16(u+2,Math.min(fe,Math.max(0,Math.round(t))),!0),l.setUint16(u+4,Math.min(65535,Math.round(i*10)),!0),l.setUint8(u+6,Math.min(255,Math.round(o))),l.setUint8(u+7,(r?1:0)|(s?2:0)),l.setUint8(u+8,Math.round((s?.[0]??0)*255)),l.setUint8(u+9,Math.round((s?.[1]??0)*255)),l.setUint8(u+10,Math.round((s?.[2]??0)*255)),l.setUint8(u+11,Math.round(Rn(n*.0731+t*.19137)*255)),this.count+=1}done(n){if(this.count!==0)return{lamps:new Uint8Array(this.#e.slice(0,this.count*Mn)),mapped:n,estimated:this.count-n}}};function Rn(e){let n=Math.sin(e*12.9898+78.233)*43758.5453;return n-Math.floor(n)}var oo=Object.freeze({source:"tileflow",layers:Object.freeze({streetFurniture:"street_furniture",transportation:"transportation",sidewalk:"sidewalk"}),estimate:"lit",color:"#ffcf8f",intensity:1});var Me=["round","open","tall","conifer","columnar","palm"];var ut=Object.freeze({height:"height",diameterCrown:"diameter_crown",circumference:"circumference",genus:"genus",species:"species",leafType:"leaf_type",taxon:"taxon",canopyRank:"rank",canopyClearance:"clearance_px_z15",canopyCover:"cover_pct",canopyHeight:"height_m",subclass:"subclass",hedge:"hedge"}),Sn=Object.freeze({round:1,open:1,tall:1}),tn=16,q=8192,rn=16,st={round:{height:[6,12],crown:[.66,.9]},open:{height:[5,10],crown:[.8,1.05]},tall:{height:[9,17],crown:[.48,.68]},conifer:{height:[7,16],crown:[.46,.66]},columnar:{height:[9,18],crown:[.22,.36]},palm:{height:[12,20],crown:[.42,.55]}};var on=[2,45],_n=[1,25],xr=1.2,Tr=1.5,Mr=1.3,kr=1,vr=[.3,10],Rr=new Set(["acoelorrhaphe","adonidia","archontophoenix","areca","arecastrum","bismarckia","brahea","butia","caryota","chamaedorea","chamaerops","coccothrinax","cocos","dypsis","elaeis","howea","jubaea","licuala","livistona","phoenix","pritchardia","ptychosperma","rhapis","roystonea","sabal","serenoa","syagrus","thrinax","trachycarpus","veitchia","washingtonia","wodyetia"]),_r=new Set(["cupressus","calocedrus","thuja"]),Fr=new Set(["abies","araucaria","cedrus","cryptomeria","juniperus","larix","metasequoia","picea","pinus","pseudotsuga","sequoia","sequoiadendron","taxodium","taxus","tsuga"]),at=Object.freeze({...Object.fromEntries(["acacia","albizia","arbutus","bursera","ceratonia","delonix","ficus","gleditsia","jacaranda","olea","quercus","robinia","schinus","sophora","styphnolobium","tamarix"].map(e=>[e,"open"])),...Object.fromEntries(["betula","celtis","fraxinus","ginkgo","liquidambar","liriodendron","magnolia","platanus","populus","pyrus","ulmus","zelkova"].map(e=>[e,"tall"])),...Object.fromEntries(["acer","aesculus","carpinus","castanea","catalpa","cercis","citrus","fagus","lagerstroemia","malus","melia","morus","prunus","sorbus","tilia"].map(e=>[e,"round"]))});function lt(e,n={}){let t={...ut,...n},i=String(e[t.leafType]??"").toLowerCase(),o=String(e[t.taxon]??"").toLowerCase(),r=Fn(e[t.genus])??Fn(e[t.species])??(o.endsWith("aceae")?void 0:Fn(e[t.taxon]));if(i.includes("palm")||o.includes("arecaceae")||r&&Rr.has(r))return"palm";if(o.includes("cupressaceae")&&!r||o.includes("pinaceae"))return"conifer";if(r&&_r.has(r))return"columnar";if(i.includes("needle")||r&&Fr.has(r))return"conifer";if(r&&at[r])return at[r];if(i.includes("broad"))return"broadleaf"}function Fn(e){return typeof e!="string"?void 0:e.trim().split(/\\s+/u)[0]?.toLowerCase()||void 0}function ct(e,n){let t={...ut,...n.fields},i=n.unknownForms??Sn,o=n.regions??[],{tile:r,tileMetres:s}=n,a=s/2**(15-r.z)/512,l=[],u=0,c=0,f=(w,y)=>{if(o.length===0)return i;let[b,x]=Sr(r,w/q,y/q);for(let T of o){let[A,v,L,O]=T.bounds;if(x>=v&&x<=O&&(A<=L?b>=A&&b<=L:b>=A||b<=L))return T.unknownForms}return i},d=(w,y,b,x)=>{let T=st[w],A=An(T.crown,ee(y,2)),v=b,L=x;return v===void 0&&L===void 0&&(v=An(T.height,ee(y,1))),v===void 0&&(v=L/A),L===void 0&&(L=v*A),{height:Te(v,on),crown:Te(L,_n)}},g=(w,y,b,x,T,A)=>{let v=ze(r.x*q+w,r.y*q+y,7),L=b===void 0?sn(f(w,y),ee(v,3)):b==="broadleaf"?sn(Ar(f(w,y)),ee(v,3)):b,O=x===void 0&&T===void 0&&A!==void 0?d(L,v,An(st[L].height,Te(A/3,[0,1]))):d(L,v,x,T);l.push({x:w,y,...O,turn:ee(v,4),shade:ee(v,5),form:Me.indexOf(L),rank:Math.floor(ee(v,6)*rn),seed:ee(v,7),canopy:0}),u+=1},m=e.trees;if(m){let w=q/m.extent;for(let y of m.features){if(y.type!=="Point")continue;let b=y.properties,x=lt(b,t),T=xe(b[t.height],on),A=xe(b[t.diameterCrown],_n),v=xe(b[t.circumference],[.1,12]);for(let L of y.geometry)for(let O=0;O+1<L.length;O+=2){let V=L[O],R=L[O+1];V<0||R<0||V>=m.extent||R>=m.extent||g(V*w,R*w,x,T,A,v)}}}let p=e.trees;if(p){let w=q/p.extent,y=(n.rowSpacing??8)/(s/p.extent);for(let b of p.features){if(b.type!=="LineString")continue;let x=b.properties,T=lt(x,t),A=xe(x[t.height],on),v=xe(x[t.diameterCrown],_n);for(let L of b.geometry){let O=y/2,V=0;for(let R=0;R+3<L.length;R+=2){let[S,z,P,Z]=[L[R],L[R+1],L[R+2],L[R+3]],j=Math.hypot(P-S,Z-z);for(;O<=V+j;){let G=j>0?(O-V)/j:0,W=S+(P-S)*G,se=z+(Z-z)*G;W>=0&&se>=0&&W<p.extent&&se<p.extent&&g(W*w,se*w,T,A,v,void 0),O+=y}V+=j}}}}let h=e.canopy;if(h){let w=q/h.extent;for(let y of h.features){if(y.type!=="Point")continue;let b=y.properties,x=Te(Math.floor(Number(b[t.canopyRank]??8)),[0,rn-1]),T=Math.max(4,Number(b[t.canopyClearance]??8))*a,A=Number(b[t.canopyCover]??30),v=A>=60?3:A>=30?2:1;for(let L of y.geometry)for(let O=0;O+1<L.length;O+=2){let V=L[O],R=L[O+1];if(V<0||R<0||V>=h.extent||R>=h.extent)continue;let S=V*w,z=R*w,P=ze(r.x*q+S,r.y*q+z,11),Z=f(S,z),j=xe(b[t.canopyHeight],on),G=Te(Math.min(T*(v===1?1.3:.95),11)*(.85+ee(P,1)*.25),[3,12]),W=Math.max(0,Math.min(G*.5,T-G/2)),se=ee(P,2)*Math.PI*2;for(let ae=0;ae<v;ae+=1){let H=ze(P,ae,13),J=se+ae*Math.PI*2/v,re=v===1?W*.3*ee(H,1):W,ne=S+Math.cos(J)*re/(s/q),te=z+Math.sin(J)*re/(s/q);if(ne<0||te<0||ne>=q||te>=q)continue;let le=sn(Z,ee(H,3)),de=G*(.85+ee(H,2)*.3),me=j===void 0?void 0:j*(.85+ee(H,6)*.25),ce=d(le,H,me,le==="palm"?void 0:de);l.push({x:ne,y:te,...ce,turn:ee(H,4),shade:ee(H,5),form:Me.indexOf(le),rank:x,seed:ee(H,7),canopy:1}),c+=1}}}}let _=[],F=e.hedges;if(F){let w=q/F.extent,y=xr/(s/F.extent);for(let b of F.features){if(b.type==="Point"||b.properties[t.subclass]!=="hedge")continue;let x=b.properties[t.hedge]==="hedge_bank"?kr:0,T=(xe(b.properties[t.height],vr)??Mr)+x;for(let A of b.geometry){let v=y/2,L=0;for(let O=0;O+3<A.length;O+=2){let[V,R,S,z]=[A[O],A[O+1],A[O+2],A[O+3]],P=Math.hypot(S-V,z-R),Z=(Math.atan2(R-z,S-V)/(Math.PI*2)+1)%1;for(;v<=L+P;){let j=P>0?(v-L)/P:0,G=V+(S-V)*j,W=R+(z-R)*j;if(G>=0&&W>=0&&G<F.extent&&W<F.extent){let se=ze(r.x*q+G*w,r.y*q+W*w,17);_.push({x:G*w,y:W*w,height:T,turn:Z,shade:ee(se,5),seed:ee(se,7)})}v+=y}L+=P}}}}let k=w=>Te(Math.floor(n.variants?.[Me[w]]??1),[1,4]),M=w=>Math.min(k(w.form)-1,Math.floor(ee(Math.floor(w.seed*256),9)*k(w.form))),B=l.map(M),U=l.map((w,y)=>y);U.sort((w,y)=>l[w].form-l[y].form||B[w]-B[y]||l[w].rank-l[y].rank);let E=new Uint8Array(l.length*tn),C=new DataView(E.buffer),I=0,D=()=>({start:0,count:0,upTo:new Array(rn).fill(0)}),K=Object.fromEntries(Me.map((w,y)=>[w,{...D(),variants:Array.from({length:k(y)},D)}])),$=(w,y,b)=>{w.count===0&&(w.start=y),w.count+=1;for(let x=b;x<rn;x+=1)w.upTo[x]+=1};U.forEach((w,y)=>{let b=l[w],x=y*tn;C.setUint16(x,Math.min(q-1,Math.round(b.x)),!0),C.setUint16(x+2,Math.min(q-1,Math.round(b.y)),!0),C.setUint16(x+4,Math.round(b.height*10),!0),C.setUint16(x+6,Math.round(b.crown*10),!0),E[x+8]=Math.floor(b.turn*256)&255,E[x+9]=Math.floor(b.shade*256)&255,E[x+10]=b.form,E[x+11]=b.rank,E[x+12]=Math.floor(b.seed*256)&255,E[x+13]=b.canopy,E[x+14]=B[w],I=Math.max(I,b.height);let T=K[Me[b.form]];$(T,y,b.rank),$(T.variants[B[w]],y,b.rank)});let N=new Uint8Array(_.length*tn),Y=new DataView(N.buffer);return _.forEach((w,y)=>{let b=y*tn;Y.setUint16(b,Math.min(q-1,Math.round(w.x)),!0),Y.setUint16(b+2,Math.min(q-1,Math.round(w.y)),!0),Y.setUint16(b+4,Math.round(w.height*10),!0),Y.setUint16(b+6,Math.round(Tr*10),!0),N[b+8]=Math.round(w.turn*256)&255,N[b+9]=Math.floor(w.shade*256)&255,N[b+12]=Math.floor(w.seed*256)&255,I=Math.max(I,w.height)}),{trees:E,forms:K,hedges:N,tallest:I,mapped:u,canopy:c}}function Ar(e){let n={round:e.round??0,open:e.open??0,tall:e.tall??0};return n.round+n.open+n.tall>0?n:Sn}function sn(e,n){let t=0;for(let o of Me)t+=Math.max(0,e[o]??0);if(t<=0)return sn(Sn,n);let i=n*t;for(let o of Me){let r=Math.max(0,e[o]??0);if(i<r)return o;i-=r}return"round"}function xe(e,n){let t=typeof e=="number"?e:typeof e=="string"?Number.parseFloat(e):NaN;return Number.isFinite(t)&&t>0?Te(t,n):void 0}function Te(e,[n,t]){return Math.min(t,Math.max(n,e))}function An([e,n],t){return e+(n-e)*t}function Sr(e,n,t){let i=2**e.z,o=(e.x+n)/i*360-180,r=Math.atan(Math.sinh(Math.PI*(1-2*(e.y+t)/i)))*180/Math.PI;return[o,r]}function ze(e,n,t){let i=(Math.imul(Math.floor(e)|0,668265261)^Math.imul(Math.floor(n)|0,374761393)^Math.imul(t,2654435761))>>>0;return i=Math.imul(i^i>>>15,2246822507)>>>0,i=Math.imul(i^i>>>13,3266489909)>>>0,(i^i>>>16)>>>0}function ee(e,n){return ze(e,n,20973)/4294967296}var Lr=[void 0,"Point","LineString","Polygon"];function ft(e,n={}){let t=n.layers?new Set(n.layers):void 0,i={},o=new Bn(e,0,e.length);for(;o.more();){let[r,s]=o.tag();if(r!==3){o.skip(s);continue}let a=o.message(),l=Br(a,t);l&&!(l.name in i)&&(i[l.name]=l.layer)}return i}function Br(e,n){let t,i=4096,o=[],r=[],s=[];for(;e.more();){let[a,l]=e.tag();if(a===1?t=e.string():a===2?s.push(e.message()):a===3?o.push(e.string()):a===4?r.push(Cr(e.message())):a===5?i=e.varint():e.skip(l),t!==void 0&&n&&!n.has(t))return}if(!(t===void 0||n&&!n.has(t)))return{name:t,layer:Object.freeze({extent:i,features:Object.freeze(s.flatMap(a=>{let l=Or(a,o,r);return l?[l]:[]}))})}}function Or(e,n,t){let i,o,r={},s=[];for(;e.more();){let[a,l]=e.tag();if(a===1)i=e.varint();else if(a===2){let u=e.packed();for(let c=0;c+1<u.length;c+=2){let f=n[u[c]],d=t[u[c+1]];f!==void 0&&d!==void 0&&(r[f]=d)}}else a===3?o=Lr[e.varint()]:a===4?s=e.packed():e.skip(l)}if(o)return Object.freeze({...i===void 0?{}:{id:i},type:o,properties:Object.freeze(r),geometry:Object.freeze(Ur(s,o))})}function Ur(e,n){let t=[],i,o=0,r=0,s=0;for(;s<e.length;){let a=e[s++],l=a&7,u=a>>>3;if(l===7){i&&i.length>=2&&i.push(i[0],i[1]);continue}if(l!==1&&l!==2)throw new Error(`Unknown geometry command ${l} in vector tile.`);if(s+u*2>e.length)throw new Error("Truncated vector tile geometry.");for(let c=0;c<u;c+=1){if(o+=Ln(e[s++]),r+=Ln(e[s++]),l===1&&(n!=="Point"||c===0)&&t.push(i=[]),!i)throw new Error("Vector tile geometry draws a line before moving to its start.");i.push(o,r)}}return t}var Ln=e=>e%2===1?-(e+1)/2:e/2;function Cr(e){let n="";for(;e.more();){let[t,i]=e.tag();t===1?n=e.string():t===2?n=e.float():t===3?n=e.double():t===4?n=e.varint(!0):t===5?n=e.varint():t===6?n=Ln(e.varint()):t===7?n=e.varint()!==0:e.skip(i)}return n}var Pr=new TextDecoder,Bn=class e{constructor(n,t,i){this.bytes=n;this.end=i;this.position=t,this.view=new DataView(n.buffer,n.byteOffset,n.byteLength)}bytes;end;position;view;more(){return this.position<this.end}tag(){let n=this.varint();return[Math.floor(n/8),n&7]}varint(n=!1){let t=0,i=0;for(let o=0;o<10;o+=1){if(this.position>=this.end)throw new Error("Truncated vector tile.");let r=this.bytes[this.position++];if(o<4?t|=(r&127)<<o*7:o===4?(t|=(r&15)<<28,i=(r&112)>>4):o<9?i|=(r&127)<<(o-5)*7+3:i|=(r&1)<<31,r<128)return n?i*4294967296+(t>>>0):(i>>>0)*4294967296+(t>>>0)}throw new Error("Invalid varint in vector tile.")}span(){let n=this.varint(),t=this.position;if(t+n>this.end)throw new Error("Truncated vector tile.");return this.position=t+n,[t,t+n]}message(){let[n,t]=this.span();return new e(this.bytes,n,t)}string(){let[n,t]=this.span();return Pr.decode(this.bytes.subarray(n,t))}packed(){let[n,t]=this.span(),i=new e(this.bytes,n,t),o=[];for(;i.more();)o.push(i.varint());return o}float(){if(this.position+4>this.end)throw new Error("Truncated vector tile.");let n=this.view.getFloat32(this.position,!0);return this.position+=4,n}double(){if(this.position+8>this.end)throw new Error("Truncated vector tile.");let n=this.view.getFloat64(this.position,!0);return this.position+=8,n}skip(n){if(n===0)this.varint();else if(n===1)this.position+=8;else if(n===2)this.span();else if(n===5)this.position+=4;else throw new Error(`Unsupported protocol buffer wire type ${n} in vector tile.`);if(this.position>this.end)throw new Error("Truncated vector tile.")}};function dt(e){return Object.values(e.layers).filter(n=>typeof n=="string")}function mt(e,n){if(e.kind==="buildings"){let r=n(e.layers.building);if(!r)return;let s=n(e.layers.places),a=Kn(r,{...e.options,...s?{places:s}:{}});return a&&et(a)}if(e.kind==="trees"){let r=n(e.layers.tree),s=n(e.layers.canopy),a=n(e.layers.hedge);if(!r&&!s&&!a)return;let l=ct({...r?{trees:r}:{},...s?{canopy:s}:{},...a?{hedges:a}:{}},e.options);return l.trees.length>0||l.hedges.length>0?l:void 0}let t=n(e.layers.streetFurniture),i=n(e.layers.transportation),o=n(e.layers.sidewalk);return it({...t?{streetFurniture:t}:{},...i?{transportation:i}:{},...o?{sidewalks:o}:{}},e.options)}function ht(e,n){if(!n)return[];if(e==="buildings")return nt(n);if(e==="trees"){let{trees:t,hedges:i}=n;return[t.buffer,i.buffer].filter((o,r,s)=>s.indexOf(o)===r)}return[n.lamps.buffer]}function pt(e=16){let n=new Map;return{read(t,i,o){let r=n.get(t);for(n.delete(t),r??={bytes:i,layers:new Map},n.set(t,r);n.size>e;)n.delete(n.keys().next().value);let s=o.filter(l=>!r.layers.has(l));if(s.length>0){let l=ft(r.bytes,{layers:s});for(let u of s)r.layers.set(u,l[u])}let a=r.layers;return l=>l===void 0?void 0:a.get(l)}}}var On=globalThis,Er=pt();On.onmessage=({data:{url:e,bytes:n,task:t}})=>{try{let i=mt(t,Er.read(e,n,dt(t)));On.postMessage({result:i},ht(t.kind,i))}catch(i){On.postMessage({error:String(i)})}};})();\n'], { type: "text/javascript" })
|
|
10143
|
+
new Blob(['"use strict";(()=>{var Be=new Set,ln=!1;function Pe(e,n,t=2){let i=n&&n.length,o=i?n[0]*t:e.length;Be.size&&Be.clear();let r=In(e,0,o,t,!0),s=[];if(!r||r.next===r.prev)return s;let a=0,l=0,u=0;if(i&&(r=xt(e,n,r,t)),e.length>80*t){a=e[0],l=e[1];let c=a,f=l;for(let d=t;d<o;d+=t){let g=e[d],m=e[d+1];g<a&&(a=g),m<l&&(l=m),g>c&&(c=g),m>f&&(f=m)}u=Math.max(c-a,f-l),u=u!==0?32767/u:0}return un(r,s,a,l,u),s}function In(e,n,t,i,o){let r=null;if(o===Ct(e,n,t,i)>0)for(let s=n;s<t;s+=i)r=En(s/i|0,e[s],e[s+1],r);else for(let s=t-i;s>=n;s-=i)r=En(s/i|0,e[s],e[s+1],r);return r&&Oe(r,r.next)&&(Ue(r),r=r.next),r}function ge(e,n=e){let t=n===e,i=e,o;do o=!1,i!==i.next&&(Be.size===0||!Be.has(i))&&(Oe(i,i.next)||Q(i.prev,i,i.next)===0)?((t||i===n)&&(n=i.prev),ln=!0,Ue(i),i=i.prev,o=!0):(t||i!==n)&&(i=i.next,o=!t);while(o||i!==n);return n}function un(e,n,t,i,o){o&&Ft(e,t,i,o);let r=e,s=!1;for(;e.prev!==e.next;){let a=e.prev,l=e.next;if(Q(a,e,l)<0&&(o?bt(e,t,i,o):yt(e))){n.push(a.i,e.i,l.i),Ue(e),e=l,r=l;continue}if(e=l,e===r){if(ln=!1,e=ge(e),ln){r=e;continue}if(!s){e=gt(e,n),r=e,s=!0;continue}wt(e,n,t,i,o);break}}}function yt(e){let n=e.prev,t=e,i=e.next,o=n.x,r=t.x,s=i.x,a=n.y,l=t.y,u=i.y,c=Math.min(o,r,s),f=Math.min(a,l,u),d=Math.max(o,r,s),g=Math.max(a,l,u),m=i.next;for(;m!==n;){if(m.x>=c&&m.x<=d&&m.y>=f&&m.y<=g&&!(o===m.x&&a===m.y)&&Ke(o,a,r,l,s,u,m.x,m.y)&&Q(m.prev,m,m.next)>=0)return!1;m=m.next}return!0}function bt(e,n,t,i){let o=e.prev,r=e,s=e.next,a=o.x,l=r.x,u=s.x,c=o.y,f=r.y,d=s.y,g=Math.min(a,l,u),m=Math.min(c,f,d),p=Math.max(a,l,u),h=Math.max(c,f,d),A=mn(g,m,n,t,i),F=mn(p,h,n,t,i),k=e.prevZ;for(;k&&k.z>=A;){if(k.x>=g&&k.x<=p&&k.y>=m&&k.y<=h&&k!==s&&!(a===k.x&&c===k.y)&&Ke(a,c,l,f,u,d,k.x,k.y)&&Q(k.prev,k,k.next)>=0)return!1;k=k.prevZ}let M=e.nextZ;for(;M&&M.z<=F;){if(M.x>=g&&M.x<=p&&M.y>=m&&M.y<=h&&M!==s&&!(a===M.x&&c===M.y)&&Ke(a,c,l,f,u,d,M.x,M.y)&&Q(M.prev,M,M.next)>=0)return!1;M=M.nextZ}return!0}function gt(e,n){let t=e,i=!1;do{let o=t.prev,r=t.next.next;Dn(o,t,t.next,r,!1)&&Ce(o,r)&&Ce(r,o)&&(n.push(o.i,t.i,r.i),Ue(t),Ue(t.next),t=e=r,i=!0),t=t.next}while(t!==e);return i?ge(t):t}function wt(e,n,t,i,o){let r=e;do{let s=r.next.next;for(;s!==r.prev;){if(r.i!==s.i&&Lt(r,s)){let a=Vn(r,s);r=ge(r,r.next),a=ge(a,a.next),un(r,n,t,i,o),un(a,n,t,i,o);return}s=s.next}r=r.next}while(r!==e)}var cn=!1;function xt(e,n,t,i){let o=[];for(let r=0,s=n.length;r<s;r++){let a=n[r]*i,l=r<s-1?n[r+1]*i:e.length,u=In(e,a,l,i,!1);u===u.next&&Be.add(u),o.push(St(u))}o.sort(Tt),kt(e.length/i,n.length),Nn(t,t),cn=!0;for(let r=0;r<o.length;r++)t=Mt(o[r],t);return cn=!1,ge(t)}function Tt(e,n){return e.x-n.x||e.y-n.y||(e.next.y-e.y)/(e.next.x-e.x)-(n.next.y-n.y)/(n.next.x-n.x)}function Mt(e,n){let t=Rt(e,n);if(!t)return n;let i=Vn(t,e),o=i.next;return Nn(t,o.next),ge(i,i.next),ge(t,t.next)}var jn=16,X=new Float64Array(0),Je=0,fn=[],dn=[];function kt(e,n){let t=Math.ceil((e+2*n)/jn)+n+2;X.length<t*4&&(X=new Float64Array(t*4)),Je=0}function Nn(e,n){let t=e;do{let i=Je++;fn[i]=t;let o=t.x,r=t.y,s=t.x,a=t.y,l=0;do{let c=t.next;t.z=i,c.x<o&&(o=c.x),c.x>s&&(s=c.x),c.y<r&&(r=c.y),c.y>a&&(a=c.y),t=c}while(++l<jn&&t!==n);dn[i]=t;let u=i*4;X[u]=o,X[u+1]=r,X[u+2]=s,X[u+3]=a}while(t!==n)}function vt(e,n){let t=e.z*4;n.x<X[t]&&(X[t]=n.x),n.y<X[t+1]&&(X[t+1]=n.y),n.x>X[t+2]&&(X[t+2]=n.x),n.y>X[t+3]&&(X[t+3]=n.y)}function Pn(e){let n=dn[e];for(;n.prev.next!==n;)n=n.next;return dn[e]=n,n}function zn(e){let n=fn[e];for(;n.prev.next!==n;)n=n.next;return fn[e]=n,n}function Rt(e,n){let t=n,i=e.x,o=e.y,r=-1/0,s;if(Oe(e,t))return t;for(let d=0,g=0;d<Je;d++,g+=4){if(o<X[g+1]||o>X[g+3]||X[g]>i||X[g+2]<=r)continue;let m=Pn(d);t=zn(d);do{if(t.prev.next===t){if(Oe(e,t.next))return t.next;if(o<=t.y&&o>=t.next.y&&t.next.y!==t.y){let p=t.x+(o-t.y)*(t.next.x-t.x)/(t.next.y-t.y);if(p<=i&&p>r&&(r=p,s=t.x<t.next.x?t:t.next,p===i))return s}}t=t.next}while(t!==m)}if(!s)return null;let a=s.x,l=s.y,u=Math.min(o,l),c=Math.max(o,l),f=1/0;for(let d=0,g=0;d<Je;d++,g+=4){if(X[g+2]<a||X[g]>i||X[g+3]<u||X[g+1]>c)continue;let m=Pn(d);t=zn(d);do{if(t.prev.next===t&&i>=t.x&&t.x>=a&&i!==t.x&&Ke(o<l?i:r,o,a,l,o<l?r:i,o,t.x,t.y)){let p=Math.abs(o-t.y)/(i-t.x);(Ce(t,e)||t.y===o&&t.next.y===o&&t.next.x>i)&&(p<f||p===f&&(t.x>s.x||t.x===s.x&&At(s,t)))&&(s=t,f=p)}t=t.next}while(t!==m)}return s}function At(e,n){return Q(e.prev,e,n.prev)<0&&Q(n.next,e,e.next)<0}var ie=[],ve=[],be=new Uint32Array(0),Se=new Uint32Array(0),Le=new Uint32Array(256);function Ft(e,n,t,i){let o=e,r=0;do o.z=mn(o.x,o.y,n,t,i),ie[r++]=o,o=o.next;while(o!==e);_t(r);let s=null;for(let a=0;a<r;a++){let l=ie[a];l.prevZ=s,s&&(s.nextZ=l),s=l}s.nextZ=null,ie.fill(null,0,r),ve.fill(null,0,r)}function _t(e){if(e<=32){for(let n=1;n<e;n++){let t=ie[n],i=t.z,o=n-1;for(;o>=0&&ie[o].z>i;)ie[o+1]=ie[o],o--;ie[o+1]=t}return}be.length<e&&(be=new Uint32Array(e),Se=new Uint32Array(e),ve=new Array(e));for(let n=0;n<e;n++)be[n]=ie[n].z;Xe(e,ie,be,ve,Se,0),Xe(e,ve,Se,ie,be,8),Xe(e,ie,be,ve,Se,16),Xe(e,ve,Se,ie,be,24)}function Xe(e,n,t,i,o,r){Le.fill(0);for(let a=0;a<e;a++)Le[t[a]>>>r&255]++;let s=0;for(let a=0;a<256;a++){let l=Le[a];Le[a]=s,s+=l}for(let a=0;a<e;a++){let l=t[a],u=Le[l>>>r&255]++;i[u]=n[a],o[u]=l}}function mn(e,n,t,i,o){return e=(e-t)*o|0,n=(n-i)*o|0,e=(e|e<<8)&16711935,e=(e|e<<4)&252645135,e=(e|e<<2)&858993459,e=(e|e<<1)&1431655765,n=(n|n<<8)&16711935,n=(n|n<<4)&252645135,n=(n|n<<2)&858993459,n=(n|n<<1)&1431655765,e|n<<1}function St(e){let n=e,t=e;do(n.x<t.x||n.x===t.x&&n.y<t.y)&&(t=n),n=n.next;while(n!==e);return t}function Ke(e,n,t,i,o,r,s,a){return(o-s)*(n-a)>=(e-s)*(r-a)&&(e-s)*(i-a)>=(t-s)*(n-a)&&(t-s)*(r-a)>=(o-s)*(i-a)}function Lt(e,n){let t=Oe(e,n)&&Q(e.prev,e,e.next)>0&&Q(n.prev,n,n.next)>0;return e.next.i!==n.i&&(t||Ce(e,n)&&Ce(n,e)&&(Q(e.prev,e,n.prev)!==0||Q(e,n.prev,n)!==0))&&!Bt(e,n)&&(t||Ot(e,n))}function Q(e,n,t){return(n.y-e.y)*(t.x-n.x)-(n.x-e.x)*(t.y-n.y)}function Oe(e,n){return e.x===n.x&&e.y===n.y}function Dn(e,n,t,i,o=!0){let r=Q(e,n,t),s=Q(e,n,i),a=Q(t,i,e),l=Q(t,i,n);return(r>0&&s<0||r<0&&s>0)&&(a>0&&l<0||a<0&&l>0)?!0:o?!!(r===0&&Ye(e,t,n)||s===0&&Ye(e,i,n)||a===0&&Ye(t,e,i)||l===0&&Ye(t,n,i)):!1}function Ye(e,n,t){return n.x<=Math.max(e.x,t.x)&&n.x>=Math.min(e.x,t.x)&&n.y<=Math.max(e.y,t.y)&&n.y>=Math.min(e.y,t.y)}function Bt(e,n){let t=Math.min(e.x,n.x),i=Math.max(e.x,n.x),o=Math.min(e.y,n.y),r=Math.max(e.y,n.y),s=e;do{let a=s.next;if(s.x>i&&a.x>i||s.x<t&&a.x<t||s.y>r&&a.y>r||s.y<o&&a.y<o){s=a;continue}if(s.i!==e.i&&a.i!==e.i&&s.i!==n.i&&a.i!==n.i&&Dn(s,a,e,n))return!0;s=a}while(s!==e);return!1}function Ce(e,n){return Q(e.prev,e,e.next)<0?Q(e,n,e.next)>=0&&Q(e,e.prev,n)>=0:Q(e,n,e.prev)<0||Q(e,e.next,n)<0}function Ot(e,n){let t=e,i=!1,o=(e.x+n.x)/2,r=(e.y+n.y)/2;do{let s=t.next;t.y>r!=s.y>r&&o<(s.x-t.x)*(r-t.y)/(s.y-t.y)+t.x&&(i=!i),t=s}while(t!==e);return i}function Vn(e,n){let t=hn(e.i,e.x,e.y),i=hn(n.i,n.x,n.y),o=e.next,r=n.prev;return e.next=n,n.prev=e,t.next=o,o.prev=t,i.next=t,t.prev=i,r.next=i,i.prev=r,i}function En(e,n,t,i){let o=hn(e,n,t);return i?(o.next=i.next,o.prev=i,i.next.prev=o,i.next=o):(o.prev=o,o.next=o),o}function Ue(e){e.next.prev=e.prev,e.prev.next=e.next,e.prevZ&&(e.prevZ.nextZ=e.nextZ),e.nextZ&&(e.nextZ.prevZ=e.prevZ),cn&&vt(e.prev,e.next)}function hn(e,n,t){return{i:e,x:n,y:t,prev:null,next:null,z:0,prevZ:null,nextZ:null}}function Ct(e,n,t,i){let o=0;for(let r=n,s=t-i;r<t;r+=i)o+=(e[s]-e[r])*(e[r+1]+e[s+1]),s=r;return o}var Ut=.7,Pt=Math.tan(Math.PI/6),zt=Math.tan(35*Math.PI/180),Et=Math.tan(Math.PI/18),ze=.65,Ee=.4;function Zn(e,n,t,i,o,r,s){let a=String(t.roof_shape??"");if(!a||a==="flat"||a==="sawtooth"||Vt(e,s))return;let l=Nt(e);if(!l||Math.abs(pn(e))<Ut*4*l.halfU*l.halfV)return;let u=l.u,c=l.v,f=l.halfU*r,d=l.halfV*r;f<d&&([u,c,f,d]=[c,u,d,f]);let g=Gn(t.roof_direction),m=g===void 0?void 0:[Math.sin(g*Math.PI/180),-Math.cos(g*Math.PI/180)];(m!==void 0?Math.abs(m[0]*u[0]+m[1]*u[1])>Math.abs(m[0]*c[0]+m[1]*c[1]):t.roof_orientation==="across")&&a!=="skillion"&&([u,c,f,d]=[c,u,d,f]);let h=jt(a,f,d,m&&[$n(m,u),$n(m,c)]);if(!h)return;let A=Math.max(0,o-i),F=Gn(t.roof_height),k,M;if(F!==void 0&&F>0)M=o,k=Math.max(i+Math.min(2,A/2),o-F);else{let y=Math.min(It(a,d),A*.6,30);t.height_source==="height"?(M=o,k=o-y):(k=o,M=o+y)}let B=M-k;if(!(B>=.3))return;let[C,z]=l.centre,U=(y,b)=>{let x=(y-C)*r,T=(b-z)*r;return[x*u[0]+T*u[1],x*c[0]+T*c[1]]},E=(y,b)=>[C+(y*u[0]+b*c[0])/r,z+(y*u[1]+b*c[1])/r],D=(y,b)=>{let x=1/0;for(let[T,_,v]of h)x=Math.min(x,T*y+_*b+v);return Math.max(0,x)},K=(y,b)=>k+B*D(...U(y,b)),$=[];for(let y=0;y+1<n.length;y+=2)$.push(...U(n[y],n[y+1]));pn($)<0&&Ht($);let N=1.01,Y=[-f*N,-d*N,f*N,-d*N,f*N,d*N,-f*N,d*N],w=[];for(let[y,b]of h.entries()){let x=Y;for(let[P,Z]of h.entries()){if(P===y)continue;let j=b[0]-Z[0],G=b[1]-Z[1],W=b[2]-Z[2];if(Math.abs(j)+Math.abs(G)+Math.abs(W)<1e-9){P<y&&(x=[]);continue}if(x=Hn(x,j,G,W),x.length<6)break}if(x.length<6)continue;let T=$,_=x.length/2;for(let P=0;P<_&&T.length>=6;P+=1){let[Z,j]=[x[P*2],x[P*2+1]],[G,W]=[x[(P+1)%_*2],x[(P+1)%_*2+1]];T=Hn(T,W-j,Z-G,-(W-j)*Z-(Z-G)*j)}if(T.length<6||Math.abs(pn(T))<1e-6)continue;let v=[];for(let P=0;P<T.length;P+=2)v.push(...E(T[P],T[P+1]));let L=Pe(v);if(L.length===0)continue;let O=B*b[0],V=B*b[1],R=O*u[0]+V*c[0],S=O*u[1]+V*c[1],I=Math.hypot(R,S,1);w.push({ring:v,triangles:L,normal:[-R/I,-S/I]})}if(w.length!==0)return{eaves:k,ridge:M,faces:w,heightAt:K,breaks(y,b,x,T){let[_,v]=U(y,b),[L,O]=U(x,T),V=[];for(let R=0;R<h.length;R+=1)for(let S=R+1;S<h.length;S+=1){let I=(ae,H)=>(h[R][0]-h[S][0])*ae+(h[R][1]-h[S][1])*H+(h[R][2]-h[S][2]),P=I(_,v),Z=I(L,O);if(P===Z||P*Z>0)continue;let j=P/(P-Z);if(j<=1e-4||j>=1-1e-4)continue;let G=_+(L-_)*j,W=v+(O-v)*j;h[R][0]*G+h[R][1]*W+h[R][2]<=D(G,W)+1e-6&&V.push(j)}return[...new Set(V.map(R=>Math.round(R*1e6)/1e6))].sort((R,S)=>R-S)}}}function It(e,n){switch(e){case"skillion":return 2*n*Et;case"pyramidal":return n*zt;case"gambrel":case"mansard":return n*.8;case"dome":case"onion":case"round":return n;default:return n*Pt}}function jt(e,n,t,i){let o=n,r=t,s=[[0,-1/r,1],[0,1/r,1]],a=u=>u.flatMap(c=>[1,-1].flatMap(f=>{let d=c==="v"?r:o,g=ze/(Ee*r)*f,m=(1-ze)/((1-Ee)*r)*f,p=h=>c==="v"?[0,-h]:[-h,0];return[[...p(g),ze/(Ee*r)*d],[...p(m),ze+(1-ze)/((1-Ee)*r)*(d-Ee*r)]]})),l=[.99,.8,.5,.2];switch(e){case"gabled":return s;case"saltbox":{let u=r/3;return[[0,-1/(r-u),1+u/(r-u)],[0,1/(r+u),1-u/(r+u)]]}case"hipped":return[...s,[-1/r,0,o/r],[1/r,0,o/r]];case"half_hipped":return[...s,[-1/r,0,.5+o/r],[1/r,0,.5+o/r]];case"pyramidal":return[...s,[-1/o,0,1],[1/o,0,1]];case"gambrel":return a(["v"]);case"mansard":return a(["v","u"]);case"skillion":{let[u,c]=i??[0,1],f=Math.abs(u)*o+Math.abs(c)*r;return f>0?[[-u/(2*f),-c/(2*f),.5]]:void 0}case"round":return[[0,0,1],...l.flatMap(u=>{let c=Math.sqrt(1-u*u);return[1,-1].map(f=>[0,-f*u/(r*c),1/c])})];case"dome":case"onion":return[[0,0,1],...l.flatMap(u=>{let c=Math.sqrt(1-u*u);return Array.from({length:12},(f,d)=>{let g=d*Math.PI/6;return[-u*Math.cos(g)/(o*c),-u*Math.sin(g)/(r*c),1/c]})})];default:return}}function Hn(e,n,t,i){let o=e.length/2,r=[];for(let s=0;s<o;s+=1){let a=e[s*2],l=e[s*2+1],u=e[(s+1)%o*2],c=e[(s+1)%o*2+1],f=n*a+t*l+i,d=n*u+t*c+i;if(f<=0&&r.push(a,l),f<0&&d>0||f>0&&d<0){let g=f/(f-d);r.push(a+(u-a)*g,l+(c-l)*g)}}return r}function Nt(e){let n=Dt(e);if(n.length<3)return;let t,i=1/0;for(let o=0;o<n.length;o+=1){let[r,s]=n[o],[a,l]=n[(o+1)%n.length],u=Math.hypot(a-r,l-s);if(u===0)continue;let c=[(a-r)/u,(l-s)/u],f=[-c[1],c[0]],[d,g,m,p]=[1/0,-1/0,1/0,-1/0];for(let[A,F]of n){let k=A*c[0]+F*c[1],M=A*f[0]+F*f[1];d=Math.min(d,k),g=Math.max(g,k),m=Math.min(m,M),p=Math.max(p,M)}let h=(g-d)*(p-m);if(h<i){i=h;let A=(d+g)/2,F=(m+p)/2;t={centre:[A*c[0]+F*f[0],A*c[1]+F*f[1]],u:c,v:f,halfU:(g-d)/2,halfV:(p-m)/2}}}return t&&t.halfU>0&&t.halfV>0?t:void 0}function Dt(e){let n=[];for(let r=0;r+1<e.length;r+=2)n.push([e[r],e[r+1]]);n.sort((r,s)=>r[0]-s[0]||r[1]-s[1]);let t=(r,s,a)=>(s[0]-r[0])*(a[1]-r[1])-(s[1]-r[1])*(a[0]-r[0]),i=[];for(let r of n){for(;i.length>=2&&t(i.at(-2),i.at(-1),r)<=0;)i.pop();i.push(r)}let o=[];for(let r of n.reverse()){for(;o.length>=2&&t(o.at(-2),o.at(-1),r)<=0;)o.pop();o.push(r)}return[...i.slice(0,-1),...o.slice(0,-1)]}function Vt(e,n){let[t,i,o,r]=[1/0,-1/0,1/0,-1/0];for(let a=0;a+1<e.length;a+=2)t=Math.min(t,e[a]),i=Math.max(i,e[a]),o=Math.min(o,e[a+1]),r=Math.max(r,e[a+1]);let s=e.length/2;for(let a=0;a<s;a+=1){let l=e[a*2],u=e[a*2+1],c=e[(a+1)%s*2],f=e[(a+1)%s*2+1];if(t<0&&l===t&&c===t||i>n&&l===i&&c===i||o<0&&u===o&&f===o||r>n&&u===r&&f===r)return!0}return!1}function pn(e){let n=0,t=e.length/2;for(let i=0;i<t;i+=1){let o=(i+1)%t;n+=e[i*2]*e[o*2+1]-e[o*2]*e[i*2+1]}return n/2}function Ht(e){let n=[];for(let t=0;t<e.length;t+=2)n.push([e[t],e[t+1]]);n.reverse(),e.splice(0,e.length,...n.flat())}function $n(e,n){return e[0]*n[0]+e[1]*n[1]}function Gn(e){let n=typeof e=="string"?Number(e):e;return typeof n=="number"&&Number.isFinite(n)?n:void 0}var $t=Object.freeze({surface:0,secondary:1,glass:2,accent:3,roof:4}),Nr=Object.freeze(Object.keys($t));var Dr=Object.freeze({unclassified:0,wall:1,door:2,roof:3,window:4,lamp:5,logo:6});var Vr=Object.freeze({levels:3,vertices:2e5,triangles:2e5,footprintPoints:4096,radius:2e3,height:1e3,models:512,bytes:16*1024*1024,parts:16});function yn(e,n,t){for(let i of e){let o=!1;for(let r=0,s=i.length-2;r<i.length;s=r,r+=2){let a=i[r],l=i[r+1],u=i[s],c=i[s+1];l>t!=c>t&&n<(u-a)*(t-l)/(c-l)+a&&(o=!o)}if(o)return!0}return!1}function Yn(e,n,t){for(let i of n){let[o,r,s,a]=Xn(i);for(let l of e){let[u,c,f,d]=Xn(l);if(!(u>s-t||f<o+t||c>a-t||d<r+t)&&(Wn(l,i,t)||Wn(i,l,t)))return!0}}return!1}function Wn(e,n,t){let i=(o,r)=>yn([n],o,r)&&Zt(n,o,r)>t;for(let o=0;o+1<e.length;o+=2)if(i(e[o],e[o+1]))return!0;for(let o=0,r=e.length-2;o<e.length;r=o,o+=2){let[s,a,l,u]=[e[r],e[r+1],e[o],e[o+1]],c=[0,1];for(let f=0,d=n.length-2;f<n.length;d=f,f+=2){let g=Gt(s,a,l,u,n[d],n[d+1],n[f],n[f+1]);g!==void 0&&c.push(g)}if(c.length!==2){c.sort((f,d)=>f-d);for(let f=1;f<c.length;f+=1){let d=(c[f-1]+c[f])/2;if(i(s+(l-s)*d,a+(u-a)*d))return!0}}}return!1}function Gt(e,n,t,i,o,r,s,a){let l=t-e,u=i-n,c=s-o,f=a-r,d=l*f-u*c;if(d===0)return;let g=((o-e)*f-(r-n)*c)/d,m=((o-e)*u-(r-n)*l)/d;return g>0&&g<1&&m>=0&&m<=1?g:void 0}function Zt(e,n,t){let i=1/0;for(let o=0,r=e.length-2;o<e.length;r=o,o+=2){let[s,a,l,u]=[e[r],e[r+1],e[o],e[o+1]],c=(l-s)**2+(u-a)**2,f=c>0?Math.max(0,Math.min(1,((n-s)*(l-s)+(t-a)*(u-a))/c)):0;i=Math.min(i,Math.hypot(n-(s+(l-s)*f),t-(a+(u-a)*f)))}return i}function Xn(e){let[n,t,i,o]=[1/0,1/0,-1/0,-1/0];for(let r=0;r+1<e.length;r+=2)n=Math.min(n,e[r]),i=Math.max(i,e[r]),t=Math.min(t,e[r+1]),o=Math.max(o,e[r+1]);return[n,t,i,o]}var ue=8192,pe=28,Wt={commercial:1,active:2,destination:3},Xt={residential:1,...Object.fromEntries(["civic","commercial","education","entertainment","medical","transportation"].map(e=>[e,2])),...Object.fromEntries(["agricultural","industrial","military","outbuilding","religious","service"].map(e=>[e,3]))},Yt={dining:1,entertainment:2,nightlife:3},bn={...Object.fromEntries(["alcoholic_beverage_venue","bar","beer","biergarten","brewery","casino","cocktail_bar","dance_club","karaoke","lounge","music_venue","night_club","nightclub","pub","wine_bar"].map(e=>[e,3])),...Object.fromEntries(["arts_centre","bowling_alley","cinema","comedy_club","concert_hall","movie_theater","opera","performing_arts_venue","theater","theatre","theatre_venue"].map(e=>[e,2])),...Object.fromEntries(["casual_eatery","fast_food","fast_food_restaurant","food_court","restaurant"].map(e=>[e,1]))},Jt=6,Kt=.5,Qt=.5;function Kn(e,n){let t=ue/e.extent,i=n.tileMetres/ue,o=n.defaultHeight??5,r=Number.isFinite(n.edgeRadius)?Math.max(0,Math.min(1.5,n.edgeRadius))/i:0,s=new wn,a=new Qe,l=new Qe,u=[],c=[],f=0,d=tr(e,n);for(let[M,B]of e.features.entries()){if(B.type!=="Polygon"||u.length>=65535)continue;let C=B.properties,z=C.hide_3d;if(z===!0||z===1||z==="1"||z==="true")continue;let U=Math.min(6e3,Jn(C.render_height)??o),E=Math.min(U,Jn(C.render_min_height)??0),D=Wt[String(C.building_tone??"")]??0,K=Xt[String(C.class??"")]??0,$=d.get(M)??0,N=u.length,Y=!1;for(let w of rr(B.geometry,t)){let y=w.map(ir).filter(S=>S.length>=6);if(y.length===0||qe(y[0])===0)continue;let[b,x]=or(y[0]);if(n.masks?.length&&(yn(n.masks,b,x)||Yn(y,n.masks,Qt/i)))continue;let T={cell:Math.min(7,Math.max(0,Math.floor(x/1024)))*8+Math.min(7,Math.max(0,Math.floor(b/1024))),bounds:[1/0,1/0,-1/0,-1/0,U+.1],roofsFrom:a.length,roofsCount:0,wallsFrom:l.length,wallsCount:0};for(let S of y)for(let I=0;I<S.length;I+=2)T.bounds[0]=Math.min(T.bounds[0],S[I]-1),T.bounds[1]=Math.min(T.bounds[1],S[I+1]-1),T.bounds[2]=Math.max(T.bounds[2],S[I]+1),T.bounds[3]=Math.max(T.bounds[3],S[I+1]+1);Y=!0,f=Math.max(f,U);let _=Number.isSafeInteger(B.id),v=gn(_?B.id*.0731:b*.0731+x*.19137+N*1.618),L=!_&&y[0].some(S=>S<=0||S>=ue)?gn(U*7.31+E*3.17+D):v,O={base:E,top:U,jitter:L,seed:v,tone:D,group:K,use:$,cx:b,cy:x,index:N},V=y.map((S,I)=>nr(S,I,r,n.cornerAngle));y=V.map(({ring:S})=>S);let R=w.length===1&&y.length===1?Zn(w[0],y[0],C,E,U,i,ue):void 0;R?(f=Math.max(f,R.ridge),T.bounds[4]=Math.max(T.bounds[4],R.ridge+.1),er(R,O,s,a)):qt(y,O,s,a);for(let[S,I]of y.entries()){let P=qe(I)>0,Z=S===0?P?-1:1:P?1:-1,j=I.length/2,G=H=>{let J=(H%j+j)%j;return[I[J*2],I[J*2+1]]},W=H=>{let[J,re]=G(H-1),[ne,te]=G(H),[le,de]=G(H+1);if(we(J,re,ne,te)||we(ne,te,le,de))return!1;let me=Math.hypot(ne-J,te-re),ce=Math.hypot(le-ne,de-te);if(!me||!ce)return!1;let je=-(te-re)/me*Z,Ne=(ne-J)/me*Z;return(je*(le-ne)+Ne*(de-te))/ce>Kt},se=(H,J)=>R?R.heightAt(H,J):U,ae=0;for(let H=0;H<j;H+=1){let[J,re]=G(H),[ne,te]=G(H+1),le=Math.hypot(ne-J,te-re);if(le===0||we(J,re,ne,te))continue;let de=-(te-re)/le*Z,me=(ne-J)/le*Z,ce=V[S].normals[H]??[de,me],je=V[S].normals[(H+1)%j]??[de,me],Ne=oe=>{let Ae=ce[0]+(je[0]-ce[0])*oe,Fe=ce[1]+(je[1]-ce[1])*oe,ye=Math.hypot(Ae,Fe)||1;return[Ae/ye,Fe/ye]},he=[0,...R?R.breaks(J,re,ne,te):[],1];for(let oe=0;oe+1<he.length;oe+=1){let Ae=oe===0,Fe=oe+2===he.length,ye=J+(ne-J)*he[oe],De=re+(te-re)*he[oe],Ve=J+(ne-J)*he[oe+1],He=re+(te-re)*he[oe+1],_e=Math.hypot(Ve-ye,He-De)/ue*n.tileMetres,$e=(Ae&&W(H)?1:0)|(Fe&&W(H+1)?2:0)|(S>0?4:0),Ge=(Ae&&xn(J,re)?1:0)|(Fe&&xn(ne,te)?2:0),an=ae+_e,Ze=Ne(he[oe]),We=Ne(he[oe+1]),Cn=se(ye,De),Un=se(Ve,He),ke=s.write(O,ye,De,0,Ze[0],Ze[1],1,ae,$e,_e,0,Ge,Cn);s.write(O,Ve,He,0,We[0],We[1],1,an,$e,_e,1,Ge,Un),s.write(O,ye,De,1,Ze[0],Ze[1],1,ae,$e,_e,0,Ge,Cn),s.write(O,Ve,He,1,We[0],We[1],1,an,$e,_e,1,Ge,Un),l.push(ke,ke+1,ke+2,ke+1,ke+3,ke+2),ae=an}}}T.roofsCount=a.length-T.roofsFrom,T.wallsCount=l.length-T.wallsFrom,c.push(T)}Y&&u.push(C)}if(s.count===0)return;let g=new Uint32Array(a.length+l.length),m=[],p=0,h=a.length,A=a.values(),F=l.values();c.sort((M,B)=>M.cell-B.cell);let k=-1;for(let M of c){M.cell!==k&&(k=M.cell,m.push({bounds:[...M.bounds],roofsFrom:p,roofsCount:0,wallsFrom:h,wallsCount:0}));let B=m.at(-1);for(let C=0;C<5;C+=1)B.bounds[C]=C<2?Math.min(B.bounds[C],M.bounds[C]):Math.max(B.bounds[C],M.bounds[C]);g.set(A.subarray(M.roofsFrom,M.roofsFrom+M.roofsCount),p),g.set(F.subarray(M.wallsFrom,M.wallsFrom+M.wallsCount),h),p+=M.roofsCount,h+=M.wallsCount,B.roofsCount+=M.roofsCount,B.wallsCount+=M.wallsCount}return{groups:m,vertices:s.bytes(),indices:g,wallsFrom:a.length,top:f,features:u}}function qt(e,n,t,i){let o=[],r=[];for(let l of e)r.push(o.length/2),o.push(...l);r.push(o.length/2);let s=(l,u)=>{let c=r.findIndex((p,h)=>l>=p&&l<r[h+1]),[f,d]=[r[c],r[c+1]-1];if(u<f||u>d)return!1;let[g,m]=l<u?[l,u]:[u,l];return m-g!==1&&!(g===f&&m===d)?!1:!we(o[l*2],o[l*2+1],o[u*2],o[u*2+1])},a=Pe(o,r.slice(1,-1),2);for(let l=0;l+2<a.length;l+=3){let u=[a[l],a[l+1],a[l+2]],c=0;for(let f=0;f<3;f+=1)s(u[(f+1)%3],u[(f+2)%3])&&(c|=1<<f);for(let[f,d]of u.entries())i.push(t.write(n,o[d*2],o[d*2+1],1,0,0,0,0,0,0,f,c))}}function er(e,n,t,i){for(let o of e.faces){let r=o.ring,s=r.length/2,a=(l,u)=>{let[c,f]=l<u?[l,u]:[u,l];return f-c!==1&&!(c===0&&f===s-1)?!1:!we(r[l*2],r[l*2+1],r[u*2],r[u*2+1])};for(let l=0;l+2<o.triangles.length;l+=3){let u=[o.triangles[l],o.triangles[l+1],o.triangles[l+2]],c=0;for(let f=0;f<3;f+=1)a(u[(f+1)%3],u[(f+2)%3])&&(c|=1<<f);for(let[f,d]of u.entries()){let g=r[d*2],m=r[d*2+1];i.push(t.write(n,g,m,1,o.normal[0],o.normal[1],0,0,0,0,f,c,e.heightAt(g,m)))}}}}function nr(e,n,t,i=Math.PI/6){if(t<1)return{ring:e,normals:[]};let o=e.length/2,r=qe(e)>0,s=n===0?r?-1:1:r?1:-1,a=[],l=[],u=(c,f,d)=>{c=Re(c),f=Re(f),!(a.at(-2)===c&&a.at(-1)===f)&&(a.push(c,f),l.push(d))};for(let c=0;c<o;c+=1){let f=(c+o-1)%o,d=(c+1)%o,[g,m]=[e[f*2],e[f*2+1]],[p,h]=[e[c*2],e[c*2+1]],[A,F]=[e[d*2],e[d*2+1]],k=Math.hypot(p-g,h-m),M=Math.hypot(A-p,F-h);if(!k||!M||xn(p,h)||we(g,m,p,h)||we(p,h,A,F)){u(p,h);continue}let[B,C]=[(p-g)/k,(h-m)/k],[z,U]=[(A-p)/M,(F-h)/M],E=Math.atan2(B*U-C*z,B*z+C*U);if(E*s>=-.08||Math.abs(E)>Math.PI*.85){u(p,h);continue}let D=Math.tan(Math.abs(E)/2),K=Math.min(t*D,k*.2,M*.2),$=K/D;if($<1){u(p,h);continue}let[N,Y]=[-C*s,B*s],[w,y]=[p-B*K-N*$,h-C*K-Y*$],b=Math.atan2(Y,N),x=Math.max(i<=Math.PI/6?2:1,Math.ceil(Math.abs(E)/Math.max(Math.PI/6,Math.min(Math.PI/3,i))));for(let T=0;T<=x;T+=1){let _=b+E*T/x,v=[Math.cos(_),Math.sin(_)];u(w+v[0]*$,y+v[1]*$,v)}}return a[0]===a.at(-2)&&a[1]===a.at(-1)&&(a.splice(-2),l.pop()),a.length>=6?{ring:a,normals:l}:{ring:e,normals:[]}}var wn=class{#e=new ArrayBuffer(4096*pe);#n=new DataView(this.#e);count=0;write(n,t,i,o,r,s,a,l,u,c,f=0,d=0,g=n.top){let m=pe;if((this.count+1)*m>this.#e.byteLength){let A=new ArrayBuffer(this.#e.byteLength*2);new Uint8Array(A).set(new Uint8Array(this.#e)),this.#e=A,this.#n=new DataView(A)}let p=this.#n,h=this.count*m;return p.setUint16(h,Re(t),!0),p.setUint16(h+2,Re(i),!0),p.setUint16(h+4,Math.min(65535,Math.round(n.base*10)),!0),p.setUint16(h+6,Math.min(65535,Math.max(0,Math.round(g*10))),!0),p.setInt8(h+8,Math.round(r*127)),p.setInt8(h+9,Math.round(s*127)),p.setUint8(h+10,o),p.setUint8(h+11,a),p.setUint16(h+12,Math.round(l*10)%65536,!0),p.setUint8(h+14,Math.round(n.jitter*255)),p.setUint8(h+15,Math.round(n.seed*255)),p.setUint16(h+16,Re(n.cx),!0),p.setUint16(h+18,Re(n.cy),!0),p.setUint8(h+20,n.tone+4*n.group),p.setUint8(h+21,n.use),p.setUint8(h+22,u),p.setUint8(h+23,Math.min(255,Math.round(c))),p.setUint16(h+24,n.index,!0),p.setUint8(h+26,f),p.setUint8(h+27,d),this.count+=1,this.count-1}bytes(){return new Uint8Array(this.#e.slice(0,this.count*pe))}},Qe=class{#e=new Uint32Array(8192);length=0;push(...n){if(this.length+n.length>this.#e.length){let t=new Uint32Array(Math.max(this.length+n.length,this.#e.length*2));t.set(this.#e),this.#e=t}for(let t of n)this.#e[this.length++]=t}values(){return this.#e.subarray(0,this.length)}};function tr(e,n){let t=new Map;if(e.features.some(a=>a.properties.night_use!==void 0)){for(let[a,l]of e.features.entries()){let u=Yt[String(l.properties.night_use??"")];u&&t.set(a,u)}return t}let i=n.places;if(!i||i.features.length===0)return t;let o=Jt/n.tileMetres*e.extent,r=[];for(let[a,l]of e.features.entries()){if(l.type!=="Polygon")continue;let u=l.properties.hide_3d;if(u===!0||u===1||u==="1"||u==="true")continue;let c=[1/0,1/0,-1/0,-1/0];for(let f of l.geometry)for(let d=0;d+1<f.length;d+=2)c[0]=Math.min(c[0],f[d]),c[1]=Math.min(c[1],f[d+1]),c[2]=Math.max(c[2],f[d]),c[3]=Math.max(c[3],f[d+1]);r.push({index:a,rings:l.geometry,box:c})}let s=e.extent/i.extent;for(let a of i.features){if(a.type!=="Point")continue;let l=a.properties,u=bn[String(l.type??"")]??bn[String(l.subclass??"")]??bn[String(l.class??"")];if(u)for(let c of a.geometry)for(let f=0;f+1<c.length;f+=2){let d=c[f]*s,g=c[f+1]*s,m,p,h=o;for(let F of r){let[k,M,B,C]=F.box;if(d<k-o||d>B+o||g<M-o||g>C+o)continue;let z=!1;for(let U of F.rings)for(let E=0,D=U.length-2;E+1<U.length;D=E,E+=2){let K=U[D],$=U[D+1],N=U[E],Y=U[E+1];Y>g!=$>g&&d<(K-N)*(g-Y)/($-Y)+N&&(z=!z);let w=N-K,y=Y-$,b=w*w+y*y,x=b?Math.min(1,Math.max(0,((d-K)*w+(g-$)*y)/b)):0,T=Math.hypot(d-K-x*w,g-$-x*y);T<h&&(h=T,p=F.index)}if(z){m=F.index;break}}let A=m??p;A!==void 0&&t.set(A,Math.max(t.get(A)??0,u))}}return t}function Re(e){return Math.min(ue,Math.max(0,Math.round(e)))}function Jn(e){let n=Number(e);return Number.isFinite(n)&&n>0?n:void 0}function rr(e,n){let t=[],i;for(let o of e){let r=[];for(let a=0;a+1<o.length;a+=2){let l=o[a]*n,u=o[a+1]*n;r.length&&l===r.at(-2)&&u===r.at(-1)||r.push(l,u)}if(r.length>=6&&r[0]===r.at(-2)&&r[1]===r.at(-1)&&(r.length-=2),r.length<6)continue;let s=Math.sign(qe(r));s&&(i??=s,s===i||t.length===0?t.push([r]):t.at(-1).push(r))}return t}function qe(e){let n=0,t=e.length/2;for(let i=0;i<t;i+=1){let o=(i+1)%t;n+=e[i*2]*e[o*2+1]-e[o*2]*e[i*2+1]}return n}function or(e){let n=0,t=0,i=e.length/2;for(let o=0;o<i;o+=1)n+=e[o*2],t+=e[o*2+1];return[n/i,t/i]}function xn(e,n){return e<=0||n<=0||e>=ue||n>=ue}function we(e,n,t,i){let o=ue;return e<=0&&t<=0||e>=o&&t>=o||n<=0&&i<=0||n>=o&&i>=o}function ir(e){let n=ue,t=[...e],i=[[0,0,o=>o>=0],[0,n,o=>o<=n],[1,0,o=>o>=0],[1,n,o=>o<=n]];for(let[o,r,s]of i){let a=[],l=t.length/2;for(let u=0;u<l;u+=1){let c=[t[u*2],t[u*2+1]],f=[t[(u+1)%l*2],t[(u+1)%l*2+1]],d=s(c[o]),g=s(f[o]);if(d&&a.push(c[0],c[1]),d!==g){let m=(r-c[o])/(f[o]-c[o]);a.push(c[0]+(f[0]-c[0])*m,c[1]+(f[1]-c[1])*m)}}if(t=a,t.length<6)return[]}return t}function gn(e){let n=Math.sin(e*12.9898+78.233)*43758.5453;return n-Math.floor(n)}var Qn=`\nin float v_haze_depth;\nuniform vec3 u_haze_colour;\nuniform vec3 u_haze; // strength; the view depths where the haze starts and is complete\n\nfloat hazeOf() {\n return u_haze.x > 0.0 ? u_haze.x * smoothstep(u_haze.y, u_haze.z, v_haze_depth) : 0.0;\n}\n\nvec3 hazed(vec3 colour) {\n return mix(colour, u_haze_colour, hazeOf());\n}`;function qn(e){let n=(e.indices.length-e.wallsFrom)/6,t=new Uint8Array(n*16);for(let i=0;i<n;i+=1){let o=e.wallsFrom+i*6,r=e.indices[o]*pe,s=e.indices[o+1]*pe;t.set(e.vertices.subarray(r,r+4),i*16),t.set(e.vertices.subarray(s,s+4),i*16+4),t.set(e.vertices.subarray(r+4,r+8),i*16+8),t[i*16+12]=e.vertices[r+14],t[i*16+13]=e.vertices[r+27]}return t}var Kr=`#version 300 es\nprecision highp float;\nuniform highp sampler2D u_contact;\n${Qn}\nout vec4 fragColor;\nvoid main() {\n float shade = mix(texelFetch(u_contact, ivec2(gl_FragCoord.xy), 0).r, 1.0, hazeOf());\n fragColor = vec4(vec3(shade), 1.0);\n}`;function et(e){let n=e.vertices.length/pe;return{mesh:{...e.groups?{groups:e.groups}:{},wallsFrom:e.wallsFrom,top:e.top,features:e.features,vertexCount:n,indexCount:e.indices.length},data:{vertices:e.vertices,indices:n<=65536?Uint16Array.from(e.indices):e.indices,contact:qn(e)}}}function nt({data:e}){return[e.vertices.buffer,e.indices.buffer,e.contact.buffer]}function Tn(e){let n=sr(e);return n?[Math.min(1,Math.max(0,n[0]/255)),Math.min(1,Math.max(0,n[1]/255)),Math.min(1,Math.max(0,n[2]/255)),Math.min(1,Math.max(0,n[3]))]:null}function sr(e){let n=e.trim().toLowerCase(),t=/^#([\\da-f]{3,8})$/u.exec(n)?.[1];if(t&&[3,4,6,8].includes(t.length)){let A=(t.length<=4?[...t].map(F=>F+F).join(""):t).match(/../gu).map(F=>Number.parseInt(F,16));return[A[0],A[1],A[2],A.length>3?A[3]/255:1]}let i=/^(rgba?|hsla?)\\(([^)]+)\\)$/u.exec(n);if(!i)return null;let o=i[2].split(/[\\s,/]+/u).filter(Boolean);if(o.length<3||o.length>4)return null;let r=o[3]===void 0?1:en(o[3],1);if(i[1].startsWith("rgb")){let[h,A,F]=o.slice(0,3).map(k=>en(k,255));return[h,A,F,r].some(k=>k===null)?null:[h,A,F,r]}let s=Number.parseFloat(o[0]),a=en(o[1],1),l=en(o[2],1);if(!Number.isFinite(s)||a===null||l===null||r===null)return null;let u=(1-Math.abs(2*l-1))*a,c=(s%360+360)%360/60,f=u*(1-Math.abs(c%2-1)),[d,g,m]=c<1?[u,f,0]:c<2?[f,u,0]:c<3?[0,u,f]:c<4?[0,f,u]:c<5?[f,0,u]:[u,0,f],p=l-u/2;return[(d+p)*255,(g+p)*255,(m+p)*255,r]}function en(e,n){let t=e.endsWith("%"),i=Number.parseFloat(e);return Number.isFinite(i)?t?i/100*n:i:null}var fe=8192,Mn=12,ar={primary:{spacing:30,kerb:10},secondary:{spacing:32,kerb:8.5},tertiary:{spacing:34,kerb:7},minor:{spacing:36,kerb:5.5},pedestrian:{spacing:26,kerb:3}},lr={motorway:{spacing:45,kerb:14},trunk:{spacing:40,kerb:12},service:{spacing:38,kerb:4},path:{spacing:28,kerb:1.5},track:{spacing:40,kerb:2.5}},ur={spacing:30,kerb:0},cr=12,fr=18,dr=9,mr={sodium:"#ffa64d",high_pressure_sodium:"#ffa64d",low_pressure_sodium:"#ff9326",led:"#fff1db",mercury:"#e3ecff",metal_halide:"#f4f4ff",fluorescent:"#eef9ff",electric:"#ffd59a",incandescent:"#ffd59a",halogen:"#ffe3b0",gas:"#ffd28a",gaslight:"#ffd28a"},hr={orange:"#ffa64d",yellow:"#ffd27a",warm_white:"#ffe2b8",white:"#fff4e6",cool_white:"#eef4ff",neutral_white:"#fff8f0",blue:"#b8d0ff",green:"#c4ffd0",red:"#ff9a8a"},pr=new Set(["wall","wall_mounted","wall_bracket"]),yr=new Set(["suspended","cable","catenary","wire"]);function it(e,n){let t=n.estimate??"lit",i=new vn,o=new nn(fr),r=new nn(dr),s=e.streetFurniture;if(s){let m=fe/s.extent;for(let p of s.features){let h=p.properties;if(p.type!=="Point"||h.subclass!=="street_lamp")continue;let A=br(h),F=gr(h),k=Math.max(1,Math.min(4,Number(h.light_count)||1)),M=Math.min(24,Math.max(5,A*1.7*(k>1?1.15:1)));for(let B of p.geometry)for(let C=0;C+1<B.length;C+=2){let z=B[C]*m,U=B[C+1]*m;if(!rt(z,U))continue;i.write(z,U,A,M,!0,F);let E=ot(z,U,n.tileMetres);o.add(...E),r.add(...E)}}}let a=i.count;if(t==="none")return i.done(a);let l=e.transportation,u=0;if(l){let m=n.tileMetres/l.extent;for(let p of l.features)if(!(p.type!=="LineString"||!tt(p.properties,"streets")))for(let h of p.geometry)u+=wr(h,l.extent)*m}let c=u>0&&a/(u/1e3)>=cr,f=t==="streets"&&!c?"streets":"lit",d=(m,p,h,A)=>{let F=fe/m.extent,k=[];for(let D=0;D+1<p.length;D+=2)k.push(p[D]*F,p[D+1]*F);let M=n.tileMetres/fe,B=h.kerb*.45/M,C=Rn(k[0]*.013+k[1]*.029+A)*h.spacing,z=0,U=C,E=Rn(k[0]+k[1]*3.1)<.5?1:-1;for(let D=2;D<k.length;D+=2){let K=k[D-2],$=k[D-1],N=k[D],Y=k[D+1],w=Math.hypot(N-K,Y-$)*M;if(w!==0){for(;U<=z+w;){let y=(U-z)/w,b=-(Y-$)/(w/M)*E,x=(N-K)/(w/M)*E,T=K+(N-K)*y+b*B,_=$+(Y-$)*y+x*B;if(U+=h.kerb>0?h.spacing/2:h.spacing,h.kerb>0&&(E=-E),!rt(T,_))continue;let v=ot(T,_,n.tileMetres);o.near(...v)||r.near(...v)||(r.add(...v),i.write(T,_,7,15,!1))}z+=w}}};if(l)for(let m of l.features){if(m.type!=="LineString")continue;let p=tt(m.properties,f);if(p)for(let h of m.geometry)d(l,h,p,1)}let g=e.sidewalks;if(g){for(let m of g.features)if(!(m.type==="Point"||!kn(m.properties.lit)))for(let p of m.geometry)d(g,p,ur,2)}return i.done(a)}function tt(e,n){if(e.brunnel==="tunnel"||e.covered===!0)return;let t=e.lit;if(t===!1||t==="no")return;let i=String(e.class??""),o=String(e.subclass??""),r=i==="path"&&(o==="pedestrian"||o==="living_street")?"pedestrian":i,s=ar[r];if(s&&(n==="streets"||kn(t)))return s;let a=lr[r];if(a&&kn(t))return a}function kn(e){return e===!0||e==="yes"||e===1||e==="1"||e==="true"}function br(e){let n=Number(e.height);if(Number.isFinite(n)&&n>=.5&&n<=40)return n;let t=String(e.lamp_mount??"").toLowerCase();return pr.has(t)?4.5:yr.has(t)?7.5:7}function gr(e){let n=e.light_colour??e["light:colour"];if(typeof n=="string"&&n){let r=n.toLowerCase().replaceAll(" ","_"),s=Tn(hr[r]??n);if(s)return[s[0],s[1],s[2]]}let t=String(e.lamp_type??"").toLowerCase().replaceAll("-","_").replaceAll(" ","_"),i=mr[t];if(!i)return;let o=Tn(i);return[o[0],o[1],o[2]]}function rt(e,n){return e>=0&&n>=0&&e<fe&&n<fe}function ot(e,n,t){return[e/fe*t,n/fe*t]}function wr(e,n){let t=0;for(let i=2;i+1<e.length;i+=2){let o=(e[i-2]+e[i])/2,r=(e[i-1]+e[i+1])/2;o<0||r<0||o>=n||r>=n||(t+=Math.hypot(e[i]-e[i-2],e[i+1]-e[i-1]))}return t}var nn=class{constructor(n){this.size=n}size;#e=new Map;add(n,t){let i=`${Math.floor(n/this.size)}/${Math.floor(t/this.size)}`,o=this.#e.get(i);o?o.push([n,t]):this.#e.set(i,[[n,t]])}near(n,t){let i=Math.floor(n/this.size),o=Math.floor(t/this.size);for(let r=-1;r<=1;r+=1)for(let s=-1;s<=1;s+=1)for(let[a,l]of this.#e.get(`${i+r}/${o+s}`)??[])if(Math.hypot(a-n,l-t)<this.size)return!0;return!1}},vn=class{#e=new ArrayBuffer(256*Mn);#n=new DataView(this.#e);count=0;write(n,t,i,o,r,s){let a=Mn;if((this.count+1)*a>this.#e.byteLength){let c=new ArrayBuffer(this.#e.byteLength*2);new Uint8Array(c).set(new Uint8Array(this.#e)),this.#e=c,this.#n=new DataView(c)}let l=this.#n,u=this.count*a;l.setUint16(u,Math.min(fe,Math.max(0,Math.round(n))),!0),l.setUint16(u+2,Math.min(fe,Math.max(0,Math.round(t))),!0),l.setUint16(u+4,Math.min(65535,Math.round(i*10)),!0),l.setUint8(u+6,Math.min(255,Math.round(o))),l.setUint8(u+7,(r?1:0)|(s?2:0)),l.setUint8(u+8,Math.round((s?.[0]??0)*255)),l.setUint8(u+9,Math.round((s?.[1]??0)*255)),l.setUint8(u+10,Math.round((s?.[2]??0)*255)),l.setUint8(u+11,Math.round(Rn(n*.0731+t*.19137)*255)),this.count+=1}done(n){if(this.count!==0)return{lamps:new Uint8Array(this.#e.slice(0,this.count*Mn)),mapped:n,estimated:this.count-n}}};function Rn(e){let n=Math.sin(e*12.9898+78.233)*43758.5453;return n-Math.floor(n)}var oo=Object.freeze({source:"tileflow",layers:Object.freeze({streetFurniture:"street_furniture",transportation:"transportation",sidewalk:"sidewalk"}),estimate:"lit",color:"#ffcf8f",intensity:1});var Me=["round","open","tall","conifer","columnar","palm"];var ut=Object.freeze({height:"height",diameterCrown:"diameter_crown",circumference:"circumference",genus:"genus",species:"species",leafType:"leaf_type",taxon:"taxon",canopyRank:"rank",canopyClearance:"clearance_px_z15",canopyCover:"cover_pct",canopyHeight:"height_m",subclass:"subclass",hedge:"hedge"}),Sn=Object.freeze({round:1,open:1,tall:1}),tn=16,q=8192,rn=16,st={round:{height:[6,12],crown:[.66,.9]},open:{height:[5,10],crown:[.8,1.05]},tall:{height:[9,17],crown:[.48,.68]},conifer:{height:[7,16],crown:[.46,.66]},columnar:{height:[9,18],crown:[.22,.36]},palm:{height:[12,20],crown:[.42,.55]}};var on=[2,45],An=[1,25],xr=1.2,Tr=1.5,Mr=1.3,kr=1,vr=[.3,10],Rr=new Set(["acoelorrhaphe","adonidia","archontophoenix","areca","arecastrum","bismarckia","brahea","butia","caryota","chamaedorea","chamaerops","coccothrinax","cocos","dypsis","elaeis","howea","jubaea","licuala","livistona","phoenix","pritchardia","ptychosperma","rhapis","roystonea","sabal","serenoa","syagrus","thrinax","trachycarpus","veitchia","washingtonia","wodyetia"]),Ar=new Set(["cupressus","calocedrus","thuja"]),Fr=new Set(["abies","araucaria","cedrus","cryptomeria","juniperus","larix","metasequoia","picea","pinus","pseudotsuga","sequoia","sequoiadendron","taxodium","taxus","tsuga"]),at=Object.freeze({...Object.fromEntries(["acacia","albizia","arbutus","bursera","ceratonia","delonix","ficus","gleditsia","jacaranda","olea","quercus","robinia","schinus","sophora","styphnolobium","tamarix"].map(e=>[e,"open"])),...Object.fromEntries(["betula","celtis","fraxinus","ginkgo","liquidambar","liriodendron","magnolia","platanus","populus","pyrus","ulmus","zelkova"].map(e=>[e,"tall"])),...Object.fromEntries(["acer","aesculus","carpinus","castanea","catalpa","cercis","citrus","fagus","lagerstroemia","malus","melia","morus","prunus","sorbus","tilia"].map(e=>[e,"round"]))});function lt(e,n={}){let t={...ut,...n},i=String(e[t.leafType]??"").toLowerCase(),o=String(e[t.taxon]??"").toLowerCase(),r=Fn(e[t.genus])??Fn(e[t.species])??(o.endsWith("aceae")?void 0:Fn(e[t.taxon]));if(i.includes("palm")||o.includes("arecaceae")||r&&Rr.has(r))return"palm";if(o.includes("cupressaceae")&&!r||o.includes("pinaceae"))return"conifer";if(r&&Ar.has(r))return"columnar";if(i.includes("needle")||r&&Fr.has(r))return"conifer";if(r&&at[r])return at[r];if(i.includes("broad"))return"broadleaf"}function Fn(e){return typeof e!="string"?void 0:e.trim().split(/\\s+/u)[0]?.toLowerCase()||void 0}function ct(e,n){let t={...ut,...n.fields},i=n.unknownForms??Sn,o=n.regions??[],{tile:r,tileMetres:s}=n,a=s/2**(15-r.z)/512,l=[],u=0,c=0,f=(w,y)=>{if(o.length===0)return i;let[b,x]=Sr(r,w/q,y/q);for(let T of o){let[_,v,L,O]=T.bounds;if(x>=v&&x<=O&&(_<=L?b>=_&&b<=L:b>=_||b<=L))return T.unknownForms}return i},d=(w,y,b,x)=>{let T=st[w],_=_n(T.crown,ee(y,2)),v=b,L=x;return v===void 0&&L===void 0&&(v=_n(T.height,ee(y,1))),v===void 0&&(v=L/_),L===void 0&&(L=v*_),{height:Te(v,on),crown:Te(L,An)}},g=(w,y,b,x,T,_)=>{let v=Ie(r.x*q+w,r.y*q+y,7),L=b===void 0?sn(f(w,y),ee(v,3)):b==="broadleaf"?sn(_r(f(w,y)),ee(v,3)):b,O=x===void 0&&T===void 0&&_!==void 0?d(L,v,_n(st[L].height,Te(_/3,[0,1]))):d(L,v,x,T);l.push({x:w,y,...O,turn:ee(v,4),shade:ee(v,5),form:Me.indexOf(L),rank:Math.floor(ee(v,6)*rn),seed:ee(v,7),canopy:0}),u+=1},m=e.trees;if(m){let w=q/m.extent;for(let y of m.features){if(y.type!=="Point")continue;let b=y.properties,x=lt(b,t),T=xe(b[t.height],on),_=xe(b[t.diameterCrown],An),v=xe(b[t.circumference],[.1,12]);for(let L of y.geometry)for(let O=0;O+1<L.length;O+=2){let V=L[O],R=L[O+1];V<0||R<0||V>=m.extent||R>=m.extent||g(V*w,R*w,x,T,_,v)}}}let p=e.trees;if(p){let w=q/p.extent,y=(n.rowSpacing??8)/(s/p.extent);for(let b of p.features){if(b.type!=="LineString")continue;let x=b.properties,T=lt(x,t),_=xe(x[t.height],on),v=xe(x[t.diameterCrown],An);for(let L of b.geometry){let O=y/2,V=0;for(let R=0;R+3<L.length;R+=2){let[S,I,P,Z]=[L[R],L[R+1],L[R+2],L[R+3]],j=Math.hypot(P-S,Z-I);for(;O<=V+j;){let G=j>0?(O-V)/j:0,W=S+(P-S)*G,se=I+(Z-I)*G;W>=0&&se>=0&&W<p.extent&&se<p.extent&&g(W*w,se*w,T,_,v,void 0),O+=y}V+=j}}}}let h=e.canopy;if(h){let w=q/h.extent;for(let y of h.features){if(y.type!=="Point")continue;let b=y.properties,x=Te(Math.floor(Number(b[t.canopyRank]??8)),[0,rn-1]),T=Math.max(4,Number(b[t.canopyClearance]??8))*a,_=Number(b[t.canopyCover]??30),v=_>=60?3:_>=30?2:1;for(let L of y.geometry)for(let O=0;O+1<L.length;O+=2){let V=L[O],R=L[O+1];if(V<0||R<0||V>=h.extent||R>=h.extent)continue;let S=V*w,I=R*w,P=Ie(r.x*q+S,r.y*q+I,11),Z=f(S,I),j=xe(b[t.canopyHeight],on),G=Te(Math.min(T*(v===1?1.3:.95),11)*(.85+ee(P,1)*.25),[3,12]),W=Math.max(0,Math.min(G*.5,T-G/2)),se=ee(P,2)*Math.PI*2;for(let ae=0;ae<v;ae+=1){let H=Ie(P,ae,13),J=se+ae*Math.PI*2/v,re=v===1?W*.3*ee(H,1):W,ne=S+Math.cos(J)*re/(s/q),te=I+Math.sin(J)*re/(s/q);if(ne<0||te<0||ne>=q||te>=q)continue;let le=sn(Z,ee(H,3)),de=G*(.85+ee(H,2)*.3),me=j===void 0?void 0:j*(.85+ee(H,6)*.25),ce=d(le,H,me,le==="palm"?void 0:de);l.push({x:ne,y:te,...ce,turn:ee(H,4),shade:ee(H,5),form:Me.indexOf(le),rank:x,seed:ee(H,7),canopy:1}),c+=1}}}}let A=[],F=e.hedges;if(F){let w=q/F.extent,y=xr/(s/F.extent);for(let b of F.features){if(b.type==="Point"||b.properties[t.subclass]!=="hedge")continue;let x=b.properties[t.hedge]==="hedge_bank"?kr:0,T=(xe(b.properties[t.height],vr)??Mr)+x;for(let _ of b.geometry){let v=y/2,L=0;for(let O=0;O+3<_.length;O+=2){let[V,R,S,I]=[_[O],_[O+1],_[O+2],_[O+3]],P=Math.hypot(S-V,I-R),Z=(Math.atan2(R-I,S-V)/(Math.PI*2)+1)%1;for(;v<=L+P;){let j=P>0?(v-L)/P:0,G=V+(S-V)*j,W=R+(I-R)*j;if(G>=0&&W>=0&&G<F.extent&&W<F.extent){let se=Ie(r.x*q+G*w,r.y*q+W*w,17);A.push({x:G*w,y:W*w,height:T,turn:Z,shade:ee(se,5),seed:ee(se,7)})}v+=y}L+=P}}}}let k=w=>Te(Math.floor(n.variants?.[Me[w]]??1),[1,4]),M=w=>Math.min(k(w.form)-1,Math.floor(ee(Math.floor(w.seed*256),9)*k(w.form))),B=l.map(M),C=l.map((w,y)=>y);C.sort((w,y)=>l[w].form-l[y].form||B[w]-B[y]||l[w].rank-l[y].rank);let z=new Uint8Array(l.length*tn),U=new DataView(z.buffer),E=0,D=()=>({start:0,count:0,upTo:new Array(rn).fill(0)}),K=Object.fromEntries(Me.map((w,y)=>[w,{...D(),variants:Array.from({length:k(y)},D)}])),$=(w,y,b)=>{w.count===0&&(w.start=y),w.count+=1;for(let x=b;x<rn;x+=1)w.upTo[x]+=1};C.forEach((w,y)=>{let b=l[w],x=y*tn;U.setUint16(x,Math.min(q-1,Math.round(b.x)),!0),U.setUint16(x+2,Math.min(q-1,Math.round(b.y)),!0),U.setUint16(x+4,Math.round(b.height*10),!0),U.setUint16(x+6,Math.round(b.crown*10),!0),z[x+8]=Math.floor(b.turn*256)&255,z[x+9]=Math.floor(b.shade*256)&255,z[x+10]=b.form,z[x+11]=b.rank,z[x+12]=Math.floor(b.seed*256)&255,z[x+13]=b.canopy,z[x+14]=B[w],E=Math.max(E,b.height);let T=K[Me[b.form]];$(T,y,b.rank),$(T.variants[B[w]],y,b.rank)});let N=new Uint8Array(A.length*tn),Y=new DataView(N.buffer);return A.forEach((w,y)=>{let b=y*tn;Y.setUint16(b,Math.min(q-1,Math.round(w.x)),!0),Y.setUint16(b+2,Math.min(q-1,Math.round(w.y)),!0),Y.setUint16(b+4,Math.round(w.height*10),!0),Y.setUint16(b+6,Math.round(Tr*10),!0),N[b+8]=Math.round(w.turn*256)&255,N[b+9]=Math.floor(w.shade*256)&255,N[b+12]=Math.floor(w.seed*256)&255,E=Math.max(E,w.height)}),{trees:z,forms:K,hedges:N,tallest:E,mapped:u,canopy:c}}function _r(e){let n={round:e.round??0,open:e.open??0,tall:e.tall??0};return n.round+n.open+n.tall>0?n:Sn}function sn(e,n){let t=0;for(let o of Me)t+=Math.max(0,e[o]??0);if(t<=0)return sn(Sn,n);let i=n*t;for(let o of Me){let r=Math.max(0,e[o]??0);if(i<r)return o;i-=r}return"round"}function xe(e,n){let t=typeof e=="number"?e:typeof e=="string"?Number.parseFloat(e):NaN;return Number.isFinite(t)&&t>0?Te(t,n):void 0}function Te(e,[n,t]){return Math.min(t,Math.max(n,e))}function _n([e,n],t){return e+(n-e)*t}function Sr(e,n,t){let i=2**e.z,o=(e.x+n)/i*360-180,r=Math.atan(Math.sinh(Math.PI*(1-2*(e.y+t)/i)))*180/Math.PI;return[o,r]}function Ie(e,n,t){let i=(Math.imul(Math.floor(e)|0,668265261)^Math.imul(Math.floor(n)|0,374761393)^Math.imul(t,2654435761))>>>0;return i=Math.imul(i^i>>>15,2246822507)>>>0,i=Math.imul(i^i>>>13,3266489909)>>>0,(i^i>>>16)>>>0}function ee(e,n){return Ie(e,n,20973)/4294967296}var Lr=[void 0,"Point","LineString","Polygon"];function ft(e,n={}){let t=n.layers?new Set(n.layers):void 0,i={},o=new Bn(e,0,e.length);for(;o.more();){let[r,s]=o.tag();if(r!==3){o.skip(s);continue}let a=o.message(),l=Br(a,t);l&&!(l.name in i)&&(i[l.name]=l.layer)}return i}function Br(e,n){let t,i=4096,o=[],r=[],s=[];for(;e.more();){let[a,l]=e.tag();if(a===1?t=e.string():a===2?s.push(e.message()):a===3?o.push(e.string()):a===4?r.push(Ur(e.message())):a===5?i=e.varint():e.skip(l),t!==void 0&&n&&!n.has(t))return}if(!(t===void 0||n&&!n.has(t)))return{name:t,layer:Object.freeze({extent:i,features:Object.freeze(s.flatMap(a=>{let l=Or(a,o,r);return l?[l]:[]}))})}}function Or(e,n,t){let i,o,r={},s=[];for(;e.more();){let[a,l]=e.tag();if(a===1)i=e.varint();else if(a===2){let u=e.packed();for(let c=0;c+1<u.length;c+=2){let f=n[u[c]],d=t[u[c+1]];f!==void 0&&d!==void 0&&(r[f]=d)}}else a===3?o=Lr[e.varint()]:a===4?s=e.packed():e.skip(l)}if(o)return Object.freeze({...i===void 0?{}:{id:i},type:o,properties:Object.freeze(r),geometry:Object.freeze(Cr(s,o))})}function Cr(e,n){let t=[],i,o=0,r=0,s=0;for(;s<e.length;){let a=e[s++],l=a&7,u=a>>>3;if(l===7){i&&i.length>=2&&i.push(i[0],i[1]);continue}if(l!==1&&l!==2)throw new Error(`Unknown geometry command ${l} in vector tile.`);if(s+u*2>e.length)throw new Error("Truncated vector tile geometry.");for(let c=0;c<u;c+=1){if(o+=Ln(e[s++]),r+=Ln(e[s++]),l===1&&(n!=="Point"||c===0)&&t.push(i=[]),!i)throw new Error("Vector tile geometry draws a line before moving to its start.");i.push(o,r)}}return t}var Ln=e=>e%2===1?-(e+1)/2:e/2;function Ur(e){let n="";for(;e.more();){let[t,i]=e.tag();t===1?n=e.string():t===2?n=e.float():t===3?n=e.double():t===4?n=e.varint(!0):t===5?n=e.varint():t===6?n=Ln(e.varint()):t===7?n=e.varint()!==0:e.skip(i)}return n}var Pr=new TextDecoder,Bn=class e{constructor(n,t,i){this.bytes=n;this.end=i;this.position=t,this.view=new DataView(n.buffer,n.byteOffset,n.byteLength)}bytes;end;position;view;more(){return this.position<this.end}tag(){let n=this.varint();return[Math.floor(n/8),n&7]}varint(n=!1){let t=0,i=0;for(let o=0;o<10;o+=1){if(this.position>=this.end)throw new Error("Truncated vector tile.");let r=this.bytes[this.position++];if(o<4?t|=(r&127)<<o*7:o===4?(t|=(r&15)<<28,i=(r&112)>>4):o<9?i|=(r&127)<<(o-5)*7+3:i|=(r&1)<<31,r<128)return n?i*4294967296+(t>>>0):(i>>>0)*4294967296+(t>>>0)}throw new Error("Invalid varint in vector tile.")}span(){let n=this.varint(),t=this.position;if(t+n>this.end)throw new Error("Truncated vector tile.");return this.position=t+n,[t,t+n]}message(){let[n,t]=this.span();return new e(this.bytes,n,t)}string(){let[n,t]=this.span();return Pr.decode(this.bytes.subarray(n,t))}packed(){let[n,t]=this.span(),i=new e(this.bytes,n,t),o=[];for(;i.more();)o.push(i.varint());return o}float(){if(this.position+4>this.end)throw new Error("Truncated vector tile.");let n=this.view.getFloat32(this.position,!0);return this.position+=4,n}double(){if(this.position+8>this.end)throw new Error("Truncated vector tile.");let n=this.view.getFloat64(this.position,!0);return this.position+=8,n}skip(n){if(n===0)this.varint();else if(n===1)this.position+=8;else if(n===2)this.span();else if(n===5)this.position+=4;else throw new Error(`Unsupported protocol buffer wire type ${n} in vector tile.`);if(this.position>this.end)throw new Error("Truncated vector tile.")}};function dt(e){return Object.values(e.layers).filter(n=>typeof n=="string")}function mt(e,n){if(e.kind==="buildings"){let r=n(e.layers.building);if(!r)return;let s=n(e.layers.places),a=Kn(r,{...e.options,...s?{places:s}:{}});return a&&et(a)}if(e.kind==="trees"){let r=n(e.layers.tree),s=n(e.layers.canopy),a=n(e.layers.hedge);if(!r&&!s&&!a)return;let l=ct({...r?{trees:r}:{},...s?{canopy:s}:{},...a?{hedges:a}:{}},e.options);return l.trees.length>0||l.hedges.length>0?l:void 0}let t=n(e.layers.streetFurniture),i=n(e.layers.transportation),o=n(e.layers.sidewalk);return it({...t?{streetFurniture:t}:{},...i?{transportation:i}:{},...o?{sidewalks:o}:{}},e.options)}function ht(e,n){if(!n)return[];if(e==="buildings")return nt(n);if(e==="trees"){let{trees:t,hedges:i}=n;return[t.buffer,i.buffer].filter((o,r,s)=>s.indexOf(o)===r)}return[n.lamps.buffer]}function pt(e=16){let n=new Map;return{read(t,i,o){let r=n.get(t);for(n.delete(t),r??={bytes:i,layers:new Map},n.set(t,r);n.size>e;)n.delete(n.keys().next().value);let s=o.filter(l=>!r.layers.has(l));if(s.length>0){let l=ft(r.bytes,{layers:s});for(let u of s)r.layers.set(u,l[u])}let a=r.layers;return l=>l===void 0?void 0:a.get(l)}}}var On=globalThis,zr=pt();On.onmessage=({data:{url:e,bytes:n,task:t}})=>{try{let i=mt(t,zr.read(e,n,dt(t)));On.postMessage({result:i},ht(t.kind,i))}catch(i){On.postMessage({error:String(i)})}};})();\n'], { type: "text/javascript" })
|
|
10073
10144
|
);
|
|
10074
10145
|
try {
|
|
10075
10146
|
return new Worker(url, { name: "tileflow-tiles" });
|
|
@@ -11558,7 +11629,8 @@ function createCameraTiles(options) {
|
|
|
11558
11629
|
const chosen = cameraTileRing(
|
|
11559
11630
|
{ ...centre, zoom: currentZoom, pitch: map.getPitch(), bearing: map.getBearing() },
|
|
11560
11631
|
zoom,
|
|
11561
|
-
options.maxTiles
|
|
11632
|
+
options.maxTiles,
|
|
11633
|
+
cameraViewport(map, zoom)
|
|
11562
11634
|
);
|
|
11563
11635
|
ring = chosen;
|
|
11564
11636
|
wanted = chosen.tiles.map(({ x: x3, y: y2 }) => `${x3}/${y2}`);
|
|
@@ -11570,7 +11642,7 @@ function createCameraTiles(options) {
|
|
|
11570
11642
|
return;
|
|
11571
11643
|
}
|
|
11572
11644
|
const now = performance.now();
|
|
11573
|
-
for (const { x: x3, y: y2
|
|
11645
|
+
for (const [priority, { x: x3, y: y2 }] of chosen.tiles.entries()) {
|
|
11574
11646
|
const key = `${x3}/${y2}`;
|
|
11575
11647
|
let entry = tiles.get(key);
|
|
11576
11648
|
if (!entry) {
|
|
@@ -11578,8 +11650,8 @@ function createCameraTiles(options) {
|
|
|
11578
11650
|
tiles.set(key, entry);
|
|
11579
11651
|
}
|
|
11580
11652
|
entry.used = now;
|
|
11581
|
-
entry.
|
|
11582
|
-
if ((!entry.value || entry.retryAt !== void 0) && !entry.loading && (entry.retryAt ?? 0) <= now)
|
|
11653
|
+
entry.priority = priority;
|
|
11654
|
+
if ((!entry.value && !entry.pending || entry.retryAt !== void 0) && !entry.loading && (entry.retryAt ?? 0) <= now)
|
|
11583
11655
|
load(source, key, entry, chosen.tileMetres);
|
|
11584
11656
|
}
|
|
11585
11657
|
evict();
|
|
@@ -11591,10 +11663,12 @@ function createCameraTiles(options) {
|
|
|
11591
11663
|
entry.retryAt = void 0;
|
|
11592
11664
|
source.read(
|
|
11593
11665
|
{ z: zoom, x: entry.x, y: entry.y },
|
|
11594
|
-
{ signal: controller.signal, priority: entry.
|
|
11666
|
+
{ signal: controller.signal, priority: entry.priority ?? 0 }
|
|
11595
11667
|
).then((tile) => {
|
|
11596
11668
|
if (disposed || tiles.get(key) !== entry || entry.loading !== controller) return;
|
|
11597
11669
|
if (!tile) {
|
|
11670
|
+
if (entry.pending && entry.pending !== options.empty) options.release(entry.pending);
|
|
11671
|
+
entry.pending = void 0;
|
|
11598
11672
|
if (entry.value && entry.value !== options.empty) options.release(entry.value);
|
|
11599
11673
|
entry.value = options.empty;
|
|
11600
11674
|
entry.loading = void 0;
|
|
@@ -11624,14 +11698,14 @@ function createCameraTiles(options) {
|
|
|
11624
11698
|
while (!disposed && queue.length && performance.now() - started < buildBudgetMs) {
|
|
11625
11699
|
let nearest = 0;
|
|
11626
11700
|
for (let at = 1; at < queue.length; at += 1)
|
|
11627
|
-
if ((queue[at].entry.
|
|
11701
|
+
if ((queue[at].entry.priority ?? 0) < (queue[nearest].entry.priority ?? 0))
|
|
11628
11702
|
nearest = at;
|
|
11629
11703
|
const { key, entry, controller, tile, metres: tileMetres } = queue.splice(nearest, 1)[0];
|
|
11630
11704
|
const current = () => !disposed && tiles.get(key) === entry && entry.loading === controller && !controller.signal.aborted;
|
|
11631
11705
|
if (!current()) continue;
|
|
11632
11706
|
let value;
|
|
11633
11707
|
try {
|
|
11634
|
-
value = await options.build(tile, tileMetres, controller.signal, entry.
|
|
11708
|
+
value = await options.build(tile, tileMetres, controller.signal, entry.priority ?? 0);
|
|
11635
11709
|
} catch {
|
|
11636
11710
|
if (current()) {
|
|
11637
11711
|
entry.loading = void 0;
|
|
@@ -11643,10 +11717,11 @@ function createCameraTiles(options) {
|
|
|
11643
11717
|
if (value !== options.empty) options.release(value);
|
|
11644
11718
|
continue;
|
|
11645
11719
|
}
|
|
11646
|
-
|
|
11647
|
-
|
|
11720
|
+
if (entry.pending && entry.pending !== options.empty && entry.pending !== value)
|
|
11721
|
+
options.release(entry.pending);
|
|
11722
|
+
entry.pending = value;
|
|
11648
11723
|
entry.loading = void 0;
|
|
11649
|
-
|
|
11724
|
+
commit(entry);
|
|
11650
11725
|
built = true;
|
|
11651
11726
|
}
|
|
11652
11727
|
if (built && !disposed) {
|
|
@@ -11663,12 +11738,24 @@ function createCameraTiles(options) {
|
|
|
11663
11738
|
void step();
|
|
11664
11739
|
});
|
|
11665
11740
|
}
|
|
11741
|
+
function commit(entry) {
|
|
11742
|
+
const value = entry.pending;
|
|
11743
|
+
if (value === void 0 || value !== options.empty && options.isReady && !options.isReady(value))
|
|
11744
|
+
return;
|
|
11745
|
+
const previous = entry.value;
|
|
11746
|
+
entry.value = value;
|
|
11747
|
+
entry.pending = void 0;
|
|
11748
|
+
if (previous && previous !== options.empty && previous !== value) options.release(previous);
|
|
11749
|
+
options.changed();
|
|
11750
|
+
map.triggerRepaint();
|
|
11751
|
+
}
|
|
11666
11752
|
function evict() {
|
|
11667
11753
|
const keep = new Set(wanted);
|
|
11668
11754
|
const spare = [...tiles.entries()].filter(([key]) => !keep.has(key)).sort((a, b2) => b2[1].used - a[1].used);
|
|
11669
11755
|
for (const [key, entry] of spare.slice(options.maxTiles)) {
|
|
11670
11756
|
entry.loading?.abort();
|
|
11671
11757
|
if (entry.value && entry.value !== options.empty) options.release(entry.value);
|
|
11758
|
+
if (entry.pending && entry.pending !== options.empty) options.release(entry.pending);
|
|
11672
11759
|
tiles.delete(key);
|
|
11673
11760
|
options.changed();
|
|
11674
11761
|
}
|
|
@@ -11688,17 +11775,26 @@ function createCameraTiles(options) {
|
|
|
11688
11775
|
map.on("sourcedata", onSource);
|
|
11689
11776
|
map.on("move", onMove);
|
|
11690
11777
|
map.on("moveend", onMoveEnd);
|
|
11778
|
+
map.on("resize", onMoveEnd);
|
|
11691
11779
|
return {
|
|
11692
11780
|
update,
|
|
11693
11781
|
ready() {
|
|
11694
11782
|
const list = [];
|
|
11695
11783
|
for (const key of wanted) {
|
|
11696
11784
|
const entry = tiles.get(key);
|
|
11785
|
+
if (entry) commit(entry);
|
|
11697
11786
|
if (entry?.value && entry.value !== options.empty)
|
|
11698
11787
|
list.push(entry);
|
|
11699
11788
|
}
|
|
11700
11789
|
return list;
|
|
11701
11790
|
},
|
|
11791
|
+
built() {
|
|
11792
|
+
return wanted.flatMap((key) => {
|
|
11793
|
+
const entry = tiles.get(key);
|
|
11794
|
+
const value = entry?.pending ?? entry?.value;
|
|
11795
|
+
return entry && value && value !== options.empty ? [{ ...entry, value }] : [];
|
|
11796
|
+
});
|
|
11797
|
+
},
|
|
11702
11798
|
coverage: () => covered,
|
|
11703
11799
|
ring: () => ring,
|
|
11704
11800
|
all: () => tiles.values(),
|
|
@@ -11720,6 +11816,8 @@ function createCameraTiles(options) {
|
|
|
11720
11816
|
for (const [key, entry] of tiles) {
|
|
11721
11817
|
if (!which(entry)) continue;
|
|
11722
11818
|
entry.loading?.abort();
|
|
11819
|
+
if (entry.pending && entry.pending !== options.empty) options.release(entry.pending);
|
|
11820
|
+
entry.pending = void 0;
|
|
11723
11821
|
entry.retryAt = void 0;
|
|
11724
11822
|
const latitude = Math.atan(Math.sinh(Math.PI * (1 - 2 * (entry.y + 0.5) / 2 ** zoom))) * 180 / Math.PI;
|
|
11725
11823
|
load(source, key, entry, earth * Math.cos(latitude * Math.PI / 180) / 2 ** zoom);
|
|
@@ -11732,7 +11830,11 @@ function createCameraTiles(options) {
|
|
|
11732
11830
|
map.off("sourcedata", onSource);
|
|
11733
11831
|
map.off("move", onMove);
|
|
11734
11832
|
map.off("moveend", onMoveEnd);
|
|
11735
|
-
|
|
11833
|
+
map.off("resize", onMoveEnd);
|
|
11834
|
+
for (const entry of tiles.values()) {
|
|
11835
|
+
entry.loading?.abort();
|
|
11836
|
+
if (entry.pending && entry.pending !== options.empty) options.release(entry.pending);
|
|
11837
|
+
}
|
|
11736
11838
|
tiles.clear();
|
|
11737
11839
|
queue.length = 0;
|
|
11738
11840
|
reader?.clear();
|
|
@@ -11796,33 +11898,110 @@ function cameraFrame(callback) {
|
|
|
11796
11898
|
if (typeof requestAnimationFrame === "function") requestAnimationFrame(callback);
|
|
11797
11899
|
else setTimeout(callback, 16);
|
|
11798
11900
|
}
|
|
11799
|
-
function cameraTileRing(camera, tileZoom, maxTiles) {
|
|
11901
|
+
function cameraTileRing(camera, tileZoom, maxTiles, viewport) {
|
|
11800
11902
|
const reach = Math.min(
|
|
11801
11903
|
5e3,
|
|
11802
11904
|
Math.max(800, 1600 * 2 ** (16 - camera.zoom) * (1 + camera.pitch / 60))
|
|
11803
11905
|
);
|
|
11804
11906
|
const bearing = camera.bearing * Math.PI / 180;
|
|
11907
|
+
const direction = [Math.sin(bearing), -Math.cos(bearing)];
|
|
11805
11908
|
const ahead = reach * 0.35 * Math.min(1, camera.pitch / 60);
|
|
11806
11909
|
const latitude = camera.lat + Math.cos(bearing) * ahead / 111320;
|
|
11807
11910
|
const longitude = camera.lng + Math.sin(bearing) * ahead / (111320 * Math.cos(camera.lat * Math.PI / 180));
|
|
11808
11911
|
const [cx, cy] = cameraTileAt(longitude, latitude, tileZoom);
|
|
11809
|
-
const
|
|
11912
|
+
const [ox, oy] = cameraTileAt(camera.lng, camera.lat, tileZoom);
|
|
11913
|
+
const tileMetres = earth * Math.cos(camera.lat * Math.PI / 180) / 2 ** tileZoom;
|
|
11914
|
+
const far = (reach + ahead) / tileMetres;
|
|
11915
|
+
const along = ([x3, y2]) => (x3 - ox) * direction[0] + (y2 - oy) * direction[1];
|
|
11916
|
+
const visible = viewport && clipGround(viewport, (point) => far - along(point));
|
|
11810
11917
|
const span = Math.ceil(reach / tileMetres);
|
|
11918
|
+
const left = Math.floor(Math.min(cx - span, ...visible?.map(([x3]) => x3) ?? []));
|
|
11919
|
+
const right = Math.floor(Math.max(cx + span, ...visible?.map(([x3]) => x3) ?? []));
|
|
11920
|
+
const top = Math.floor(Math.min(cy - span, ...visible?.map(([, y2]) => y2) ?? []));
|
|
11921
|
+
const bottom = Math.floor(Math.max(cy + span, ...visible?.map(([, y2]) => y2) ?? []));
|
|
11811
11922
|
const candidates = [];
|
|
11812
|
-
for (let
|
|
11813
|
-
for (let
|
|
11814
|
-
const
|
|
11815
|
-
|
|
11816
|
-
const
|
|
11817
|
-
|
|
11818
|
-
|
|
11819
|
-
|
|
11820
|
-
|
|
11923
|
+
for (let x3 = left; x3 <= right; x3++)
|
|
11924
|
+
for (let y2 = top; y2 <= bottom; y2++) {
|
|
11925
|
+
const distance = Math.hypot(Math.max(x3 - cx, 0, cx - x3 - 1), Math.max(y2 - cy, 0, cy - y2 - 1));
|
|
11926
|
+
let intersection = visible ?? [];
|
|
11927
|
+
for (const boundary of [
|
|
11928
|
+
([px]) => px - x3,
|
|
11929
|
+
([px]) => x3 + 1 - px,
|
|
11930
|
+
([, py]) => py - y2,
|
|
11931
|
+
([, py]) => y2 + 1 - py
|
|
11932
|
+
])
|
|
11933
|
+
intersection = clipGround(intersection, boundary);
|
|
11934
|
+
const near2 = Math.min(...intersection.map(along));
|
|
11935
|
+
if (near2 < Infinity || distance * tileMetres <= reach)
|
|
11936
|
+
candidates.push({ x: x3, y: y2, distance, near: near2 });
|
|
11937
|
+
}
|
|
11938
|
+
candidates.sort((a, b2) => a.near - b2.near || a.distance - b2.distance);
|
|
11939
|
+
const tiles = candidates.slice(0, maxTiles).map(({ x: x3, y: y2, distance }) => ({ x: x3, y: y2, distance }));
|
|
11940
|
+
const omitted = candidates.slice(tiles.length);
|
|
11941
|
+
const radius = omitted.reduce(
|
|
11942
|
+
(radius2, tile) => Math.min(radius2, tile.distance),
|
|
11943
|
+
reach / tileMetres
|
|
11944
|
+
);
|
|
11945
|
+
const end = Math.min(far, ...omitted.map((tile) => tile.near));
|
|
11946
|
+
const near = visible?.length ? Math.min(...visible.map(along)) : end;
|
|
11947
|
+
return {
|
|
11948
|
+
tiles,
|
|
11949
|
+
centre: [cx, cy],
|
|
11950
|
+
radius,
|
|
11951
|
+
tileMetres,
|
|
11952
|
+
...visible?.length ? {
|
|
11953
|
+
fade: {
|
|
11954
|
+
origin: [ox, oy],
|
|
11955
|
+
start: end - Math.max(0.25, (end - near) * 0.2),
|
|
11956
|
+
end
|
|
11957
|
+
}
|
|
11958
|
+
} : {}
|
|
11959
|
+
};
|
|
11960
|
+
}
|
|
11961
|
+
function cameraViewport(map, zoom) {
|
|
11962
|
+
const canvas = map.getCanvas?.();
|
|
11963
|
+
const width = canvas?.clientWidth ?? 0;
|
|
11964
|
+
const height = canvas?.clientHeight ?? 0;
|
|
11965
|
+
if (!map.unproject || width <= 0 || height <= 0) return void 0;
|
|
11966
|
+
const origin = cameraTileAt(map.getCenter().lng, map.getCenter().lat, zoom)[0];
|
|
11967
|
+
const world = 2 ** zoom;
|
|
11968
|
+
const pointAt = (x3, y2) => {
|
|
11969
|
+
const location = map.unproject([x3, y2]);
|
|
11970
|
+
const [tx, ty] = cameraTileAt(location.lng, location.lat, zoom);
|
|
11971
|
+
return [tx + Math.round((origin - tx) / world) * world, ty];
|
|
11972
|
+
};
|
|
11973
|
+
const bearing = map.getBearing() * Math.PI / 180;
|
|
11974
|
+
const points = [];
|
|
11975
|
+
for (const x3 of [0, width]) {
|
|
11976
|
+
const bottom = pointAt(x3, height);
|
|
11977
|
+
const middle = pointAt(x3, height / 2);
|
|
11978
|
+
let top = pointAt(x3, 0);
|
|
11979
|
+
if ((top[0] - middle[0]) * Math.sin(bearing) - (top[1] - middle[1]) * Math.cos(bearing) <= 0) {
|
|
11980
|
+
const stretch = world / Math.hypot(middle[0] - bottom[0], middle[1] - bottom[1]);
|
|
11981
|
+
top = [
|
|
11982
|
+
middle[0] + (middle[0] - bottom[0]) * stretch,
|
|
11983
|
+
middle[1] + (middle[1] - bottom[1]) * stretch
|
|
11984
|
+
];
|
|
11821
11985
|
}
|
|
11822
|
-
|
|
11823
|
-
|
|
11824
|
-
|
|
11825
|
-
return
|
|
11986
|
+
points.push(bottom, top);
|
|
11987
|
+
}
|
|
11988
|
+
if (points.some((point) => point.some((value) => !Number.isFinite(value)))) return void 0;
|
|
11989
|
+
return [points[0], points[1], points[3], points[2]];
|
|
11990
|
+
}
|
|
11991
|
+
function clipGround(points, distance) {
|
|
11992
|
+
const result = [];
|
|
11993
|
+
for (let i2 = 0; i2 < points.length; i2++) {
|
|
11994
|
+
const a = points[i2];
|
|
11995
|
+
const b2 = points[(i2 + 1) % points.length];
|
|
11996
|
+
const da = distance(a);
|
|
11997
|
+
const db = distance(b2);
|
|
11998
|
+
if (da >= 0) result.push([a[0], a[1]]);
|
|
11999
|
+
if (da < 0 !== db < 0) {
|
|
12000
|
+
const t = da / (da - db);
|
|
12001
|
+
result.push([a[0] + (b2[0] - a[0]) * t, a[1] + (b2[1] - a[1]) * t]);
|
|
12002
|
+
}
|
|
12003
|
+
}
|
|
12004
|
+
return result;
|
|
11826
12005
|
}
|
|
11827
12006
|
function cameraTileAt(longitude, latitude, zoom) {
|
|
11828
12007
|
const phi = Math.min(85.05, Math.max(-85.05, latitude)) * Math.PI / 180;
|
|
@@ -12459,7 +12638,9 @@ function tileflowModelCameraDistance(model, view) {
|
|
|
12459
12638
|
function tileflowModelLevel(model, view, previous) {
|
|
12460
12639
|
const thresholds = tileflowModelLevelDistancesOf(model.bounds);
|
|
12461
12640
|
const last = Math.max(0, Math.min(model.levels, thresholds.length + 1) - 1);
|
|
12462
|
-
const
|
|
12641
|
+
const fov = view.verticalFieldOfView;
|
|
12642
|
+
const lens = fov !== void 0 && fov > 0 && fov < 180 ? Math.tan(fov * Math.PI / 360) * 3 : 1;
|
|
12643
|
+
const distance = tileflowModelCameraDistance(model, view) * lens;
|
|
12463
12644
|
if (!Number.isFinite(distance)) return 0;
|
|
12464
12645
|
const margin = previous === void 0 ? 1 : tileflowModelLevelHysteresis;
|
|
12465
12646
|
let level = Math.max(0, Math.min(last, previous ?? 0));
|
|
@@ -12912,6 +13093,7 @@ out vec3 v_shadow;
|
|
|
12912
13093
|
out float v_light;
|
|
12913
13094
|
flat out int v_lighting_role;
|
|
12914
13095
|
out float v_height;
|
|
13096
|
+
out float v_ground_height;
|
|
12915
13097
|
out vec4 v_uv;
|
|
12916
13098
|
out vec4 v_rgba;
|
|
12917
13099
|
out vec3 v_position;
|
|
@@ -12940,6 +13122,7 @@ void main() {
|
|
|
12940
13122
|
v_light = a_paint.z / 255.0;
|
|
12941
13123
|
v_lighting_role = clamp(int(a_lighting_role + 0.5), 0, 6);
|
|
12942
13124
|
v_height = (m.z - u_model_height.x) / max(u_model_height.y, 0.001);
|
|
13125
|
+
v_ground_height = m.z;
|
|
12943
13126
|
}`;
|
|
12944
13127
|
var tileflowModelFragment = `#version 300 es
|
|
12945
13128
|
precision highp float;
|
|
@@ -12949,6 +13132,9 @@ in vec3 v_shadow;
|
|
|
12949
13132
|
in float v_light;
|
|
12950
13133
|
flat in int v_lighting_role;
|
|
12951
13134
|
in float v_height;
|
|
13135
|
+
in float v_ground_height;
|
|
13136
|
+
uniform vec3 u_facade_shading; // vertical gradient, ground-contact strength and radius in metres
|
|
13137
|
+
uniform float u_role_color_scale[7];
|
|
12952
13138
|
uniform vec3 u_sun_dir;
|
|
12953
13139
|
uniform vec3 u_sun_light;
|
|
12954
13140
|
uniform vec3 u_sky_light;
|
|
@@ -12976,6 +13162,16 @@ vec3 shade(vec3 normal, float lit, float occlusion) {
|
|
|
12976
13162
|
return min(pow(light / max(roof, vec3(1e-4)), vec3(1.0 / 2.2)), vec3(1.7));
|
|
12977
13163
|
}
|
|
12978
13164
|
|
|
13165
|
+
// Same quiet ground-to-facade transition as ordinary tile buildings, evaluated in metres.
|
|
13166
|
+
// Only map-shaded roles opt in; roofs and physical materials keep their own response.
|
|
13167
|
+
float facadeShade(vec3 normal, int role) {
|
|
13168
|
+
float wall = 1.0 - abs(normal.z);
|
|
13169
|
+
float up = max(v_ground_height, 0.0);
|
|
13170
|
+
float gradient = 0.1 * u_facade_shading.x * (1.0 - smoothstep(0.0, 3.0, up));
|
|
13171
|
+
float contact = u_facade_shading.y * exp(-up / max(u_facade_shading.z, 0.001));
|
|
13172
|
+
return 1.0 - max(gradient, contact) * wall * u_role_appearance[role].x;
|
|
13173
|
+
}
|
|
13174
|
+
|
|
12979
13175
|
void main() {
|
|
12980
13176
|
vec3 normal = normalize(gl_FrontFacing ? v_normal : -v_normal);
|
|
12981
13177
|
if (u_physical) normal = materialNormal(normal);
|
|
@@ -12990,7 +13186,7 @@ void main() {
|
|
|
12990
13186
|
float emission = clamp(u_role_emission[role] * multiplier, 0.0, 1.0);
|
|
12991
13187
|
if (u_physical) {
|
|
12992
13188
|
float alpha = materialAlpha();
|
|
12993
|
-
vec3 base = materialBase(role);
|
|
13189
|
+
vec3 base = materialBase(role) * fromSRGB(vec3(u_role_color_scale[role]));
|
|
12994
13190
|
float mapShare = u_role_appearance[role].x;
|
|
12995
13191
|
vec3 radiance;
|
|
12996
13192
|
if (mapShare >= 1.0) {
|
|
@@ -13000,13 +13196,14 @@ void main() {
|
|
|
13000
13196
|
if (mapShare > 0.0)
|
|
13001
13197
|
radiance = mix(radiance, base * fromSRGB(shade(normal, lit, u_role_appearance[role].y)), mapShare);
|
|
13002
13198
|
}
|
|
13199
|
+
radiance *= fromSRGB(vec3(facadeShade(normal, role)));
|
|
13003
13200
|
radiance += u_emissive * fromSRGB(materialTexture(4).rgb);
|
|
13004
13201
|
vec4 own = u_role_emission_colour[role];
|
|
13005
13202
|
radiance = mix(radiance, mix(base, fromSRGB(own.rgb), own.a), emission);
|
|
13006
13203
|
fragColor = vec4(hazed(toSRGB(radiance)), alpha * u_opacity);
|
|
13007
13204
|
return;
|
|
13008
13205
|
}
|
|
13009
|
-
vec3 colour = v_colour * shade(normal, lit, u_role_appearance[role].y);
|
|
13206
|
+
vec3 colour = v_colour * u_role_color_scale[role] * shade(normal, lit, u_role_appearance[role].y) * facadeShade(normal, role);
|
|
13010
13207
|
if (emission > 0.0) {
|
|
13011
13208
|
vec4 own = u_role_emission_colour[role];
|
|
13012
13209
|
vec3 target = mix(v_colour, own.rgb, own.a);
|
|
@@ -13864,7 +14061,7 @@ function createTileflowBuildings3D(options) {
|
|
|
13864
14061
|
let ahead = [0, -1];
|
|
13865
14062
|
const scene = tileflowScene3D(map);
|
|
13866
14063
|
let generation = 0;
|
|
13867
|
-
let
|
|
14064
|
+
let registered2 = false;
|
|
13868
14065
|
let unregister = () => {
|
|
13869
14066
|
};
|
|
13870
14067
|
const models = createTileflowPlacedModels({
|
|
@@ -13913,7 +14110,7 @@ function createTileflowBuildings3D(options) {
|
|
|
13913
14110
|
if (program) context.deleteProgram(program.program);
|
|
13914
14111
|
for (const entry of linking ?? []) context.deleteProgram(entry.program);
|
|
13915
14112
|
unregister();
|
|
13916
|
-
|
|
14113
|
+
registered2 = false;
|
|
13917
14114
|
scene.setReach(void 0);
|
|
13918
14115
|
scene.release(context);
|
|
13919
14116
|
if (ground) {
|
|
@@ -13944,12 +14141,12 @@ function createTileflowBuildings3D(options) {
|
|
|
13944
14141
|
drawMasks(context, args);
|
|
13945
14142
|
if (!programs.depth) return;
|
|
13946
14143
|
if (!design().shadows || visibleScale() <= 0 && modelScale() <= 0) {
|
|
13947
|
-
if (
|
|
13948
|
-
|
|
14144
|
+
if (registered2) unregister();
|
|
14145
|
+
registered2 = false;
|
|
13949
14146
|
return;
|
|
13950
14147
|
}
|
|
13951
|
-
if (!
|
|
13952
|
-
|
|
14148
|
+
if (!registered2) unregister = scene.register(caster);
|
|
14149
|
+
registered2 = true;
|
|
13953
14150
|
scene.prepare(context, lighting(), camera.metres);
|
|
13954
14151
|
},
|
|
13955
14152
|
render(context, args) {
|
|
@@ -14006,6 +14203,7 @@ function createTileflowBuildings3D(options) {
|
|
|
14006
14203
|
return prepared ? { mesh: prepared.mesh, data: prepared.data } : emptyTile;
|
|
14007
14204
|
},
|
|
14008
14205
|
empty: emptyTile,
|
|
14206
|
+
isReady: (value) => value === emptyTile || value.gl !== void 0,
|
|
14009
14207
|
release(value) {
|
|
14010
14208
|
if (gl) release(gl, value);
|
|
14011
14209
|
},
|
|
@@ -14066,7 +14264,7 @@ function createTileflowBuildings3D(options) {
|
|
|
14066
14264
|
models.upload(context);
|
|
14067
14265
|
if (modelKey !== models.key()) map.triggerRepaint();
|
|
14068
14266
|
let budget = 2;
|
|
14069
|
-
for (const { value: entry } of camera.
|
|
14267
|
+
for (const { value: entry } of camera.built()) {
|
|
14070
14268
|
if (entry.gl || !entry.data) continue;
|
|
14071
14269
|
if (budget-- <= 0) {
|
|
14072
14270
|
map.triggerRepaint();
|
|
@@ -14309,7 +14507,7 @@ function createTileflowBuildings3D(options) {
|
|
|
14309
14507
|
for (const { x: x3, y: y2, value } of shown > 0 ? drawn() : []) {
|
|
14310
14508
|
const offset = frame.offsetOf({ x: x3, y: y2 }, camera.zoom);
|
|
14311
14509
|
const ring = ringIn(x3, y2);
|
|
14312
|
-
if (!
|
|
14510
|
+
if (!insideRing2(ring, 0, 0, tileflowBuildingExtent, tileflowBuildingExtent)) continue;
|
|
14313
14511
|
if (!buildingBoxVisible(frame.light.matrix, [
|
|
14314
14512
|
(offset[0] - 1) * frame.metres,
|
|
14315
14513
|
-(offset[1] + tileflowBuildingExtent + 1) * frame.metres,
|
|
@@ -14321,7 +14519,7 @@ function createTileflowBuildings3D(options) {
|
|
|
14321
14519
|
continue;
|
|
14322
14520
|
const ranges = buildingDrawRanges(
|
|
14323
14521
|
value.mesh,
|
|
14324
|
-
({ bounds: [left, top, right, bottom, height] }) =>
|
|
14522
|
+
({ bounds: [left, top, right, bottom, height] }) => insideRing2(ring, left, top, right, bottom) && buildingBoxVisible(frame.light.matrix, [
|
|
14325
14523
|
(left + offset[0]) * frame.metres,
|
|
14326
14524
|
-(bottom + offset[1]) * frame.metres,
|
|
14327
14525
|
0,
|
|
@@ -14334,6 +14532,7 @@ function createTileflowBuildings3D(options) {
|
|
|
14334
14532
|
context.uniform2f(program.uniforms.u_offset, ...offset);
|
|
14335
14533
|
context.uniform4f(program.uniforms.u_ring ?? null, ...ring);
|
|
14336
14534
|
context.uniform2f(program.uniforms.u_ring_ahead ?? null, ...ahead);
|
|
14535
|
+
context.uniform1i(program.uniforms.u_ring_directional ?? null, camera.ring()?.fade ? 1 : 0);
|
|
14337
14536
|
const buffers = value.gl;
|
|
14338
14537
|
context.bindVertexArray(buffers.vao);
|
|
14339
14538
|
for (const range of ranges)
|
|
@@ -14402,7 +14601,10 @@ function createTileflowBuildings3D(options) {
|
|
|
14402
14601
|
return [ax - reach, ay - reach, Math.min(0, low), ax + reach, ay + reach, high + 0.1];
|
|
14403
14602
|
}
|
|
14404
14603
|
function modelView(model) {
|
|
14405
|
-
return {
|
|
14604
|
+
return {
|
|
14605
|
+
camera: modelCamera(model),
|
|
14606
|
+
verticalFieldOfView: map.getVerticalFieldOfView?.()
|
|
14607
|
+
};
|
|
14406
14608
|
}
|
|
14407
14609
|
function levelOf(model) {
|
|
14408
14610
|
return models.levelOf(model, modelView(model));
|
|
@@ -14524,12 +14726,14 @@ function createTileflowBuildings3D(options) {
|
|
|
14524
14726
|
const gradients = new Float32Array(28);
|
|
14525
14727
|
const powers = new Float32Array(7);
|
|
14526
14728
|
const materialColours = new Float32Array(28);
|
|
14729
|
+
const colorScales = new Float32Array(7);
|
|
14527
14730
|
const materials = new Float32Array(28);
|
|
14528
14731
|
const appearance = new Float32Array(21);
|
|
14529
14732
|
for (const [role, id] of Object.entries(tileflowModelLightingRoles)) {
|
|
14530
14733
|
const from = themes[lower].modelLighting?.[role], to = themes[upper].modelLighting?.[role];
|
|
14531
14734
|
const sampledFrom = sampleModelRole(from, `${identity}:${role}`);
|
|
14532
14735
|
const sampledTo = sampleModelRole(to, `${identity}:${role}`);
|
|
14736
|
+
colorScales[id] = (from?.colorScale ?? 1) * (1 - mix2) + (to?.colorScale ?? 1) * mix2;
|
|
14533
14737
|
appearance[id * 3] = (from?.shading === "map" ? 1 - mix2 : 0) + (to?.shading === "map" ? mix2 : 0);
|
|
14534
14738
|
appearance[id * 3 + 1] = (from?.ambientOcclusion ?? 1) * (1 - mix2) + (to?.ambientOcclusion ?? 1) * mix2;
|
|
14535
14739
|
appearance[id * 3 + 2] = (from?.partColorMix ?? 1) * (1 - mix2) + (to?.partColorMix ?? 1) * mix2;
|
|
@@ -14552,7 +14756,16 @@ function createTileflowBuildings3D(options) {
|
|
|
14552
14756
|
gradients[id * 4 + component] = first[component] * (1 - mix2) + second[component] * mix2;
|
|
14553
14757
|
powers[id] = first[4] * (1 - mix2) + second[4] * mix2;
|
|
14554
14758
|
}
|
|
14555
|
-
const result = {
|
|
14759
|
+
const result = {
|
|
14760
|
+
strengths,
|
|
14761
|
+
colours,
|
|
14762
|
+
gradients,
|
|
14763
|
+
powers,
|
|
14764
|
+
materialColours,
|
|
14765
|
+
colorScales,
|
|
14766
|
+
materials,
|
|
14767
|
+
appearance
|
|
14768
|
+
};
|
|
14556
14769
|
if (modelLightingCache.size >= 1024)
|
|
14557
14770
|
modelLightingCache.delete(modelLightingCache.keys().next().value);
|
|
14558
14771
|
modelLightingCache.set(identity, result);
|
|
@@ -14602,13 +14815,21 @@ function createTileflowBuildings3D(options) {
|
|
|
14602
14815
|
return {
|
|
14603
14816
|
lng: ring.centre[0] / n * 360 - 180,
|
|
14604
14817
|
lat: Math.atan(Math.sinh(Math.PI * (1 - 2 * ring.centre[1] / n))) * 180 / Math.PI,
|
|
14605
|
-
radius: ring.radius * ring.tileMetres
|
|
14818
|
+
radius: ring.radius * ring.tileMetres,
|
|
14819
|
+
...ring.fade ? { forward: ring.fade.end * ring.tileMetres } : {}
|
|
14606
14820
|
};
|
|
14607
14821
|
}
|
|
14608
14822
|
function ringIn(x3, y2) {
|
|
14609
14823
|
const ring = camera.ring();
|
|
14610
14824
|
if (!ring) return [0, 0, 0, 0];
|
|
14611
14825
|
const extent5 = tileflowBuildingExtent;
|
|
14826
|
+
if (ring.fade)
|
|
14827
|
+
return [
|
|
14828
|
+
(ring.fade.origin[0] - x3) * extent5,
|
|
14829
|
+
(ring.fade.origin[1] - y2) * extent5,
|
|
14830
|
+
ring.fade.start * extent5,
|
|
14831
|
+
ring.fade.end * extent5
|
|
14832
|
+
];
|
|
14612
14833
|
const cx = (ring.centre[0] - x3) * extent5;
|
|
14613
14834
|
const cy = (ring.centre[1] - y2) * extent5;
|
|
14614
14835
|
const inner = ring.radius * extent5 * 0.8;
|
|
@@ -14621,7 +14842,9 @@ function createTileflowBuildings3D(options) {
|
|
|
14621
14842
|
const bearing = map.getBearing() * Math.PI / 180;
|
|
14622
14843
|
return [Math.sin(bearing), -Math.cos(bearing)];
|
|
14623
14844
|
}
|
|
14624
|
-
function
|
|
14845
|
+
function insideRing2(ring, left, top, right, bottom) {
|
|
14846
|
+
if (camera.ring()?.fade)
|
|
14847
|
+
return Math.min(ahead[0] * (left - ring[0]), ahead[0] * (right - ring[0])) + Math.min(ahead[1] * (top - ring[1]), ahead[1] * (bottom - ring[1])) < ring[3];
|
|
14625
14848
|
const radius = ring[3];
|
|
14626
14849
|
if (!(radius > 0)) return true;
|
|
14627
14850
|
const cx = ring[0];
|
|
@@ -14640,7 +14863,7 @@ function createTileflowBuildings3D(options) {
|
|
|
14640
14863
|
const reach = margin / camera.metres + 1;
|
|
14641
14864
|
const ring = ringIn(tile.x, tile.y);
|
|
14642
14865
|
const hazed = mercator && hazeDepth < Infinity;
|
|
14643
|
-
const shows = (box) => (!mercator || buildingBoxVisible(data.mainMatrix, box)) &&
|
|
14866
|
+
const shows = (box) => (!mercator || buildingBoxVisible(data.mainMatrix, box)) && insideRing2(ring, box[0], box[1], box[3], box[4]) && (!hazed || buildingBoxDepth(data.mainMatrix, box) < hazeDepth);
|
|
14644
14867
|
const extent5 = tileflowBuildingExtent + reach;
|
|
14645
14868
|
if (!shows([-reach, -reach, 0, extent5, extent5, tile.value.mesh.top + 0.1])) return [];
|
|
14646
14869
|
return buildingDrawRanges(
|
|
@@ -14687,20 +14910,21 @@ function createTileflowBuildings3D(options) {
|
|
|
14687
14910
|
masks = {};
|
|
14688
14911
|
const shown = visibleScale();
|
|
14689
14912
|
const entries = variant === args.shaderData.variantName && shown > 0 && ground ? drawn() : [];
|
|
14690
|
-
|
|
14913
|
+
const contactRadius = mixed2((entry) => entry.groundOcclusionRadius ?? tileflowBuildingOcclusion.ground);
|
|
14914
|
+
if (design().occlusion && contactRadius > 0 && entries.length > 0) {
|
|
14691
14915
|
const program = programs.contact;
|
|
14692
14916
|
masks.contact = contactMask.render(context, () => {
|
|
14693
14917
|
context.useProgram(program.program);
|
|
14694
14918
|
context.uniform1f(program.uniforms.u_scale, shown);
|
|
14695
14919
|
context.uniform1f(program.uniforms.u_metres, camera.metres);
|
|
14696
|
-
context.uniform1f(program.uniforms.u_band,
|
|
14920
|
+
context.uniform1f(program.uniforms.u_band, contactRadius);
|
|
14697
14921
|
context.uniform1f(
|
|
14698
14922
|
program.uniforms.u_band_strength,
|
|
14699
14923
|
mixed2((entry) => entry.groundOcclusion ?? tileflowBuildingOcclusion.groundStrength) * visibleOpacity()
|
|
14700
14924
|
);
|
|
14701
14925
|
for (const tile of entries) {
|
|
14702
14926
|
const { x: x3, y: y2, value } = tile;
|
|
14703
|
-
const ranges = viewRanges(args, tile,
|
|
14927
|
+
const ranges = viewRanges(args, tile, contactRadius, true);
|
|
14704
14928
|
if (!ranges.length) continue;
|
|
14705
14929
|
const { contact } = value.gl;
|
|
14706
14930
|
project(context, program, args, x3, y2);
|
|
@@ -14838,6 +15062,7 @@ function createTileflowBuildings3D(options) {
|
|
|
14838
15062
|
);
|
|
14839
15063
|
context.uniform4f(u.u_ring ?? null, ...ringIn(x3, y2));
|
|
14840
15064
|
context.uniform2f(u.u_ring_ahead ?? null, ...ahead);
|
|
15065
|
+
context.uniform1i(u.u_ring_directional ?? null, camera.ring()?.fade ? 1 : 0);
|
|
14841
15066
|
const palette = themes ? paletteOf(context, entry, themes.themes) : void 0;
|
|
14842
15067
|
context.uniform1f(u.u_palette_on, palette ? 1 : 0);
|
|
14843
15068
|
context.activeTexture(context.TEXTURE1);
|
|
@@ -14908,6 +15133,12 @@ function createTileflowBuildings3D(options) {
|
|
|
14908
15133
|
context.uniform3fv(m.u_sun_light, light.sunLight);
|
|
14909
15134
|
context.uniform3fv(m.u_sky_light, light.skyLight);
|
|
14910
15135
|
context.uniform1f(m.u_night, light.night);
|
|
15136
|
+
context.uniform3f(
|
|
15137
|
+
m.u_facade_shading,
|
|
15138
|
+
mixed2((entry) => entry.verticalGradient ? 1 : 0),
|
|
15139
|
+
occlusionOn ? mixed2((entry) => entry.groundOcclusion ?? 0.16) : 0,
|
|
15140
|
+
mixed2((entry) => entry.groundOcclusionRadius ?? 3)
|
|
15141
|
+
);
|
|
14911
15142
|
context.uniform1f(
|
|
14912
15143
|
m.u_ambient_occlusion,
|
|
14913
15144
|
occlusionOn ? mixed2((entry) => entry.modelOcclusion ?? 0.75) : 0
|
|
@@ -14924,6 +15155,7 @@ function createTileflowBuildings3D(options) {
|
|
|
14924
15155
|
context.uniform4fv(m.u_role_emission_gradient, emission.gradients);
|
|
14925
15156
|
context.uniform1fv(m.u_role_emission_power, emission.powers);
|
|
14926
15157
|
context.uniform4fv(m.u_role_colour, emission.materialColours);
|
|
15158
|
+
context.uniform1fv(m.u_role_color_scale, emission.colorScales);
|
|
14927
15159
|
context.uniform4fv(m.u_role_material, emission.materials);
|
|
14928
15160
|
context.uniform3fv(m.u_role_appearance, emission.appearance);
|
|
14929
15161
|
const at = placed2(stand.tileX, stand.tileY);
|
|
@@ -16476,6 +16708,7 @@ uniform float u_metres; // metres per tile unit
|
|
|
16476
16708
|
uniform vec2 u_offset; // this tile's corner from the scene's origin, in tile units
|
|
16477
16709
|
uniform float u_minimum_height; // optional visual height floor, in metres
|
|
16478
16710
|
uniform vec2 u_size_scale; // the map's height and crown scales, for this form
|
|
16711
|
+
uniform vec3 u_size_compression; // reference height, reference crown, strength
|
|
16479
16712
|
uniform float u_round; // how far normals turn from the facets to the round shape, by finish
|
|
16480
16713
|
|
|
16481
16714
|
float growthOf() {
|
|
@@ -16492,7 +16725,14 @@ vec2 turned(vec2 v) {
|
|
|
16492
16725
|
|
|
16493
16726
|
vec2 displaySize() {
|
|
16494
16727
|
vec2 size = a_tree_size * 0.1 * u_size_scale;
|
|
16495
|
-
|
|
16728
|
+
size *= max(1.0, u_minimum_height / max(size.x, 0.001));
|
|
16729
|
+
// Scale the complete tree together to preserve crown, trunk and branch proportions.
|
|
16730
|
+
if (u_size_compression.z > 0.0) {
|
|
16731
|
+
vec2 relative = max(u_size_compression.xy, vec2(0.001)) / max(size, vec2(0.001));
|
|
16732
|
+
// Balance height and footprint, so a short but broad crown is not enlarged.
|
|
16733
|
+
size *= min(1.35, pow(relative.x * relative.y, u_size_compression.z * 0.5));
|
|
16734
|
+
}
|
|
16735
|
+
return size;
|
|
16496
16736
|
}
|
|
16497
16737
|
|
|
16498
16738
|
vec3 standing(float growth) {
|
|
@@ -16773,7 +17013,7 @@ function createTileflowTrees3D(options) {
|
|
|
16773
17013
|
let disposed = false;
|
|
16774
17014
|
let drawnLast = 0;
|
|
16775
17015
|
let generation = 0;
|
|
16776
|
-
let
|
|
17016
|
+
let registered2 = false;
|
|
16777
17017
|
let unregister = () => {
|
|
16778
17018
|
};
|
|
16779
17019
|
const scene = tileflowScene3D(map);
|
|
@@ -17038,7 +17278,9 @@ function createTileflowTrees3D(options) {
|
|
|
17038
17278
|
forms: tileflowTreeForms.map((form) => [
|
|
17039
17279
|
theme?.forms[form]?.heightScale ?? 1,
|
|
17040
17280
|
theme?.forms[form]?.crownScale ?? 1,
|
|
17041
|
-
|
|
17281
|
+
theme?.forms[form]?.sizeAnchor ?? 8.5,
|
|
17282
|
+
theme?.forms[form]?.crownAnchor ?? 5,
|
|
17283
|
+
theme?.forms[form]?.sizeCompression ?? 0
|
|
17042
17284
|
]),
|
|
17043
17285
|
edges: [[theme?.edges ?? 0, 0, 0]],
|
|
17044
17286
|
edgeColor: [[...rgb(theme?.edgeColor ?? "#000000") ?? [0, 0, 0]]],
|
|
@@ -17063,6 +17305,12 @@ function createTileflowTrees3D(options) {
|
|
|
17063
17305
|
[size[0] * forms[index][0], size[1] * forms[index][1]]
|
|
17064
17306
|
])
|
|
17065
17307
|
),
|
|
17308
|
+
compressions: Object.fromEntries(
|
|
17309
|
+
tileflowTreeForms.map((form, index) => [
|
|
17310
|
+
form,
|
|
17311
|
+
[forms[index][2], forms[index][3], forms[index][4]]
|
|
17312
|
+
])
|
|
17313
|
+
),
|
|
17066
17314
|
finish: (t < 0.5 ? a : b2)?.finish ?? "faceted",
|
|
17067
17315
|
edges: mixList(x3.edges, y2.edges)[0][0],
|
|
17068
17316
|
edgeColor: mixList(x3.edgeColor, y2.edgeColor)[0],
|
|
@@ -17099,17 +17347,21 @@ function createTileflowTrees3D(options) {
|
|
|
17099
17347
|
tallest = Math.max(tallest, value.placement.tallest);
|
|
17100
17348
|
}
|
|
17101
17349
|
if (!Number.isFinite(left)) return void 0;
|
|
17102
|
-
const
|
|
17350
|
+
const palette2 = colours();
|
|
17351
|
+
const maximumGrowth = Object.values(palette2.compressions).some(
|
|
17352
|
+
([, , strength]) => strength > 0
|
|
17353
|
+
) ? 1.35 : 1;
|
|
17354
|
+
const maximumScale = maximumGrowth > 1 ? Math.max(...Object.values(palette2.sizes).map((size) => size[0])) : palette2.size[0];
|
|
17103
17355
|
return {
|
|
17104
17356
|
zoom: preferredZoom3,
|
|
17105
17357
|
tiles: [left, top, right, bottom],
|
|
17106
|
-
tallest: Math.max(tallest *
|
|
17358
|
+
tallest: Math.max(tallest * maximumScale, palette2.minimumHeight) * maximumGrowth * shown
|
|
17107
17359
|
};
|
|
17108
17360
|
},
|
|
17109
17361
|
// Camera-dependent density, detail and fading also change the trees casting shadows.
|
|
17110
17362
|
key: () => `trees:${colours().minimumHeight.toFixed(3)}:${map.isMoving?.() ? view().movingKey : view().key}:${fadeIn().toFixed(4)}:${visibleScale().toFixed(4)}:${generation}:${programs.depth ? 1 : 0}:${Object.values(
|
|
17111
17363
|
colours().sizes
|
|
17112
|
-
).flat().map((value) => value.toFixed(3)).join()}:${drawn().map(({ x: x3, y: y2 }) => `${x3}/${y2}`).join(";")}`,
|
|
17364
|
+
).flat().map((value) => value.toFixed(3)).join()}:${Object.values(colours().compressions).flat().join()}:${drawn().map(({ x: x3, y: y2 }) => `${x3}/${y2}`).join(";")}`,
|
|
17113
17365
|
drawDepth(context, frame) {
|
|
17114
17366
|
const program = programs.depth;
|
|
17115
17367
|
if (!program || !meshes) return;
|
|
@@ -17119,6 +17371,7 @@ function createTileflowTrees3D(options) {
|
|
|
17119
17371
|
context.uniform1f(u.u_metres, frame.metres);
|
|
17120
17372
|
context.uniformMatrix4fv(u.u_light_matrix, false, frame.light.matrix);
|
|
17121
17373
|
const sizes = colours().sizes;
|
|
17374
|
+
const compressions = colours().compressions;
|
|
17122
17375
|
const minimumHeight = colours().minimumHeight;
|
|
17123
17376
|
const camera = view();
|
|
17124
17377
|
context.uniform1f(u.u_fade, 1);
|
|
@@ -17139,12 +17392,14 @@ function createTileflowTrees3D(options) {
|
|
|
17139
17392
|
const drawing = value.gl.vaos.get(`${form}:${model}:${selection.level}`);
|
|
17140
17393
|
if (instances === 0 || !drawing) return;
|
|
17141
17394
|
context.uniform2f(u.u_size_scale, sizes[form][0], sizes[form][1] * drawing.crown);
|
|
17395
|
+
context.uniform3f(u.u_size_compression, ...compressions[form]);
|
|
17142
17396
|
context.bindVertexArray(drawing.vao);
|
|
17143
17397
|
context.drawArraysInstanced(context.TRIANGLES, 0, drawing.count, instances);
|
|
17144
17398
|
});
|
|
17145
17399
|
const hedge = value.gl.hedge;
|
|
17146
17400
|
if (hedge) {
|
|
17147
17401
|
context.uniform1f(u.u_minimum_height, 0);
|
|
17402
|
+
context.uniform3f(u.u_size_compression, 1, 1, 0);
|
|
17148
17403
|
context.uniform2f(u.u_size_scale, 1, 1);
|
|
17149
17404
|
context.bindVertexArray(hedge.vao);
|
|
17150
17405
|
context.drawArraysInstanced(
|
|
@@ -17230,6 +17485,7 @@ function createTileflowTrees3D(options) {
|
|
|
17230
17485
|
];
|
|
17231
17486
|
context.uniform1f(u.u_minimum_height, palette2.minimumHeight);
|
|
17232
17487
|
context.uniform2f(u.u_size_scale, ...size);
|
|
17488
|
+
context.uniform3f(u.u_size_compression, ...palette2.compressions[form]);
|
|
17233
17489
|
context.bindVertexArray(drawing.vao);
|
|
17234
17490
|
context.drawArraysInstanced(context.TRIANGLES, 0, drawing.count, instances);
|
|
17235
17491
|
count += instances;
|
|
@@ -17240,6 +17496,7 @@ function createTileflowTrees3D(options) {
|
|
|
17240
17496
|
leaves,
|
|
17241
17497
|
size,
|
|
17242
17498
|
minimumHeight: palette2.minimumHeight,
|
|
17499
|
+
compression: palette2.compressions[form],
|
|
17243
17500
|
instances,
|
|
17244
17501
|
drawing
|
|
17245
17502
|
});
|
|
@@ -17250,6 +17507,7 @@ function createTileflowTrees3D(options) {
|
|
|
17250
17507
|
const instances = value.placement.hedges.length / tileflowTreeBytes;
|
|
17251
17508
|
context.uniform3fv(u.u_leaves, palette2.hedge.flat());
|
|
17252
17509
|
context.uniform1f(u.u_minimum_height, 0);
|
|
17510
|
+
context.uniform3f(u.u_size_compression, 1, 1, 0);
|
|
17253
17511
|
context.uniform2f(u.u_size_scale, 1, 1);
|
|
17254
17512
|
context.bindVertexArray(hedge.vao);
|
|
17255
17513
|
context.drawArraysInstanced(context.TRIANGLES, 0, hedge.count, instances);
|
|
@@ -17260,6 +17518,7 @@ function createTileflowTrees3D(options) {
|
|
|
17260
17518
|
leaves: palette2.hedge,
|
|
17261
17519
|
size: [1, 1],
|
|
17262
17520
|
minimumHeight: 0,
|
|
17521
|
+
compression: [1, 1, 0],
|
|
17263
17522
|
instances,
|
|
17264
17523
|
drawing: hedge
|
|
17265
17524
|
});
|
|
@@ -17302,6 +17561,7 @@ function createTileflowTrees3D(options) {
|
|
|
17302
17561
|
);
|
|
17303
17562
|
context.uniform1f(e.u_minimum_height, draw2.minimumHeight);
|
|
17304
17563
|
context.uniform2f(e.u_size_scale, ...draw2.size);
|
|
17564
|
+
context.uniform3f(e.u_size_compression, ...draw2.compression);
|
|
17305
17565
|
context.bindVertexArray(draw2.drawing.vao);
|
|
17306
17566
|
context.drawArraysInstanced(context.TRIANGLES, 0, draw2.drawing.count, draw2.instances);
|
|
17307
17567
|
}
|
|
@@ -17490,7 +17750,7 @@ ${shaderData.define}`;
|
|
|
17490
17750
|
context.deleteBuffer(ground.vbo);
|
|
17491
17751
|
}
|
|
17492
17752
|
unregister();
|
|
17493
|
-
|
|
17753
|
+
registered2 = false;
|
|
17494
17754
|
scene.release(context);
|
|
17495
17755
|
programs = {};
|
|
17496
17756
|
meshes = void 0;
|
|
@@ -17503,8 +17763,8 @@ ${shaderData.define}`;
|
|
|
17503
17763
|
if (!isWebGL23(context)) return;
|
|
17504
17764
|
ensureTiles();
|
|
17505
17765
|
if (!programs.depth) return;
|
|
17506
|
-
if (!
|
|
17507
|
-
|
|
17766
|
+
if (!registered2) unregister = scene.register(caster);
|
|
17767
|
+
registered2 = true;
|
|
17508
17768
|
const metres = tiles[0]?.metres ?? 1;
|
|
17509
17769
|
scene.prepare(context, tileflowSceneLight(sunNow()), metres);
|
|
17510
17770
|
},
|
|
@@ -19636,6 +19896,320 @@ function createChannel() {
|
|
|
19636
19896
|
return `bridge_${Date.now().toString(36)}_${channelSequence.toString(36)}`;
|
|
19637
19897
|
}
|
|
19638
19898
|
|
|
19899
|
+
// src/path-ground-geometry.ts
|
|
19900
|
+
var coverClasses = /* @__PURE__ */ new Set(["grass", "wood", "forest", "wetland"]);
|
|
19901
|
+
var useClasses = /* @__PURE__ */ new Set(["cemetery", "pitch", "track", "playground", "zoo"]);
|
|
19902
|
+
var pathClasses = /* @__PURE__ */ new Set([
|
|
19903
|
+
"footway",
|
|
19904
|
+
"path",
|
|
19905
|
+
"bridleway",
|
|
19906
|
+
"corridor",
|
|
19907
|
+
"pedestrian",
|
|
19908
|
+
"steps",
|
|
19909
|
+
"cycleway"
|
|
19910
|
+
]);
|
|
19911
|
+
function deriveTileflowGreenPaths(bytes, bindings) {
|
|
19912
|
+
const tile = decodeTileflowVectorTile(bytes, {
|
|
19913
|
+
layers: [bindings.road, bindings.landcover, bindings.landuse]
|
|
19914
|
+
});
|
|
19915
|
+
const road = tile[bindings.road];
|
|
19916
|
+
if (!road) return encodeLines(bindings.road, 4096, []);
|
|
19917
|
+
const polygons = [];
|
|
19918
|
+
for (const name of [bindings.landcover, bindings.landuse]) {
|
|
19919
|
+
const layer = tile[name];
|
|
19920
|
+
if (!layer) continue;
|
|
19921
|
+
for (const feature of layer.features) {
|
|
19922
|
+
const kind = String(feature.properties[bindings.class]);
|
|
19923
|
+
const subclass = String(feature.properties[bindings.subclass]);
|
|
19924
|
+
const green = name === bindings.landcover ? coverClasses.has(kind) || kind === "farmland" && ["orchard", "plant_nursery"].includes(subclass) : useClasses.has(kind);
|
|
19925
|
+
if (feature.type !== "Polygon" || !green) continue;
|
|
19926
|
+
let current;
|
|
19927
|
+
for (const raw of feature.geometry) {
|
|
19928
|
+
const ring = raw.map((n) => n * road.extent / layer.extent);
|
|
19929
|
+
if (signedArea2(ring) > 0 || !current) {
|
|
19930
|
+
current = [ring];
|
|
19931
|
+
polygons.push({ rings: current, bounds: boundsOf2(ring) });
|
|
19932
|
+
} else current.push(ring);
|
|
19933
|
+
}
|
|
19934
|
+
}
|
|
19935
|
+
}
|
|
19936
|
+
const features = [];
|
|
19937
|
+
for (const feature of road.features) {
|
|
19938
|
+
const p = feature.properties;
|
|
19939
|
+
if (feature.type !== "LineString" || !["path", "path_construction"].includes(String(p[bindings.class])) || !pathClasses.has(String(p[bindings.subclass])) || ["bridge", "tunnel"].includes(String(p[bindings.brunnel])))
|
|
19940
|
+
continue;
|
|
19941
|
+
const geometry2 = feature.geometry.flatMap((line) => clipLineToGreen(line, polygons));
|
|
19942
|
+
if (geometry2.length) features.push({ ...feature, geometry: geometry2 });
|
|
19943
|
+
}
|
|
19944
|
+
return encodeLines(bindings.road, road.extent, features);
|
|
19945
|
+
}
|
|
19946
|
+
function signedArea2(ring) {
|
|
19947
|
+
let area3 = 0;
|
|
19948
|
+
for (let i2 = 0, j2 = ring.length - 2; i2 < ring.length; j2 = i2, i2 += 2)
|
|
19949
|
+
area3 += ring[j2] * ring[i2 + 1] - ring[i2] * ring[j2 + 1];
|
|
19950
|
+
return area3 / 2;
|
|
19951
|
+
}
|
|
19952
|
+
function boundsOf2(line) {
|
|
19953
|
+
const box = [Infinity, Infinity, -Infinity, -Infinity];
|
|
19954
|
+
for (let i2 = 0; i2 < line.length; i2 += 2) {
|
|
19955
|
+
box[0] = Math.min(box[0], line[i2]);
|
|
19956
|
+
box[1] = Math.min(box[1], line[i2 + 1]);
|
|
19957
|
+
box[2] = Math.max(box[2], line[i2]);
|
|
19958
|
+
box[3] = Math.max(box[3], line[i2 + 1]);
|
|
19959
|
+
}
|
|
19960
|
+
return box;
|
|
19961
|
+
}
|
|
19962
|
+
function overlaps(a, b2) {
|
|
19963
|
+
return a[0] <= b2[2] && a[2] >= b2[0] && a[1] <= b2[3] && a[3] >= b2[1];
|
|
19964
|
+
}
|
|
19965
|
+
function insideRing(point, ring) {
|
|
19966
|
+
const [x3, y2] = point;
|
|
19967
|
+
let inside2 = false;
|
|
19968
|
+
for (let i2 = 0, j2 = ring.length - 2; i2 < ring.length; j2 = i2, i2 += 2) {
|
|
19969
|
+
const ax = ring[j2], ay = ring[j2 + 1], bx = ring[i2], by = ring[i2 + 1];
|
|
19970
|
+
const cross = (x3 - ax) * (by - ay) - (y2 - ay) * (bx - ax);
|
|
19971
|
+
if (Math.abs(cross) < 1e-7 && x3 >= Math.min(ax, bx) && x3 <= Math.max(ax, bx) && y2 >= Math.min(ay, by) && y2 <= Math.max(ay, by))
|
|
19972
|
+
return true;
|
|
19973
|
+
if (ay > y2 !== by > y2 && x3 < (bx - ax) * (y2 - ay) / (by - ay) + ax) inside2 = !inside2;
|
|
19974
|
+
}
|
|
19975
|
+
return inside2;
|
|
19976
|
+
}
|
|
19977
|
+
function clipLineToGreen(line, all) {
|
|
19978
|
+
const polygons = all.filter((polygon) => overlaps(boundsOf2(line), polygon.bounds));
|
|
19979
|
+
if (!polygons.length) return [];
|
|
19980
|
+
const output = [];
|
|
19981
|
+
let active;
|
|
19982
|
+
for (let i2 = 2; i2 < line.length; i2 += 2) {
|
|
19983
|
+
const ax = line[i2 - 2], ay = line[i2 - 1], dx = line[i2] - ax, dy = line[i2 + 1] - ay;
|
|
19984
|
+
if (dx === 0 && dy === 0) continue;
|
|
19985
|
+
const cuts = [0, 1];
|
|
19986
|
+
for (const polygon of polygons)
|
|
19987
|
+
for (const ring of polygon.rings)
|
|
19988
|
+
for (let k = 0, j2 = ring.length - 2; k < ring.length; j2 = k, k += 2) {
|
|
19989
|
+
const bx = ring[j2], by = ring[j2 + 1], ex = ring[k] - bx, ey = ring[k + 1] - by;
|
|
19990
|
+
const denominator = dx * ey - dy * ex;
|
|
19991
|
+
if (Math.abs(denominator) < 1e-10) continue;
|
|
19992
|
+
const t = ((bx - ax) * ey - (by - ay) * ex) / denominator;
|
|
19993
|
+
const u = ((bx - ax) * dy - (by - ay) * dx) / denominator;
|
|
19994
|
+
if (t > 0 && t < 1 && u >= 0 && u <= 1) cuts.push(t);
|
|
19995
|
+
}
|
|
19996
|
+
cuts.sort((a, b2) => a - b2);
|
|
19997
|
+
for (let k = 1; k < cuts.length; k++) {
|
|
19998
|
+
const lo = cuts[k - 1], hi = cuts[k];
|
|
19999
|
+
if (hi - lo < 1e-9) continue;
|
|
20000
|
+
const mid = (lo + hi) / 2;
|
|
20001
|
+
const point = [ax + dx * mid, ay + dy * mid];
|
|
20002
|
+
const inside2 = polygons.some(
|
|
20003
|
+
(p) => insideRing(point, p.rings[0]) && !p.rings.slice(1).some((hole) => insideRing(point, hole))
|
|
20004
|
+
);
|
|
20005
|
+
if (!inside2) {
|
|
20006
|
+
active = void 0;
|
|
20007
|
+
continue;
|
|
20008
|
+
}
|
|
20009
|
+
const start = [Math.round(ax + dx * lo), Math.round(ay + dy * lo)];
|
|
20010
|
+
const end = [Math.round(ax + dx * hi), Math.round(ay + dy * hi)];
|
|
20011
|
+
if (start[0] === end[0] && start[1] === end[1]) continue;
|
|
20012
|
+
if (!active || active.at(-2) !== start[0] || active.at(-1) !== start[1]) {
|
|
20013
|
+
active = [...start];
|
|
20014
|
+
output.push(active);
|
|
20015
|
+
}
|
|
20016
|
+
active.push(...end);
|
|
20017
|
+
}
|
|
20018
|
+
}
|
|
20019
|
+
return output;
|
|
20020
|
+
}
|
|
20021
|
+
var Writer = class {
|
|
20022
|
+
bytes = [];
|
|
20023
|
+
uint(n) {
|
|
20024
|
+
while (n > 127) {
|
|
20025
|
+
this.bytes.push(n % 128 | 128);
|
|
20026
|
+
n = Math.floor(n / 128);
|
|
20027
|
+
}
|
|
20028
|
+
this.bytes.push(n);
|
|
20029
|
+
}
|
|
20030
|
+
field(tag, value) {
|
|
20031
|
+
this.uint(tag * 8);
|
|
20032
|
+
this.uint(value);
|
|
20033
|
+
}
|
|
20034
|
+
message(tag, value) {
|
|
20035
|
+
this.uint(tag * 8 + 2);
|
|
20036
|
+
this.uint(value.length);
|
|
20037
|
+
for (const n of value) this.bytes.push(n);
|
|
20038
|
+
}
|
|
20039
|
+
text(tag, value) {
|
|
20040
|
+
this.message(tag, new TextEncoder().encode(value));
|
|
20041
|
+
}
|
|
20042
|
+
};
|
|
20043
|
+
function zigzag2(n) {
|
|
20044
|
+
return n < 0 ? -n * 2 - 1 : n * 2;
|
|
20045
|
+
}
|
|
20046
|
+
function encodeLines(name, extent5, features) {
|
|
20047
|
+
const layer = new Writer();
|
|
20048
|
+
layer.text(1, name);
|
|
20049
|
+
const keys = [];
|
|
20050
|
+
const values = [];
|
|
20051
|
+
const keyMap = /* @__PURE__ */ new Map(), valueMap = /* @__PURE__ */ new Map();
|
|
20052
|
+
for (const feature of features) {
|
|
20053
|
+
const message = new Writer(), tags = new Writer(), geometry2 = new Writer();
|
|
20054
|
+
if (feature.id !== void 0) message.field(1, feature.id);
|
|
20055
|
+
for (const [key, value] of Object.entries(feature.properties)) {
|
|
20056
|
+
if (!keyMap.has(key)) {
|
|
20057
|
+
keyMap.set(key, keys.length);
|
|
20058
|
+
keys.push(key);
|
|
20059
|
+
}
|
|
20060
|
+
const identity = typeof value + ":" + value;
|
|
20061
|
+
if (!valueMap.has(identity)) {
|
|
20062
|
+
valueMap.set(identity, values.length);
|
|
20063
|
+
values.push(value);
|
|
20064
|
+
}
|
|
20065
|
+
tags.uint(keyMap.get(key));
|
|
20066
|
+
tags.uint(valueMap.get(identity));
|
|
20067
|
+
}
|
|
20068
|
+
message.message(2, tags.bytes);
|
|
20069
|
+
message.field(3, feature.type === "Polygon" ? 3 : 2);
|
|
20070
|
+
let x3 = 0, y2 = 0;
|
|
20071
|
+
for (const raw of feature.geometry) {
|
|
20072
|
+
const points = feature.type === "Polygon" && raw[0] === raw.at(-2) && raw[1] === raw.at(-1) ? raw.slice(0, -2) : raw;
|
|
20073
|
+
if (points.length < 4) continue;
|
|
20074
|
+
geometry2.uint(9);
|
|
20075
|
+
geometry2.uint(zigzag2(Math.round(points[0]) - x3));
|
|
20076
|
+
geometry2.uint(zigzag2(Math.round(points[1]) - y2));
|
|
20077
|
+
x3 = Math.round(points[0]);
|
|
20078
|
+
y2 = Math.round(points[1]);
|
|
20079
|
+
geometry2.uint((points.length / 2 - 1) * 8 + 2);
|
|
20080
|
+
for (let i2 = 2; i2 < points.length; i2 += 2) {
|
|
20081
|
+
const nx = Math.round(points[i2]), ny = Math.round(points[i2 + 1]);
|
|
20082
|
+
geometry2.uint(zigzag2(nx - x3));
|
|
20083
|
+
geometry2.uint(zigzag2(ny - y2));
|
|
20084
|
+
x3 = nx;
|
|
20085
|
+
y2 = ny;
|
|
20086
|
+
}
|
|
20087
|
+
if (feature.type === "Polygon") geometry2.uint(15);
|
|
20088
|
+
}
|
|
20089
|
+
message.message(4, geometry2.bytes);
|
|
20090
|
+
layer.message(2, message.bytes);
|
|
20091
|
+
}
|
|
20092
|
+
for (const key of keys) layer.text(3, key);
|
|
20093
|
+
for (const value of values) {
|
|
20094
|
+
const message = new Writer();
|
|
20095
|
+
if (typeof value === "string") message.text(1, value);
|
|
20096
|
+
else if (typeof value === "boolean") message.field(7, value ? 1 : 0);
|
|
20097
|
+
else if (Number.isSafeInteger(value)) {
|
|
20098
|
+
message.field(value < 0 ? 6 : 4, value < 0 ? zigzag2(value) : value);
|
|
20099
|
+
} else {
|
|
20100
|
+
message.uint(25);
|
|
20101
|
+
const b2 = new Uint8Array(8);
|
|
20102
|
+
new DataView(b2.buffer).setFloat64(0, value, true);
|
|
20103
|
+
message.bytes.push(...b2);
|
|
20104
|
+
}
|
|
20105
|
+
layer.message(4, message.bytes);
|
|
20106
|
+
}
|
|
20107
|
+
layer.field(5, extent5);
|
|
20108
|
+
layer.field(15, 2);
|
|
20109
|
+
const tile = new Writer();
|
|
20110
|
+
tile.message(3, layer.bytes);
|
|
20111
|
+
return new Uint8Array(tile.bytes);
|
|
20112
|
+
}
|
|
20113
|
+
|
|
20114
|
+
// src/path-ground-protocol.ts
|
|
20115
|
+
var tileflowPathGroundProtocol = "tileflow-path-ground";
|
|
20116
|
+
function pathGroundProtocolUrl(source, tile = false) {
|
|
20117
|
+
return `${tileflowPathGroundProtocol}://source/${tile ? "{z}/{x}/{y}.pbf" : "index.json"}?source=${encodeURIComponent(JSON.stringify(source))}`;
|
|
20118
|
+
}
|
|
20119
|
+
function parsePathGroundRequest(value) {
|
|
20120
|
+
if (value.length > 16e3) throw new Error("Path context URL is too long");
|
|
20121
|
+
const url = new URL(value);
|
|
20122
|
+
if (url.protocol !== `${tileflowPathGroundProtocol}:` || url.hostname !== "source" || url.username || url.password || url.hash)
|
|
20123
|
+
throw new Error("Invalid path context URL");
|
|
20124
|
+
const source = JSON.parse(url.searchParams.get("source") ?? "null");
|
|
20125
|
+
if (!source || !["road", "landcover", "landuse", "class", "subclass", "brunnel"].every(
|
|
20126
|
+
(k) => typeof source[k] === "string"
|
|
20127
|
+
))
|
|
20128
|
+
throw new Error("Invalid path context bindings");
|
|
20129
|
+
if (!source.url && !source.tiles?.length) throw new Error("Missing path context source");
|
|
20130
|
+
for (const endpoint of [source.url, ...source.tiles ?? []].filter((s) => !!s)) {
|
|
20131
|
+
const u = new URL(
|
|
20132
|
+
endpoint.replaceAll("{z}", "0").replaceAll("{x}", "0").replaceAll("{y}", "0")
|
|
20133
|
+
);
|
|
20134
|
+
if (!["https:", "http:"].includes(u.protocol) || u.username || u.password)
|
|
20135
|
+
throw new Error("Path context requires an HTTP(S) vector source");
|
|
20136
|
+
}
|
|
20137
|
+
if (url.pathname === "/index.json") return { source };
|
|
20138
|
+
const match = /^\/(\d{1,2})\/(\d+)\/(\d+)\.pbf$/.exec(url.pathname);
|
|
20139
|
+
if (!match) throw new Error("Invalid path context tile");
|
|
20140
|
+
const [z2, x3, y2] = match.slice(1).map(Number);
|
|
20141
|
+
if (z2 < 0 || z2 > 24 || x3 < 0 || y2 < 0 || x3 >= 2 ** z2 || y2 >= 2 ** z2)
|
|
20142
|
+
throw new Error("Invalid path context coordinates");
|
|
20143
|
+
return { source, tile: { z: z2, x: x3, y: y2 } };
|
|
20144
|
+
}
|
|
20145
|
+
|
|
20146
|
+
// src/path-ground-browser.ts
|
|
20147
|
+
var registered = /* @__PURE__ */ new WeakSet();
|
|
20148
|
+
function registerTileflowPathGroundProtocol(registry, options = {}) {
|
|
20149
|
+
if (registered.has(registry.addProtocol)) return;
|
|
20150
|
+
const request = options.fetch ?? globalThis.fetch;
|
|
20151
|
+
const transform = options.transformUrl ?? ((url) => url);
|
|
20152
|
+
const descriptions = /* @__PURE__ */ new Map();
|
|
20153
|
+
const tiles = /* @__PURE__ */ new Map();
|
|
20154
|
+
let cacheBytes = 0;
|
|
20155
|
+
async function description(source, signal) {
|
|
20156
|
+
if (!source.url)
|
|
20157
|
+
return { tiles: source.tiles, minzoom: source.minzoom, maxzoom: source.maxzoom };
|
|
20158
|
+
const previous = descriptions.get(source.url);
|
|
20159
|
+
if (previous) return previous;
|
|
20160
|
+
const response = await request(transform(source.url), { signal });
|
|
20161
|
+
if (!response.ok) throw new Error(`Path context TileJSON: HTTP ${response.status}`);
|
|
20162
|
+
const json = await response.json();
|
|
20163
|
+
if (!Array.isArray(json.tiles) || !json.tiles.length || json.tiles.some((url) => typeof url !== "string"))
|
|
20164
|
+
throw new Error("Path context TileJSON has no tile templates");
|
|
20165
|
+
const result = {
|
|
20166
|
+
...json,
|
|
20167
|
+
tiles: json.tiles.map(
|
|
20168
|
+
(url) => new URL(url, source.url).href.replaceAll("%7B", "{").replaceAll("%7D", "}")
|
|
20169
|
+
)
|
|
20170
|
+
};
|
|
20171
|
+
if (descriptions.size >= 16) descriptions.delete(descriptions.keys().next().value);
|
|
20172
|
+
descriptions.set(source.url, result);
|
|
20173
|
+
return result;
|
|
20174
|
+
}
|
|
20175
|
+
registry.addProtocol(tileflowPathGroundProtocol, async (input, abort) => {
|
|
20176
|
+
const { source, tile } = parsePathGroundRequest(input.url);
|
|
20177
|
+
const signal = abort.signal;
|
|
20178
|
+
signal.throwIfAborted();
|
|
20179
|
+
const json = await description(source, signal);
|
|
20180
|
+
if (!tile)
|
|
20181
|
+
return {
|
|
20182
|
+
data: {
|
|
20183
|
+
tiles: [pathGroundProtocolUrl(source, true)],
|
|
20184
|
+
minzoom: Math.max(12, json.minzoom ?? 0),
|
|
20185
|
+
maxzoom: json.maxzoom ?? source.maxzoom ?? 15,
|
|
20186
|
+
...json.attribution ? { attribution: json.attribution } : {}
|
|
20187
|
+
}
|
|
20188
|
+
};
|
|
20189
|
+
const cached = tiles.get(input.url);
|
|
20190
|
+
if (cached) return { data: cached.slice().buffer };
|
|
20191
|
+
const y2 = json.scheme === "tms" ? 2 ** tile.z - 1 - tile.y : tile.y;
|
|
20192
|
+
const url = json.tiles[0].replaceAll("{z}", String(tile.z)).replaceAll("{x}", String(tile.x)).replaceAll("{y}", String(y2));
|
|
20193
|
+
if (!/^https?:\/\//.test(url))
|
|
20194
|
+
throw new Error("Path context requires an HTTP(S) tile template");
|
|
20195
|
+
const response = await request(transform(url), { signal });
|
|
20196
|
+
if (!response.ok) throw new Error(`Path context tile: HTTP ${response.status}`);
|
|
20197
|
+
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
20198
|
+
if (bytes.byteLength > 16 * 1024 * 1024) throw new Error("Path context tile exceeds 16 MiB");
|
|
20199
|
+
signal.throwIfAborted();
|
|
20200
|
+
const result = deriveTileflowGreenPaths(bytes, source);
|
|
20201
|
+
while (tiles.size && (tiles.size >= 64 || cacheBytes + result.byteLength > 16 * 1024 * 1024)) {
|
|
20202
|
+
const key = tiles.keys().next().value;
|
|
20203
|
+
cacheBytes -= tiles.get(key).byteLength;
|
|
20204
|
+
tiles.delete(key);
|
|
20205
|
+
}
|
|
20206
|
+
tiles.set(input.url, result);
|
|
20207
|
+
cacheBytes += result.byteLength;
|
|
20208
|
+
return { data: result.slice().buffer };
|
|
20209
|
+
});
|
|
20210
|
+
registered.add(registry.addProtocol);
|
|
20211
|
+
}
|
|
20212
|
+
|
|
19639
20213
|
// src/terrain/contour-protocol.ts
|
|
19640
20214
|
var tileflowContourProtocol = "tileflow-contour";
|
|
19641
20215
|
var tileflowContourSourceLayer = "contours";
|
|
@@ -19884,11 +20458,11 @@ async function loadPinnedMaplibreContour() {
|
|
|
19884
20458
|
}
|
|
19885
20459
|
function resolveMaplibreContourLibrary(module) {
|
|
19886
20460
|
if (!module || typeof module !== "object") {
|
|
19887
|
-
throw new Error("maplibre-contour 0.1.
|
|
20461
|
+
throw new Error("maplibre-contour 0.1.1 did not expose its browser module.");
|
|
19888
20462
|
}
|
|
19889
20463
|
const library = module.default;
|
|
19890
20464
|
if (!library || typeof library !== "object" || typeof library.DemSource !== "function") {
|
|
19891
|
-
throw new Error("maplibre-contour 0.1.
|
|
20465
|
+
throw new Error("maplibre-contour 0.1.1 did not expose DemSource.");
|
|
19892
20466
|
}
|
|
19893
20467
|
return library;
|
|
19894
20468
|
}
|
|
@@ -20026,6 +20600,130 @@ function createTileflowVegetation(options) {
|
|
|
20026
20600
|
};
|
|
20027
20601
|
}
|
|
20028
20602
|
|
|
20603
|
+
// src/building-flat-layers-browser.ts
|
|
20604
|
+
function createBuildingFlatLayers(map) {
|
|
20605
|
+
const saved = /* @__PURE__ */ new Map();
|
|
20606
|
+
let updating = false;
|
|
20607
|
+
function restore() {
|
|
20608
|
+
if (!map.setLayoutProperty || !map.getLayoutProperty || updating) return;
|
|
20609
|
+
updating = true;
|
|
20610
|
+
try {
|
|
20611
|
+
for (const [id, { visibility, layer }] of saved)
|
|
20612
|
+
if (map.getLayer(id) === layer && map.getLayoutProperty(id, "visibility") !== visibility)
|
|
20613
|
+
map.setLayoutProperty(id, "visibility", visibility);
|
|
20614
|
+
saved.clear();
|
|
20615
|
+
} finally {
|
|
20616
|
+
updating = false;
|
|
20617
|
+
}
|
|
20618
|
+
}
|
|
20619
|
+
return {
|
|
20620
|
+
update(layers, hidden) {
|
|
20621
|
+
if (updating || !map.setLayoutProperty || !map.getLayoutProperty) return;
|
|
20622
|
+
if (!hidden || layers.length === 0) {
|
|
20623
|
+
restore();
|
|
20624
|
+
return;
|
|
20625
|
+
}
|
|
20626
|
+
updating = true;
|
|
20627
|
+
try {
|
|
20628
|
+
const authored = new Map(layers.map((layer) => [layer.id, layer.visible]));
|
|
20629
|
+
const ids = map.getLayersOrder?.() ?? (map.getStyle()?.layers ?? []).map(({ id }) => id);
|
|
20630
|
+
for (const id of ids) {
|
|
20631
|
+
const visible = authored.get(id.split("::")[0]);
|
|
20632
|
+
if (visible === void 0 || !map.getLayer(id)) continue;
|
|
20633
|
+
const current = map.getLayoutProperty(id, "visibility") ?? "visible";
|
|
20634
|
+
if (!saved.has(id) || saved.get(id).layer !== map.getLayer(id))
|
|
20635
|
+
saved.set(id, { visibility: visible ? current : "none", layer: map.getLayer(id) });
|
|
20636
|
+
if (current !== "none") map.setLayoutProperty(id, "visibility", "none");
|
|
20637
|
+
}
|
|
20638
|
+
} finally {
|
|
20639
|
+
updating = false;
|
|
20640
|
+
}
|
|
20641
|
+
},
|
|
20642
|
+
restore,
|
|
20643
|
+
/** Removing a map must not write to its destroyed style. */
|
|
20644
|
+
forget() {
|
|
20645
|
+
saved.clear();
|
|
20646
|
+
}
|
|
20647
|
+
};
|
|
20648
|
+
}
|
|
20649
|
+
|
|
20650
|
+
// src/camera.ts
|
|
20651
|
+
var tileflowCameraMetadataKey = "tileflow:camera";
|
|
20652
|
+
function readTileflowCamera(metadata) {
|
|
20653
|
+
if (!metadata || typeof metadata !== "object") return {};
|
|
20654
|
+
const value = metadata[tileflowCameraMetadataKey];
|
|
20655
|
+
if (!value || typeof value !== "object") return {};
|
|
20656
|
+
const policy = value;
|
|
20657
|
+
return policy.version === 1 && typeof policy.adaptivePerspective === "boolean" ? { adaptivePerspective: policy.adaptivePerspective } : {};
|
|
20658
|
+
}
|
|
20659
|
+
|
|
20660
|
+
// src/camera-browser.ts
|
|
20661
|
+
function tileflowAdaptiveFieldOfView(pitch, zoom, height, normalFieldOfView) {
|
|
20662
|
+
if (pitch >= 15 || zoom <= 13 || height <= 0) return normalFieldOfView;
|
|
20663
|
+
const tangent = Math.tan(normalFieldOfView * Math.PI / 360);
|
|
20664
|
+
const distance = height / (2 * tangent);
|
|
20665
|
+
const mix2 = (Math.max(0, pitch) / 15) ** 5;
|
|
20666
|
+
const nearTangent = Math.max(
|
|
20667
|
+
Math.tan(Math.min(6, normalFieldOfView) * Math.PI / 360),
|
|
20668
|
+
height * mix2 / (2 * (1 - mix2 + mix2 * distance))
|
|
20669
|
+
);
|
|
20670
|
+
const t = Math.min(1, Math.max(0, (zoom - 13) / 2));
|
|
20671
|
+
const amount = t * t * (3 - 2 * t);
|
|
20672
|
+
return Math.atan(tangent + (nearTangent - tangent) * amount) * 360 / Math.PI;
|
|
20673
|
+
}
|
|
20674
|
+
function createTileflowAdaptiveCamera(map) {
|
|
20675
|
+
let normal;
|
|
20676
|
+
let applying = false;
|
|
20677
|
+
let disposed = false;
|
|
20678
|
+
const write = (next) => {
|
|
20679
|
+
if (applying || Math.abs((map.getVerticalFieldOfView?.() ?? next) - next) < 1e-6) return;
|
|
20680
|
+
applying = true;
|
|
20681
|
+
try {
|
|
20682
|
+
map.setVerticalFieldOfView?.(next);
|
|
20683
|
+
} finally {
|
|
20684
|
+
applying = false;
|
|
20685
|
+
}
|
|
20686
|
+
};
|
|
20687
|
+
const update = () => {
|
|
20688
|
+
if (disposed || applying || normal === void 0) return;
|
|
20689
|
+
write(
|
|
20690
|
+
tileflowAdaptiveFieldOfView(
|
|
20691
|
+
map.getPitch(),
|
|
20692
|
+
map.getZoom(),
|
|
20693
|
+
map.getCanvas().clientHeight,
|
|
20694
|
+
normal
|
|
20695
|
+
)
|
|
20696
|
+
);
|
|
20697
|
+
};
|
|
20698
|
+
const setEnabled = (enabled) => {
|
|
20699
|
+
if (disposed) return;
|
|
20700
|
+
if (enabled) {
|
|
20701
|
+
if (!map.getVerticalFieldOfView || !map.setVerticalFieldOfView || !map.getCanvas) return;
|
|
20702
|
+
normal ??= map.getVerticalFieldOfView();
|
|
20703
|
+
update();
|
|
20704
|
+
} else if (normal !== void 0) {
|
|
20705
|
+
const restore = normal;
|
|
20706
|
+
normal = void 0;
|
|
20707
|
+
write(restore);
|
|
20708
|
+
}
|
|
20709
|
+
};
|
|
20710
|
+
const onRemove = () => dispose(false);
|
|
20711
|
+
function dispose(restore = true) {
|
|
20712
|
+
if (disposed) return;
|
|
20713
|
+
if (restore) setEnabled(false);
|
|
20714
|
+
disposed = true;
|
|
20715
|
+
map.off("pitch", update);
|
|
20716
|
+
map.off("zoom", update);
|
|
20717
|
+
map.off("resize", update);
|
|
20718
|
+
map.off("remove", onRemove);
|
|
20719
|
+
}
|
|
20720
|
+
map.on("pitch", update);
|
|
20721
|
+
map.on("zoom", update);
|
|
20722
|
+
map.on("resize", update);
|
|
20723
|
+
map.on("remove", onRemove);
|
|
20724
|
+
return { setEnabled, dispose };
|
|
20725
|
+
}
|
|
20726
|
+
|
|
20029
20727
|
// src/map-3d-attach-browser.ts
|
|
20030
20728
|
var tileflowMap3DMetadataKeys = Object.freeze([
|
|
20031
20729
|
tileflowBuildingsMetadataKey,
|
|
@@ -20051,6 +20749,7 @@ function attachTileflowMap3D(options) {
|
|
|
20051
20749
|
const { map, load, onError, ...sceneOptions } = options;
|
|
20052
20750
|
let viewMode = options.viewMode ?? "3d";
|
|
20053
20751
|
let vegetation = options.vegetation;
|
|
20752
|
+
let adaptivePerspective = options.camera?.adaptivePerspective;
|
|
20054
20753
|
let scene;
|
|
20055
20754
|
let loading = false;
|
|
20056
20755
|
let disposed = false;
|
|
@@ -20066,7 +20765,13 @@ function attachTileflowMap3D(options) {
|
|
|
20066
20765
|
stopWatching();
|
|
20067
20766
|
load().then(({ createTileflowMap3D: createTileflowMap3D2 }) => {
|
|
20068
20767
|
if (disposed) return;
|
|
20069
|
-
scene = createTileflowMap3D2({
|
|
20768
|
+
scene = createTileflowMap3D2({
|
|
20769
|
+
...sceneOptions,
|
|
20770
|
+
map,
|
|
20771
|
+
viewMode,
|
|
20772
|
+
vegetation,
|
|
20773
|
+
camera: { adaptivePerspective }
|
|
20774
|
+
});
|
|
20070
20775
|
}).catch((error) => {
|
|
20071
20776
|
if (!disposed) onError?.(error);
|
|
20072
20777
|
});
|
|
@@ -20084,28 +20789,36 @@ function attachTileflowMap3D(options) {
|
|
|
20084
20789
|
if (disposed) return;
|
|
20085
20790
|
disposed = true;
|
|
20086
20791
|
stopWatching();
|
|
20087
|
-
map.off("remove",
|
|
20792
|
+
map.off("remove", onRemove);
|
|
20088
20793
|
scene?.dispose();
|
|
20089
20794
|
scene = void 0;
|
|
20090
20795
|
}
|
|
20796
|
+
function onRemove() {
|
|
20797
|
+
scene = void 0;
|
|
20798
|
+
dispose();
|
|
20799
|
+
}
|
|
20091
20800
|
map.on("styledata", restyle);
|
|
20092
20801
|
map.on("style.load", restyle);
|
|
20093
20802
|
map.on("idle", check);
|
|
20094
|
-
map.on("remove",
|
|
20803
|
+
map.on("remove", onRemove);
|
|
20095
20804
|
check();
|
|
20096
20805
|
return {
|
|
20097
20806
|
get scene() {
|
|
20098
20807
|
return scene;
|
|
20099
20808
|
},
|
|
20100
|
-
setViewMode(mode) {
|
|
20809
|
+
setViewMode(mode, change) {
|
|
20101
20810
|
if (mode === viewMode) return;
|
|
20102
20811
|
viewMode = mode;
|
|
20103
|
-
if (scene) void (mode === "3d" ? scene.show() : scene.hide());
|
|
20812
|
+
if (scene) void (mode === "3d" ? scene.show(change) : scene.hide(change));
|
|
20104
20813
|
},
|
|
20105
20814
|
setVegetation(visible) {
|
|
20106
20815
|
vegetation = visible;
|
|
20107
20816
|
scene?.setVegetation(visible);
|
|
20108
20817
|
},
|
|
20818
|
+
setAdaptivePerspective(enabled) {
|
|
20819
|
+
adaptivePerspective = enabled;
|
|
20820
|
+
scene?.setAdaptivePerspective(enabled);
|
|
20821
|
+
},
|
|
20109
20822
|
dispose
|
|
20110
20823
|
};
|
|
20111
20824
|
}
|
|
@@ -20115,9 +20828,15 @@ function createTileflowMap3D(options) {
|
|
|
20115
20828
|
const { map, controller, transformRequest } = options;
|
|
20116
20829
|
let viewMode = options.viewMode ?? "3d";
|
|
20117
20830
|
let vegetationVisible = options.vegetation;
|
|
20831
|
+
let adaptivePerspective = options.camera?.adaptivePerspective;
|
|
20832
|
+
const camera = createTileflowAdaptiveCamera(map);
|
|
20833
|
+
let authoredPerspective;
|
|
20118
20834
|
let buildings;
|
|
20119
20835
|
let vegetation;
|
|
20120
20836
|
let streetLights;
|
|
20837
|
+
const flatBuildings = createBuildingFlatLayers(map);
|
|
20838
|
+
let footprintLayers;
|
|
20839
|
+
let footprintZoom = 15.3;
|
|
20121
20840
|
let disposed = false;
|
|
20122
20841
|
let syncing = false;
|
|
20123
20842
|
const shared4 = {
|
|
@@ -20132,6 +20851,19 @@ function createTileflowMap3D(options) {
|
|
|
20132
20851
|
syncing = true;
|
|
20133
20852
|
try {
|
|
20134
20853
|
const shown = viewMode === "3d";
|
|
20854
|
+
if (footprintLayers === void 0) {
|
|
20855
|
+
const themes = controller?.getThemeMetadata?.(tileflowBuildingsMetadataKey);
|
|
20856
|
+
const metadata = themes ? { [tileflowBuildingsMetadataKey]: themes.values[Math.round(themes.position)] } : map.getStyle()?.metadata;
|
|
20857
|
+
const design = readTileflowBuildings3D(metadata);
|
|
20858
|
+
footprintLayers = design?.flatLayers ?? [];
|
|
20859
|
+
footprintZoom = design?.entrance?.buildings?.[1] ?? 15.3;
|
|
20860
|
+
}
|
|
20861
|
+
if (authoredPerspective === void 0) {
|
|
20862
|
+
const themes = controller?.getThemeMetadata?.(tileflowCameraMetadataKey);
|
|
20863
|
+
const metadata = themes ? { [tileflowCameraMetadataKey]: themes.values[Math.round(themes.position)] } : map.getStyle()?.metadata;
|
|
20864
|
+
authoredPerspective = readTileflowCamera(metadata).adaptivePerspective ?? false;
|
|
20865
|
+
}
|
|
20866
|
+
camera.setEnabled(shown && (adaptivePerspective ?? authoredPerspective));
|
|
20135
20867
|
const declared = declarations ??= tileflowMap3DDeclarations({
|
|
20136
20868
|
map,
|
|
20137
20869
|
...controller ? { controller } : {}
|
|
@@ -20145,6 +20877,7 @@ function createTileflowMap3D(options) {
|
|
|
20145
20877
|
}
|
|
20146
20878
|
if (!vegetation && (declares(tileflowVegetationMetadataKey) || declares(tileflowVegetationDisplayMetadataKey)))
|
|
20147
20879
|
vegetation = createTileflowVegetation({ ...shared4, visible: vegetationVisible, viewMode });
|
|
20880
|
+
syncFlatBuildings();
|
|
20148
20881
|
if (shown && declares(tileflowStreetLightsMetadataKey))
|
|
20149
20882
|
streetLights ??= createTileflowStreetLights(shared4);
|
|
20150
20883
|
else if (streetLights) {
|
|
@@ -20155,9 +20888,22 @@ function createTileflowMap3D(options) {
|
|
|
20155
20888
|
syncing = false;
|
|
20156
20889
|
}
|
|
20157
20890
|
}
|
|
20891
|
+
function syncFlatBuildings() {
|
|
20892
|
+
if (disposed) return;
|
|
20893
|
+
if (!footprintLayers?.length) {
|
|
20894
|
+
flatBuildings.restore();
|
|
20895
|
+
return;
|
|
20896
|
+
}
|
|
20897
|
+
const canvas = map.getCanvas?.();
|
|
20898
|
+
flatBuildings.update(
|
|
20899
|
+
footprintLayers,
|
|
20900
|
+
viewMode === "3d" && Boolean(buildings) && map.getZoom() >= footprintZoom && Boolean(canvas?.getContext?.("webgl2"))
|
|
20901
|
+
);
|
|
20902
|
+
}
|
|
20158
20903
|
function change(next, transition) {
|
|
20159
20904
|
if (disposed) return Promise.resolve();
|
|
20160
20905
|
viewMode = next;
|
|
20906
|
+
camera.setEnabled(next === "3d" && (adaptivePerspective ?? authoredPerspective ?? false));
|
|
20161
20907
|
vegetation?.setViewMode(next);
|
|
20162
20908
|
if (next === "3d") {
|
|
20163
20909
|
const existing = buildings;
|
|
@@ -20173,10 +20919,13 @@ function createTileflowMap3D(options) {
|
|
|
20173
20919
|
function dispose() {
|
|
20174
20920
|
if (disposed) return;
|
|
20175
20921
|
disposed = true;
|
|
20922
|
+
flatBuildings.restore();
|
|
20923
|
+
camera.dispose();
|
|
20176
20924
|
map.off("styledata", restyle);
|
|
20177
20925
|
map.off("style.load", restyle);
|
|
20178
20926
|
map.off("idle", sync);
|
|
20179
|
-
map.off("remove",
|
|
20927
|
+
map.off("remove", onRemove);
|
|
20928
|
+
map.off("move", syncFlatBuildings);
|
|
20180
20929
|
streetLights?.dispose();
|
|
20181
20930
|
buildings?.dispose();
|
|
20182
20931
|
vegetation?.dispose();
|
|
@@ -20185,13 +20934,21 @@ function createTileflowMap3D(options) {
|
|
|
20185
20934
|
vegetation = void 0;
|
|
20186
20935
|
}
|
|
20187
20936
|
function restyle() {
|
|
20937
|
+
if (syncing) return;
|
|
20938
|
+
footprintLayers = void 0;
|
|
20188
20939
|
declarations = void 0;
|
|
20940
|
+
authoredPerspective = void 0;
|
|
20189
20941
|
sync();
|
|
20190
20942
|
}
|
|
20943
|
+
function onRemove() {
|
|
20944
|
+
flatBuildings.forget();
|
|
20945
|
+
dispose();
|
|
20946
|
+
}
|
|
20191
20947
|
map.on("styledata", restyle);
|
|
20192
20948
|
map.on("style.load", restyle);
|
|
20193
20949
|
map.on("idle", sync);
|
|
20194
|
-
map.on("remove",
|
|
20950
|
+
map.on("remove", onRemove);
|
|
20951
|
+
map.on("move", syncFlatBuildings);
|
|
20195
20952
|
sync();
|
|
20196
20953
|
return {
|
|
20197
20954
|
show: (transition) => change("3d", transition),
|
|
@@ -20203,6 +20960,11 @@ function createTileflowMap3D(options) {
|
|
|
20203
20960
|
vegetationVisible = visible;
|
|
20204
20961
|
vegetation?.setVisible(visible);
|
|
20205
20962
|
},
|
|
20963
|
+
setAdaptivePerspective(enabled) {
|
|
20964
|
+
adaptivePerspective = enabled;
|
|
20965
|
+
camera.setEnabled(viewMode === "3d" && (adaptivePerspective ?? authoredPerspective ?? false));
|
|
20966
|
+
sync();
|
|
20967
|
+
},
|
|
20206
20968
|
get buildings() {
|
|
20207
20969
|
return buildings;
|
|
20208
20970
|
},
|
|
@@ -21731,6 +22493,7 @@ function isPromiseLike(value) {
|
|
|
21731
22493
|
export {
|
|
21732
22494
|
attachTileflowAtmosphere,
|
|
21733
22495
|
attachTileflowFairUseNotice,
|
|
22496
|
+
attachTileflowHorizonQueries,
|
|
21734
22497
|
attachTileflowLabelPlacement,
|
|
21735
22498
|
attachTileflowMap3D,
|
|
21736
22499
|
attachTileflowMapLifecycle,
|
|
@@ -21772,6 +22535,7 @@ export {
|
|
|
21772
22535
|
readTileflowVegetation3D,
|
|
21773
22536
|
readTileflowVegetationDisplay,
|
|
21774
22537
|
registerTileflowContourProtocol,
|
|
22538
|
+
registerTileflowPathGroundProtocol,
|
|
21775
22539
|
registerTileflowPmtilesProtocol,
|
|
21776
22540
|
registerTileflowWorldRequestBridge,
|
|
21777
22541
|
resolveTileflowSun,
|
|
@@ -21788,6 +22552,7 @@ export {
|
|
|
21788
22552
|
tileflowDepthMarkerPlacement,
|
|
21789
22553
|
tileflowFairUseNoticeMessage,
|
|
21790
22554
|
tileflowGroundBeforeId,
|
|
22555
|
+
tileflowHorizonScaleFactor,
|
|
21791
22556
|
tileflowLayerDomainMetadataKey,
|
|
21792
22557
|
tileflowLightRhythm,
|
|
21793
22558
|
tileflowLightRhythmConventions,
|