@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.
Files changed (50) hide show
  1. package/README.md +56 -69
  2. package/THIRD_PARTY_NOTICES.md +3 -3
  3. package/dist/{3d-CzLTD0RK.d.ts → 3d-CW5Ls0An.d.ts} +32 -2
  4. package/dist/3d.d.ts +1 -1
  5. package/dist/3d.js +425 -50
  6. package/dist/browser.d.ts +95 -5
  7. package/dist/browser.js +866 -101
  8. package/dist/build.d.ts +8 -4
  9. package/dist/build.js +250 -3
  10. package/dist/config-reference.json +3395 -2140
  11. package/dist/{icon-composition-B1A2udKb.d.ts → icon-composition-Bbw9umUA.d.ts} +37 -2
  12. package/dist/index.d.ts +13 -4
  13. package/dist/index.js +193 -3
  14. package/dist/{manifest-types-B0lQjabX.d.ts → manifest-types-CwjHd4qc.d.ts} +8 -0
  15. package/dist/manifest.d.ts +2 -2
  16. package/dist/native-profile.d.ts +4 -0
  17. package/dist/native-profile.js +2 -0
  18. package/dist/native.js +789 -462
  19. package/dist/runtime.d.ts +1 -1
  20. package/dist/worker/camera-tile-worker.global.js +2 -2
  21. package/package.json +5 -6
  22. package/docs/application-tile-reading.md +0 -86
  23. package/docs/authoring-model.md +0 -269
  24. package/docs/boundary-areas-and-choropleths.md +0 -230
  25. package/docs/buildings-3d.md +0 -624
  26. package/docs/camera-moves-and-tile-cache.md +0 -112
  27. package/docs/capture-scenes.md +0 -40
  28. package/docs/capture-shots.md +0 -173
  29. package/docs/cartographic-defaults.md +0 -214
  30. package/docs/compiled-style-performance.md +0 -286
  31. package/docs/data-is-separate-from-design.md +0 -610
  32. package/docs/depth-markers.md +0 -65
  33. package/docs/dynamic-style-images.md +0 -100
  34. package/docs/globe-atmosphere.md +0 -113
  35. package/docs/hosted-session-authorization.md +0 -106
  36. package/docs/map-and-terrain-examples.md +0 -156
  37. package/docs/map-emphasis.md +0 -89
  38. package/docs/native-artifact-profile.md +0 -152
  39. package/docs/native-resource-urls.md +0 -369
  40. package/docs/nautical-marks.md +0 -308
  41. package/docs/public-api-and-browser-subpath.md +0 -101
  42. package/docs/route-drawing.md +0 -191
  43. package/docs/shared-visual-primitives.md +0 -101
  44. package/docs/street-lights.md +0 -127
  45. package/docs/street-sky.md +0 -156
  46. package/docs/style-states.md +0 -73
  47. package/docs/sun-and-light.md +0 -167
  48. package/docs/theme-transitions-and-blends.md +0 -317
  49. package/docs/themes-and-module-styles.md +0 -156
  50. 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.0/node_modules/maplibre-contour/dist/index.mjs
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.0/node_modules/maplibre-contour/dist/index.mjs"() {
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
- const clone = copy(arrayBuffer);
1601
- return {
1602
- arrayBuffer: clone,
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 zigzag2(num2) {
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(zigzag2(dx));
2736
- pbf.writeVarint(zigzag2(dy));
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
- return this.contourCache.get(key, (_2, childAbortController) => __awaiter(this, void 0, void 0, function* () {
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 = decodeOptions;
3058
- exports.b = generateIsolines;
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 = prepareContourTile;
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.f(((_a2 = this.managers[managerId]) === null || _a2 === void 0 ? void 0 : _a2.fetchContourTile(z2, x3, y2, options, abortController, timer)) || noManager(managerId));
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] = this.parseUrl(request.url);
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] = this.parseUrl(request.url);
3179
- const options = actor.a(request.url);
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.b,
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) map.addImage(entry.name, entry.pixels, { pixelRatio: entry.pixelRatio });
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
- // The disc the city's tiles cover whole, in this tile's units: its centre, where heights start to
8368
- // ease down and where they are gone; none while its radius is 0. And the view's direction along the
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. Only its far side does: where the tile limit holds the ring short, the
8384
- // buildings round the camera, nearer than its centre, keep standing.
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, distance } of chosen.tiles) {
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.distance = distance;
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.distance ?? 0 }
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.distance ?? 0) < (queue[nearest].entry.distance ?? 0))
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.distance ?? 0);
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
- const previous = entry.value;
11647
- entry.value = value;
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
- if (previous && previous !== options.empty && previous !== value) options.release(previous);
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
- for (const entry of tiles.values()) entry.loading?.abort();
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 tileMetres = earth * Math.cos(latitude * Math.PI / 180) / 2 ** tileZoom;
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 dx = -span; dx <= span; dx += 1)
11813
- for (let dy = -span; dy <= span; dy += 1) {
11814
- const x3 = Math.floor(cx) + dx;
11815
- const y2 = Math.floor(cy) + dy;
11816
- const distance = Math.hypot(
11817
- Math.max(x3, Math.min(cx, x3 + 1)) - cx,
11818
- Math.max(y2, Math.min(cy, y2 + 1)) - cy
11819
- );
11820
- if (distance * tileMetres <= reach) candidates.push({ x: x3, y: y2, distance });
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
- candidates.sort((a, b2) => a.distance - b2.distance);
11823
- const tiles = candidates.slice(0, maxTiles);
11824
- const radius = Math.min(reach / tileMetres, candidates[tiles.length]?.distance ?? Infinity);
11825
- return { tiles, centre: [cx, cy], radius, tileMetres };
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 distance = tileflowModelCameraDistance(model, view);
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 registered = false;
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
- registered = false;
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 (registered) unregister();
13948
- registered = false;
14144
+ if (registered2) unregister();
14145
+ registered2 = false;
13949
14146
  return;
13950
14147
  }
13951
- if (!registered) unregister = scene.register(caster);
13952
- registered = true;
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.ready()) {
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 (!insideRing(ring, 0, 0, tileflowBuildingExtent, tileflowBuildingExtent)) continue;
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] }) => insideRing(ring, left, top, right, bottom) && buildingBoxVisible(frame.light.matrix, [
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 { camera: modelCamera(model) };
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 = { strengths, colours, gradients, powers, materialColours, materials, appearance };
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 insideRing(ring, left, top, right, bottom) {
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)) && insideRing(ring, box[0], box[1], box[3], box[4]) && (!hazed || buildingBoxDepth(data.mainMatrix, box) < hazeDepth);
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
- if (design().occlusion && entries.length > 0) {
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, tileflowBuildingOcclusion.ground);
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, tileflowBuildingOcclusion.ground, true);
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
- return size * max(1.0, u_minimum_height / max(size.x, 0.001));
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 registered = false;
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
- 0
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 size = colours().size;
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 * size[0], colours().minimumHeight) * shown
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
- registered = false;
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 (!registered) unregister = scene.register(caster);
17507
- registered = true;
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.0 did not expose its browser module.");
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.0 did not expose DemSource.");
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({ ...sceneOptions, map, viewMode, vegetation });
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", dispose);
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", dispose);
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", dispose);
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", dispose);
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,