@tileflow/core 0.1.0-alpha.41 → 0.1.0-alpha.43

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 (51) hide show
  1. package/README.md +51 -69
  2. package/THIRD_PARTY_NOTICES.md +1 -1
  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 +337 -34
  6. package/dist/browser.d.ts +119 -7
  7. package/dist/browser.js +754 -61
  8. package/dist/build.d.ts +8 -4
  9. package/dist/build.js +284 -4
  10. package/dist/config-reference.json +4005 -2284
  11. package/dist/{icon-composition-HUh_Lj8Z.d.ts → icon-composition-Bbw9umUA.d.ts} +46 -3
  12. package/dist/index.d.ts +22 -5
  13. package/dist/index.js +254 -6
  14. package/dist/{manifest-types-DnhSJjCM.d.ts → manifest-types-CwjHd4qc.d.ts} +10 -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.d.ts +87 -1
  19. package/dist/native.js +980 -460
  20. package/dist/runtime.d.ts +1 -1
  21. package/dist/worker/camera-tile-worker.global.js +2 -2
  22. package/package.json +4 -5
  23. package/docs/application-tile-reading.md +0 -86
  24. package/docs/authoring-model.md +0 -269
  25. package/docs/boundary-areas-and-choropleths.md +0 -217
  26. package/docs/buildings-3d.md +0 -608
  27. package/docs/camera-moves-and-tile-cache.md +0 -112
  28. package/docs/capture-scenes.md +0 -40
  29. package/docs/capture-shots.md +0 -173
  30. package/docs/cartographic-defaults.md +0 -210
  31. package/docs/compiled-style-performance.md +0 -286
  32. package/docs/data-is-separate-from-design.md +0 -610
  33. package/docs/depth-markers.md +0 -65
  34. package/docs/dynamic-style-images.md +0 -100
  35. package/docs/globe-atmosphere.md +0 -113
  36. package/docs/hosted-session-authorization.md +0 -106
  37. package/docs/map-and-terrain-examples.md +0 -156
  38. package/docs/map-emphasis.md +0 -89
  39. package/docs/native-artifact-profile.md +0 -152
  40. package/docs/native-resource-urls.md +0 -369
  41. package/docs/nautical-marks.md +0 -308
  42. package/docs/public-api-and-browser-subpath.md +0 -101
  43. package/docs/route-drawing.md +0 -191
  44. package/docs/shared-visual-primitives.md +0 -101
  45. package/docs/street-lights.md +0 -127
  46. package/docs/street-sky.md +0 -156
  47. package/docs/style-states.md +0 -73
  48. package/docs/sun-and-light.md +0 -167
  49. package/docs/theme-transitions-and-blends.md +0 -317
  50. package/docs/themes-and-module-styles.md +0 -156
  51. package/docs/trees-3d.md +0 -295
