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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/3d.js CHANGED
@@ -331,6 +331,57 @@ function createBuildingFlatLayers(map) {
331
331
  };
332
332
  }
333
333
 
334
+ // src/building-layer-ids.ts
335
+ var tileflowNativeBuildingsLayerId = "tileflow-buildings-native-extrusion";
336
+ var tileflowBuildingsSceneLayerId = "tileflow-buildings-scene-3d";
337
+
338
+ // src/building-native-layers-browser.ts
339
+ function createBuildingNativeLayers(map) {
340
+ let saved;
341
+ let updating = false;
342
+ function restore() {
343
+ if (updating || !saved || !map.getLayoutProperty || !map.setLayoutProperty) return;
344
+ updating = true;
345
+ try {
346
+ if (map.getLayer(tileflowNativeBuildingsLayerId) === saved.layer && map.getLayoutProperty(tileflowNativeBuildingsLayerId, "visibility") !== saved.visibility)
347
+ map.setLayoutProperty(tileflowNativeBuildingsLayerId, "visibility", saved.visibility);
348
+ saved = void 0;
349
+ } finally {
350
+ updating = false;
351
+ }
352
+ }
353
+ return {
354
+ /** Undefined gives control back to the compiled style. */
355
+ setVisible(visible) {
356
+ if (visible === void 0) return restore();
357
+ if (updating || !map.getLayoutProperty || !map.setLayoutProperty) return;
358
+ const layer = map.getLayer(tileflowNativeBuildingsLayerId);
359
+ if (!layer) {
360
+ saved = void 0;
361
+ return;
362
+ }
363
+ updating = true;
364
+ try {
365
+ if (!saved || saved.layer !== layer)
366
+ saved = {
367
+ layer,
368
+ visibility: map.getLayoutProperty(tileflowNativeBuildingsLayerId, "visibility") ?? "visible"
369
+ };
370
+ const next = visible ? "visible" : "none";
371
+ if (map.getLayoutProperty(tileflowNativeBuildingsLayerId, "visibility") !== next)
372
+ map.setLayoutProperty(tileflowNativeBuildingsLayerId, "visibility", next);
373
+ } finally {
374
+ updating = false;
375
+ }
376
+ },
377
+ restore,
378
+ /** Removing a map must not write to its destroyed style. */
379
+ forget() {
380
+ saved = void 0;
381
+ }
382
+ };
383
+ }
384
+
334
385
  // src/models-3d-model.ts