package/dist/browser.js CHANGED
@@ -2708,7 +2708,7 @@ var init_dist = __esm({
2708
2708
  function command(cmd, length) {
2709
2709
  return (length << 3) + (cmd & 7);
2710
2710
  }
2711
- function zigzag2(num2) {
2711
+ function zigzag3(num2) {
2712
2712
  return num2 << 1 ^ num2 >> 31;
2713
2713
  }
2714
2714
  function writeGeometry(feature, pbf) {
@@ -2732,8 +2732,8 @@ var init_dist = __esm({
2732
2732
  }
2733
2733
  const dx = ring[i2 * 2] - x3;
2734
2734
  const dy = ring[i2 * 2 + 1] - y2;
2735
- pbf.writeVarint(zigzag2(dx));
2736
- pbf.writeVarint(zigzag2(dy));
2735
+ pbf.writeVarint(zigzag3(dx));
2736
+ pbf.writeVarint(zigzag3(dy));
2737
2737
  x3 += dx;
2738
2738
  y2 += dy;
2739
2739
  }
@@ -3304,7 +3304,11 @@ function createTileflowDynamicImageRegistry(input, context, beforeRestore) {
3304
3304
  if (existing && existing !== entry.installed && !isRestoredCopy(existing, entry.recoveryImage)) {
3305
3305
  throw new Error(`Dynamic image "${entry.name}" conflicts with an existing image owner.`);
3306
3306
  }
3307
- if (!existing) map.addImage(entry.name, entry.pixels, { pixelRatio: entry.pixelRatio });
3307
+ if (!existing)
3308
+ map.addImage(entry.name, entry.pixels, {
3309
+ pixelRatio: entry.pixelRatio,
3310
+ ...entry.definition.sdf ? { sdf: true } : {}
3311
+ });
3308
3312
  else if (changed) map.updateImage(entry.name, entry.pixels);
3309
3313
  entry.installed = map.getImage(entry.name);
3310
3314
  entry.recoveryImage = void 0;
@@ -5737,6 +5741,59 @@ function withAlpha(color, alpha) {
5737
5741
  // src/browser.ts
5738
5742
  init_camera_limits();
5739
5743
 
5744
+ // src/horizon-queries-browser.ts
5745
+ var horizonShare2 = 0.85;
5746
+ var maximumHorizonAngle = 89.25 * Math.PI / 180;
5747
+ function tileflowHorizonScaleFactor(view) {
5748
+ const pitch = view.pitch * Math.PI / 180;
5749
+ const horizon = Math.min(
5750
+ Math.tan(Math.PI / 2 - pitch) * horizonShare2,
5751
+ Math.tan(maximumHorizonAngle - pitch)
5752
+ );
5753
+ const top = Math.min(view.centerY / view.cameraToCenterDistance, horizon);
5754
+ return 1 / (1 - Math.tan(pitch) * top);
5755
+ }
5756
+ function attachTileflowHorizonQueries(map) {
5757
+ const target = map;
5758
+ const query = target.queryRenderedFeatures;
5759
+ if (typeof query !== "function") return () => {
5760
+ };
5761
+ const own = Object.prototype.hasOwnProperty.call(target, "queryRenderedFeatures");
5762
+ const corrected = /* @__PURE__ */ new Map();
5763
+ const correct = (transform) => {
5764
+ const original = transform?.maxPitchScaleFactor;
5765
+ if (!transform || typeof original !== "function" || corrected.has(transform)) return;
5766
+ const own2 = Object.prototype.hasOwnProperty.call(transform, "maxPitchScaleFactor");
5767
+ corrected.set(transform, own2 ? original : void 0);
5768
+ transform.maxPitchScaleFactor = function() {
5769
+ const value = original.call(this);
5770
+ if (value > 0 && Number.isFinite(value)) return value;
5771
+ const fallback = tileflowHorizonScaleFactor({
5772
+ pitch: this.pitch,
5773
+ centerY: this.centerPoint.y,
5774
+ cameraToCenterDistance: this.cameraToCenterDistance
5775
+ });
5776
+ return fallback > 0 && Number.isFinite(fallback) ? fallback : value;
5777
+ };
5778
+ };
5779
+ const wrapped = function(...args) {
5780
+ correct(target._camera?.transform ?? target.transform);
5781
+ return query.apply(this, args);
5782
+ };
5783
+ target.queryRenderedFeatures = wrapped;
5784
+ return () => {
5785
+ if (target.queryRenderedFeatures === wrapped) {
5786
+ if (own) target.queryRenderedFeatures = query;
5787
+ else delete target.queryRenderedFeatures;
5788
+ }
5789
+ for (const [transform, original] of corrected) {
5790
+ if (original) transform.maxPitchScaleFactor = original;
5791
+ else delete transform.maxPitchScaleFactor;
5792
+ }
5793
+ corrected.clear();
5794
+ };
5795
+ }
5796
+
5740
5797
  // src/canvas-context-browser.ts
5741
5798
  function tileflowCanvasContextAttributes(attributes4) {
5742
5799
  return { antialias: true, ...attributes4 };
@@ -6384,8 +6441,12 @@ function readModelRoleLighting(value) {
6384
6441
  ...typeof entry.emissiveColor === "string" ? { emissiveColor: entry.emissiveColor } : {},
6385
6442
  ...typeof entry.color === "string" ? { color: entry.color } : {},
6386
6443
  ...entry.colorMix === void 0 ? {} : { colorMix: bounded(entry.colorMix, 0, 1, 1) },
6444
+ ...entry.colorScale === void 0 ? {} : { colorScale: bounded(entry.colorScale, 0, 1, 1) },
6387
6445
  ...entry.metallic === void 0 ? {} : { metallic: bounded(entry.metallic, 0, 1, 0) },
6388
6446
  ...entry.roughness === void 0 ? {} : { roughness: bounded(entry.roughness, 0, 1, 1) },
6447
+ ...entry.shading === "map" || entry.shading === "physical" ? { shading: entry.shading } : {},
6448
+ ...entry.ambientOcclusion === void 0 ? {} : { ambientOcclusion: bounded(entry.ambientOcclusion, 0, 1, 1) },
6449
+ ...entry.partColorMix === void 0 ? {} : { partColorMix: bounded(entry.partColorMix, 0, 1, 1) },
6389
6450
  ...readRoleColorVariation(entry.colorVariation),
6390
6451
  emissiveHeight: Array.isArray(gradient) && gradient.length === 5 && gradient.every(
6391
6452
  (v2, i2) => typeof v2 === "number" && Number.isFinite(v2) && v2 <= 1 && v2 >= (i2 === 4 ? -1 : 0)
@@ -6482,6 +6543,8 @@ var tileflowDefaultBuildings3DDesign = Object.freeze({
6482
6543
  windows: false,
6483
6544
  shadows: true,
6484
6545
  occlusion: true,
6546
+ groundOcclusion: 0.16,
6547
+ groundOcclusionRadius: 3,
6485
6548
  modelOcclusion: 0.75
6486
6549
  });
6487
6550
  function readTileflowBuildings3D(metadata) {
@@ -6505,7 +6568,7 @@ function readTileflowBuildings3D(metadata) {
6505
6568
  },
6506
6569
  color,
6507
6570
  edges: within(value.edges, 1, 0),
6508
- edgeRadius: within(value.edgeRadius, 1, defaults.edgeRadius),
6571
+ edgeRadius: within(value.edgeRadius, 1.5, defaults.edgeRadius),
6509
6572
  lighting: value.lighting === "style" ? "style" : defaults.lighting,
6510
6573
  colorVariation: within(value.colorVariation, 1, 0),
6511
6574
  verticalGradient: value.verticalGradient !== false,
@@ -6518,7 +6581,12 @@ function readTileflowBuildings3D(metadata) {
6518
6581
  ...readTileflowBuildingsEntrance(value.entrance),
6519
6582
  shadows: typeof value.shadows === "boolean" ? value.shadows : defaults.shadows,
6520
6583
  occlusion: typeof value.occlusion === "boolean" ? value.occlusion : defaults.occlusion,
6584
+ groundOcclusion: within(value.groundOcclusion, 1, defaults.groundOcclusion),
6585
+ groundOcclusionRadius: within(value.groundOcclusionRadius, 20, defaults.groundOcclusionRadius),
6521
6586
  modelOcclusion: within(value.modelOcclusion, 1, defaults.modelOcclusion),
6587
+ ...Array.isArray(value.flatLayers) && value.flatLayers.length <= 128 && value.flatLayers.every(
6588
+ (entry) => isRecord6(entry) && typeof entry.id === "string" && typeof entry.visible === "boolean"
6589
+ ) ? { flatLayers: value.flatLayers } : {},
6522
6590
  ...modelsOf(value.models),
6523
6591
  ...modelColorsOf(value.modelColors),
6524
6592
  ...landmarksOf(value.landmarks)
@@ -7525,7 +7593,7 @@ function meshTileflowBuildings(layer, options) {
7525
7593
  const scale = tileflowBuildingExtent / layer.extent;
7526
7594
  const metresPerUnit = options.tileMetres / tileflowBuildingExtent;
7527
7595
  const fallback = options.defaultHeight ?? 5;
7528
- const edgeRadius = Number.isFinite(options.edgeRadius) ? Math.max(0, Math.min(1, options.edgeRadius)) / metresPerUnit : 0;
7596
+ const edgeRadius = Number.isFinite(options.edgeRadius) ? Math.max(0, Math.min(1.5, options.edgeRadius)) / metresPerUnit : 0;
7529
7597
  const vertices = new VertexWriter();
7530
7598
  const roofs = new IndexWriter();
7531
7599
  const walls = new IndexWriter();
@@ -9745,6 +9813,9 @@ function readTileflowVegetation3D(metadata) {
9745
9813
  {
9746
9814
  heightScale: scale(own.heightScale),
9747
9815
  crownScale: scale(own.crownScale),
9816
+ ...typeof own.sizeAnchor === "number" && Number.isFinite(own.sizeAnchor) ? { sizeAnchor: clamp(own.sizeAnchor, [1, 45]) } : {},
9817
+ ...typeof own.crownAnchor === "number" && Number.isFinite(own.crownAnchor) ? { crownAnchor: clamp(own.crownAnchor, [1, 25]) } : {},
9818
+ ...typeof own.sizeCompression === "number" && Number.isFinite(own.sizeCompression) ? { sizeCompression: clamp(own.sizeCompression, [0, 1]) } : {},
9748
9819
  ...drawn.length > 0 ? { models: drawn } : {}
9749
9820
  }
9750
9821
  ]
@@ -10064,7 +10135,7 @@ function browserWorker() {
10064
10135
  if (typeof Worker === "undefined" || false)
10065
10136
  return;
10066
10137
  const url = URL.createObjectURL(
10067
- 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,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" })
10138
+ 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" })
10068
10139
  );
10069
10140
  try {
10070
10141
  return new Worker(url, { name: "tileflow-tiles" });
@@ -11054,7 +11125,7 @@ var protocolPrefix = `${tileflowPmtilesProtocol}://`;
11054
11125
  function registerTileflowPmtilesProtocol(registry, options = {}) {
11055
11126
  if (registeredPmtilesProtocols.has(registry.addProtocol)) return;
11056
11127
  const maximumDirectoryDepth = normalizeMaximumDirectoryDepth(options.maximumDirectoryDepth);
11057
- const protocol2 = new TileflowPmtilesProtocol(maximumDirectoryDepth);
11128
+ const protocol2 = new TileflowPmtilesProtocol(maximumDirectoryDepth, options.transformArchiveUrl);
11058
11129
  sharedProtocol ??= protocol2;
11059
11130
  registry.addProtocol(tileflowPmtilesProtocol, protocol2.tile);
11060
11131
  registeredPmtilesProtocols.add(registry.addProtocol);
@@ -11076,10 +11147,12 @@ function isTileflowPmtilesUrl(url) {
11076
11147
  return url.startsWith(protocolPrefix);
11077
11148
  }
11078
11149
  var TileflowPmtilesProtocol = class {
11079
- constructor(maximumDirectoryDepth) {
11150
+ constructor(maximumDirectoryDepth, transformArchiveUrl = (url) => url) {
11080
11151
  this.maximumDirectoryDepth = maximumDirectoryDepth;
11152
+ this.transformArchiveUrl = transformArchiveUrl;
11081
11153
  }
11082
11154
  maximumDirectoryDepth;
11155
+ transformArchiveUrl;
11083
11156
  #archives = /* @__PURE__ */ new Map();
11084
11157
  tilev4 = async (request, abortController) => {
11085
11158
  if (request.type === "json") {
@@ -11112,7 +11185,10 @@ var TileflowPmtilesProtocol = class {
11112
11185
  #archive(target) {
11113
11186
  let archive = this.#archives.get(target);
11114
11187
  if (!archive) {
11115
- archive = new TileflowPmtilesArchive(target, this.maximumDirectoryDepth);
11188
+ archive = new TileflowPmtilesArchive(
11189
+ this.transformArchiveUrl(target),
11190
+ this.maximumDirectoryDepth
11191
+ );
11116
11192
  this.#archives.set(target, archive);
11117
11193
  }
11118
11194
  return archive;
@@ -11569,7 +11645,7 @@ function createCameraTiles(options) {
11569
11645
  }
11570
11646
  entry.used = now;
11571
11647
  entry.distance = distance;
11572
- if ((!entry.value || entry.retryAt !== void 0) && !entry.loading && (entry.retryAt ?? 0) <= now)
11648
+ if ((!entry.value && !entry.pending || entry.retryAt !== void 0) && !entry.loading && (entry.retryAt ?? 0) <= now)
11573
11649
  load(source, key, entry, chosen.tileMetres);
11574
11650
  }
11575
11651
  evict();
@@ -11585,6 +11661,8 @@ function createCameraTiles(options) {
11585
11661
  ).then((tile) => {
11586
11662
  if (disposed || tiles.get(key) !== entry || entry.loading !== controller) return;
11587
11663
  if (!tile) {
11664
+ if (entry.pending && entry.pending !== options.empty) options.release(entry.pending);
11665
+ entry.pending = void 0;
11588
11666
  if (entry.value && entry.value !== options.empty) options.release(entry.value);
11589
11667
  entry.value = options.empty;
11590
11668
  entry.loading = void 0;
@@ -11633,10 +11711,11 @@ function createCameraTiles(options) {
11633
11711
  if (value !== options.empty) options.release(value);
11634
11712
  continue;
11635
11713
  }
11636
- const previous = entry.value;
11637
- entry.value = value;
11714
+ if (entry.pending && entry.pending !== options.empty && entry.pending !== value)
11715
+ options.release(entry.pending);
11716
+ entry.pending = value;
11638
11717
  entry.loading = void 0;
11639
- if (previous && previous !== options.empty && previous !== value) options.release(previous);
11718
+ commit(entry);
11640
11719
  built = true;
11641
11720
  }
11642
11721
  if (built && !disposed) {
@@ -11653,12 +11732,24 @@ function createCameraTiles(options) {
11653
11732
  void step();
11654
11733
  });
11655
11734
  }
11735
+ function commit(entry) {
11736
+ const value = entry.pending;
11737
+ if (value === void 0 || value !== options.empty && options.isReady && !options.isReady(value))
11738
+ return;
11739
+ const previous = entry.value;
11740
+ entry.value = value;
11741
+ entry.pending = void 0;
11742
+ if (previous && previous !== options.empty && previous !== value) options.release(previous);
11743
+ options.changed();
11744
+ map.triggerRepaint();
11745
+ }
11656
11746
  function evict() {
11657
11747
  const keep = new Set(wanted);
11658
11748
  const spare = [...tiles.entries()].filter(([key]) => !keep.has(key)).sort((a, b2) => b2[1].used - a[1].used);
11659
11749
  for (const [key, entry] of spare.slice(options.maxTiles)) {
11660
11750
  entry.loading?.abort();
11661
11751
  if (entry.value && entry.value !== options.empty) options.release(entry.value);
11752
+ if (entry.pending && entry.pending !== options.empty) options.release(entry.pending);
11662
11753
  tiles.delete(key);
11663
11754
  options.changed();
11664
11755
  }
@@ -11684,11 +11775,19 @@ function createCameraTiles(options) {
11684
11775
  const list = [];
11685
11776
  for (const key of wanted) {
11686
11777
  const entry = tiles.get(key);
11778
+ if (entry) commit(entry);
11687
11779
  if (entry?.value && entry.value !== options.empty)
11688
11780
  list.push(entry);
11689
11781
  }
11690
11782
  return list;
11691
11783
  },
11784
+ built() {
11785
+ return wanted.flatMap((key) => {
11786
+ const entry = tiles.get(key);
11787
+ const value = entry?.pending ?? entry?.value;
11788
+ return entry && value && value !== options.empty ? [{ ...entry, value }] : [];
11789
+ });
11790
+ },
11692
11791
  coverage: () => covered,
11693
11792
  ring: () => ring,
11694
11793
  all: () => tiles.values(),
@@ -11710,6 +11809,8 @@ function createCameraTiles(options) {
11710
11809
  for (const [key, entry] of tiles) {
11711
11810
  if (!which(entry)) continue;
11712
11811
  entry.loading?.abort();
11812
+ if (entry.pending && entry.pending !== options.empty) options.release(entry.pending);
11813
+ entry.pending = void 0;
11713
11814
  entry.retryAt = void 0;
11714
11815
  const latitude = Math.atan(Math.sinh(Math.PI * (1 - 2 * (entry.y + 0.5) / 2 ** zoom))) * 180 / Math.PI;
11715
11816
  load(source, key, entry, earth * Math.cos(latitude * Math.PI / 180) / 2 ** zoom);
@@ -11722,7 +11823,10 @@ function createCameraTiles(options) {
11722
11823
  map.off("sourcedata", onSource);
11723
11824
  map.off("move", onMove);
11724
11825
  map.off("moveend", onMoveEnd);
11725
- for (const entry of tiles.values()) entry.loading?.abort();
11826
+ for (const entry of tiles.values()) {
11827
+ entry.loading?.abort();
11828
+ if (entry.pending && entry.pending !== options.empty) options.release(entry.pending);
11829
+ }
11726
11830
  tiles.clear();
11727
11831
  queue.length = 0;
11728
11832
  reader?.clear();
@@ -12449,7 +12553,9 @@ function tileflowModelCameraDistance(model, view) {
12449
12553
  function tileflowModelLevel(model, view, previous) {
12450
12554
  const thresholds = tileflowModelLevelDistancesOf(model.bounds);
12451
12555
  const last = Math.max(0, Math.min(model.levels, thresholds.length + 1) - 1);
12452
- const distance = tileflowModelCameraDistance(model, view);
12556
+ const fov = view.verticalFieldOfView;
12557
+ const lens = fov !== void 0 && fov > 0 && fov < 180 ? Math.tan(fov * Math.PI / 360) * 3 : 1;
12558
+ const distance = tileflowModelCameraDistance(model, view) * lens;
12453
12559
  if (!Number.isFinite(distance)) return 0;
12454
12560
  const margin = previous === void 0 ? 1 : tileflowModelLevelHysteresis;
12455
12561
  let level = Math.max(0, Math.min(last, previous ?? 0));
@@ -12741,6 +12847,7 @@ uniform bool u_unlit;
12741
12847
  uniform vec4 u_parts[${tileflowModelLimits.parts}];
12742
12848
  uniform vec4 u_role_colour[7];
12743
12849
  uniform vec4 u_role_material[7]; // metallic, roughness, their respective override weights
12850
+ uniform vec3 u_role_appearance[7]; // map shading share, ambient occlusion multiplier, part colour share
12744
12851
 
12745
12852
  vec3 fromSRGB(vec3 colour) {
12746
12853
  return pow(max(colour, vec3(0.0)), vec3(2.2));
@@ -12771,7 +12878,7 @@ vec3 materialBase(int role) {
12771
12878
  vec4 own = u_role_colour[role];
12772
12879
  vec3 factor = mix(u_base_colour.rgb, fromSRGB(own.rgb), own.a);
12773
12880
  vec4 part = u_parts[v_part];
12774
- factor = mix(factor, fromSRGB(part.rgb), part.a);
12881
+ factor = mix(factor, fromSRGB(part.rgb), part.a * u_role_appearance[role].z);
12775
12882
  return factor * v_rgba.rgb * fromSRGB(materialTexture(0).rgb);
12776
12883
  }
12777
12884
 
@@ -12808,7 +12915,7 @@ vec3 physicalLight(vec3 base, vec3 normal, float lit, int role) {
12808
12915
  float exposure = (0.96 + 0.04 * clamp(normal.z, -1.0, 1.0)) *
12809
12916
  (1.0 - 0.3 * min(directional, 1.0) * max(-dot(normal, u_sun_dir), 0.0));
12810
12917
  float ao = mix(1.0, v_light * mix(1.0, materialTexture(3).r, u_occlusion_strength),
12811
- u_ambient_occlusion);
12918
+ u_ambient_occlusion * u_role_appearance[role].y);
12812
12919
  vec3 ambient = (diffuse + reflectedSky) * u_sky_light * exposure * ao;
12813
12920
  return ambient + min(direct, vec3(1.0));
12814
12921
  }
@@ -12901,6 +13008,7 @@ out vec3 v_shadow;
12901
13008
  out float v_light;
12902
13009
  flat out int v_lighting_role;
12903
13010
  out float v_height;
13011
+ out float v_ground_height;
12904
13012
  out vec4 v_uv;
12905
13013
  out vec4 v_rgba;
12906
13014
  out vec3 v_position;
@@ -12929,6 +13037,7 @@ void main() {
12929
13037
  v_light = a_paint.z / 255.0;
12930
13038
  v_lighting_role = clamp(int(a_lighting_role + 0.5), 0, 6);
12931
13039
  v_height = (m.z - u_model_height.x) / max(u_model_height.y, 0.001);
13040
+ v_ground_height = m.z;
12932
13041
  }`;
12933
13042
  var tileflowModelFragment = `#version 300 es
12934
13043
  precision highp float;
@@ -12938,6 +13047,9 @@ in vec3 v_shadow;
12938
13047
  in float v_light;
12939
13048
  flat in int v_lighting_role;
12940
13049
  in float v_height;
13050
+ in float v_ground_height;
13051
+ uniform vec3 u_facade_shading; // vertical gradient, ground-contact strength and radius in metres
13052
+ uniform float u_role_color_scale[7];
12941
13053
  uniform vec3 u_sun_dir;
12942
13054
  uniform vec3 u_sun_light;
12943
13055
  uniform vec3 u_sky_light;
@@ -12956,15 +13068,25 @@ ${modelPhysicalLighting}
12956
13068
 
12957
13069
  // The buildings' light: a sunlit roof keeps its colour, a face turned to a low sun glows, and shade
12958
13070
  // takes the sky's colour; a face that looks down sees little sky.
12959
- vec3 shade(vec3 normal, float lit) {
13071
+ vec3 shade(vec3 normal, float lit, float occlusion) {
12960
13072
  float facing = dot(normal, u_sun_dir);
12961
13073
  vec3 sky = u_sky_light * mix(mix(0.8, 0.5, u_night), 1.0, max(normal.z, -0.4));
12962
- sky *= mix(1.0, v_light, u_ambient_occlusion);
13074
+ sky *= mix(1.0, v_light, u_ambient_occlusion * occlusion);
12963
13075
  vec3 light = sky + u_sun_light * max(facing, 0.0) * (1.0 - u_shadow * (1.0 - lit));
12964
13076
  vec3 roof = u_sky_light + u_sun_light * max(u_sun_dir.z, 0.0);
12965
13077
  return min(pow(light / max(roof, vec3(1e-4)), vec3(1.0 / 2.2)), vec3(1.7));
12966
13078
  }
12967
13079
 
13080
+ // Same quiet ground-to-facade transition as ordinary tile buildings, evaluated in metres.
13081
+ // Only map-shaded roles opt in; roofs and physical materials keep their own response.
13082
+ float facadeShade(vec3 normal, int role) {
13083
+ float wall = 1.0 - abs(normal.z);
13084
+ float up = max(v_ground_height, 0.0);
13085
+ float gradient = 0.1 * u_facade_shading.x * (1.0 - smoothstep(0.0, 3.0, up));
13086
+ float contact = u_facade_shading.y * exp(-up / max(u_facade_shading.z, 0.001));
13087
+ return 1.0 - max(gradient, contact) * wall * u_role_appearance[role].x;
13088
+ }
13089
+
12968
13090
  void main() {
12969
13091
  vec3 normal = normalize(gl_FrontFacing ? v_normal : -v_normal);
12970
13092
  if (u_physical) normal = materialNormal(normal);
@@ -12979,15 +13101,24 @@ void main() {
12979
13101
  float emission = clamp(u_role_emission[role] * multiplier, 0.0, 1.0);
12980
13102
  if (u_physical) {
12981
13103
  float alpha = materialAlpha();
12982
- vec3 base = materialBase(role);
12983
- vec3 radiance = physicalLight(base, normal, lit, role);
13104
+ vec3 base = materialBase(role) * fromSRGB(vec3(u_role_color_scale[role]));
13105
+ float mapShare = u_role_appearance[role].x;
13106
+ vec3 radiance;
13107
+ if (mapShare >= 1.0) {
13108
+ radiance = base * fromSRGB(shade(normal, lit, u_role_appearance[role].y));
13109
+ } else {
13110
+ radiance = physicalLight(base, normal, lit, role);
13111
+ if (mapShare > 0.0)
13112
+ radiance = mix(radiance, base * fromSRGB(shade(normal, lit, u_role_appearance[role].y)), mapShare);
13113
+ }
13114
+ radiance *= fromSRGB(vec3(facadeShade(normal, role)));
12984
13115
  radiance += u_emissive * fromSRGB(materialTexture(4).rgb);
12985
13116
  vec4 own = u_role_emission_colour[role];
12986
13117
  radiance = mix(radiance, mix(base, fromSRGB(own.rgb), own.a), emission);
12987
13118
  fragColor = vec4(hazed(toSRGB(radiance)), alpha * u_opacity);
12988
13119
  return;
12989
13120
  }
12990
- vec3 colour = v_colour * shade(normal, lit);
13121
+ vec3 colour = v_colour * u_role_color_scale[role] * shade(normal, lit, u_role_appearance[role].y) * facadeShade(normal, role);
12991
13122
  if (emission > 0.0) {
12992
13123
  vec4 own = u_role_emission_colour[role];
12993
13124
  vec3 target = mix(v_colour, own.rgb, own.a);
@@ -13779,7 +13910,7 @@ function sampleModelRole(profile, identity) {
13779
13910
  };
13780
13911
  const variation = profile?.colorVariation;
13781
13912
  let color = profile?.color ? tileflowColourChannels(profile.color)?.slice(0, 3) : void 0;
13782
- if (variation) {
13913
+ if (variation && !color) {
13783
13914
  const hsl = [variation.hue, variation.saturation, variation.lightness].map(
13784
13915
  ([low, high], channel) => low + (high - low) * random(channel + 1)
13785
13916
  );
@@ -13845,7 +13976,7 @@ function createTileflowBuildings3D(options) {
13845
13976
  let ahead = [0, -1];
13846
13977
  const scene = tileflowScene3D(map);
13847
13978
  let generation = 0;
13848
- let registered = false;
13979
+ let registered2 = false;
13849
13980
  let unregister = () => {
13850
13981
  };
13851
13982
  const models = createTileflowPlacedModels({
@@ -13894,7 +14025,7 @@ function createTileflowBuildings3D(options) {
13894
14025
  if (program) context.deleteProgram(program.program);
13895
14026
  for (const entry of linking ?? []) context.deleteProgram(entry.program);
13896
14027
  unregister();
13897
- registered = false;
14028
+ registered2 = false;
13898
14029
  scene.setReach(void 0);
13899
14030
  scene.release(context);
13900
14031
  if (ground) {
@@ -13925,12 +14056,12 @@ function createTileflowBuildings3D(options) {
13925
14056
  drawMasks(context, args);
13926
14057
  if (!programs.depth) return;
13927
14058
  if (!design().shadows || visibleScale() <= 0 && modelScale() <= 0) {
13928
- if (registered) unregister();
13929
- registered = false;
14059
+ if (registered2) unregister();
14060
+ registered2 = false;
13930
14061
  return;
13931
14062
  }
13932
- if (!registered) unregister = scene.register(caster);
13933
- registered = true;
14063
+ if (!registered2) unregister = scene.register(caster);
14064
+ registered2 = true;
13934
14065
  scene.prepare(context, lighting(), camera.metres);
13935
14066
  },
13936
14067
  render(context, args) {
@@ -13987,6 +14118,7 @@ function createTileflowBuildings3D(options) {
13987
14118
  return prepared ? { mesh: prepared.mesh, data: prepared.data } : emptyTile;
13988
14119
  },
13989
14120
  empty: emptyTile,
14121
+ isReady: (value) => value === emptyTile || value.gl !== void 0,
13990
14122
  release(value) {
13991
14123
  if (gl) release(gl, value);
13992
14124
  },
@@ -14047,7 +14179,7 @@ function createTileflowBuildings3D(options) {
14047
14179
  models.upload(context);
14048
14180
  if (modelKey !== models.key()) map.triggerRepaint();
14049
14181
  let budget = 2;
14050
- for (const { value: entry } of camera.ready()) {
14182
+ for (const { value: entry } of camera.built()) {
14051
14183
  if (entry.gl || !entry.data) continue;
14052
14184
  if (budget-- <= 0) {
14053
14185
  map.triggerRepaint();
@@ -14290,7 +14422,7 @@ function createTileflowBuildings3D(options) {
14290
14422
  for (const { x: x3, y: y2, value } of shown > 0 ? drawn() : []) {
14291
14423
  const offset = frame.offsetOf({ x: x3, y: y2 }, camera.zoom);
14292
14424
  const ring = ringIn(x3, y2);
14293
- if (!insideRing(ring, 0, 0, tileflowBuildingExtent, tileflowBuildingExtent)) continue;
14425
+ if (!insideRing2(ring, 0, 0, tileflowBuildingExtent, tileflowBuildingExtent)) continue;
14294
14426
  if (!buildingBoxVisible(frame.light.matrix, [
14295
14427
  (offset[0] - 1) * frame.metres,
14296
14428
  -(offset[1] + tileflowBuildingExtent + 1) * frame.metres,
@@ -14302,7 +14434,7 @@ function createTileflowBuildings3D(options) {
14302
14434
  continue;
14303
14435
  const ranges = buildingDrawRanges(
14304
14436
  value.mesh,
14305
- ({ bounds: [left, top, right, bottom, height] }) => insideRing(ring, left, top, right, bottom) && buildingBoxVisible(frame.light.matrix, [
14437
+ ({ bounds: [left, top, right, bottom, height] }) => insideRing2(ring, left, top, right, bottom) && buildingBoxVisible(frame.light.matrix, [
14306
14438
  (left + offset[0]) * frame.metres,
14307
14439
  -(bottom + offset[1]) * frame.metres,
14308
14440
  0,
@@ -14383,7 +14515,10 @@ function createTileflowBuildings3D(options) {
14383
14515
  return [ax - reach, ay - reach, Math.min(0, low), ax + reach, ay + reach, high + 0.1];
14384
14516
  }
14385
14517
  function modelView(model) {
14386
- return { camera: modelCamera(model) };
14518
+ return {
14519
+ camera: modelCamera(model),
14520
+ verticalFieldOfView: map.getVerticalFieldOfView?.()
14521
+ };
14387
14522
  }
14388
14523
  function levelOf(model) {
14389
14524
  return models.levelOf(model, modelView(model));
@@ -14505,11 +14640,17 @@ function createTileflowBuildings3D(options) {
14505
14640
  const gradients = new Float32Array(28);
14506
14641
  const powers = new Float32Array(7);
14507
14642
  const materialColours = new Float32Array(28);
14643
+ const colorScales = new Float32Array(7);
14508
14644
  const materials = new Float32Array(28);
14645
+ const appearance = new Float32Array(21);
14509
14646
  for (const [role, id] of Object.entries(tileflowModelLightingRoles)) {
14510
14647
  const from = themes[lower].modelLighting?.[role], to = themes[upper].modelLighting?.[role];
14511
14648
  const sampledFrom = sampleModelRole(from, `${identity}:${role}`);
14512
14649
  const sampledTo = sampleModelRole(to, `${identity}:${role}`);
14650
+ colorScales[id] = (from?.colorScale ?? 1) * (1 - mix2) + (to?.colorScale ?? 1) * mix2;
14651
+ appearance[id * 3] = (from?.shading === "map" ? 1 - mix2 : 0) + (to?.shading === "map" ? mix2 : 0);
14652
+ appearance[id * 3 + 1] = (from?.ambientOcclusion ?? 1) * (1 - mix2) + (to?.ambientOcclusion ?? 1) * mix2;
14653
+ appearance[id * 3 + 2] = (from?.partColorMix ?? 1) * (1 - mix2) + (to?.partColorMix ?? 1) * mix2;
14513
14654
  strengths[id] = sampledFrom.strength * (1 - mix2) + sampledTo.strength * mix2;
14514
14655
  const ca = sampledFrom.color, cb = sampledTo.color;
14515
14656
  for (let channel = 0; channel < 3; channel++)
@@ -14529,7 +14670,16 @@ function createTileflowBuildings3D(options) {
14529
14670
  gradients[id * 4 + component] = first[component] * (1 - mix2) + second[component] * mix2;
14530
14671
  powers[id] = first[4] * (1 - mix2) + second[4] * mix2;
14531
14672
  }
14532
- const result = { strengths, colours, gradients, powers, materialColours, materials };
14673
+ const result = {
14674
+ strengths,
14675
+ colours,
14676
+ gradients,
14677
+ powers,
14678
+ materialColours,
14679
+ colorScales,
14680
+ materials,
14681
+ appearance
14682
+ };
14533
14683
  if (modelLightingCache.size >= 1024)
14534
14684
  modelLightingCache.delete(modelLightingCache.keys().next().value);
14535
14685
  modelLightingCache.set(identity, result);
@@ -14598,7 +14748,7 @@ function createTileflowBuildings3D(options) {
14598
14748
  const bearing = map.getBearing() * Math.PI / 180;
14599
14749
  return [Math.sin(bearing), -Math.cos(bearing)];
14600
14750
  }
14601
- function insideRing(ring, left, top, right, bottom) {
14751
+ function insideRing2(ring, left, top, right, bottom) {
14602
14752
  const radius = ring[3];
14603
14753
  if (!(radius > 0)) return true;
14604
14754
  const cx = ring[0];
@@ -14617,7 +14767,7 @@ function createTileflowBuildings3D(options) {
14617
14767
  const reach = margin / camera.metres + 1;
14618
14768
  const ring = ringIn(tile.x, tile.y);
14619
14769
  const hazed = mercator && hazeDepth < Infinity;
14620
- const shows = (box) => (!mercator || buildingBoxVisible(data.mainMatrix, box)) && insideRing(ring, box[0], box[1], box[3], box[4]) && (!hazed || buildingBoxDepth(data.mainMatrix, box) < hazeDepth);
14770
+ const shows = (box) => (!mercator || buildingBoxVisible(data.mainMatrix, box)) && insideRing2(ring, box[0], box[1], box[3], box[4]) && (!hazed || buildingBoxDepth(data.mainMatrix, box) < hazeDepth);
14621
14771
  const extent5 = tileflowBuildingExtent + reach;
14622
14772
  if (!shows([-reach, -reach, 0, extent5, extent5, tile.value.mesh.top + 0.1])) return [];
14623
14773
  return buildingDrawRanges(
@@ -14664,20 +14814,21 @@ function createTileflowBuildings3D(options) {
14664
14814
  masks = {};
14665
14815
  const shown = visibleScale();
14666
14816
  const entries = variant === args.shaderData.variantName && shown > 0 && ground ? drawn() : [];
14667
- if (design().occlusion && entries.length > 0) {
14817
+ const contactRadius = mixed2((entry) => entry.groundOcclusionRadius ?? tileflowBuildingOcclusion.ground);
14818
+ if (design().occlusion && contactRadius > 0 && entries.length > 0) {
14668
14819
  const program = programs.contact;
14669
14820
  masks.contact = contactMask.render(context, () => {
14670
14821
  context.useProgram(program.program);
14671
14822
  context.uniform1f(program.uniforms.u_scale, shown);
14672
14823
  context.uniform1f(program.uniforms.u_metres, camera.metres);
14673
- context.uniform1f(program.uniforms.u_band, tileflowBuildingOcclusion.ground);
14824
+ context.uniform1f(program.uniforms.u_band, contactRadius);
14674
14825
  context.uniform1f(
14675
14826
  program.uniforms.u_band_strength,
14676
- tileflowBuildingOcclusion.groundStrength * visibleOpacity()
14827
+ mixed2((entry) => entry.groundOcclusion ?? tileflowBuildingOcclusion.groundStrength) * visibleOpacity()
14677
14828
  );
14678
14829
  for (const tile of entries) {
14679
14830
  const { x: x3, y: y2, value } = tile;
14680
- const ranges = viewRanges(args, tile, tileflowBuildingOcclusion.ground, true);
14831
+ const ranges = viewRanges(args, tile, contactRadius, true);
14681
14832
  if (!ranges.length) continue;
14682
14833
  const { contact } = value.gl;
14683
14834
  project(context, program, args, x3, y2);
@@ -14885,6 +15036,12 @@ function createTileflowBuildings3D(options) {
14885
15036
  context.uniform3fv(m.u_sun_light, light.sunLight);
14886
15037
  context.uniform3fv(m.u_sky_light, light.skyLight);
14887
15038
  context.uniform1f(m.u_night, light.night);
15039
+ context.uniform3f(
15040
+ m.u_facade_shading,
15041
+ mixed2((entry) => entry.verticalGradient ? 1 : 0),
15042
+ occlusionOn ? mixed2((entry) => entry.groundOcclusion ?? 0.16) : 0,
15043
+ mixed2((entry) => entry.groundOcclusionRadius ?? 3)
15044
+ );
14888
15045
  context.uniform1f(
14889
15046
  m.u_ambient_occlusion,
14890
15047
  occlusionOn ? mixed2((entry) => entry.modelOcclusion ?? 0.75) : 0
@@ -14901,7 +15058,9 @@ function createTileflowBuildings3D(options) {
14901
15058
  context.uniform4fv(m.u_role_emission_gradient, emission.gradients);
14902
15059
  context.uniform1fv(m.u_role_emission_power, emission.powers);
14903
15060
  context.uniform4fv(m.u_role_colour, emission.materialColours);
15061
+ context.uniform1fv(m.u_role_color_scale, emission.colorScales);
14904
15062
  context.uniform4fv(m.u_role_material, emission.materials);
15063
+ context.uniform3fv(m.u_role_appearance, emission.appearance);
14905
15064
  const at = placed2(stand.tileX, stand.tileY);
14906
15065
  context.uniform2f(m.u_offset, ...at.offset);
14907
15066
  context.uniform1f(m.u_metres, at.metres);
@@ -15039,7 +15198,7 @@ function createTileflowBuildings3D(options) {
15039
15198
  if (strength <= 0) continue;
15040
15199
  const own = lighting2.colours.subarray(role * 4, role * 4 + 4);
15041
15200
  const tint = lighting2.materialColours.subarray(role * 4, role * 4 + 4);
15042
- const tintWeight = tint[3] * (1 - part[3]);
15201
+ const tintWeight = tint[3] * (1 - part[3] * lighting2.appearance[role * 3 + 2]);
15043
15202
  const colour = [0, 1, 2].map(
15044
15203
  (channel) => own[3] > 0 ? own[channel] : part[channel] * (1 - tintWeight) + tint[channel] * tintWeight
15045
15204
  );
@@ -16452,6 +16611,7 @@ uniform float u_metres; // metres per tile unit
16452
16611
  uniform vec2 u_offset; // this tile's corner from the scene's origin, in tile units
16453
16612
  uniform float u_minimum_height; // optional visual height floor, in metres
16454
16613
  uniform vec2 u_size_scale; // the map's height and crown scales, for this form
16614
+ uniform vec3 u_size_compression; // reference height, reference crown, strength
16455
16615
  uniform float u_round; // how far normals turn from the facets to the round shape, by finish
16456
16616
 
16457
16617
  float growthOf() {
@@ -16468,7 +16628,14 @@ vec2 turned(vec2 v) {
16468
16628
 
16469
16629
  vec2 displaySize() {
16470
16630
  vec2 size = a_tree_size * 0.1 * u_size_scale;
16471
- return size * max(1.0, u_minimum_height / max(size.x, 0.001));
16631
+ size *= max(1.0, u_minimum_height / max(size.x, 0.001));
16632
+ // Scale the complete tree together to preserve crown, trunk and branch proportions.
16633
+ if (u_size_compression.z > 0.0) {
16634
+ vec2 relative = max(u_size_compression.xy, vec2(0.001)) / max(size, vec2(0.001));
16635
+ // Balance height and footprint, so a short but broad crown is not enlarged.
16636
+ size *= min(1.35, pow(relative.x * relative.y, u_size_compression.z * 0.5));
16637
+ }
16638
+ return size;
16472
16639
  }
16473
16640
 
16474
16641
  vec3 standing(float growth) {
@@ -16749,7 +16916,7 @@ function createTileflowTrees3D(options) {
16749
16916
  let disposed = false;
16750
16917
  let drawnLast = 0;
16751
16918
  let generation = 0;
16752
- let registered = false;
16919
+ let registered2 = false;
16753
16920
  let unregister = () => {
16754
16921
  };
16755
16922
  const scene = tileflowScene3D(map);
@@ -17014,7 +17181,9 @@ function createTileflowTrees3D(options) {
17014
17181
  forms: tileflowTreeForms.map((form) => [
17015
17182
  theme?.forms[form]?.heightScale ?? 1,
17016
17183
  theme?.forms[form]?.crownScale ?? 1,
17017
- 0
17184
+ theme?.forms[form]?.sizeAnchor ?? 8.5,
17185
+ theme?.forms[form]?.crownAnchor ?? 5,
17186
+ theme?.forms[form]?.sizeCompression ?? 0
17018
17187
  ]),
17019
17188
  edges: [[theme?.edges ?? 0, 0, 0]],
17020
17189
  edgeColor: [[...rgb(theme?.edgeColor ?? "#000000") ?? [0, 0, 0]]],
@@ -17039,6 +17208,12 @@ function createTileflowTrees3D(options) {
17039
17208
  [size[0] * forms[index][0], size[1] * forms[index][1]]
17040
17209
  ])
17041
17210
  ),
17211
+ compressions: Object.fromEntries(
17212
+ tileflowTreeForms.map((form, index) => [
17213
+ form,
17214
+ [forms[index][2], forms[index][3], forms[index][4]]
17215
+ ])
17216
+ ),
17042
17217
  finish: (t < 0.5 ? a : b2)?.finish ?? "faceted",
17043
17218
  edges: mixList(x3.edges, y2.edges)[0][0],
17044
17219
  edgeColor: mixList(x3.edgeColor, y2.edgeColor)[0],
@@ -17075,17 +17250,21 @@ function createTileflowTrees3D(options) {
17075
17250
  tallest = Math.max(tallest, value.placement.tallest);
17076
17251
  }
17077
17252
  if (!Number.isFinite(left)) return void 0;
17078
- const size = colours().size;
17253
+ const palette2 = colours();
17254
+ const maximumGrowth = Object.values(palette2.compressions).some(
17255
+ ([, , strength]) => strength > 0
17256
+ ) ? 1.35 : 1;
17257
+ const maximumScale = maximumGrowth > 1 ? Math.max(...Object.values(palette2.sizes).map((size) => size[0])) : palette2.size[0];
17079
17258
  return {
17080
17259
  zoom: preferredZoom3,
17081
17260
  tiles: [left, top, right, bottom],
17082
- tallest: Math.max(tallest * size[0], colours().minimumHeight) * shown
17261
+ tallest: Math.max(tallest * maximumScale, palette2.minimumHeight) * maximumGrowth * shown
17083
17262
  };
17084
17263
  },
17085
17264
  // Camera-dependent density, detail and fading also change the trees casting shadows.
17086
17265
  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(
17087
17266
  colours().sizes
17088
- ).flat().map((value) => value.toFixed(3)).join()}:${drawn().map(({ x: x3, y: y2 }) => `${x3}/${y2}`).join(";")}`,
17267
+ ).flat().map((value) => value.toFixed(3)).join()}:${Object.values(colours().compressions).flat().join()}:${drawn().map(({ x: x3, y: y2 }) => `${x3}/${y2}`).join(";")}`,
17089
17268
  drawDepth(context, frame) {
17090
17269
  const program = programs.depth;
17091
17270
  if (!program || !meshes) return;
@@ -17095,6 +17274,7 @@ function createTileflowTrees3D(options) {
17095
17274
  context.uniform1f(u.u_metres, frame.metres);
17096
17275
  context.uniformMatrix4fv(u.u_light_matrix, false, frame.light.matrix);
17097
17276
  const sizes = colours().sizes;
17277
+ const compressions = colours().compressions;
17098
17278
  const minimumHeight = colours().minimumHeight;
17099
17279
  const camera = view();
17100
17280
  context.uniform1f(u.u_fade, 1);
@@ -17115,12 +17295,14 @@ function createTileflowTrees3D(options) {
17115
17295
  const drawing = value.gl.vaos.get(`${form}:${model}:${selection.level}`);
17116
17296
  if (instances === 0 || !drawing) return;
17117
17297
  context.uniform2f(u.u_size_scale, sizes[form][0], sizes[form][1] * drawing.crown);
17298
+ context.uniform3f(u.u_size_compression, ...compressions[form]);
17118
17299
  context.bindVertexArray(drawing.vao);
17119
17300
  context.drawArraysInstanced(context.TRIANGLES, 0, drawing.count, instances);
17120
17301
  });
17121
17302
  const hedge = value.gl.hedge;
17122
17303
  if (hedge) {
17123
17304
  context.uniform1f(u.u_minimum_height, 0);
17305
+ context.uniform3f(u.u_size_compression, 1, 1, 0);
17124
17306
  context.uniform2f(u.u_size_scale, 1, 1);
17125
17307
  context.bindVertexArray(hedge.vao);
17126
17308
  context.drawArraysInstanced(
@@ -17206,6 +17388,7 @@ function createTileflowTrees3D(options) {
17206
17388
  ];
17207
17389
  context.uniform1f(u.u_minimum_height, palette2.minimumHeight);
17208
17390
  context.uniform2f(u.u_size_scale, ...size);
17391
+ context.uniform3f(u.u_size_compression, ...palette2.compressions[form]);
17209
17392
  context.bindVertexArray(drawing.vao);
17210
17393
  context.drawArraysInstanced(context.TRIANGLES, 0, drawing.count, instances);
17211
17394
  count += instances;
@@ -17216,6 +17399,7 @@ function createTileflowTrees3D(options) {
17216
17399
  leaves,
17217
17400
  size,
17218
17401
  minimumHeight: palette2.minimumHeight,
17402
+ compression: palette2.compressions[form],
17219
17403
  instances,
17220
17404
  drawing
17221
17405
  });
@@ -17226,6 +17410,7 @@ function createTileflowTrees3D(options) {
17226
17410
  const instances = value.placement.hedges.length / tileflowTreeBytes;
17227
17411
  context.uniform3fv(u.u_leaves, palette2.hedge.flat());
17228
17412
  context.uniform1f(u.u_minimum_height, 0);
17413
+ context.uniform3f(u.u_size_compression, 1, 1, 0);
17229
17414
  context.uniform2f(u.u_size_scale, 1, 1);
17230
17415
  context.bindVertexArray(hedge.vao);
17231
17416
  context.drawArraysInstanced(context.TRIANGLES, 0, hedge.count, instances);
@@ -17236,6 +17421,7 @@ function createTileflowTrees3D(options) {
17236
17421
  leaves: palette2.hedge,
17237
17422
  size: [1, 1],
17238
17423
  minimumHeight: 0,
17424
+ compression: [1, 1, 0],
17239
17425
  instances,
17240
17426
  drawing: hedge
17241
17427
  });
@@ -17278,6 +17464,7 @@ function createTileflowTrees3D(options) {
17278
17464
  );
17279
17465
  context.uniform1f(e.u_minimum_height, draw2.minimumHeight);
17280
17466
  context.uniform2f(e.u_size_scale, ...draw2.size);
17467
+ context.uniform3f(e.u_size_compression, ...draw2.compression);
17281
17468
  context.bindVertexArray(draw2.drawing.vao);
17282
17469
  context.drawArraysInstanced(context.TRIANGLES, 0, draw2.drawing.count, draw2.instances);
17283
17470
  }
@@ -17466,7 +17653,7 @@ ${shaderData.define}`;
17466
17653
  context.deleteBuffer(ground.vbo);
17467
17654
  }
17468
17655
  unregister();
17469
- registered = false;
17656
+ registered2 = false;
17470
17657
  scene.release(context);
17471
17658
  programs = {};
17472
17659
  meshes = void 0;
@@ -17479,8 +17666,8 @@ ${shaderData.define}`;
17479
17666
  if (!isWebGL23(context)) return;
17480
17667
  ensureTiles();
17481
17668
  if (!programs.depth) return;
17482
- if (!registered) unregister = scene.register(caster);
17483
- registered = true;
17669
+ if (!registered2) unregister = scene.register(caster);
17670
+ registered2 = true;
17484
17671
  const metres = tiles[0]?.metres ?? 1;
17485
17672
  scene.prepare(context, tileflowSceneLight(sunNow()), metres);
17486
17673
  },
@@ -19612,6 +19799,320 @@ function createChannel() {
19612
19799
  return `bridge_${Date.now().toString(36)}_${channelSequence.toString(36)}`;
19613
19800
  }
19614
19801
 
19802
+ // src/path-ground-geometry.ts
19803
+ var coverClasses = /* @__PURE__ */ new Set(["grass", "wood", "forest", "wetland"]);
19804
+ var useClasses = /* @__PURE__ */ new Set(["cemetery", "pitch", "track", "playground", "zoo"]);
19805
+ var pathClasses = /* @__PURE__ */ new Set([
19806
+ "footway",
19807
+ "path",
19808
+ "bridleway",
19809
+ "corridor",
19810
+ "pedestrian",
19811
+ "steps",
19812
+ "cycleway"
19813
+ ]);
19814
+ function deriveTileflowGreenPaths(bytes, bindings) {
19815
+ const tile = decodeTileflowVectorTile(bytes, {
19816
+ layers: [bindings.road, bindings.landcover, bindings.landuse]
19817
+ });
19818
+ const road = tile[bindings.road];
19819
+ if (!road) return encodeLines(bindings.road, 4096, []);
19820
+ const polygons = [];
19821
+ for (const name of [bindings.landcover, bindings.landuse]) {
19822
+ const layer = tile[name];
19823
+ if (!layer) continue;
19824
+ for (const feature of layer.features) {
19825
+ const kind = String(feature.properties[bindings.class]);
19826
+ const subclass = String(feature.properties[bindings.subclass]);
19827
+ const green = name === bindings.landcover ? coverClasses.has(kind) || kind === "farmland" && ["orchard", "plant_nursery"].includes(subclass) : useClasses.has(kind);
19828
+ if (feature.type !== "Polygon" || !green) continue;
19829
+ let current;
19830
+ for (const raw of feature.geometry) {
19831
+ const ring = raw.map((n) => n * road.extent / layer.extent);
19832
+ if (signedArea2(ring) > 0 || !current) {
19833
+ current = [ring];
19834
+ polygons.push({ rings: current, bounds: boundsOf2(ring) });
19835
+ } else current.push(ring);
19836
+ }
19837
+ }
19838
+ }
19839
+ const features = [];
19840
+ for (const feature of road.features) {
19841
+ const p = feature.properties;
19842
+ 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])))
19843
+ continue;
19844
+ const geometry2 = feature.geometry.flatMap((line) => clipLineToGreen(line, polygons));
19845
+ if (geometry2.length) features.push({ ...feature, geometry: geometry2 });
19846
+ }
19847
+ return encodeLines(bindings.road, road.extent, features);
19848
+ }
19849
+ function signedArea2(ring) {
19850
+ let area3 = 0;
19851
+ for (let i2 = 0, j2 = ring.length - 2; i2 < ring.length; j2 = i2, i2 += 2)
19852
+ area3 += ring[j2] * ring[i2 + 1] - ring[i2] * ring[j2 + 1];
19853
+ return area3 / 2;
19854
+ }
19855
+ function boundsOf2(line) {
19856
+ const box = [Infinity, Infinity, -Infinity, -Infinity];
19857
+ for (let i2 = 0; i2 < line.length; i2 += 2) {
19858
+ box[0] = Math.min(box[0], line[i2]);
19859
+ box[1] = Math.min(box[1], line[i2 + 1]);
19860
+ box[2] = Math.max(box[2], line[i2]);
19861
+ box[3] = Math.max(box[3], line[i2 + 1]);
19862
+ }
19863
+ return box;
19864
+ }
19865
+ function overlaps(a, b2) {
19866
+ return a[0] <= b2[2] && a[2] >= b2[0] && a[1] <= b2[3] && a[3] >= b2[1];
19867
+ }
19868
+ function insideRing(point, ring) {
19869
+ const [x3, y2] = point;
19870
+ let inside2 = false;
19871
+ for (let i2 = 0, j2 = ring.length - 2; i2 < ring.length; j2 = i2, i2 += 2) {
19872
+ const ax = ring[j2], ay = ring[j2 + 1], bx = ring[i2], by = ring[i2 + 1];
19873
+ const cross = (x3 - ax) * (by - ay) - (y2 - ay) * (bx - ax);
19874
+ 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))
19875
+ return true;
19876
+ if (ay > y2 !== by > y2 && x3 < (bx - ax) * (y2 - ay) / (by - ay) + ax) inside2 = !inside2;
19877
+ }
19878
+ return inside2;
19879
+ }
19880
+ function clipLineToGreen(line, all) {
19881
+ const polygons = all.filter((polygon) => overlaps(boundsOf2(line), polygon.bounds));
19882
+ if (!polygons.length) return [];
19883
+ const output = [];
19884
+ let active;
19885
+ for (let i2 = 2; i2 < line.length; i2 += 2) {
19886
+ const ax = line[i2 - 2], ay = line[i2 - 1], dx = line[i2] - ax, dy = line[i2 + 1] - ay;
19887
+ if (dx === 0 && dy === 0) continue;
19888
+ const cuts = [0, 1];
19889
+ for (const polygon of polygons)
19890
+ for (const ring of polygon.rings)
19891
+ for (let k = 0, j2 = ring.length - 2; k < ring.length; j2 = k, k += 2) {
19892
+ const bx = ring[j2], by = ring[j2 + 1], ex = ring[k] - bx, ey = ring[k + 1] - by;
19893
+ const denominator = dx * ey - dy * ex;
19894
+ if (Math.abs(denominator) < 1e-10) continue;
19895
+ const t = ((bx - ax) * ey - (by - ay) * ex) / denominator;
19896
+ const u = ((bx - ax) * dy - (by - ay) * dx) / denominator;
19897
+ if (t > 0 && t < 1 && u >= 0 && u <= 1) cuts.push(t);
19898
+ }
19899
+ cuts.sort((a, b2) => a - b2);
19900
+ for (let k = 1; k < cuts.length; k++) {
19901
+ const lo = cuts[k - 1], hi = cuts[k];
19902
+ if (hi - lo < 1e-9) continue;
19903
+ const mid = (lo + hi) / 2;
19904
+ const point = [ax + dx * mid, ay + dy * mid];
19905
+ const inside2 = polygons.some(
19906
+ (p) => insideRing(point, p.rings[0]) && !p.rings.slice(1).some((hole) => insideRing(point, hole))
19907
+ );
19908
+ if (!inside2) {
19909
+ active = void 0;
19910
+ continue;
19911
+ }
19912
+ const start = [Math.round(ax + dx * lo), Math.round(ay + dy * lo)];
19913
+ const end = [Math.round(ax + dx * hi), Math.round(ay + dy * hi)];
19914
+ if (start[0] === end[0] && start[1] === end[1]) continue;
19915
+ if (!active || active.at(-2) !== start[0] || active.at(-1) !== start[1]) {
19916
+ active = [...start];
19917
+ output.push(active);
19918
+ }
19919
+ active.push(...end);
19920
+ }
19921
+ }
19922
+ return output;
19923
+ }
19924
+ var Writer = class {
19925
+ bytes = [];
19926
+ uint(n) {
19927
+ while (n > 127) {
19928
+ this.bytes.push(n % 128 | 128);
19929
+ n = Math.floor(n / 128);
19930
+ }
19931
+ this.bytes.push(n);
19932
+ }
19933
+ field(tag, value) {
19934
+ this.uint(tag * 8);
19935
+ this.uint(value);
19936
+ }
19937
+ message(tag, value) {
19938
+ this.uint(tag * 8 + 2);
19939
+ this.uint(value.length);
19940
+ for (const n of value) this.bytes.push(n);
19941
+ }
19942
+ text(tag, value) {
19943
+ this.message(tag, new TextEncoder().encode(value));
19944
+ }
19945
+ };
19946
+ function zigzag2(n) {
19947
+ return n < 0 ? -n * 2 - 1 : n * 2;
19948
+ }
19949
+ function encodeLines(name, extent5, features) {
19950
+ const layer = new Writer();
19951
+ layer.text(1, name);
19952
+ const keys = [];
19953
+ const values = [];
19954
+ const keyMap = /* @__PURE__ */ new Map(), valueMap = /* @__PURE__ */ new Map();
19955
+ for (const feature of features) {
19956
+ const message = new Writer(), tags = new Writer(), geometry2 = new Writer();
19957
+ if (feature.id !== void 0) message.field(1, feature.id);
19958
+ for (const [key, value] of Object.entries(feature.properties)) {
19959
+ if (!keyMap.has(key)) {
19960
+ keyMap.set(key, keys.length);
19961
+ keys.push(key);
19962
+ }
19963
+ const identity = typeof value + ":" + value;
19964
+ if (!valueMap.has(identity)) {
19965
+ valueMap.set(identity, values.length);
19966
+ values.push(value);
19967
+ }
19968
+ tags.uint(keyMap.get(key));
19969
+ tags.uint(valueMap.get(identity));
19970
+ }
19971
+ message.message(2, tags.bytes);
19972
+ message.field(3, feature.type === "Polygon" ? 3 : 2);
19973
+ let x3 = 0, y2 = 0;
19974
+ for (const raw of feature.geometry) {
19975
+ const points = feature.type === "Polygon" && raw[0] === raw.at(-2) && raw[1] === raw.at(-1) ? raw.slice(0, -2) : raw;
19976
+ if (points.length < 4) continue;
19977
+ geometry2.uint(9);
19978
+ geometry2.uint(zigzag2(Math.round(points[0]) - x3));
19979
+ geometry2.uint(zigzag2(Math.round(points[1]) - y2));
19980
+ x3 = Math.round(points[0]);
19981
+ y2 = Math.round(points[1]);
19982
+ geometry2.uint((points.length / 2 - 1) * 8 + 2);
19983
+ for (let i2 = 2; i2 < points.length; i2 += 2) {
19984
+ const nx = Math.round(points[i2]), ny = Math.round(points[i2 + 1]);
19985
+ geometry2.uint(zigzag2(nx - x3));
19986
+ geometry2.uint(zigzag2(ny - y2));
19987
+ x3 = nx;
19988
+ y2 = ny;
19989
+ }
19990
+ if (feature.type === "Polygon") geometry2.uint(15);
19991
+ }
19992
+ message.message(4, geometry2.bytes);
19993
+ layer.message(2, message.bytes);
19994
+ }
19995
+ for (const key of keys) layer.text(3, key);
19996
+ for (const value of values) {
19997
+ const message = new Writer();
19998
+ if (typeof value === "string") message.text(1, value);
19999
+ else if (typeof value === "boolean") message.field(7, value ? 1 : 0);
20000
+ else if (Number.isSafeInteger(value)) {
20001
+ message.field(value < 0 ? 6 : 4, value < 0 ? zigzag2(value) : value);
20002
+ } else {
20003
+ message.uint(25);
20004
+ const b2 = new Uint8Array(8);
20005
+ new DataView(b2.buffer).setFloat64(0, value, true);
20006
+ message.bytes.push(...b2);
20007
+ }
20008
+ layer.message(4, message.bytes);
20009
+ }
20010
+ layer.field(5, extent5);
20011
+ layer.field(15, 2);
20012
+ const tile = new Writer();
20013
+ tile.message(3, layer.bytes);
20014
+ return new Uint8Array(tile.bytes);
20015
+ }
20016
+
20017
+ // src/path-ground-protocol.ts
20018
+ var tileflowPathGroundProtocol = "tileflow-path-ground";
20019
+ function pathGroundProtocolUrl(source, tile = false) {
20020
+ return `${tileflowPathGroundProtocol}://source/${tile ? "{z}/{x}/{y}.pbf" : "index.json"}?source=${encodeURIComponent(JSON.stringify(source))}`;
20021
+ }
20022
+ function parsePathGroundRequest(value) {
20023
+ if (value.length > 16e3) throw new Error("Path context URL is too long");
20024
+ const url = new URL(value);
20025
+ if (url.protocol !== `${tileflowPathGroundProtocol}:` || url.hostname !== "source" || url.username || url.password || url.hash)
20026
+ throw new Error("Invalid path context URL");
20027
+ const source = JSON.parse(url.searchParams.get("source") ?? "null");
20028
+ if (!source || !["road", "landcover", "landuse", "class", "subclass", "brunnel"].every(
20029
+ (k) => typeof source[k] === "string"
20030
+ ))
20031
+ throw new Error("Invalid path context bindings");
20032
+ if (!source.url && !source.tiles?.length) throw new Error("Missing path context source");
20033
+ for (const endpoint of [source.url, ...source.tiles ?? []].filter((s) => !!s)) {
20034
+ const u = new URL(
20035
+ endpoint.replaceAll("{z}", "0").replaceAll("{x}", "0").replaceAll("{y}", "0")
20036
+ );
20037
+ if (!["https:", "http:"].includes(u.protocol) || u.username || u.password)
20038
+ throw new Error("Path context requires an HTTP(S) vector source");
20039
+ }
20040
+ if (url.pathname === "/index.json") return { source };
20041
+ const match = /^\/(\d{1,2})\/(\d+)\/(\d+)\.pbf$/.exec(url.pathname);
20042
+ if (!match) throw new Error("Invalid path context tile");
20043
+ const [z2, x3, y2] = match.slice(1).map(Number);
20044
+ if (z2 < 0 || z2 > 24 || x3 < 0 || y2 < 0 || x3 >= 2 ** z2 || y2 >= 2 ** z2)
20045
+ throw new Error("Invalid path context coordinates");
20046
+ return { source, tile: { z: z2, x: x3, y: y2 } };
20047
+ }
20048
+
20049
+ // src/path-ground-browser.ts
20050
+ var registered = /* @__PURE__ */ new WeakSet();
20051
+ function registerTileflowPathGroundProtocol(registry, options = {}) {
20052
+ if (registered.has(registry.addProtocol)) return;
20053
+ const request = options.fetch ?? globalThis.fetch;
20054
+ const transform = options.transformUrl ?? ((url) => url);
20055
+ const descriptions = /* @__PURE__ */ new Map();
20056
+ const tiles = /* @__PURE__ */ new Map();
20057
+ let cacheBytes = 0;
20058
+ async function description(source, signal) {
20059
+ if (!source.url)
20060
+ return { tiles: source.tiles, minzoom: source.minzoom, maxzoom: source.maxzoom };
20061
+ const previous = descriptions.get(source.url);
20062
+ if (previous) return previous;
20063
+ const response = await request(transform(source.url), { signal });
20064
+ if (!response.ok) throw new Error(`Path context TileJSON: HTTP ${response.status}`);
20065
+ const json = await response.json();
20066
+ if (!Array.isArray(json.tiles) || !json.tiles.length || json.tiles.some((url) => typeof url !== "string"))
20067
+ throw new Error("Path context TileJSON has no tile templates");
20068
+ const result = {
20069
+ ...json,
20070
+ tiles: json.tiles.map(
20071
+ (url) => new URL(url, source.url).href.replaceAll("%7B", "{").replaceAll("%7D", "}")
20072
+ )
20073
+ };
20074
+ if (descriptions.size >= 16) descriptions.delete(descriptions.keys().next().value);
20075
+ descriptions.set(source.url, result);
20076
+ return result;
20077
+ }
20078
+ registry.addProtocol(tileflowPathGroundProtocol, async (input, abort) => {
20079
+ const { source, tile } = parsePathGroundRequest(input.url);
20080
+ const signal = abort.signal;
20081
+ signal.throwIfAborted();
20082
+ const json = await description(source, signal);
20083
+ if (!tile)
20084
+ return {
20085
+ data: {
20086
+ tiles: [pathGroundProtocolUrl(source, true)],
20087
+ minzoom: Math.max(12, json.minzoom ?? 0),
20088
+ maxzoom: json.maxzoom ?? source.maxzoom ?? 15,
20089
+ ...json.attribution ? { attribution: json.attribution } : {}
20090
+ }
20091
+ };
20092
+ const cached = tiles.get(input.url);
20093
+ if (cached) return { data: cached.slice().buffer };
20094
+ const y2 = json.scheme === "tms" ? 2 ** tile.z - 1 - tile.y : tile.y;
20095
+ const url = json.tiles[0].replaceAll("{z}", String(tile.z)).replaceAll("{x}", String(tile.x)).replaceAll("{y}", String(y2));
20096
+ if (!/^https?:\/\//.test(url))
20097
+ throw new Error("Path context requires an HTTP(S) tile template");
20098
+ const response = await request(transform(url), { signal });
20099
+ if (!response.ok) throw new Error(`Path context tile: HTTP ${response.status}`);
20100
+ const bytes = new Uint8Array(await response.arrayBuffer());
20101
+ if (bytes.byteLength > 16 * 1024 * 1024) throw new Error("Path context tile exceeds 16 MiB");
20102
+ signal.throwIfAborted();
20103
+ const result = deriveTileflowGreenPaths(bytes, source);
20104
+ while (tiles.size && (tiles.size >= 64 || cacheBytes + result.byteLength > 16 * 1024 * 1024)) {
20105
+ const key = tiles.keys().next().value;
20106
+ cacheBytes -= tiles.get(key).byteLength;
20107
+ tiles.delete(key);
20108
+ }
20109
+ tiles.set(input.url, result);
20110
+ cacheBytes += result.byteLength;
20111
+ return { data: result.slice().buffer };
20112
+ });
20113
+ registered.add(registry.addProtocol);
20114
+ }
20115
+
19615
20116
  // src/terrain/contour-protocol.ts
19616
20117
  var tileflowContourProtocol = "tileflow-contour";
19617
20118
  var tileflowContourSourceLayer = "contours";
@@ -19808,12 +20309,13 @@ var registeredContourProtocols = /* @__PURE__ */ new WeakSet();
19808
20309
  function registerTileflowContourProtocol(registry, options = {}) {
19809
20310
  if (registeredContourProtocols.has(registry.addProtocol)) return;
19810
20311
  const handler = createTileflowContourProtocolHandler(
19811
- options.loadMaplibreContour ?? loadPinnedMaplibreContour
20312
+ options.loadMaplibreContour ?? loadPinnedMaplibreContour,
20313
+ options.transformDemUrl
19812
20314
  );
19813
20315
  registry.addProtocol(tileflowContourProtocol, handler);
19814
20316
  registeredContourProtocols.add(registry.addProtocol);
19815
20317
  }
19816
- function createTileflowContourProtocolHandler(loadModule) {
20318
+ function createTileflowContourProtocolHandler(loadModule, transformDemUrl = (url) => url) {
19817
20319
  let library;
19818
20320
  const sources = /* @__PURE__ */ new Map();
19819
20321
  return async (request, abortController) => {
@@ -19828,7 +20330,7 @@ function createTileflowContourProtocolHandler(loadModule) {
19828
20330
  (module) => new module.DemSource({
19829
20331
  encoding: config.encoding,
19830
20332
  maxzoom: config.demMaxzoom,
19831
- url: config.demUrl,
20333
+ url: transformDemUrl(config.demUrl),
19832
20334
  // Upstream workers use a generated `blob:` URL. The main-thread manager keeps the
19833
20335
  // protocol usable in strict-CSP applications and deterministic local captures.
19834
20336
  worker: false
@@ -20001,6 +20503,130 @@ function createTileflowVegetation(options) {
20001
20503
  };
20002
20504
  }
20003
20505
 
20506
+ // src/building-flat-layers-browser.ts
20507
+ function createBuildingFlatLayers(map) {
20508
+ const saved = /* @__PURE__ */ new Map();
20509
+ let updating = false;
20510
+ function restore() {
20511
+ if (!map.setLayoutProperty || !map.getLayoutProperty || updating) return;
20512
+ updating = true;
20513
+ try {
20514
+ for (const [id, { visibility, layer }] of saved)
20515
+ if (map.getLayer(id) === layer && map.getLayoutProperty(id, "visibility") !== visibility)
20516
+ map.setLayoutProperty(id, "visibility", visibility);
20517
+ saved.clear();
20518
+ } finally {
20519
+ updating = false;
20520
+ }
20521
+ }
20522
+ return {
20523
+ update(layers, hidden) {
20524
+ if (updating || !map.setLayoutProperty || !map.getLayoutProperty) return;
20525
+ if (!hidden || layers.length === 0) {
20526
+ restore();
20527
+ return;
20528
+ }
20529
+ updating = true;
20530
+ try {
20531
+ const authored = new Map(layers.map((layer) => [layer.id, layer.visible]));
20532
+ const ids = map.getLayersOrder?.() ?? (map.getStyle()?.layers ?? []).map(({ id }) => id);
20533
+ for (const id of ids) {
20534
+ const visible = authored.get(id.split("::")[0]);
20535
+ if (visible === void 0 || !map.getLayer(id)) continue;
20536
+ const current = map.getLayoutProperty(id, "visibility") ?? "visible";
20537
+ if (!saved.has(id) || saved.get(id).layer !== map.getLayer(id))
20538
+ saved.set(id, { visibility: visible ? current : "none", layer: map.getLayer(id) });
20539
+ if (current !== "none") map.setLayoutProperty(id, "visibility", "none");
20540
+ }
20541
+ } finally {
20542
+ updating = false;
20543
+ }
20544
+ },
20545
+ restore,
20546
+ /** Removing a map must not write to its destroyed style. */
20547
+ forget() {
20548
+ saved.clear();
20549
+ }
20550
+ };
20551
+ }
20552
+
20553
+ // src/camera.ts
20554
+ var tileflowCameraMetadataKey = "tileflow:camera";
20555
+ function readTileflowCamera(metadata) {
20556
+ if (!metadata || typeof metadata !== "object") return {};
20557
+ const value = metadata[tileflowCameraMetadataKey];
20558
+ if (!value || typeof value !== "object") return {};
20559
+ const policy = value;
20560
+ return policy.version === 1 && typeof policy.adaptivePerspective === "boolean" ? { adaptivePerspective: policy.adaptivePerspective } : {};
20561
+ }
20562
+
20563
+ // src/camera-browser.ts
20564
+ function tileflowAdaptiveFieldOfView(pitch, zoom, height, normalFieldOfView) {
20565
+ if (pitch >= 15 || zoom <= 13 || height <= 0) return normalFieldOfView;
20566
+ const tangent = Math.tan(normalFieldOfView * Math.PI / 360);
20567
+ const distance = height / (2 * tangent);
20568
+ const mix2 = (Math.max(0, pitch) / 15) ** 5;
20569
+ const nearTangent = Math.max(
20570
+ Math.tan(Math.min(6, normalFieldOfView) * Math.PI / 360),
20571
+ height * mix2 / (2 * (1 - mix2 + mix2 * distance))
20572
+ );
20573
+ const t = Math.min(1, Math.max(0, (zoom - 13) / 2));
20574
+ const amount = t * t * (3 - 2 * t);
20575
+ return Math.atan(tangent + (nearTangent - tangent) * amount) * 360 / Math.PI;
20576
+ }
20577
+ function createTileflowAdaptiveCamera(map) {
20578
+ let normal;
20579
+ let applying = false;
20580
+ let disposed = false;
20581
+ const write = (next) => {
20582
+ if (applying || Math.abs((map.getVerticalFieldOfView?.() ?? next) - next) < 1e-6) return;
20583
+ applying = true;
20584
+ try {
20585
+ map.setVerticalFieldOfView?.(next);
20586
+ } finally {
20587
+ applying = false;
20588
+ }
20589
+ };
20590
+ const update = () => {
20591
+ if (disposed || applying || normal === void 0) return;
20592
+ write(
20593
+ tileflowAdaptiveFieldOfView(
20594
+ map.getPitch(),
20595
+ map.getZoom(),
20596
+ map.getCanvas().clientHeight,
20597
+ normal
20598
+ )
20599
+ );
20600
+ };
20601
+ const setEnabled = (enabled) => {
20602
+ if (disposed) return;
20603
+ if (enabled) {
20604
+ if (!map.getVerticalFieldOfView || !map.setVerticalFieldOfView || !map.getCanvas) return;
20605
+ normal ??= map.getVerticalFieldOfView();
20606
+ update();
20607
+ } else if (normal !== void 0) {
20608
+ const restore = normal;
20609
+ normal = void 0;
20610
+ write(restore);
20611
+ }
20612
+ };
20613
+ const onRemove = () => dispose(false);
20614
+ function dispose(restore = true) {
20615
+ if (disposed) return;
20616
+ if (restore) setEnabled(false);
20617
+ disposed = true;
20618
+ map.off("pitch", update);
20619
+ map.off("zoom", update);
20620
+ map.off("resize", update);
20621
+ map.off("remove", onRemove);
20622
+ }
20623
+ map.on("pitch", update);
20624
+ map.on("zoom", update);
20625
+ map.on("resize", update);
20626
+ map.on("remove", onRemove);
20627
+ return { setEnabled, dispose };
20628
+ }
20629
+
20004
20630
  // src/map-3d-attach-browser.ts
20005
20631
  var tileflowMap3DMetadataKeys = Object.freeze([
20006
20632
  tileflowBuildingsMetadataKey,
@@ -20026,6 +20652,7 @@ function attachTileflowMap3D(options) {
20026
20652
  const { map, load, onError, ...sceneOptions } = options;
20027
20653
  let viewMode = options.viewMode ?? "3d";
20028
20654
  let vegetation = options.vegetation;
20655
+ let adaptivePerspective = options.camera?.adaptivePerspective;
20029
20656
  let scene;
20030
20657
  let loading = false;
20031
20658
  let disposed = false;
@@ -20041,7 +20668,13 @@ function attachTileflowMap3D(options) {
20041
20668
  stopWatching();
20042
20669
  load().then(({ createTileflowMap3D: createTileflowMap3D2 }) => {
20043
20670
  if (disposed) return;
20044
- scene = createTileflowMap3D2({ ...sceneOptions, map, viewMode, vegetation });
20671
+ scene = createTileflowMap3D2({
20672
+ ...sceneOptions,
20673
+ map,
20674
+ viewMode,
20675
+ vegetation,
20676
+ camera: { adaptivePerspective }
20677
+ });
20045
20678
  }).catch((error) => {
20046
20679
  if (!disposed) onError?.(error);
20047
20680
  });
@@ -20059,28 +20692,36 @@ function attachTileflowMap3D(options) {
20059
20692
  if (disposed) return;
20060
20693
  disposed = true;
20061
20694
  stopWatching();
20062
- map.off("remove", dispose);
20695
+ map.off("remove", onRemove);
20063
20696
  scene?.dispose();
20064
20697
  scene = void 0;
20065
20698
  }
20699
+ function onRemove() {
20700
+ scene = void 0;
20701
+ dispose();
20702
+ }
20066
20703
  map.on("styledata", restyle);
20067
20704
  map.on("style.load", restyle);
20068
20705
  map.on("idle", check);
20069
- map.on("remove", dispose);
20706
+ map.on("remove", onRemove);
20070
20707
  check();
20071
20708
  return {
20072
20709
  get scene() {
20073
20710
  return scene;
20074
20711
  },
20075
- setViewMode(mode) {
20712
+ setViewMode(mode, change) {
20076
20713
  if (mode === viewMode) return;
20077
20714
  viewMode = mode;
20078
- if (scene) void (mode === "3d" ? scene.show() : scene.hide());
20715
+ if (scene) void (mode === "3d" ? scene.show(change) : scene.hide(change));
20079
20716
  },
20080
20717
  setVegetation(visible) {
20081
20718
  vegetation = visible;
20082
20719
  scene?.setVegetation(visible);
20083
20720
  },
20721
+ setAdaptivePerspective(enabled) {
20722
+ adaptivePerspective = enabled;
20723
+ scene?.setAdaptivePerspective(enabled);
20724
+ },
20084
20725
  dispose
20085
20726
  };
20086
20727
  }
@@ -20090,9 +20731,15 @@ function createTileflowMap3D(options) {
20090
20731
  const { map, controller, transformRequest } = options;
20091
20732
  let viewMode = options.viewMode ?? "3d";
20092
20733
  let vegetationVisible = options.vegetation;
20734
+ let adaptivePerspective = options.camera?.adaptivePerspective;
20735
+ const camera = createTileflowAdaptiveCamera(map);
20736
+ let authoredPerspective;
20093
20737
  let buildings;
20094
20738
  let vegetation;
20095
20739
  let streetLights;
20740
+ const flatBuildings = createBuildingFlatLayers(map);
20741
+ let footprintLayers;
20742
+ let footprintZoom = 15.3;
20096
20743
  let disposed = false;
20097
20744
  let syncing = false;
20098
20745
  const shared4 = {
@@ -20107,6 +20754,19 @@ function createTileflowMap3D(options) {
20107
20754
  syncing = true;
20108
20755
  try {
20109
20756
  const shown = viewMode === "3d";
20757
+ if (footprintLayers === void 0) {
20758
+ const themes = controller?.getThemeMetadata?.(tileflowBuildingsMetadataKey);
20759
+ const metadata = themes ? { [tileflowBuildingsMetadataKey]: themes.values[Math.round(themes.position)] } : map.getStyle()?.metadata;
20760
+ const design = readTileflowBuildings3D(metadata);
20761
+ footprintLayers = design?.flatLayers ?? [];
20762
+ footprintZoom = design?.entrance?.buildings?.[1] ?? 15.3;
20763
+ }
20764
+ if (authoredPerspective === void 0) {
20765
+ const themes = controller?.getThemeMetadata?.(tileflowCameraMetadataKey);
20766
+ const metadata = themes ? { [tileflowCameraMetadataKey]: themes.values[Math.round(themes.position)] } : map.getStyle()?.metadata;
20767
+ authoredPerspective = readTileflowCamera(metadata).adaptivePerspective ?? false;
20768
+ }
20769
+ camera.setEnabled(shown && (adaptivePerspective ?? authoredPerspective));
20110
20770
  const declared = declarations ??= tileflowMap3DDeclarations({
20111
20771
  map,
20112
20772
  ...controller ? { controller } : {}
@@ -20120,6 +20780,7 @@ function createTileflowMap3D(options) {
20120
20780
  }
20121
20781
  if (!vegetation && (declares(tileflowVegetationMetadataKey) || declares(tileflowVegetationDisplayMetadataKey)))
20122
20782
  vegetation = createTileflowVegetation({ ...shared4, visible: vegetationVisible, viewMode });
20783
+ syncFlatBuildings();
20123
20784
  if (shown && declares(tileflowStreetLightsMetadataKey))
20124
20785
  streetLights ??= createTileflowStreetLights(shared4);
20125
20786
  else if (streetLights) {
@@ -20130,9 +20791,22 @@ function createTileflowMap3D(options) {
20130
20791
  syncing = false;
20131
20792
  }
20132
20793
  }
20794
+ function syncFlatBuildings() {
20795
+ if (disposed) return;
20796
+ if (!footprintLayers?.length) {
20797
+ flatBuildings.restore();
20798
+ return;
20799
+ }
20800
+ const canvas = map.getCanvas?.();
20801
+ flatBuildings.update(
20802
+ footprintLayers,
20803
+ viewMode === "3d" && Boolean(buildings) && map.getZoom() >= footprintZoom && Boolean(canvas?.getContext?.("webgl2"))
20804
+ );
20805
+ }
20133
20806
  function change(next, transition) {
20134
20807
  if (disposed) return Promise.resolve();
20135
20808
  viewMode = next;
20809
+ camera.setEnabled(next === "3d" && (adaptivePerspective ?? authoredPerspective ?? false));
20136
20810
  vegetation?.setViewMode(next);
20137
20811
  if (next === "3d") {
20138
20812
  const existing = buildings;
@@ -20148,10 +20822,13 @@ function createTileflowMap3D(options) {
20148
20822
  function dispose() {
20149
20823
  if (disposed) return;
20150
20824
  disposed = true;
20825
+ flatBuildings.restore();
20826
+ camera.dispose();
20151
20827
  map.off("styledata", restyle);
20152
20828
  map.off("style.load", restyle);
20153
20829
  map.off("idle", sync);
20154
- map.off("remove", dispose);
20830
+ map.off("remove", onRemove);
20831
+ map.off("move", syncFlatBuildings);
20155
20832
  streetLights?.dispose();
20156
20833
  buildings?.dispose();
20157
20834
  vegetation?.dispose();
@@ -20160,13 +20837,21 @@ function createTileflowMap3D(options) {
20160
20837
  vegetation = void 0;
20161
20838
  }
20162
20839
  function restyle() {
20840
+ if (syncing) return;
20841
+ footprintLayers = void 0;
20163
20842
  declarations = void 0;
20843
+ authoredPerspective = void 0;
20164
20844
  sync();
20165
20845
  }
20846
+ function onRemove() {
20847
+ flatBuildings.forget();
20848
+ dispose();
20849
+ }
20166
20850
  map.on("styledata", restyle);
20167
20851
  map.on("style.load", restyle);
20168
20852
  map.on("idle", sync);
20169
- map.on("remove", dispose);
20853
+ map.on("remove", onRemove);
20854
+ map.on("move", syncFlatBuildings);
20170
20855
  sync();
20171
20856
  return {
20172
20857
  show: (transition) => change("3d", transition),
@@ -20178,6 +20863,11 @@ function createTileflowMap3D(options) {
20178
20863
  vegetationVisible = visible;
20179
20864
  vegetation?.setVisible(visible);
20180
20865
  },
20866
+ setAdaptivePerspective(enabled) {
20867
+ adaptivePerspective = enabled;
20868
+ camera.setEnabled(viewMode === "3d" && (adaptivePerspective ?? authoredPerspective ?? false));
20869
+ sync();
20870
+ },
20181
20871
  get buildings() {
20182
20872
  return buildings;
20183
20873
  },
@@ -21706,6 +22396,7 @@ function isPromiseLike(value) {
21706
22396
  export {
21707
22397
  attachTileflowAtmosphere,
21708
22398
  attachTileflowFairUseNotice,
22399
+ attachTileflowHorizonQueries,
21709
22400
  attachTileflowLabelPlacement,
21710
22401
  attachTileflowMap3D,
21711
22402
  attachTileflowMapLifecycle,
@@ -21747,6 +22438,7 @@ export {
21747
22438
  readTileflowVegetation3D,
21748
22439
  readTileflowVegetationDisplay,
21749
22440
  registerTileflowContourProtocol,
22441
+ registerTileflowPathGroundProtocol,
21750
22442
  registerTileflowPmtilesProtocol,
21751
22443
  registerTileflowWorldRequestBridge,
21752
22444
  resolveTileflowSun,
@@ -21763,6 +22455,7 @@ export {
21763
22455
  tileflowDepthMarkerPlacement,
21764
22456
  tileflowFairUseNoticeMessage,
21765
22457
  tileflowGroundBeforeId,
22458
+ tileflowHorizonScaleFactor,
21766
22459
  tileflowLayerDomainMetadataKey,
21767
22460
  tileflowLightRhythm,
21768
22461
  tileflowLightRhythmConventions,