335
386
  var tileflowModelParts = Object.freeze({
336
387
  surface: 0,
@@ -678,8 +729,9 @@ function readTileflowBuildings3D(metadata) {
678
729
  };
679
730
  }
680
731
  function readTileflowBuildingsEntrance(value) {
732
+ if (value === false) return { entrance: false };
681
733
  if (!isRecord(value)) return {};
682
- const band = (entry) => Array.isArray(entry) && entry.length === 2 && entry.every((zoom) => typeof zoom === "number" && zoom >= 0 && zoom <= 24) && entry[0] < entry[1] ? [entry[0], entry[1]] : void 0;
734
+ const band = (entry) => Array.isArray(entry) && entry.length === 2 && entry.every((zoom) => typeof zoom === "number" && zoom >= 0 && zoom <= 24) && entry[0] <= entry[1] ? [entry[0], entry[1]] : void 0;
683
735
  const buildings = band(value.buildings);
684
736
  const models = band(value.models);
685
737
  return buildings || models ? { entrance: { ...buildings ? { buildings } : {}, ...models ? { models } : {} } } : {};
@@ -724,6 +776,116 @@ function isRecord(value) {
724
776
  return typeof value === "object" && value !== null && !Array.isArray(value);
725
777
  }
726
778
 
779
+ // src/sun.ts
780
+ var tileflowSunMetadataKey = "tileflow:sun";
781
+ var tileflowDefaultSunPreset = Object.freeze({
782
+ azimuth: 210,
783
+ altitude: 60,
784
+ color: "#ffffff",
785
+ intensity: 0.2,
786
+ shadowIntensity: 1,
787
+ ambient: Object.freeze({ color: "#ffffff", intensity: 0.8 })
788
+ });
789
+ var degrees = Math.PI / 180;
790
+ function normalizeTileflowAzimuth(azimuth) {
791
+ const turned = azimuth % 360;
792
+ return turned < 0 ? turned + 360 : turned === 0 ? 0 : turned;
793
+ }
794
+ function tileflowSunDirection(azimuth, altitude) {
795
+ const a = azimuth * degrees;
796
+ const h2 = altitude * degrees;
797
+ return Object.freeze([
798
+ Math.sin(a) * Math.cos(h2),
799
+ Math.cos(a) * Math.cos(h2),
800
+ Math.sin(h2)
801
+ ]);
802
+ }
803
+ function resolveTileflowSun(preset, direction = preset, source = "theme") {
804
+ const azimuth = normalizeTileflowAzimuth(direction.azimuth);
805
+ const altitude = Math.min(90, Math.max(-90, direction.altitude));
806
+ const horizon = smoothstep(-0.5, 3, altitude);
807
+ const intensity = clamp01(preset.intensity) * horizon;
808
+ const rgb = rgbOf(preset.color);
809
+ const ambientRgb = rgbOf(preset.ambient.color);
810
+ const ambientIntensity = clamp01(preset.ambient.intensity);
811
+ const brightness = clamp01(
812
+ (luminance(ambientRgb) * ambientIntensity + luminance(rgb) * intensity * Math.max(0, Math.sin(altitude * degrees))) / 2
813
+ );
814
+ return Object.freeze({
815
+ azimuth,
816
+ altitude,
817
+ direction: tileflowSunDirection(azimuth, altitude),
818
+ color: preset.color,
819
+ rgb,
820
+ intensity,
821
+ shadowIntensity: clamp01(preset.shadowIntensity),
822
+ ambient: Object.freeze({
823
+ color: preset.ambient.color,
824
+ rgb: ambientRgb,
825
+ intensity: ambientIntensity
826
+ }),
827
+ brightness: Number(brightness.toFixed(6)),
828
+ source
829
+ });
830
+ }
831
+ function readTileflowSunPreset(metadata) {
832
+ if (!isRecord2(metadata)) return void 0;
833
+ const value = metadata[tileflowSunMetadataKey];
834
+ if (!isRecord2(value) || value.version !== 1 || !isRecord2(value.ambient)) return void 0;
835
+ const { azimuth, altitude, color, intensity, shadowIntensity } = value;
836
+ const ambient = value.ambient;
837
+ if (!isFiniteNumber(azimuth) || !isFiniteNumber(altitude) || !isUnit(intensity) || !isUnit(shadowIntensity) || !isUnit(ambient.intensity) || !isColour(color) || !isColour(ambient.color))
838
+ return void 0;
839
+ return Object.freeze({
840
+ azimuth: normalizeTileflowAzimuth(azimuth),
841
+ altitude: Math.min(90, Math.max(-90, altitude)),
842
+ color,
843
+ intensity,
844
+ shadowIntensity,
845
+ ambient: Object.freeze({ color: ambient.color, intensity: ambient.intensity })
846
+ });
847
+ }
848
+ function tileflowStyleSunPreset(style) {
849
+ const published = readTileflowSunPreset(style?.metadata);
850
+ if (published) return published;
851
+ const light = isRecord2(style?.light) ? style.light : void 0;
852
+ const position = light?.position;
853
+ if (!position) return tileflowDefaultSunPreset;
854
+ return Object.freeze({
855
+ ...tileflowDefaultSunPreset,
856
+ azimuth: normalizeTileflowAzimuth(position[1]),
857
+ altitude: Math.min(90, Math.max(-90, 90 - position[2])),
858
+ ...typeof light.color === "string" && isColour(light.color) ? { color: light.color } : {}
859
+ });
860
+ }
861
+ function rgbOf(colour) {
862
+ const channels = tileflowColourChannels(colour) ?? [1, 1, 1, 1];
863
+ return Object.freeze([channels[0], channels[1], channels[2]]);
864
+ }
865
+ function luminance([r, g, b2]) {
866
+ const linear = (value) => value <= 0.04045 ? value / 12.92 : ((value + 0.055) / 1.055) ** 2.4;
867
+ return 0.2126 * linear(r) + 0.7152 * linear(g) + 0.0722 * linear(b2);
868
+ }
869
+ function smoothstep(from, to, value) {
870
+ const t = clamp01((value - from) / (to - from));
871
+ return t * t * (3 - 2 * t);
872
+ }
873
+ function clamp01(value) {
874
+ return Math.min(1, Math.max(0, Number.isFinite(value) ? value : 0));
875
+ }
876
+ function isRecord2(value) {
877
+ return typeof value === "object" && value !== null && !Array.isArray(value);
878
+ }
879
+ function isFiniteNumber(value) {
880
+ return typeof value === "number" && Number.isFinite(value);
881
+ }
882
+ function isUnit(value) {
883
+ return isFiniteNumber(value) && value >= 0 && value <= 1;
884
+ }
885
+ function isColour(value) {
886
+ return typeof value === "string" && tileflowColourChannels(value) !== null;
887
+ }
888
+
727
889
  // src/theme-blend.ts
728
890
  function tileflowColourChannels(colour) {
729
891
  const rgba = parseColour(colour);
@@ -2553,11 +2715,11 @@ var growth = `
2553
2715
  uniform float u_scale;
2554
2716
  uniform vec2 u_offset; // this tile's corner from the scene's origin, in tile units
2555
2717
  uniform float u_metres; // metres per tile unit
2556
- // The disc the city's tiles cover whole, in this tile's units: its centre, where heights start to
2557
- // ease down and where they are gone; none while its radius is 0. And the view's direction along the
2558
- // ground, in this tile's axes.
2718
+ // In this tile's units: origin and start/end of the fade along the view, or centre and radii of the
2719
+ // fallback covered disc. The direction is along the ground in this tile's axes.
2559
2720
  uniform vec4 u_ring;
2560
2721
  uniform vec2 u_ring_ahead;
2722
+ uniform bool u_ring_directional;
2561
2723
 
2562
2724
  float progressOf() {
2563
2725
  return clamp(u_scale * 1.25 - a_wave.x * 0.25, 0.0, 1.0);
@@ -2569,9 +2731,11 @@ float elevationOf(float own, float top, float p) {
2569
2731
  }
2570
2732
 
2571
2733
  // Buildings sink into the ground over the last stretch of the city's reach, so it ends without an
2572
- // edge of cut-off blocks. Only its far side does: where the tile limit holds the ring short, the
2573
- // buildings round the camera, nearer than its centre, keep standing.
2734
+ // edge of cut-off blocks. The view-aligned fade leaves the entire near width standing; the legacy
2735
+ // disc fallback also exempts its near side.
2574
2736
  float reachOf(vec2 position) {
2737
+ if (u_ring_directional)
2738
+ return 1.0 - smoothstep(u_ring.z, u_ring.w, dot(position - u_ring.xy, u_ring_ahead));
2575
2739
  if (u_ring.w <= 0.0) return 1.0;
2576
2740
  vec2 from = position - u_ring.xy;
2577
2741
  float far = smoothstep(0.0, u_ring.w - u_ring.z, dot(from, u_ring_ahead));
@@ -2740,12 +2904,12 @@ float hash(vec2 p) {
2740
2904
  return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);
2741
2905
  }
2742
2906
 
2743
- // The contact shade rises gradually up the facade, in world metres. Use one bounded shade
2744
- // for the authored gradient, ground contact and inner corners, rather than multiplying them.
2907
+ // The authored gradient follows the facade's height, leaving its upper edge light. Ground
2908
+ // contact and inner corners stay local; their shades never multiply into a dark lower band.
2745
2909
  float facadeShade() {
2746
2910
  if (v_building.z < 0.5) return 1.0;
2747
- float reach = min(3.0, max((v_facade.z - v_base) * 0.5, 0.1));
2748
- float gradient = 0.1 * u_style_gradient * (1.0 - smoothstep(0.0, reach, v_facade.y - v_base));
2911
+ float reach = max((v_facade.z - v_base) * 0.85, 0.1);
2912
+ float gradient = 0.12 * u_style_gradient * (1.0 - smoothstep(0.0, reach, v_facade.y - v_base));
2749
2913
  // Exponential attenuation leaves a soft tail above the first floor, without a band ending
2750
2914
  // at its radius. Height above ground also keeps raised parts from acquiring a dark lower rim.
2751
2915
  float up = max(v_facade.y, 0.0);
@@ -2777,10 +2941,10 @@ vec3 styleColour(vec3 colour, vec3 normal) {
2777
2941
 
2778
2942
  // A surface's light over the light a sunlit roof takes, in the map's colours: a sunlit roof keeps
2779
2943
  // its colour, a wall turned to a low sun glows, and shade takes the sky's colour. A wall sees half
2780
- // the sky; by day the ground's light makes up some of the rest, at night little does.
2944
+ // the sky; broad daylight fill keeps facades luminous, while night has little bounced light.
2781
2945
  vec3 shade(vec3 normal, float lit) {
2782
2946
  float facing = dot(normal, u_sun_dir);
2783
- vec3 sky = u_sky_light * mix(mix(0.8, 0.5, u_night), 1.0, normal.z);
2947
+ vec3 sky = u_sky_light * mix(mix(0.92, 0.5, u_night), 1.0, normal.z);
2784
2948
  vec3 light = sky + u_sun_light * max(facing, 0.0) * (1.0 - u_shadow * (1.0 - lit));
2785
2949
  vec3 roof = u_sky_light + u_sun_light * max(u_sun_dir.z, 0.0);
2786
2950
  return min(pow(light / max(roof, vec3(1e-4)), vec3(1.0 / 2.2)), vec3(1.7));
@@ -3903,13 +4067,13 @@ function unit(seed, salt) {
3903
4067
  var tileflowTreeModelIdPattern = /^[a-z0-9]+(?:-[a-z0-9]+)*$/u;
3904
4068
  var tileflowVegetationMetadataKey = "tileflow:vegetation";
3905
4069
  function readTileflowVegetation3D(metadata) {
3906
- if (!isRecord2(metadata)) return void 0;
4070
+ if (!isRecord3(metadata)) return void 0;
3907
4071
  const value = metadata[tileflowVegetationMetadataKey];
3908
- if (!isRecord2(value) || value.version !== 1) return void 0;
4072
+ if (!isRecord3(value) || value.version !== 1) return void 0;
3909
4073
  const { source, layers, fields, colors, heightScale, crownScale, unknownForms, regions } = value;
3910
- if (typeof source !== "string" || !isRecord2(layers) || typeof layers.tree !== "string")
4074
+ if (typeof source !== "string" || !isRecord3(layers) || typeof layers.tree !== "string")
3911
4075
  return void 0;
3912
- if (!isRecord2(fields) || !isRecord2(colors) || typeof colors.bark !== "string") return void 0;
4076
+ if (!isRecord3(fields) || !isRecord3(colors) || typeof colors.bark !== "string") return void 0;
3913
4077
  const palette = (list) => Array.isArray(list) && list.length > 0 && list.every((entry) => typeof entry === "string") ? list : void 0;
3914
4078
  const broadleaf = palette(colors.broadleaf);
3915
4079
  const conifer = palette(colors.conifer);
@@ -3919,18 +4083,18 @@ function readTileflowVegetation3D(metadata) {
3919
4083
  const scale = (number) => typeof number === "number" && number > 0 && number <= 10 ? number : 1;
3920
4084
  const mix2 = tileflowTreeFormMixProblem(unknownForms) === void 0 ? unknownForms : void 0;
3921
4085
  const models = Object.fromEntries(
3922
- Object.entries(isRecord2(value.models) ? value.models : {}).filter(
3923
- ([id, model]) => tileflowTreeModelIdPattern.test(id) && isRecord2(model) && typeof model.near === "string" && (model.far === void 0 || typeof model.far === "string")
4086
+ Object.entries(isRecord3(value.models) ? value.models : {}).filter(
4087
+ ([id, model]) => tileflowTreeModelIdPattern.test(id) && isRecord3(model) && typeof model.near === "string" && (model.far === void 0 || typeof model.far === "string")
3924
4088
  ).slice(0, 16).map(([id, model]) => {
3925
4089
  const { near, far } = model;
3926
4090
  return [id, far === void 0 ? { near } : { near, far }];
3927
4091
  })
3928
4092
  );
3929
- const ownScales = isRecord2(value.forms) ? value.forms : {};
4093
+ const ownScales = isRecord3(value.forms) ? value.forms : {};
3930
4094
  const forms = Object.fromEntries(
3931
4095
  tileflowTreeForms.flatMap((form) => {
3932
4096
  const own = ownScales[form];
3933
- if (!isRecord2(own)) return [];
4097
+ if (!isRecord3(own)) return [];
3934
4098
  const drawn = Array.isArray(own.models) ? [...new Set(own.models)].filter((id) => typeof id === "string" && id in models).slice(0, 4) : [];
3935
4099
  return [
3936
4100
  [
@@ -3950,7 +4114,7 @@ function readTileflowVegetation3D(metadata) {
3950
4114
  const finish = tileflowTreeFinishes.find((name) => name === value.finish) ?? "faceted";
3951
4115
  const edges = typeof value.edges === "number" && value.edges >= 0 && value.edges <= 1 ? value.edges : 0;
3952
4116
  const zones = Array.isArray(regions) ? regions.filter(
3953
- (region) => isRecord2(region) && tileflowTreeRegionProblem(region) === void 0
4117
+ (region) => isRecord3(region) && tileflowTreeRegionProblem(region) === void 0
3954
4118
  ) : [];
3955
4119
  const named = Object.fromEntries(
3956
4120
  Object.entries(tileflowWorldTreeFields).map(([key, fallback]) => [
@@ -3982,7 +4146,7 @@ function readTileflowVegetation3D(metadata) {
3982
4146
  };
3983
4147
  }
3984
4148
  function tileflowTreeRegionProblem(region) {
3985
- if (!isRecord2(region)) return "a region is an object with bounds and unknownForms";
4149
+ if (!isRecord3(region)) return "a region is an object with bounds and unknownForms";
3986
4150
  const bounds = region.bounds;
3987
4151
  if (!Array.isArray(bounds) || bounds.length !== 4 || !bounds.every((value) => typeof value === "number" && Number.isFinite(value)))
3988
4152
  return "bounds are [west, south, east, north] in degrees";
@@ -3993,7 +4157,7 @@ function tileflowTreeRegionProblem(region) {
3993
4157
  const mix2 = tileflowTreeFormMixProblem(region.unknownForms);
3994
4158
  return mix2 ? `unknownForms: ${mix2}` : void 0;
3995
4159
  }
3996
- function isRecord2(value) {
4160
+ function isRecord3(value) {
3997
4161
  return typeof value === "object" && value !== null && !Array.isArray(value);
3998
4162
  }
3999
4163
 
@@ -4260,7 +4424,7 @@ function browserWorker() {
4260
4424
  if (typeof Worker === "undefined" || false)
4261
4425
  return;
4262
4426
  const url = URL.createObjectURL(
4263
- 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" })
4427
+ 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&&_t(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),_=mn(p,h,n,t,i),v=e.prevZ;for(;v&&v.z>=A;){if(v.x>=g&&v.x<=p&&v.y>=m&&v.y<=h&&v!==s&&!(a===v.x&&c===v.y)&&Ke(a,c,l,f,u,d,v.x,v.y)&&Q(v.prev,v,v.next)>=0)return!1;v=v.prevZ}let M=e.nextZ;for(;M&&M.z<=_;){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),vt(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 vt(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 kt(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=[],ke=[],be=new Uint32Array(0),Se=new Uint32Array(0),Le=new Uint32Array(256);function _t(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);Ft(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),ke.fill(null,0,r)}function Ft(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),ke=new Array(e));for(let n=0;n<e;n++)be[n]=ie[n].z;Xe(e,ie,be,ke,Se,0),Xe(e,ke,Se,ie,be,8),Xe(e,ie,be,ke,Se,16),Xe(e,ke,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&&kt(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),_=Gn(t.roof_height),v,M;if(_!==void 0&&_>0)M=o,v=Math.max(i+Math.min(2,A/2),o-_);else{let y=Math.min(It(a,d),A*.6,30);t.height_source==="height"?(M=o,v=o-y):(v=o,M=o+y)}let B=M-v;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,F,k]of h)x=Math.min(x,T*y+F*b+k);return Math.max(0,x)},K=(y,b)=>v+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=$,F=x.length/2;for(let P=0;P<F&&T.length>=6;P+=1){let[Z,j]=[x[P*2],x[P*2+1]],[G,W]=[x[(P+1)%F*2],x[(P+1)%F*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 k=[];for(let P=0;P<T.length;P+=2)k.push(...E(T[P],T[P+1]));let L=Pe(k);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:k,triangles:L,normal:[-R/I,-S/I]})}if(w.length!==0)return{eaves:v,ridge:M,faces:w,heightAt:K,breaks(y,b,x,T){let[F,k]=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(F,k),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=F+(L-F)*j,W=k+(O-k)*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,_]of n){let v=A*c[0]+_*c[1],M=A*f[0]+_*f[1];d=Math.min(d,v),g=Math.max(g,v),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,_=(m+p)/2;t={centre:[A*c[0]+_*f[0],A*c[1]+_*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 F=Number.isSafeInteger(B.id),k=gn(F?B.id*.0731:b*.0731+x*.19137+N*1.618),L=!F&&y[0].some(S=>S<=0||S>=ue)?gn(U*7.31+E*3.17+D):k,O={base:E,top:U,jitter:L,seed:k,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,_e=ce[1]+(je[1]-ce[1])*oe,ye=Math.hypot(Ae,_e)||1;return[Ae/ye,_e/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,_e=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],Fe=Math.hypot(Ve-ye,He-De)/ue*n.tileMetres,$e=(Ae&&W(H)?1:0)|(_e&&W(H+1)?2:0)|(S>0?4:0),Ge=(Ae&&xn(J,re)?1:0)|(_e&&xn(ne,te)?2:0),an=ae+Fe,Ze=Ne(he[oe]),We=Ne(he[oe+1]),Cn=se(ye,De),Un=se(Ve,He),ve=s.write(O,ye,De,0,Ze[0],Ze[1],1,ae,$e,Fe,0,Ge,Cn);s.write(O,Ve,He,0,We[0],We[1],1,an,$e,Fe,1,Ge,Un),s.write(O,ye,De,1,Ze[0],Ze[1],1,ae,$e,Fe,0,Ge,Cn),s.write(O,Ve,He,1,We[0],We[1],1,an,$e,Fe,1,Ge,Un),l.push(ve,ve+1,ve+2,ve+1,ve+3,ve+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(),_=l.values();c.sort((M,B)=>M.cell-B.cell);let v=-1;for(let M of c){M.cell!==v&&(v=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(_.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,_]=[e[d*2],e[d*2+1]],v=Math.hypot(p-g,h-m),M=Math.hypot(A-p,_-h);if(!v||!M||xn(p,h)||we(g,m,p,h)||we(p,h,A,_)){u(p,h);continue}let[B,C]=[(p-g)/v,(h-m)/v],[z,U]=[(A-p)/M,(_-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,v*.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 F=b+E*T/x,k=[Math.cos(F),Math.sin(F)];u(w+k[0]*$,y+k[1]*$,k)}}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 _ of r){let[v,M,B,C]=_.box;if(d<v-o||d>B+o||g<M-o||g>C+o)continue;let z=!1;for(let U of _.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=_.index)}if(z){m=_.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(_=>_+_).join(""):t).match(/../gu).map(_=>Number.parseInt(_,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,_]=o.slice(0,3).map(v=>en(v,255));return[h,A,_,r].some(v=>v===null)?null:[h,A,_,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 kn,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),_=gr(h),v=Math.max(1,Math.min(4,Number(h.light_count)||1)),M=Math.min(24,Math.max(5,A*1.7*(v>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,_);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 _=fe/m.extent,v=[];for(let D=0;D+1<p.length;D+=2)v.push(p[D]*_,p[D+1]*_);let M=n.tileMetres/fe,B=h.kerb*.45/M,C=Rn(v[0]*.013+v[1]*.029+A)*h.spacing,z=0,U=C,E=Rn(v[0]+v[1]*3.1)<.5?1:-1;for(let D=2;D<v.length;D+=2){let K=v[D-2],$=v[D-1],N=v[D],Y=v[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,F=$+(Y-$)*y+x*B;if(U+=h.kerb>0?h.spacing/2:h.spacing,h.kerb>0&&(E=-E),!rt(T,F))continue;let k=ot(T,F,n.tileMetres);o.near(...k)||r.near(...k)||(r.add(...k),i.write(T,F,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"||!vn(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"||vn(t)))return s;let a=lr[r];if(a&&vn(t))return a}function vn(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}},kn=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,vr=1,kr=[.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"]),_r=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=_n(e[t.genus])??_n(e[t.species])??(o.endsWith("aceae")?void 0:_n(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&&_r.has(r))return"conifer";if(r&&at[r])return at[r];if(i.includes("broad"))return"broadleaf"}function _n(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[F,k,L,O]=T.bounds;if(x>=k&&x<=O&&(F<=L?b>=F&&b<=L:b>=F||b<=L))return T.unknownForms}return i},d=(w,y,b,x)=>{let T=st[w],F=Fn(T.crown,ee(y,2)),k=b,L=x;return k===void 0&&L===void 0&&(k=Fn(T.height,ee(y,1))),k===void 0&&(k=L/F),L===void 0&&(L=k*F),{height:Te(k,on),crown:Te(L,An)}},g=(w,y,b,x,T,F)=>{let k=Ie(r.x*q+w,r.y*q+y,7),L=b===void 0?sn(f(w,y),ee(k,3)):b==="broadleaf"?sn(Fr(f(w,y)),ee(k,3)):b,O=x===void 0&&T===void 0&&F!==void 0?d(L,k,Fn(st[L].height,Te(F/3,[0,1]))):d(L,k,x,T);l.push({x:w,y,...O,turn:ee(k,4),shade:ee(k,5),form:Me.indexOf(L),rank:Math.floor(ee(k,6)*rn),seed:ee(k,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),F=xe(b[t.diameterCrown],An),k=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,F,k)}}}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),F=xe(x[t.height],on),k=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,F,k,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,F=Number(b[t.canopyCover]??30),k=F>=60?3:F>=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*(k===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<k;ae+=1){let H=Ie(P,ae,13),J=se+ae*Math.PI*2/k,re=k===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=[],_=e.hedges;if(_){let w=q/_.extent,y=xr/(s/_.extent);for(let b of _.features){if(b.type==="Point"||b.properties[t.subclass]!=="hedge")continue;let x=b.properties[t.hedge]==="hedge_bank"?vr:0,T=(xe(b.properties[t.height],kr)??Mr)+x;for(let F of b.geometry){let k=y/2,L=0;for(let O=0;O+3<F.length;O+=2){let[V,R,S,I]=[F[O],F[O+1],F[O+2],F[O+3]],P=Math.hypot(S-V,I-R),Z=(Math.atan2(R-I,S-V)/(Math.PI*2)+1)%1;for(;k<=L+P;){let j=P>0?(k-L)/P:0,G=V+(S-V)*j,W=R+(I-R)*j;if(G>=0&&W>=0&&G<_.extent&&W<_.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)})}k+=y}L+=P}}}}let v=w=>Te(Math.floor(n.variants?.[Me[w]]??1),[1,4]),M=w=>Math.min(v(w.form)-1,Math.floor(ee(Math.floor(w.seed*256),9)*v(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:v(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 Fr(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 Fn([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" })
4264
4428
  );
4265
4429
  try {
4266
4430
  return new Worker(url, { name: "tileflow-tiles" });
@@ -5275,7 +5439,7 @@ var TileflowPmtilesProtocol = class {
5275
5439
  const archive2 = this.#archive(parseArchiveTarget(request.url));
5276
5440
  const header2 = await archive2.getHeader();
5277
5441
  const tileJson = await archive2.getTileJson(request.url);
5278
- if (!isRecord3(tileJson))
5442
+ if (!isRecord4(tileJson))
5279
5443
  throw new TypeError("A PMTiles archive described no TileJSON object.");
5280
5444
  const data = header2.tileType === O.Mlt ? { ...tileJson, encoding: "mlt" } : tileJson;
5281
5445
  abortController.signal.throwIfAborted();
@@ -5411,7 +5575,7 @@ function assertRelativeRange(offset, length, sectionLength) {
5411
5575
  throw new Error("Tileflow PMTiles directory range is invalid.");
5412
5576
  }
5413
5577
  }
5414
- function isRecord3(value) {
5578
+ function isRecord4(value) {
5415
5579
  return value !== null && typeof value === "object" && !Array.isArray(value);
5416
5580
  }
5417
5581
  function protocolCompatibility(handler) {
@@ -5665,7 +5829,8 @@ function createCameraTiles(options) {
5665
5829
  const chosen = cameraTileRing(
5666
5830
  { ...centre, zoom: currentZoom, pitch: map.getPitch(), bearing: map.getBearing() },
5667
5831
  zoom,
5668
- options.maxTiles
5832
+ options.maxTiles,
5833
+ cameraViewport(map, zoom)
5669
5834
  );
5670
5835
  ring = chosen;
5671
5836
  wanted = chosen.tiles.map(({ x: x3, y: y2 }) => `${x3}/${y2}`);
@@ -5677,7 +5842,7 @@ function createCameraTiles(options) {
5677
5842
  return;
5678
5843
  }
5679
5844
  const now = performance.now();
5680
- for (const { x: x3, y: y2, distance } of chosen.tiles) {
5845
+ for (const [priority, { x: x3, y: y2 }] of chosen.tiles.entries()) {
5681
5846
  const key = `${x3}/${y2}`;
5682
5847
  let entry = tiles.get(key);
5683
5848
  if (!entry) {
@@ -5685,7 +5850,7 @@ function createCameraTiles(options) {
5685
5850
  tiles.set(key, entry);
5686
5851
  }
5687
5852
  entry.used = now;
5688
- entry.distance = distance;
5853
+ entry.priority = priority;
5689
5854
  if ((!entry.value && !entry.pending || entry.retryAt !== void 0) && !entry.loading && (entry.retryAt ?? 0) <= now)
5690
5855
  load(source, key, entry, chosen.tileMetres);
5691
5856
  }
@@ -5698,7 +5863,7 @@ function createCameraTiles(options) {
5698
5863
  entry.retryAt = void 0;
5699
5864
  source.read(
5700
5865
  { z: zoom, x: entry.x, y: entry.y },
5701
- { signal: controller.signal, priority: entry.distance ?? 0 }
5866
+ { signal: controller.signal, priority: entry.priority ?? 0 }
5702
5867
  ).then((tile) => {
5703
5868
  if (disposed || tiles.get(key) !== entry || entry.loading !== controller) return;
5704
5869
  if (!tile) {
@@ -5733,14 +5898,14 @@ function createCameraTiles(options) {
5733
5898
  while (!disposed && queue.length && performance.now() - started < buildBudgetMs) {
5734
5899
  let nearest = 0;
5735
5900
  for (let at = 1; at < queue.length; at += 1)
5736
- if ((queue[at].entry.distance ?? 0) < (queue[nearest].entry.distance ?? 0))
5901
+ if ((queue[at].entry.priority ?? 0) < (queue[nearest].entry.priority ?? 0))
5737
5902
  nearest = at;
5738
5903
  const { key, entry, controller, tile, metres: tileMetres } = queue.splice(nearest, 1)[0];
5739
5904
  const current = () => !disposed && tiles.get(key) === entry && entry.loading === controller && !controller.signal.aborted;
5740
5905
  if (!current()) continue;
5741
5906
  let value;
5742
5907
  try {
5743
- value = await options.build(tile, tileMetres, controller.signal, entry.distance ?? 0);
5908
+ value = await options.build(tile, tileMetres, controller.signal, entry.priority ?? 0);
5744
5909
  } catch {
5745
5910
  if (current()) {
5746
5911
  entry.loading = void 0;
@@ -5810,6 +5975,7 @@ function createCameraTiles(options) {
5810
5975
  map.on("sourcedata", onSource);
5811
5976
  map.on("move", onMove);
5812
5977
  map.on("moveend", onMoveEnd);
5978
+ map.on("resize", onMoveEnd);
5813
5979
  return {
5814
5980
  update,
5815
5981
  ready() {
@@ -5864,6 +6030,7 @@ function createCameraTiles(options) {
5864
6030
  map.off("sourcedata", onSource);
5865
6031
  map.off("move", onMove);
5866
6032
  map.off("moveend", onMoveEnd);
6033
+ map.off("resize", onMoveEnd);
5867
6034
  for (const entry of tiles.values()) {
5868
6035
  entry.loading?.abort();
5869
6036
  if (entry.pending && entry.pending !== options.empty) options.release(entry.pending);
@@ -5931,33 +6098,110 @@ function cameraFrame(callback) {
5931
6098
  if (typeof requestAnimationFrame === "function") requestAnimationFrame(callback);
5932
6099
  else setTimeout(callback, 16);
5933
6100
  }
5934
- function cameraTileRing(camera, tileZoom, maxTiles) {
6101
+ function cameraTileRing(camera, tileZoom, maxTiles, viewport) {
5935
6102
  const reach = Math.min(
5936
6103
  5e3,
5937
6104
  Math.max(800, 1600 * 2 ** (16 - camera.zoom) * (1 + camera.pitch / 60))
5938
6105
  );
5939
6106
  const bearing = camera.bearing * Math.PI / 180;
6107
+ const direction = [Math.sin(bearing), -Math.cos(bearing)];
5940
6108
  const ahead = reach * 0.35 * Math.min(1, camera.pitch / 60);
5941
6109
  const latitude = camera.lat + Math.cos(bearing) * ahead / 111320;
5942
6110
  const longitude = camera.lng + Math.sin(bearing) * ahead / (111320 * Math.cos(camera.lat * Math.PI / 180));
5943
6111
  const [cx, cy] = cameraTileAt(longitude, latitude, tileZoom);
5944
- const tileMetres = earth * Math.cos(latitude * Math.PI / 180) / 2 ** tileZoom;
6112
+ const [ox, oy] = cameraTileAt(camera.lng, camera.lat, tileZoom);
6113
+ const tileMetres = earth * Math.cos(camera.lat * Math.PI / 180) / 2 ** tileZoom;
6114
+ const far = (reach + ahead) / tileMetres;
6115
+ const along = ([x3, y2]) => (x3 - ox) * direction[0] + (y2 - oy) * direction[1];
6116
+ const visible = viewport && clipGround(viewport, (point) => far - along(point));
5945
6117
  const span = Math.ceil(reach / tileMetres);
6118
+ const left = Math.floor(Math.min(cx - span, ...visible?.map(([x3]) => x3) ?? []));
6119
+ const right = Math.floor(Math.max(cx + span, ...visible?.map(([x3]) => x3) ?? []));
6120
+ const top = Math.floor(Math.min(cy - span, ...visible?.map(([, y2]) => y2) ?? []));
6121
+ const bottom = Math.floor(Math.max(cy + span, ...visible?.map(([, y2]) => y2) ?? []));
5946
6122
  const candidates = [];
5947
- for (let dx = -span; dx <= span; dx += 1)
5948
- for (let dy = -span; dy <= span; dy += 1) {
5949
- const x3 = Math.floor(cx) + dx;
5950
- const y2 = Math.floor(cy) + dy;
5951
- const distance = Math.hypot(
5952
- Math.max(x3, Math.min(cx, x3 + 1)) - cx,
5953
- Math.max(y2, Math.min(cy, y2 + 1)) - cy
5954
- );
5955
- if (distance * tileMetres <= reach) candidates.push({ x: x3, y: y2, distance });
6123
+ for (let x3 = left; x3 <= right; x3++)
6124
+ for (let y2 = top; y2 <= bottom; y2++) {
6125
+ const distance = Math.hypot(Math.max(x3 - cx, 0, cx - x3 - 1), Math.max(y2 - cy, 0, cy - y2 - 1));
6126
+ let intersection = visible ?? [];
6127
+ for (const boundary of [
6128
+ ([px]) => px - x3,
6129
+ ([px]) => x3 + 1 - px,
6130
+ ([, py]) => py - y2,
6131
+ ([, py]) => y2 + 1 - py
6132
+ ])
6133
+ intersection = clipGround(intersection, boundary);
6134
+ const near2 = Math.min(...intersection.map(along));
6135
+ if (near2 < Infinity || distance * tileMetres <= reach)
6136
+ candidates.push({ x: x3, y: y2, distance, near: near2 });
6137
+ }
6138
+ candidates.sort((a, b2) => a.near - b2.near || a.distance - b2.distance);
6139
+ const tiles = candidates.slice(0, maxTiles).map(({ x: x3, y: y2, distance }) => ({ x: x3, y: y2, distance }));
6140
+ const omitted = candidates.slice(tiles.length);
6141
+ const radius = omitted.reduce(
6142
+ (radius2, tile) => Math.min(radius2, tile.distance),
6143
+ reach / tileMetres
6144
+ );
6145
+ const end = Math.min(far, ...omitted.map((tile) => tile.near));
6146
+ const near = visible?.length ? Math.min(...visible.map(along)) : end;
6147
+ return {
6148
+ tiles,
6149
+ centre: [cx, cy],
6150
+ radius,
6151
+ tileMetres,
6152
+ ...visible?.length ? {
6153
+ fade: {
6154
+ origin: [ox, oy],
6155
+ start: end - Math.max(0.25, (end - near) * 0.2),
6156
+ end
6157
+ }
6158
+ } : {}
6159
+ };
6160
+ }
6161
+ function cameraViewport(map, zoom) {
6162
+ const canvas = map.getCanvas?.();
6163
+ const width = canvas?.clientWidth ?? 0;
6164
+ const height = canvas?.clientHeight ?? 0;
6165
+ if (!map.unproject || width <= 0 || height <= 0) return void 0;
6166
+ const origin = cameraTileAt(map.getCenter().lng, map.getCenter().lat, zoom)[0];
6167
+ const world = 2 ** zoom;
6168
+ const pointAt = (x3, y2) => {
6169
+ const location = map.unproject([x3, y2]);
6170
+ const [tx, ty] = cameraTileAt(location.lng, location.lat, zoom);
6171
+ return [tx + Math.round((origin - tx) / world) * world, ty];
6172
+ };
6173
+ const bearing = map.getBearing() * Math.PI / 180;
6174
+ const points = [];
6175
+ for (const x3 of [0, width]) {
6176
+ const bottom = pointAt(x3, height);
6177
+ const middle = pointAt(x3, height / 2);
6178
+ let top = pointAt(x3, 0);
6179
+ if ((top[0] - middle[0]) * Math.sin(bearing) - (top[1] - middle[1]) * Math.cos(bearing) <= 0) {
6180
+ const stretch = world / Math.hypot(middle[0] - bottom[0], middle[1] - bottom[1]);
6181
+ top = [
6182
+ middle[0] + (middle[0] - bottom[0]) * stretch,
6183
+ middle[1] + (middle[1] - bottom[1]) * stretch
6184
+ ];
5956
6185
  }
5957
- candidates.sort((a, b2) => a.distance - b2.distance);
5958
- const tiles = candidates.slice(0, maxTiles);
5959
- const radius = Math.min(reach / tileMetres, candidates[tiles.length]?.distance ?? Infinity);
5960
- return { tiles, centre: [cx, cy], radius, tileMetres };
6186
+ points.push(bottom, top);
6187
+ }
6188
+ if (points.some((point) => point.some((value) => !Number.isFinite(value)))) return void 0;
6189
+ return [points[0], points[1], points[3], points[2]];
6190
+ }
6191
+ function clipGround(points, distance) {
6192
+ const result = [];
6193
+ for (let i2 = 0; i2 < points.length; i2++) {
6194
+ const a = points[i2];
6195
+ const b2 = points[(i2 + 1) % points.length];
6196
+ const da = distance(a);
6197
+ const db = distance(b2);
6198
+ if (da >= 0) result.push([a[0], a[1]]);
6199
+ if (da < 0 !== db < 0) {
6200
+ const t = da / (da - db);
6201
+ result.push([a[0] + (b2[0] - a[0]) * t, a[1] + (b2[1] - a[1]) * t]);
6202
+ }
6203
+ }
6204
+ return result;
5961
6205
  }
5962
6206
  function cameraTileAt(longitude, latitude, zoom) {
5963
6207
  const phi = Math.min(85.05, Math.max(-85.05, latitude)) * Math.PI / 180;
@@ -6640,7 +6884,7 @@ function validFootprint(footprint) {
6640
6884
  return points <= tileflowModelLimits.footprintPoints;
6641
6885
  }
6642
6886
  function readTileflowLandmarkRegion(json) {
6643
- if (!isRecord4(json)) return void 0;
6887
+ if (!isRecord5(json)) return void 0;
6644
6888
  if (json.format !== "tileflow-landmark-region-v2") return void 0;
6645
6889
  const region = json.region;
6646
6890
  if (json.zoom !== tileflowLandmarkTileZoom || !Array.isArray(region) || region.length !== 3 || region[0] !== tileflowLandmarkRegionZoom || !Array.isArray(json.tiles))
@@ -6666,7 +6910,7 @@ function readLandmarks(listed, tx, ty) {
6666
6910
  if (!Array.isArray(listed) || listed.length === 0) return void 0;
6667
6911
  const out = [];
6668
6912
  for (const landmark of listed) {
6669
- if (!isRecord4(landmark)) return void 0;
6913
+ if (!isRecord5(landmark)) return void 0;
6670
6914
  const { id, at, heading, footprint } = landmark;
6671
6915
  if (typeof id !== "string" || !landmarkId.test(id)) return void 0;
6672
6916
  if (!Array.isArray(at) || at.length !== 2 || !at.every((value) => typeof value === "number"))
@@ -6690,10 +6934,10 @@ function readLandmarks(listed, tx, ty) {
6690
6934
  return out;
6691
6935
  }
6692
6936
  function readTileflowLandmarksTileJson(json, url) {
6693
- if (!isRecord4(json) || json.format !== "tileflow-landmarks-v2") return void 0;
6937
+ if (!isRecord5(json) || json.format !== "tileflow-landmarks-v2") return void 0;
6694
6938
  const tile = Array.isArray(json.tiles) ? json.tiles[0] : void 0;
6695
6939
  const regions = json.regions;
6696
- if (typeof tile !== "string" || !tile.includes("{sha256}") || json.minzoom !== tileflowLandmarkTileZoom || json.maxzoom !== tileflowLandmarkTileZoom || !isRecord4(regions) || regions.zoom !== tileflowLandmarkRegionZoom || typeof regions.url !== "string" || !regions.url.includes("{x}") || !regions.url.includes("{y}") || !Array.isArray(regions.available))
6940
+ if (typeof tile !== "string" || !tile.includes("{sha256}") || json.minzoom !== tileflowLandmarkTileZoom || json.maxzoom !== tileflowLandmarkTileZoom || !isRecord5(regions) || regions.zoom !== tileflowLandmarkRegionZoom || typeof regions.url !== "string" || !regions.url.includes("{x}") || !regions.url.includes("{y}") || !Array.isArray(regions.available))
6697
6941
  return void 0;
6698
6942
  const available = /* @__PURE__ */ new Set();
6699
6943
  for (const region of regions.available) {
@@ -6711,7 +6955,7 @@ function readTileflowLandmarksTileJson(json, url) {
6711
6955
  regions: available
6712
6956
  };
6713
6957
  }
6714
- function isRecord4(value) {
6958
+ function isRecord5(value) {
6715
6959
  return typeof value === "object" && value !== null && !Array.isArray(value);
6716
6960
  }
6717
6961
 
@@ -8369,115 +8613,8 @@ var tileflowSceneFadeZooms = 0.25;
8369
8613
  function tileflowSceneOpacity(zoom, minzoom = tileflowSceneMinzoom) {
8370
8614
  return Math.min(1, Math.max(0, (zoom - minzoom) / tileflowSceneFadeZooms));
8371
8615
  }
8372
-
8373
- // src/sun.ts
8374
- var tileflowSunMetadataKey = "tileflow:sun";
8375
- var tileflowDefaultSunPreset = Object.freeze({
8376
- azimuth: 210,
8377
- altitude: 60,
8378
- color: "#ffffff",
8379
- intensity: 0.2,
8380
- shadowIntensity: 1,
8381
- ambient: Object.freeze({ color: "#ffffff", intensity: 0.8 })
8382
- });
8383
- var degrees = Math.PI / 180;
8384
- function normalizeTileflowAzimuth(azimuth) {
8385
- const turned = azimuth % 360;
8386
- return turned < 0 ? turned + 360 : turned === 0 ? 0 : turned;
8387
- }
8388
- function tileflowSunDirection(azimuth, altitude) {
8389
- const a = azimuth * degrees;
8390
- const h2 = altitude * degrees;
8391
- return Object.freeze([
8392
- Math.sin(a) * Math.cos(h2),
8393
- Math.cos(a) * Math.cos(h2),
8394
- Math.sin(h2)
8395
- ]);
8396
- }
8397
- function resolveTileflowSun(preset, direction = preset, source = "theme") {
8398
- const azimuth = normalizeTileflowAzimuth(direction.azimuth);
8399
- const altitude = Math.min(90, Math.max(-90, direction.altitude));
8400
- const horizon = smoothstep(-0.5, 3, altitude);
8401
- const intensity = clamp01(preset.intensity) * horizon;
8402
- const rgb = rgbOf(preset.color);
8403
- const ambientRgb = rgbOf(preset.ambient.color);
8404
- const ambientIntensity = clamp01(preset.ambient.intensity);
8405
- const brightness = clamp01(
8406
- (luminance(ambientRgb) * ambientIntensity + luminance(rgb) * intensity * Math.max(0, Math.sin(altitude * degrees))) / 2
8407
- );
8408
- return Object.freeze({
8409
- azimuth,
8410
- altitude,
8411
- direction: tileflowSunDirection(azimuth, altitude),
8412
- color: preset.color,
8413
- rgb,
8414
- intensity,
8415
- shadowIntensity: clamp01(preset.shadowIntensity),
8416
- ambient: Object.freeze({
8417
- color: preset.ambient.color,
8418
- rgb: ambientRgb,
8419
- intensity: ambientIntensity
8420
- }),
8421
- brightness: Number(brightness.toFixed(6)),
8422
- source
8423
- });
8424
- }
8425
- function readTileflowSunPreset(metadata) {
8426
- if (!isRecord5(metadata)) return void 0;
8427
- const value = metadata[tileflowSunMetadataKey];
8428
- if (!isRecord5(value) || value.version !== 1 || !isRecord5(value.ambient)) return void 0;
8429
- const { azimuth, altitude, color, intensity, shadowIntensity } = value;
8430
- const ambient = value.ambient;
8431
- if (!isFiniteNumber(azimuth) || !isFiniteNumber(altitude) || !isUnit(intensity) || !isUnit(shadowIntensity) || !isUnit(ambient.intensity) || !isColour(color) || !isColour(ambient.color))
8432
- return void 0;
8433
- return Object.freeze({
8434
- azimuth: normalizeTileflowAzimuth(azimuth),
8435
- altitude: Math.min(90, Math.max(-90, altitude)),
8436
- color,
8437
- intensity,
8438
- shadowIntensity,
8439
- ambient: Object.freeze({ color: ambient.color, intensity: ambient.intensity })
8440
- });
8441
- }
8442
- function tileflowStyleSunPreset(style) {
8443
- const published = readTileflowSunPreset(style?.metadata);
8444
- if (published) return published;
8445
- const light = isRecord5(style?.light) ? style.light : void 0;
8446
- const position = light?.position;
8447
- if (!position) return tileflowDefaultSunPreset;
8448
- return Object.freeze({
8449
- ...tileflowDefaultSunPreset,
8450
- azimuth: normalizeTileflowAzimuth(position[1]),
8451
- altitude: Math.min(90, Math.max(-90, 90 - position[2])),
8452
- ...typeof light.color === "string" && isColour(light.color) ? { color: light.color } : {}
8453
- });
8454
- }
8455
- function rgbOf(colour) {
8456
- const channels = tileflowColourChannels(colour) ?? [1, 1, 1, 1];
8457
- return Object.freeze([channels[0], channels[1], channels[2]]);
8458
- }
8459
- function luminance([r, g, b2]) {
8460
- const linear = (value) => value <= 0.04045 ? value / 12.92 : ((value + 0.055) / 1.055) ** 2.4;
8461
- return 0.2126 * linear(r) + 0.7152 * linear(g) + 0.0722 * linear(b2);
8462
- }
8463
- function smoothstep(from, to, value) {
8464
- const t = clamp01((value - from) / (to - from));
8465
- return t * t * (3 - 2 * t);
8466
- }
8467
- function clamp01(value) {
8468
- return Math.min(1, Math.max(0, Number.isFinite(value) ? value : 0));
8469
- }
8470
- function isRecord5(value) {
8471
- return typeof value === "object" && value !== null && !Array.isArray(value);
8472
- }
8473
- function isFiniteNumber(value) {
8474
- return typeof value === "number" && Number.isFinite(value);
8475
- }
8476
- function isUnit(value) {
8477
- return isFiniteNumber(value) && value >= 0 && value <= 1;
8478
- }
8479
- function isColour(value) {
8480
- return typeof value === "string" && tileflowColourChannels(value) !== null;
8616
+ function tileflowSceneEntrance(zoom, [from, to], animate) {
8617
+ return animate && to > from ? Math.min(1, Math.max(0, (zoom - from) / (to - from))) : Number(zoom >= from);
8481
8618
  }
8482
8619
 
8483
8620
  // src/sky-haze.ts
@@ -8505,6 +8642,7 @@ var tileflowSkyHazeReachFloor = 3;
8505
8642
  var nineTenths = 0.8042;
8506
8643
  function tileflowSkyReachDepth(view, reach) {
8507
8644
  const sin = Math.sin(radians(view.pitch));
8645
+ if (reach.forward !== void 0) return 1 + reach.forward * sin;
8508
8646
  const cos = Math.cos(radians(view.pitch));
8509
8647
  const back = -sin;
8510
8648
  const across = Math.atan(view.aspect * Math.tan(view.fov / 2));
@@ -8577,7 +8715,8 @@ function reachOf(map, distance) {
8577
8715
  return {
8578
8716
  ahead: (east * Math.sin(bearing) + north * Math.cos(bearing)) / metres,
8579
8717
  across: (east * Math.cos(bearing) - north * Math.sin(bearing)) / metres,
8580
- radius: reach.radius / metres
8718
+ radius: reach.radius / metres,
8719
+ ...reach.forward === void 0 ? {} : { forward: reach.forward / metres }
8581
8720
  };
8582
8721
  }
8583
8722
  function fovOf(map, args) {
@@ -8598,7 +8737,7 @@ function bindTileflowSkyHaze(context, uniforms, haze) {
8598
8737
  }
8599
8738
 
8600
8739
  // src/buildings-3d-browser.ts
8601
- var tileflowBuildings3DLayerId = "tileflow-buildings-3d";
8740
+ var tileflowBuildings3DLayerId = tileflowBuildingsSceneLayerId;
8602
8741
  var preferredZoom = 15;
8603
8742
  var defaultTransition = 0;
8604
8743
  var flood = { reach: 10, colour: [1, 0.7, 0.4] };
@@ -8637,6 +8776,20 @@ function createTileflowBuildings3D(options) {
8637
8776
  const floodMask = createBuildingContactMask();
8638
8777
  let masks = {};
8639
8778
  let disposed = false;
8779
+ let ready = false;
8780
+ let installedLayer;
8781
+ let reportedError = false;
8782
+ function setReady(next) {
8783
+ if (ready === next) return;
8784
+ ready = next;
8785
+ options.onReadyChange?.(next);
8786
+ }
8787
+ function reportError(error) {
8788
+ setReady(false);
8789
+ if (reportedError) return;
8790
+ reportedError = true;
8791
+ options.onError?.(error);
8792
+ }
8640
8793
  let hazeDepth = Infinity;
8641
8794
  let ahead = [0, -1];
8642
8795
  const scene = tileflowScene3D(map);
@@ -8684,6 +8837,8 @@ function createTileflowBuildings3D(options) {
8684
8837
  context.texParameteri(context.TEXTURE_2D, context.TEXTURE_MAG_FILTER, context.NEAREST);
8685
8838
  },
8686
8839
  onRemove(_2, context) {
8840
+ setReady(false);
8841
+ installedLayer = void 0;
8687
8842
  if (!isWebGL2(context)) return;
8688
8843
  models.release(context);
8689
8844
  for (const program of Object.values(programs))
@@ -8738,13 +8893,22 @@ function createTileflowBuildings3D(options) {
8738
8893
  map.triggerRepaint();
8739
8894
  return;
8740
8895
  }
8741
- } catch {
8896
+ } catch (error) {
8897
+ reportError(error);
8742
8898
  return;
8743
8899
  }
8744
8900
  if (target > 0 || scale > 0) upload(context);
8901
+ const coverageReady = visibleScale() > 0 && preparedCoverage();
8902
+ if (ready && !coverageReady) setReady(false);
8745
8903
  scene.setReach(visibleScale() > 0 ? reachNow() : void 0);
8746
8904
  if (visibleScale() <= 0 && modelScale() <= 0) return;
8747
- draw(context, args);
8905
+ try {
8906
+ draw(context, args);
8907
+ if (!ready && coverageReady) setReady(true);
8908
+ reportedError = false;
8909
+ } catch (error) {
8910
+ reportError(error);
8911
+ }
8748
8912
  }
8749
8913
  };
8750
8914
  const makeCamera = (layers, source, edgeRadius = 0) => createCameraTiles({
@@ -9006,7 +9170,7 @@ function createTileflowBuildings3D(options) {
9006
9170
  }
9007
9171
  let text2;
9008
9172
  for (const [layerId, property] of [
9009
- ["tileflow-buildings-render-extrusion", "fill-extrusion-color"],
9173
+ [tileflowNativeBuildingsLayerId, "fill-extrusion-color"],
9010
9174
  ["tileflow-buildings-fill", "fill-color"]
9011
9175
  ]) {
9012
9176
  if (!map.getLayer(layerId)) continue;
@@ -9031,8 +9195,9 @@ function createTileflowBuildings3D(options) {
9031
9195
  models: [minzoom - 0.8, minzoom - 0.4]
9032
9196
  };
9033
9197
  function entering(part) {
9034
- const [from, to] = design().entrance?.[part] ?? defaultEntrance[part];
9035
- return Math.min(1, Math.max(0, (map.getZoom() - from) / (to - from)));
9198
+ const entrance = design().entrance;
9199
+ const band = entrance && entrance[part] || defaultEntrance[part];
9200
+ return tileflowSceneEntrance(map.getZoom(), band, entrance !== false);
9036
9201
  }
9037
9202
  function visibleScale() {
9038
9203
  return visibleOpacity() > 0 ? scale * (reducedMotion?.matches ? 1 : entering("buildings")) : 0;
@@ -9049,6 +9214,15 @@ function createTileflowBuildings3D(options) {
9049
9214
  function drawn() {
9050
9215
  return camera.ready().filter((entry) => entry.value.gl);
9051
9216
  }
9217
+ function preparedCoverage() {
9218
+ const coverage = camera.coverage();
9219
+ if (coverage.length === 0) return false;
9220
+ const resident = new Map([...camera.all()].map((tile) => [`${tile.x}/${tile.y}`, tile.value]));
9221
+ return coverage.every(({ x: x3, y: y2 }) => {
9222
+ const value = resident.get(`${x3}/${y2}`);
9223
+ return value === emptyTile || Boolean(value?.gl);
9224
+ });
9225
+ }
9052
9226
  const caster = {
9053
9227
  groundOrder: 0,
9054
9228
  bounds() {
@@ -9112,6 +9286,7 @@ function createTileflowBuildings3D(options) {
9112
9286
  context.uniform2f(program.uniforms.u_offset, ...offset);
9113
9287
  context.uniform4f(program.uniforms.u_ring ?? null, ...ring);
9114
9288
  context.uniform2f(program.uniforms.u_ring_ahead ?? null, ...ahead);
9289
+ context.uniform1i(program.uniforms.u_ring_directional ?? null, camera.ring()?.fade ? 1 : 0);
9115
9290
  const buffers = value.gl;
9116
9291
  context.bindVertexArray(buffers.vao);
9117
9292
  for (const range of ranges)
@@ -9152,7 +9327,9 @@ function createTileflowBuildings3D(options) {
9152
9327
  return models.shown().filter((model) => model.gl);
9153
9328
  }
9154
9329
  function appearanceOf(model, now) {
9155
- if (model.standingSince === void 0) return 1;
9330
+ const entrance = design().entrance;
9331
+ if (entrance === false || entrance?.models && entrance.models[0] === entrance.models[1] || model.standingSince === void 0)
9332
+ return 1;
9156
9333
  const reduced = typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches;
9157
9334
  return reduced ? 1 : Math.min(1, Math.max(0, (now - model.standingSince) / modelFade));
9158
9335
  }
@@ -9394,13 +9571,21 @@ function createTileflowBuildings3D(options) {
9394
9571
  return {
9395
9572
  lng: ring.centre[0] / n * 360 - 180,
9396
9573
  lat: Math.atan(Math.sinh(Math.PI * (1 - 2 * ring.centre[1] / n))) * 180 / Math.PI,
9397
- radius: ring.radius * ring.tileMetres
9574
+ radius: ring.radius * ring.tileMetres,
9575
+ ...ring.fade ? { forward: ring.fade.end * ring.tileMetres } : {}
9398
9576
  };
9399
9577
  }
9400
9578
  function ringIn(x3, y2) {
9401
9579
  const ring = camera.ring();
9402
9580
  if (!ring) return [0, 0, 0, 0];
9403
9581
  const extent4 = tileflowBuildingExtent;
9582
+ if (ring.fade)
9583
+ return [
9584
+ (ring.fade.origin[0] - x3) * extent4,
9585
+ (ring.fade.origin[1] - y2) * extent4,
9586
+ ring.fade.start * extent4,
9587
+ ring.fade.end * extent4
9588
+ ];
9404
9589
  const cx = (ring.centre[0] - x3) * extent4;
9405
9590
  const cy = (ring.centre[1] - y2) * extent4;
9406
9591
  const inner = ring.radius * extent4 * 0.8;
@@ -9414,6 +9599,8 @@ function createTileflowBuildings3D(options) {
9414
9599
  return [Math.sin(bearing), -Math.cos(bearing)];
9415
9600
  }
9416
9601
  function insideRing(ring, left, top, right, bottom) {
9602
+ if (camera.ring()?.fade)
9603
+ return Math.min(ahead[0] * (left - ring[0]), ahead[0] * (right - ring[0])) + Math.min(ahead[1] * (top - ring[1]), ahead[1] * (bottom - ring[1])) < ring[3];
9417
9604
  const radius = ring[3];
9418
9605
  if (!(radius > 0)) return true;
9419
9606
  const cx = ring[0];
@@ -9631,9 +9818,10 @@ function createTileflowBuildings3D(options) {
9631
9818
  );
9632
9819
  context.uniform4f(u.u_ring ?? null, ...ringIn(x3, y2));
9633
9820
  context.uniform2f(u.u_ring_ahead ?? null, ...ahead);
9821
+ context.uniform1i(u.u_ring_directional ?? null, camera.ring()?.fade ? 1 : 0);
9822
+ context.activeTexture(context.TEXTURE1);
9634
9823
  const palette = themes ? paletteOf(context, entry, themes.themes) : void 0;
9635
9824
  context.uniform1f(u.u_palette_on, palette ? 1 : 0);
9636
- context.activeTexture(context.TEXTURE1);
9637
9825
  context.bindTexture(context.TEXTURE_2D, palette?.texture ?? blank ?? null);
9638
9826
  context.uniform1i(u.u_palette, 1);
9639
9827
  if (palette && themes) {
@@ -9994,6 +10182,7 @@ ${shaderData.define}`;
9994
10182
  if (disposed || map.getLayer(tileflowBuildings3DLayerId) || !map.isStyleLoaded()) return;
9995
10183
  try {
9996
10184
  map.addLayer(layer, beforeId());
10185
+ installedLayer = map.getLayer(tileflowBuildings3DLayerId);
9997
10186
  } catch {
9998
10187
  }
9999
10188
  }
@@ -10098,6 +10287,9 @@ ${shaderData.define}`;
10098
10287
  get scale() {
10099
10288
  return scale;
10100
10289
  },
10290
+ get ready() {
10291
+ return ready;
10292
+ },
10101
10293
  get stats() {
10102
10294
  let buildings = 0;
10103
10295
  let vertices = 0;
@@ -10126,7 +10318,8 @@ ${shaderData.define}`;
10126
10318
  scene.setReach(void 0);
10127
10319
  models.dispose();
10128
10320
  try {
10129
- if (map.getLayer(tileflowBuildings3DLayerId)) map.removeLayer(tileflowBuildings3DLayerId);
10321
+ if (installedLayer && map.getLayer(tileflowBuildings3DLayerId) === installedLayer)
10322
+ map.removeLayer(tileflowBuildings3DLayerId);
10130
10323
  } catch {
10131
10324
  }
10132
10325
  if (gl) {
@@ -10145,6 +10338,9 @@ function isWebGL2(context) {
10145
10338
  return typeof WebGL2RenderingContext !== "undefined" && context instanceof WebGL2RenderingContext;
10146
10339
  }
10147
10340
 
10341
+ // src/camera-limits.ts
10342
+ var tileflowMaxPitch = 85;
10343
+
10148
10344
  // src/camera.ts
10149
10345
  var tileflowCameraMetadataKey = "tileflow:camera";
10150
10346
  function readTileflowCamera(metadata) {
@@ -10152,7 +10348,12 @@ function readTileflowCamera(metadata) {
10152
10348
  const value = metadata[tileflowCameraMetadataKey];
10153
10349
  if (!value || typeof value !== "object") return {};
10154
10350
  const policy = value;
10155
- return policy.version === 1 && typeof policy.adaptivePerspective === "boolean" ? { adaptivePerspective: policy.adaptivePerspective } : {};
10351
+ if (policy.version !== 1) return {};
10352
+ const limit = policy.pitchLimit;
10353
+ return {
10354
+ ...typeof policy.adaptivePerspective === "boolean" ? { adaptivePerspective: policy.adaptivePerspective } : {},
10355
+ ...limit && typeof limit.maxZoom === "number" && limit.maxZoom >= 0 && limit.maxZoom <= 24 && typeof limit.maxPitch === "number" && limit.maxPitch >= 0 && limit.maxPitch <= tileflowMaxPitch ? { pitchLimit: { maxZoom: limit.maxZoom, maxPitch: limit.maxPitch } } : {}
10356
+ };
10156
10357
  }
10157
10358
 
10158
10359
  // src/camera-browser.ts
@@ -10221,6 +10422,41 @@ function createTileflowAdaptiveCamera(map) {
10221
10422
  map.on("remove", onRemove);
10222
10423
  return { setEnabled, dispose };
10223
10424
  }
10425
+ function createTileflowPitchLimit(map) {
10426
+ let limit;
10427
+ let original;
10428
+ let applying = false;
10429
+ let disposed = false;
10430
+ const update = () => {
10431
+ if (disposed || applying || original === void 0) return;
10432
+ const maximum = limit && map.getZoom() <= limit.maxZoom ? Math.min(original, limit.maxPitch) : original;
10433
+ if (map.getMaxPitch?.() === maximum) return;
10434
+ applying = true;
10435
+ try {
10436
+ map.setMaxPitch?.(maximum);
10437
+ } finally {
10438
+ applying = false;
10439
+ }
10440
+ };
10441
+ const setLimit = (next) => {
10442
+ if (disposed || !map.getMaxPitch || !map.setMaxPitch) return;
10443
+ limit = next;
10444
+ if (next) original ??= map.getMaxPitch();
10445
+ update();
10446
+ if (!next) original = void 0;
10447
+ };
10448
+ const onRemove = () => dispose(false);
10449
+ function dispose(restore = true) {
10450
+ if (disposed) return;
10451
+ if (restore) setLimit(void 0);
10452
+ disposed = true;
10453
+ map.off("zoom", update);
10454
+ map.off("remove", onRemove);
10455
+ }
10456
+ map.on("zoom", update);
10457
+ map.on("remove", onRemove);
10458
+ return { setLimit, dispose };
10459
+ }
10224
10460
 
10225
10461
  // src/vegetation-display.ts
10226
10462
  var tileflowVegetationDisplayMetadataKey = "tileflow:vegetation-display";
@@ -12811,11 +13047,13 @@ function createTileflowMap3D(options) {
12811
13047
  let vegetationVisible = options.vegetation;
12812
13048
  let adaptivePerspective = options.camera?.adaptivePerspective;
12813
13049
  const camera = createTileflowAdaptiveCamera(map);
13050
+ const pitchLimit = createTileflowPitchLimit(map);
12814
13051
  let authoredPerspective;
12815
13052
  let buildings;
12816
13053
  let vegetation;
12817
13054
  let streetLights;
12818
13055
  const flatBuildings = createBuildingFlatLayers(map);
13056
+ const nativeBuildings = createBuildingNativeLayers(map);
12819
13057
  let footprintLayers;
12820
13058
  let footprintZoom = 15.3;
12821
13059
  let disposed = false;
@@ -12827,6 +13065,14 @@ function createTileflowMap3D(options) {
12827
13065
  };
12828
13066
  const instant = { transition: { duration: 0 } };
12829
13067
  let declarations;
13068
+ let declaresBuildings = false;
13069
+ function syncNativeBuildings() {
13070
+ if (disposed) return;
13071
+ nativeBuildings.setVisible(
13072
+ declaresBuildings ? viewMode === "3d" && !buildings?.ready : void 0
13073
+ );
13074
+ syncFlatBuildings();
13075
+ }
12830
13076
  function sync() {
12831
13077
  if (disposed || syncing || !map.isStyleLoaded()) return;
12832
13078
  syncing = true;
@@ -12837,12 +13083,14 @@ function createTileflowMap3D(options) {
12837
13083
  const metadata = themes ? { [tileflowBuildingsMetadataKey]: themes.values[Math.round(themes.position)] } : map.getStyle()?.metadata;
12838
13084
  const design = readTileflowBuildings3D(metadata);
12839
13085
  footprintLayers = design?.flatLayers ?? [];
12840
- footprintZoom = design?.entrance?.buildings?.[1] ?? 15.3;
13086
+ footprintZoom = design?.entrance === false ? 15 : design?.entrance?.buildings?.[1] ?? 15.3;
12841
13087
  }
12842
13088
  if (authoredPerspective === void 0) {
12843
13089
  const themes = controller?.getThemeMetadata?.(tileflowCameraMetadataKey);
12844
13090
  const metadata = themes ? { [tileflowCameraMetadataKey]: themes.values[Math.round(themes.position)] } : map.getStyle()?.metadata;
12845
- authoredPerspective = readTileflowCamera(metadata).adaptivePerspective ?? false;
13091
+ const policy = readTileflowCamera(metadata);
13092
+ authoredPerspective = policy.adaptivePerspective ?? false;
13093
+ pitchLimit.setLimit(options.camera?.pitchLimit ?? policy.pitchLimit);
12846
13094
  }
12847
13095
  camera.setEnabled(shown && (adaptivePerspective ?? authoredPerspective));
12848
13096
  const declared = declarations ??= tileflowMap3DDeclarations({
@@ -12850,15 +13098,20 @@ function createTileflowMap3D(options) {
12850
13098
  ...controller ? { controller } : {}
12851
13099
  });
12852
13100
  const declares = (key) => declared.has(key);
12853
- if (shown && declares(tileflowBuildingsMetadataKey))
12854
- buildings ??= createTileflowBuildings3D(shared3);
12855
- else if (!declares(tileflowBuildingsMetadataKey) && buildings) {
13101
+ declaresBuildings = declares(tileflowBuildingsMetadataKey);
13102
+ if (shown && declaresBuildings)
13103
+ buildings ??= createTileflowBuildings3D({
13104
+ ...shared3,
13105
+ onReadyChange: syncNativeBuildings,
13106
+ ...options.onError ? { onError: options.onError } : {}
13107
+ });
13108
+ else if (!declaresBuildings && buildings) {
12856
13109
  buildings.dispose();
12857
13110
  buildings = void 0;
12858
13111
  }
12859
13112
  if (!vegetation && (declares(tileflowVegetationMetadataKey) || declares(tileflowVegetationDisplayMetadataKey)))
12860
13113
  vegetation = createTileflowVegetation({ ...shared3, visible: vegetationVisible, viewMode });
12861
- syncFlatBuildings();
13114
+ syncNativeBuildings();
12862
13115
  if (shown && declares(tileflowStreetLightsMetadataKey))
12863
13116
  streetLights ??= createTileflowStreetLights(shared3);
12864
13117
  else if (streetLights) {
@@ -12878,7 +13131,7 @@ function createTileflowMap3D(options) {
12878
13131
  const canvas = map.getCanvas?.();
12879
13132
  flatBuildings.update(
12880
13133
  footprintLayers,
12881
- viewMode === "3d" && Boolean(buildings) && map.getZoom() >= footprintZoom && Boolean(canvas?.getContext?.("webgl2"))
13134
+ viewMode === "3d" && Boolean(buildings?.ready) && map.getZoom() >= footprintZoom && Boolean(canvas?.getContext?.("webgl2"))
12882
13135
  );
12883
13136
  }
12884
13137
  function change(next, transition) {
@@ -12902,6 +13155,7 @@ function createTileflowMap3D(options) {
12902
13155
  disposed = true;
12903
13156
  flatBuildings.restore();
12904
13157
  camera.dispose();
13158
+ pitchLimit.dispose();
12905
13159
  map.off("styledata", restyle);
12906
13160
  map.off("style.load", restyle);
12907
13161
  map.off("idle", sync);
@@ -12909,6 +13163,7 @@ function createTileflowMap3D(options) {
12909
13163
  map.off("move", syncFlatBuildings);
12910
13164
  streetLights?.dispose();
12911
13165
  buildings?.dispose();
13166
+ nativeBuildings.restore();
12912
13167
  vegetation?.dispose();
12913
13168
  streetLights = void 0;
12914
13169
  buildings = void 0;
@@ -12923,6 +13178,7 @@ function createTileflowMap3D(options) {
12923
13178
  }
12924
13179
  function onRemove() {
12925
13180
  flatBuildings.forget();
13181
+ nativeBuildings.forget();
12926
13182
  dispose();
12927
13183
  }
12928
13184
  map.on("styledata", restyle);