@tomtom-org/maps-sdk-plugin-landmarks-3d 0.0.13 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.es.js CHANGED
@@ -1 +1 @@
1
- import{TomTomConfig as e,isProxyCredentialsMode as i}from"@tomtom-org/maps-sdk/core";import{LayerFilterComposer as t,mapStyleLayerIDs as a}from"@tomtom-org/maps-sdk/map";import{AmbientLight as s,BufferAttribute as r,Camera as n,Color as o,CustomBlending as l,DirectionalLight as h,DoubleSide as m,FrontSide as d,Group as c,LoaderUtils as u,LoadingManager as p,Matrix4 as f,OneFactor as y,OneMinusSrcAlphaFactor as g,SRGBColorSpace as v,Scene as x,ShaderMaterial as M,Vector3 as L,WebGLRenderer as w}from"three";import{MeshoptDecoder as b}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{GLTFLoader as k}from"three/examples/jsm/loaders/GLTFLoader.js";import{KTX2Loader as C}from"three/examples/jsm/loaders/KTX2Loader.js";import{toCreasedNormals as S}from"three/examples/jsm/utils/BufferGeometryUtils.js";import{MercatorCoordinate as P}from"maplibre-gl";var T={diffuseColor:"hsl(38, 6%, 90%)",opacity:.7,verticalGradient:!0},D={diffuseColor:"hsl(210, 9%, 17%)",opacity:.7,verticalGradient:!0},z=()=>{const{commonBaseURL:i,apiKey:t}=e.instance.get();return`${i}/maps/orbis/display/3d/landmarks/tile/{z}/{x}/{y}?${t?`key=${t}&`:""}apiVersion=2`},B="fillExtrusionGradient",O=`\n attribute float ${B};\n varying vec3 vWorldNormal;\n varying float vGradient;\n #ifdef USE_ALPHA_MASK\n varying vec2 vUv;\n #endif\n\n void main() {\n vWorldNormal = normalize(mat3(modelMatrix) * normal);\n vGradient = ${B};\n #ifdef USE_ALPHA_MASK\n vUv = uv;\n #endif\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n }\n`,E="\n #ifdef USE_ALPHA_MASK\n uniform sampler2D alphaMask;\n uniform float alphaMaskCutoff;\n varying vec2 vUv;\n #endif\n",I="\n #ifdef USE_ALPHA_MASK\n if (texture2D(alphaMask, vUv).a < alphaMaskCutoff) {\n discard;\n }\n #endif\n",A=`\n uniform vec3 diffuseColor;\n uniform vec3 lightPosition;\n uniform float lightIntensity;\n uniform vec3 lightColor;\n uniform float layerOpacity;\n uniform float verticalGradient;\n varying vec3 vWorldNormal;\n varying float vGradient;\n ${E}\n\n void main() {\n ${I}\n vec3 normal = normalize(vWorldNormal);\n // Double-sided (alpha-masked) surfaces show their interior through carved openings;\n // flip backface normals so those interiors shade like the facade instead of going dark.\n if (!gl_FrontFacing) {\n normal = -normal;\n }\n // Extrusions have only vertical walls and flat roofs, so a sloped landmark roof would shade\n // darker than every basemap roof around it: up-facing normals light like a flat roof, the\n // rest like a wall, blended for curved surfaces.\n vec3 flattened = vec3(normal.xy, 0.0);\n vec3 wallNormal = flattened / max(length(flattened), 1e-5);\n float upness = smoothstep(0.4, 0.8, normal.z);\n normal = normalize(mix(wallNormal, vec3(0.0, 0.0, 1.0), upness));\n float colorValue = dot(diffuseColor, vec3(0.2126, 0.7152, 0.0722));\n vec3 color = diffuseColor + vec3(0.03);\n float directional = clamp(dot(normal, lightPosition), 0.0, 1.0);\n directional = mix(1.0 - lightIntensity, max(1.0 - colorValue + lightIntensity, 1.0), directional);\n if (abs(normal.y) > 0.001) {\n directional *=\n (1.0 - verticalGradient) +\n verticalGradient * clamp(vGradient, mix(0.7, 0.98, 1.0 - lightIntensity), 1.0);\n }\n vec3 shaded = clamp(\n color * directional * lightColor,\n mix(vec3(0.0), vec3(0.3), vec3(1.0) - lightColor),\n vec3(1.0)\n );\n gl_FragColor = vec4(shaded, 1.0) * layerOpacity;\n }\n`,F=new L(.2875,-.498,.996),G=new o,_=new o,R=class extends M{constructor(e){super({uniforms:{diffuseColor:{value:new L(1,1,1)},lightPosition:{value:F.clone()},lightIntensity:{value:.5},lightColor:{value:new L(1,1,1)},layerOpacity:{value:1},verticalGradient:{value:1},...e&&{alphaMask:{value:e.map},alphaMaskCutoff:{value:e.cutoff}}},...e&&{defines:{USE_ALPHA_MASK:""}},vertexShader:O,fragmentShader:A,side:e?m:d,transparent:!0,blending:l,blendSrc:y,blendDst:g})}copyShadingFrom(e){this.uniforms.diffuseColor.value.copy(e.uniforms.diffuseColor.value),this.uniforms.lightPosition.value.copy(e.uniforms.lightPosition.value),this.uniforms.lightIntensity.value=e.uniforms.lightIntensity.value,this.uniforms.lightColor.value.copy(e.uniforms.lightColor.value),this.uniforms.layerOpacity.value=e.uniforms.layerOpacity.value,this.uniforms.verticalGradient.value=e.uniforms.verticalGradient.value}setDiffuseColor(e){G.setStyle(e),G.getRGB(_,v),this.uniforms.diffuseColor.value.set(_.r,_.g,_.b)}setLayerOpacity(e){this.uniforms.layerOpacity.value=e}setVerticalGradient(e){this.uniforms.verticalGradient.value=e?1:0}setLight(e,i,t,a){const s=Math.cos(i),r=Math.sin(i);this.uniforms.lightPosition.value.set(e.x*s-e.y*r,e.x*r+e.y*s,e.z),this.uniforms.lightIntensity.value=t,this.uniforms.lightColor.value.set(a.r,a.g,a.b)}},U=class extends M{constructor(e){super({...e&&{uniforms:{alphaMask:{value:e.map},alphaMaskCutoff:{value:e.cutoff}},defines:{USE_ALPHA_MASK:""}},vertexShader:O,fragmentShader:`\n ${E}\n void main() {\n ${I}\n gl_FragColor = vec4(0.0);\n }\n `,side:e?m:d,colorWrite:!1})}},j=e=>!0===e.isMesh,Z=1/(2*Math.PI*6378137),K=Math.PI/6,V=class{type="models";id;minzoom;maxzoom;map;tiles;scene;loadedTiles=/* @__PURE__ */new Set;sceneOrigin=null;onTileLoaded;ktx2Loader;transcoderReady;gltfLoader;specification;withCredentials;coveringTileKeys=/* @__PURE__ */new Set;constructor(e,i){this.id=e,this.minzoom=i.minzoom??0,this.maxzoom=i.maxzoom??22,this.tiles=i.tiles,this.specification=i,this.withCredentials=i.withCredentials??!1,this.scene=new c,this.ktx2Loader=new C(new p).setCrossOrigin("anonymous").setTranscoderPath(i.transcoderPath??""),this.gltfLoader=(new k).setKTX2Loader(this.ktx2Loader).setMeshoptDecoder(b)}onAdd(e,i){this.map=e,this.ktx2Loader.detectSupport(i)}updateTiles(){if(0===this.tiles.length)return;const e=this.coveringTiles();this.coveringTileKeys=new Set(e.map(e=>e.key));for(const i of e)this.loadTile(i);this.showCoveringTilesOnly()}showCoveringTilesOnly(){for(const e of this.scene.children)e.visible=this.coveringTileKeys.has(e.userData.key)}coveringTiles(){const e={tileSize:this.map._camera.transform.tileSize,minzoom:this.minzoom,maxzoom:this.maxzoom,terrain:this.map.terrain};return this.map.coveringTiles(e)}loadTile(e){if(this.loadedTiles.has(e.key))return;this.loadedTiles.add(e.key);const i=e.canonical.url(this.tiles,this.map.getPixelRatio(),this.specification.scheme);this.fetchTile(i).then(i=>{i&&(W(i),this.rebaseToSceneOrigin(i),i.userData={isTile:!0,key:e.key},i.visible=this.coveringTileKeys.has(e.key),this.scene.add(i),this.map.triggerRepaint(),this.onTileLoaded?.(i,e.key))}).catch(i=>{console.warn(`Problem with loading ${e.toString()}: ${i?.message??"unknown"}`)})}rebaseToSceneOrigin(e){const i=[];if(e.traverse(e=>{j(e)&&i.push(e)}),0===i.length)return;const t=i[0].position,a={x:Math.round(t.x),y:Math.round(t.y)};if(this.sceneOrigin){if(Math.hypot(t.x-this.sceneOrigin.x,t.y-this.sceneOrigin.y)>1e5){const e=a.x-this.sceneOrigin.x,i=a.y-this.sceneOrigin.y;this.scene.traverse(t=>{j(t)&&(t.position.x-=e,t.position.y-=i)}),this.sceneOrigin=a}}else this.sceneOrigin=a;for(const s of i)s.position.x-=this.sceneOrigin.x,s.position.y-=this.sceneOrigin.y}async fetchTile(e){const i=await fetch(e,this.withCredentials?{credentials:"include"}:void 0);if(204===i.status||404===i.status)return null;if(403===i.status&&"InvalidReferer"!==await(async e=>(await e.json().catch(()=>{}))?.detailedError?.code)(i))throw new Error("tile request failed with 403: Orbis 3D Landmarks is in Private Preview (https://docs.tomtom.com/legal/private-preview), and the API key needs access to it: request it from TomTom Sales at https://www.tomtom.com/contact-sales/?source_app=docs-portal&source_product=map-display-api-3d");if(!i.ok)throw new Error(`tile request failed with ${i.status}`);const t=await i.arrayBuffer();this.transcoderReady??=(async(e,i)=>{if(void 0!==i)return;const{resolveBundledTranscoderUrl:t}=await(import("./bundledTranscoder-Dn27cuYm.js"));e.setURLModifier(t)})(this.ktx2Loader.manager,this.specification.transcoderPath),await this.transcoderReady;const{scene:a}=await this.gltfLoader.parseAsync(t,u.extractUrlBase(e));return a}},W=e=>{e.traverse(e=>{if(!j(e))return;const i=e.material;i.alphaTest=.1,i.side=m,e.userData.originalMaterial=i,e.geometry=S(e.geometry,K),$(e)})},$=e=>{const i=e.geometry,t=i.getAttribute("position");i.computeBoundingBox();const a=i.boundingBox?.max.z??0,s=a>0?Math.sqrt(a/150)/a:0,n=new Float32Array(t.count);for(let r=0;r<t.count;r++)n[r]=t.getZ(r)*s;i.setAttribute(B,new r(n,1))},H=e=>e*Math.PI/180,N=class{id;type="custom";renderingMode="3d";renderer;scene;camera;tiles;directionalLight;ambientLight;map;source;minzoom=0;maxzoom=22;visible=!0;diffuseColor="#ffffff";fillExtrusionMaterial=new R;depthPrepassMaterial=new U;maskedFillExtrusionMaterials=/* @__PURE__ */new Map;tilesMainMatrix=/* @__PURE__ */new Float64Array(16);tilesStale=!0;markTilesStale=()=>{this.tilesStale=!0};constructor(e,i){this.id=e.id,this.source=new V(this.id,i),this.tiles=this.source.scene,this.updateProperties(e)}updateProperties(e){this.visible="none"!==e.layout?.visibility,this.diffuseColor=e.paint?.["models-base-color"]??"#ffffff",this.minzoom=e.minzoom??0,this.maxzoom=e.maxzoom??22}setDirectionalLight(e,i,t){this.directionalLight.position.setFromSphericalCoords(e,H(i),H(t))}onAdd(e,i){this.map=e,this.scene=new x,this.tiles=this.source.scene,this.camera=new n,this.directionalLight=new h(16777215,.5),this.setDirectionalLight(1.15,90,0),this.scene.add(this.directionalLight),this.ambientLight=new s(16777215,.1),this.scene.add(this.ambientLight),this.scene.add(this.tiles),this.renderer=new w({canvas:e.getCanvas(),context:i,antialias:!0}),this.renderer.autoClear=!1,this.source.onAdd(e,this.renderer),this.tilesStale=!0,e.off("data",this.markTilesStale),e.on("data",this.markTilesStale)}render(e,i){const t=this.map._camera.transform.tileZoom,a=t>=this.minzoom&&t<=this.maxzoom;this.tiles.visible=this.visible&&a,this.visible&&a&&(this.syncLighting(),this.updateTilesWhenStale(i.defaultProjectionData.mainMatrix),this.groundLandmarksOnTerrain(),this.alignCameraToMap(i),this.renderer.resetState(),this.needsTranslucentPrepass()&&this.renderDepthPrepass(),this.applyMaterials(),this.renderer.render(this.scene,this.camera))}updateTilesWhenStale(e){(this.tilesMainMatrix.some((i,t)=>i!==e[t])||this.tilesStale)&&(this.tilesMainMatrix.set(e),this.tilesStale=!1,this.source.updateTiles())}groundLandmarksOnTerrain(){for(const e of this.tiles.children)e.visible&&e.traverse(e=>{j(e)&&this.groundMeshOnTerrain(e)})}groundMeshOnTerrain(e){const i=this.terrainSamplePoints(e);if(!i)return;let t=null;for(const a of i){const i=this.map.queryTerrainElevation(a);if(null===i)return void(e.position.z=0);(null===t||i<t)&&(t=i)}null!==t&&(e.position.z=t-.5)}terrainSamplePoints(e){let i=e.userData.terrainSamplePoints;if(!i){e.geometry.boundingBox||e.geometry.computeBoundingBox();const t=e.geometry.boundingBox;if(!t||t.isEmpty())return null;const a=e.position.x+this.sceneOrigin.x,s=e.position.y+this.sceneOrigin.y,r=(t.min.x+t.max.x)/2,n=(t.min.y+t.max.y)/2;i=[[r,n],[t.min.x,t.min.y],[t.min.x,t.max.y],[t.max.x,t.min.y],[t.max.x,t.max.y],[r,t.min.y],[r,t.max.y],[t.min.x,n],[t.max.x,n]].map(([e,i])=>new P(.5+(a+e)*Z,.5-(s+i)*Z).toLngLat().toArray()),e.userData.terrainSamplePoints=i}return i}alignCameraToMap(e){const i=Z/Math.cos(H(this.map.getCenter().lat)),t=.5+Z*this.sceneOrigin.x,a=.5-Z*this.sceneOrigin.y,s=new f;s.set(Z,0,0,t,0,-Z,0,a,0,0,i,0,0,0,0,1);const r=(new f).fromArray(e.defaultProjectionData.mainMatrix);this.camera.projectionMatrix.copy(r).multiply(s)}get sceneOrigin(){return this.source.sceneOrigin??{x:0,y:0}}needsTranslucentPrepass(){return this.fillExtrusionMaterial.uniforms.layerOpacity.value<1}renderDepthPrepass(){this.tiles.traverse(e=>{j(e)&&(e.material=this.maskedFillExtrusionVariant(e)?.depth??this.depthPrepassMaterial)}),this.renderer.render(this.scene,this.camera)}setOpacity(e){this.forEachFillExtrusionMaterial(i=>i.setLayerOpacity(e))}setVerticalGradient(e){this.forEachFillExtrusionMaterial(i=>i.setVerticalGradient(e))}getMaterial(e){return this.maskedFillExtrusionVariant(e)?.color??this.fillExtrusionMaterial}maskedFillExtrusionVariant(e){const i=e.userData.originalMaterial,t=i?.map;if(!t)return null;let a=this.maskedFillExtrusionMaterials.get(t);if(!a){const e={map:t,cutoff:i.alphaTest||.1};a={color:new R(e),depth:new U(e)},a.color.copyShadingFrom(this.fillExtrusionMaterial),this.maskedFillExtrusionMaterials.set(t,a)}return a}forEachFillExtrusionMaterial(e){e(this.fillExtrusionMaterial),this.maskedFillExtrusionMaterials.forEach(i=>e(i.color))}syncLighting(){const e=this.map,i=e.style?.light,t=i?.properties,a=i?.getCartesianPosition?.();if(t&&a)try{const i=t.get("intensity");this.directionalLight.intensity=i*Math.PI,this.ambientLight.intensity=(1-i)*Math.PI;const s={x:-a[0],y:a[1],z:a[2]};this.directionalLight.position.set(s.x,s.y,s.z);const r="viewport"===t.get("anchor")?-(e._camera.transform.bearingInRadians??0):0,n=t.get("color");this.forEachFillExtrusionMaterial(e=>e.setLight(s,r,i,n))}catch{}}applyMaterials(){this.forEachFillExtrusionMaterial(e=>e.setDiffuseColor(this.diffuseColor)),this.tiles.traverse(e=>{j(e)&&(e.material=this.getMaterial(e))})}},q=["!",["coalesce",["get","has_landmark"],!1]],X=class{map;layerID="orbis-3d-landmarks";basemapBuildingLayerID="3D - Building";modelsLayer;layerMinZoom;layerMaxZoom;displayMode;constructor(e,t={}){this.map=e,this.layerMinZoom=t.minZoom,this.layerMaxZoom=t.maxZoom,this.displayMode=t.displayMode??"inherited";const a={id:this.layerID,type:"models",source:this.layerID,minzoom:t.minZoom??10,maxzoom:t.maxZoom??22},s={type:"models",tiles:[z()],minzoom:15,maxzoom:15,withCredentials:t.withCredentials??i()};this.modelsLayer=new N(a,s),this.modelsLayer.visible=t.visible??!0,this.map.addStyleChangeHandler({onStyleChanged:()=>this.install()}),this.installWhenReady()}installWhenReady(){this.map.mapReady?this.install():this.map.mapLibreMap.once("styledata",()=>this.installWhenReady())}get layer(){return this.modelsLayer}getDisplayMode(){return this.displayMode}async setDisplayMode(e){this.displayMode=e,this.map.mapReady&&this.applyDisplayMode()}isVisible(){return this.modelsLayer.visible}async setVisible(e){this.modelsLayer.visible=e,this.map.mapReady&&this.map.mapLibreMap.triggerRepaint()}install(){const e=this.map.mapLibreMap;e.getLayer(this.layerID)||e.addLayer(this.modelsLayer,this.landmarkInsertBeforeID()),e.getLayer(this.basemapBuildingLayerID)&&e.setLayoutProperty(this.basemapBuildingLayerID,"visibility","visible"),this.alignZoomRangeWithBasemapBuildings(),this.excludeLandmarkBuildingsFromBasemap(),this.modelsLayer.source.onTileLoaded=()=>{this.resolveCurrentMaterialState().opacity<1&&this.applyDisplayMode()},this.applyDisplayMode()}landmarkInsertBeforeID(){const e=a.poi;return this.map.mapLibreMap.getLayer(e)?e:void 0}alignZoomRangeWithBasemapBuildings(){const e=this.map.mapLibreMap.getLayer(this.basemapBuildingLayerID);e&&(this.modelsLayer.minzoom=this.layerMinZoom??e.minzoom??10,this.modelsLayer.maxzoom=this.layerMaxZoom??e.maxzoom??22)}excludeLandmarkBuildingsFromBasemap(){t.for(this.map).setClause(this.basemapBuildingLayerID,"landmarks3d.buildings",q)}readBasemapBuildingMaterial(){const e=this.map.mapLibreMap;if(!e.getLayer(this.basemapBuildingLayerID))return null;const i=(e=>{if("string"==typeof e)return e;if(Array.isArray(e)&&"match"===e[0]){const i=e.at(-1);if("string"==typeof i)return i}return null})(e.getPaintProperty(this.basemapBuildingLayerID,"fill-extrusion-color"));if(!i)return null;const t=e.getPaintProperty(this.basemapBuildingLayerID,"fill-extrusion-opacity"),a=e.getPaintProperty(this.basemapBuildingLayerID,"fill-extrusion-vertical-gradient");return{diffuseColor:i,..."number"==typeof t&&{opacity:t},..."boolean"==typeof a&&{verticalGradient:a}}}resolveCurrentMaterialState(){const e="inherited"===this.displayMode?this.readBasemapBuildingMaterial():null;return((e,i)=>{switch(e){case"dark":return D;case"light":return T;default:return{...T,...i}}})(this.displayMode,e)}applyDisplayMode(){const e=this.resolveCurrentMaterialState();this.modelsLayer.diffuseColor=e.diffuseColor,this.modelsLayer.setOpacity(e.opacity),this.modelsLayer.setVerticalGradient(e.verticalGradient),this.map.mapLibreMap.triggerRepaint()}};export{X as Landmarks3D,N as ModelsLayer,V as ModelsSource,z as buildLandmarksTileURL};
1
+ import{LayerFilterComposer,MERCATOR_UNITS_PER_EPSG3857_METER,StylingFoundationsModule,configWithKnobs,configWithoutKnob,knobValueIn,localFrameMatrix,parseCssColor,standardStyleIDs}from"@tomtom-org/maps-sdk/map";import{MercatorCoordinate}from"maplibre-gl";import{AmbientLight,Box2,BufferAttribute,BufferGeometry,Camera,Color,CustomBlending,DataArrayTexture,DirectionalLight,DoubleSide,FrontSide,Group,HemisphereLight,LinearFilter,LinearMipmapLinearFilter,LoaderUtils,LoadingManager,MathUtils,Mesh,MeshBasicMaterial,MeshLambertMaterial,OneFactor,OneMinusSrcAlphaFactor,PCFSoftShadowMap,PlaneGeometry,RedFormat,RepeatWrapping,SRGBColorSpace,Scene,ShaderMaterial,ShadowMaterial,ShapeUtils,UnsignedByteType,Vector2,Vector3,Vector4,WebGLRenderer}from"three";import{TomTomConfig,isProxyCredentialsMode}from"@tomtom-org/maps-sdk/core";import{MeshoptDecoder}from"three/examples/jsm/libs/meshopt_decoder.module.js";import{GLTFLoader}from"three/examples/jsm/loaders/GLTFLoader.js";import{KTX2Loader}from"three/examples/jsm/loaders/KTX2Loader.js";import{toCreasedNormals}from"three/examples/jsm/utils/BufferGeometryUtils.js";var BUILDING_GROUPS=["education","transport","leisure","healthcare","shopping"],oneColorForEveryGroup=e=>new Array(BUILDING_GROUPS.length+1).fill(e),groupColorsOfPaint=e=>{if("string"==typeof e)return oneColorForEveryGroup(e);if(!Array.isArray(e)||"match"!==e[0])return;const t=e.at(-1);if("string"!=typeof t)return;const i=e.slice(2,-1);return[...BUILDING_GROUPS.map(e=>{for(let t=0;t<i.length;t+=2){const[n,a]=[i[t],i[t+1]];if((Array.isArray(n)?n.includes(e):n===e)&&"string"==typeof a)return a}return t}),t]},landmarksOn=/* @__PURE__ */new WeakMap,buildings3DLookOn=/* @__PURE__ */new WeakMap,restyleLandmarksOn=/* @__PURE__ */new WeakMap,isMesh=e=>!0===e.isMesh,parsedCssColors=/* @__PURE__ */new Map,setCssColor=(e,t)=>{const i=(e=>{if(parsedCssColors.has(e))return parsedCssColors.get(e);parsedCssColors.size>=64&&parsedCssColors.clear();const t=parseCssColor(e);return parsedCssColors.set(e,t),t})(t);return i?e.setRGB(i[0],i[1],i[2],SRGBColorSpace):e},whenMapReady=(e,t)=>{e.mapReady?t():e.mapLibreMap.once("styledata",()=>whenMapReady(e,t))},sameLook=(e,t)=>void 0!==t&&JSON.stringify(e)===JSON.stringify(t),setMaterialOpacity=(e,t)=>{e.opacity=t;const i=t<1;i!==e.transparent&&(e.transparent=i,e.needsUpdate=!0)},mercatorMetresToLngLat=(e,t)=>new MercatorCoordinate(.5+e*MERCATOR_UNITS_PER_EPSG3857_METER,.5-t*MERCATOR_UNITS_PER_EPSG3857_METER).toLngLat().toArray(),setCameraProjection=(e,t)=>{e.projectionMatrix.fromArray(t),e.projectionMatrixInverse.copy(e.projectionMatrix).invert()},DAY={opacity:1,minZoom:15,"facade.pattern":"mixed","facade.intensity":.85,"facade.floorHeightMeters":3.4,"windows.color":"#8da3b6","reflections.intensity":.7,"litWindows.color":"#ffd08a","litWindows.fraction":0,"litWindows.intensity":.8,"light.direction":215,"light.altitude":30,"light.color":"#fff3e0","light.intensity":.75,"ambientLight.color":"#dce8f5","ambientLight.intensity":.45,"shadows.visible":!0,"shadows.intensity":.7,"roadLabels.occluded":!1,"pois.occluded":!1},NIGHT=/* @__PURE__ */(()=>({...DAY,"facade.intensity":.9,"windows.color":"#1a2330","litWindows.color":"#f2c98f","litWindows.fraction":.3,"litWindows.intensity":.35,"light.direction":135,"light.altitude":35,"light.color":"#a9bde0","light.intensity":.3,"ambientLight.color":"#5a6c94","ambientLight.intensity":.5,"shadows.intensity":.4}))(),PRESETS=/* @__PURE__ */(()=>({streetLight:DAY,streetDark:NIGHT,streetLightDriving:{...DAY,"facade.intensity":.55,"shadows.intensity":.5},streetDarkDriving:{...NIGHT,"facade.intensity":.7,"litWindows.fraction":.2},monoLight:{...DAY,"facade.intensity":.6,"windows.color":"#b4b9bf","light.color":"#ffffff","ambientLight.color":"#f2f4f7","ambientLight.intensity":.55,"shadows.intensity":.5},monoDark:{...NIGHT,"facade.intensity":.75,"windows.color":"#1f2226","litWindows.color":"#d3dae4","litWindows.fraction":.2,"litWindows.intensity":.3,"light.color":"#c7d0de","ambientLight.color":"#565d68"},streetSatellite:{...DAY,"facade.intensity":1,"walls.color":"#d8d0c2","roofs.color":"#8f8a82","windows.color":"#647b90","light.color":"#fff0d4","light.intensity":.8,"light.altitude":35,"shadows.intensity":.75}}))(),towardsSun=(e,t=new Vector3)=>{const i=MathUtils.degToRad(e["light.direction"]),n=MathUtils.degToRad(e["light.altitude"]);return t.set(Math.sin(i)*Math.cos(n),Math.cos(i)*Math.cos(n),Math.sin(n))},isDrawn=(e,t)=>!0!==e.underground&&!0!==e.has_part&&!1!==e.extrude&&!(t.withoutLandmarks&&!0===e.has_landmark),numberOr=(e,t)=>"number"==typeof e?e:t,seedOf=(e,t)=>{const i=e.id??`${t[0]?.[0]?.x},${t[0]?.[0]?.y}`;let n=2166136261;for(const a of String(i))n=Math.imul(n^(a.codePointAt(0)??0),16777619);return(n>>>0)/2**32},GROUP_INDEX=/* @__PURE__ */(()=>new Map(BUILDING_GROUPS.map((e,t)=>[e,t])))(),readBuildings=(e,t,i)=>{const n=e.latestFeatureIndex?.loadVTLayers()[t];if(!n?.length)return{footprints:[],extent:4096};const a=[];for(let o=0;o<n.length;o++){const e=n.feature(o);if(3!==e.type||!isDrawn(e.properties,i))continue;const t=e.loadGeometry();a.push({rings:t,base:numberOr(e.properties.ground_height,0),height:numberOr(e.properties.height,4),group:GROUP_INDEX.get(e.properties.group)??BUILDING_GROUPS.length,seed:seedOf(e,t)})}return{footprints:a,extent:n.extent??n.feature(0).extent}},FACADE_ATTRIBUTES={uv:"facadeUv",frame:"facadeFrame",kind:"facadeKind"},ROOF_NORMAL=[0,0,1],signedArea=e=>{let t=0;for(let i=0,n=e.length-1;i<e.length;n=i++)t+=(e[n].x-e[i].x)*(e[i].y+e[n].y);return t/2},isBorderEdge=(e,t,i)=>e.x<=0&&t.x<=0||e.x>=i&&t.x>=i||e.y<=0&&t.y<=0||e.y>=i&&t.y>=i,insideTile=(e,t,i)=>{let n=0,a=1;const o=t.x-e.x,r=t.y-e.y,s=[[-o,e.x],[o,i-e.x],[-r,e.y],[r,i-e.y]];for(const[l,d]of s){if(0===l){if(d<0)return;continue}const e=d/l;l<0?n=Math.max(n,e):a=Math.min(a,e)}return n<a?[n,a]:void 0},GeometryWriter=class{attributeSizes=[["position",3],["normal",3],[FACADE_ATTRIBUTES.uv,2],[FACADE_ATTRIBUTES.frame,4],[FACADE_ATTRIBUTES.kind,2]];count=0;capacity=4096;arrays=this.allocate();normal=ROOF_NORMAL;frame=[0,0,0,0];roof=0;group=0;startSurface(e,t,i,n){this.normal=e,this.frame=t,this.roof=i,this.group=n}vertex(e,t,i,n,a){if(this.count===this.capacity){this.capacity*=2;const e=this.arrays;this.arrays=this.allocate();for(const[t]of this.attributeSizes)this.arrays[t].set(e[t])}const o=this.count++,{normal:r,frame:s,roof:l,group:d}=this,{position:c,normal:h,[FACADE_ATTRIBUTES.uv]:m}=this.arrays,u=this.arrays[FACADE_ATTRIBUTES.frame],f=this.arrays[FACADE_ATTRIBUTES.kind];c[3*o]=e,c[3*o+1]=t,c[3*o+2]=i,h[3*o]=r[0],h[3*o+1]=r[1],h[3*o+2]=r[2],m[2*o]=n,m[2*o+1]=a,u[4*o]=s[0],u[4*o+1]=s[1],u[4*o+2]=s[2],u[4*o+3]=s[3],f[2*o]=l,f[2*o+1]=d}toGeometry(){const e=new BufferGeometry;for(const[t,i]of this.attributeSizes)e.setAttribute(t,new BufferAttribute(this.arrays[t].slice(0,this.count*i),i));return e.computeBoundingSphere(),e}allocate(){return Object.fromEntries(this.attributeSizes.map(([e,t])=>[e,new Float32Array(this.capacity*t)]))}},writeWalls=(e,t,i,n,a)=>{const{base:o,height:r,seed:s,group:l}=n,d=i.length-1,c=i[0].equals(i[d])?d:i.length;for(let h=0;h<c;h++){const n=(h+1)%i.length;if(isBorderEdge(t[h],t[n],a))continue;const d=insideTile(t[h],t[n],a);if(!d)continue;const c=i[h],m=i[n],u=c.distanceTo(m);if(0===u)continue;const f=m.x-c.x,g=m.y-c.y,p=[g/u,-f/u,0],[y,v]=d,w=y>0||v<1,x=w?(c.x*f+c.y*g)/u:0;e.startSurface(p,[w?0:u,o,r,s],0,l);const b=(t,i)=>e.vertex(c.x+f*t,c.y+g*t,i,x+t*u,i);b(y,o),b(v,o),b(v,r),b(y,o),b(v,r),b(y,r)}},clipToTile=(e,t)=>{const i=[e=>e.x,e=>t-e.x,e=>e.y,e=>t-e.y];let n=e;for(const a of i){const e=n;n=[],e.forEach((t,i)=>{const o=e[(i||e.length)-1],[r,s]=[a(t),a(o)];if(r>=0!=s>=0){const e=s/(s-r);n.push({x:o.x+(t.x-o.x)*e,y:o.y+(t.y-o.y)*e})}r>=0&&n.push(t)})}return n},writeRoof=(e,t,i,n)=>{if(t.length<3)return;const a=ShapeUtils.triangulateShape(t,i),o=[t,...i].flat(),{height:r,group:s}=n;e.startSurface(ROOF_NORMAL,[0,n.base,r,n.seed],1,s);const l=t=>e.vertex(t.x,t.y,r,t.x,t.y);for(const[d,c,h]of a){const e=o[d],t=o[c],i=o[h],n=(t.x-e.x)*(i.y-e.y)-(t.y-e.y)*(i.x-e.x)>0;l(e),l(n?t:i),l(n?i:t)}},writeBuilding=(e,t,i)=>{if(t.height<=t.base)return;const n=e=>new Vector2(i.originX+e.x*i.metresPerUnit,i.originY-e.y*i.metresPerUnit);for(const[a,...o]of(e=>{const t=[];let i;for(const n of e){const e=signedArea(n);0!==e&&(i??=e<0,i===e<0?t.push([n]):t.at(-1)?.push(n))}return t})(t.rings)){const r=(e,t)=>{const i=e.map(n);return signedArea(i)>0!==t?{tileRing:[...e].reverse(),sceneRing:[...i].reverse()}:{tileRing:e,sceneRing:i}},s=r(a,!0),l=o.map(e=>r(e,!1));for(const n of[s,...l])writeWalls(e,n.tileRing,n.sceneRing,t,i.extent);const d=e=>clipToTile(e,i.extent).map(n),c=o.map(d).filter(e=>e.length>=3);writeRoof(e,d(a),c,t)}},BuildingsExtrusion=class{buildings;frame;writer=new GeometryWriter;next=0;constructor(e,t){this.buildings=e,this.frame=t}extrudeUntil(e){do{if(this.next===this.buildings.length)break;writeBuilding(this.writer,this.buildings[this.next++],this.frame)}while(performance.now()<e);return this.next===this.buildings.length}toGeometry(){return this.writer.toGeometry()}},GLASS_GLSL="\nuniform vec3 eyePosition;\nuniform vec3 sunDirection;\nuniform vec3 sunColor;\nuniform vec3 skyColor;\nuniform float skyIntensity;\nuniform float reflectivity;\nconst float SKY_GLOW = 0.5;\nconst float SUN_GLOW = 0.6;\n\n\n\nvec3 mirroredSky(vec3 direction) {\nvec2 heading = normalize(direction.xy + 1e-4);\nvec3 sky = skyColor * skyIntensity * mix(3.0, 1.8, smoothstep(0.0, 0.7, direction.z));\nfloat sunSide = max(dot(heading, normalize(sunDirection.xy + 1e-4)), 0.0);\nreturn sky + sunColor * SKY_GLOW * sunSide * sunSide * (1.0 - smoothstep(0.0, 0.6, direction.z)) * (1.0 - sunDirection.z);\n}\n\n\nvec3 mirroredStreet() {\nreturn (skyColor * skyIntensity + sunColor * sunDirection.z * smoothstep(0.35, 0.75, sunDirection.z)) * 0.25;\n}\n\n\nvec3 mirroredSun(vec3 reflected) {\nreturn sunColor * pow(max(dot(reflected, sunDirection), 0.0), 12.0) * SUN_GLOW;\n}\n\n\nfloat glassFresnel(vec3 normal, vec3 toEye) {\nreturn 0.25 + 0.75 * pow(1.0 - clamp(dot(normal, toEye), 0.0, 1.0), 5.0);\n}\n",SUN_IN_THE_GLASS="\n#if NUM_DIR_LIGHTS > 0\nvec3 glassSunSeen = directLight.color / max(directionalLights[0].color, vec3(1e-4));\ntotalEmissiveRadiance += glassSunReflection * clamp(max(glassSunSeen.r, max(glassSunSeen.g, glassSunSeen.b)), 0.0, 1.0);\n#endif\n",WINDOW_LAYOUTS=[{across:[.29,.71],up:[.3,.78]},{across:[.1,.9],up:[.22,.8]},{across:[.05,.95],up:[.04,.95]},{across:[.06,.94],up:[.09,.85]}],coverage=(e,[t,i])=>Math.max(0,Math.min(e+1,128*i)-Math.max(e,128*t)),createWindowProfiles=()=>{const e=new Uint8Array(128*WINDOW_LAYOUTS.length*2);WINDOW_LAYOUTS.flatMap(({across:e,up:t})=>[e,t]).forEach((t,i)=>{for(let n=0;n<128;n++)e[128*i+n]=Math.round(255*coverage(n,t))});const t=new DataArrayTexture(e,128,1,2*WINDOW_LAYOUTS.length);return t.format=RedFormat,t.type=UnsignedByteType,t.wrapS=RepeatWrapping,t.magFilter=LinearFilter,t.minFilter=LinearMipmapLinearFilter,t.generateMipmaps=!0,t.needsUpdate=!0,t},GROUP_COLOR_COUNT=BUILDING_GROUPS.length+1,PATTERN_INDEX={plain:0,residential:1,office:2,glass:3,mixed:4},VERTEX_DECLARATIONS$1=/* @__PURE__ */(()=>`\nattribute vec2 ${FACADE_ATTRIBUTES.uv};\nattribute vec4 ${FACADE_ATTRIBUTES.frame};\nattribute vec2 ${FACADE_ATTRIBUTES.kind};\nvarying vec2 vFacadeUv;\nvarying vec4 vFacadeFrame;\nvarying vec2 vFacadeKind;\nvarying vec3 vScenePosition;\nvarying vec3 vSceneNormal;\n`)(),VERTEX_ASSIGNMENTS$1=/* @__PURE__ */(()=>`\nvFacadeUv = ${FACADE_ATTRIBUTES.uv};\nvFacadeFrame = ${FACADE_ATTRIBUTES.frame};\nvFacadeKind = ${FACADE_ATTRIBUTES.kind};\nvScenePosition = (modelMatrix * vec4(transformed, 1.0)).xyz;\nvSceneNormal = normalize(mat3(modelMatrix) * objectNormal);\n`)(),FRAGMENT_DECLARATIONS$1=/* @__PURE__ */(()=>`\nuniform vec3 wallColors[${GROUP_COLOR_COUNT}];\nuniform vec3 roofColor;\nuniform float roofFollowsWalls;\nuniform vec3 windowColor;\nuniform vec3 litColor;\nuniform float litFraction;\nuniform float litIntensity;\nuniform float facadeIntensity;\nuniform float floorHeight;\nuniform float facadePattern;\n${GLASS_GLSL}\nconst float GLINT_SHARPNESS = 160.0;\nconst float GLINT_STRENGTH = 2.0;\nconst float PANE_TILT = 0.04;\n\nconst float PANE_LIFT = 0.1;\n\nconst float STREET_WIDTH = 24.0;\nconst float ACROSS_WIDTH = 28.0;\n\n\nconst float ACROSS_BAY = 3.0;\nconst vec2 ACROSS_GLASS = vec2(0.6, 0.55);\nuniform sampler2DArray windowProfiles;\nvarying vec2 vFacadeUv;\nvarying vec4 vFacadeFrame;\nvarying vec2 vFacadeKind;\nvarying vec3 vScenePosition;\nvarying vec3 vSceneNormal;\n\n\nfloat facadeHash(vec3 point) {\npoint = fract(point * 0.1031);\npoint += dot(point, point.zyx + 31.32);\nreturn fract((point.x + point.y) * point.z);\n}\n\n\nfloat facadeBayWidth(float pattern) {\nreturn pattern < 1.5 ? 3.2 : (pattern < 2.5 ? 3.0 : 1.6);\n}\n\n\n\nfloat cellCoverage(float x, float share, float footprint) {\nfloat covered = 1.0 - smoothstep(-footprint, footprint, abs(fract(x) - 0.5) - share * 0.5);\nreturn mix(covered, share, smoothstep(0.25, 0.6, footprint));\n}\n\n\n\n\n\nvec3 mirroredWorld(vec3 direction, vec3 wallNormal, vec3 wallAlong, vec2 spot, vec3 wall, float building, float top, float metresPerPixel, float eyeDistance) {\nvec3 skyLight = skyColor * skyIntensity;\nvec2 heading = normalize(direction.xy + 1e-4);\nfloat travel = STREET_WIDTH * (0.7 + 0.6 * facadeHash(vec3(building, 2.0, 5.0))) / max(dot(direction, wallNormal), 0.05);\nvec2 met = spot + vec2(dot(direction, wallAlong), direction.z) * travel;\nfloat footprint = metresPerPixel * (1.0 + travel / eyeDistance);\nfloat blur = max(footprint, 0.3);\nvec3 across = vec3(floor(met.x / ACROSS_WIDTH), building, 7.0);\nfloat acrossTop = max(top, 12.0) * (0.5 + 0.9 * facadeHash(across));\n\n\nfloat facesSun = max(dot(-heading, sunDirection.xy), 0.0)\n* smoothstep(-blur, blur, met.y - acrossTop * (1.0 - smoothstep(0.1, 0.8, sunDirection.z)));\n\nfloat tone = 0.45 + 0.5 * facadeHash(across + 3.1);\nvec2 cell = met / vec2(ACROSS_BAY, floorHeight);\nfloat glass = cellCoverage(cell.x, ACROSS_GLASS.x, footprint / ACROSS_BAY)\n* cellCoverage(cell.y, ACROSS_GLASS.y, footprint / floorHeight);\nfloat lit = mix(step(facadeHash(vec3(floor(cell), building + 11.0)), litFraction), litFraction,\nsmoothstep(0.25, 0.6, footprint / ACROSS_BAY));\nvec3 facades = mix(wall * tone, windowColor, glass) * (skyLight + sunColor * facesSun)\n+ litColor * litIntensity * lit * glass * 0.8;\nvec3 seen = mix(mirroredStreet(), facades, smoothstep(-blur, blur, met.y));\nreturn mix(seen, mirroredSky(direction), smoothstep(acrossTop - blur, acrossTop + blur, met.y));\n}\n\n\nvoid applyFacade(inout vec3 albedo, out vec3 emissive, out vec3 sunReflection) {\nemissive = vec3(0.0);\nsunReflection = vec3(0.0);\nfloat wallLength = vFacadeFrame.x;\nfloat base = vFacadeFrame.y;\nfloat top = vFacadeFrame.z;\nfloat seed = vFacadeFrame.w;\n\nfloat building = floor(seed * 4096.0 + 0.5);\nvec3 wall = wallColors[int(clamp(vFacadeKind.y + 0.5, 0.0, ${GROUP_COLOR_COUNT-1}.0))] * (0.94 + 0.12 * seed);\nfloat height = vFacadeUv.y;\n\nfloat pattern = facadePattern;\nif (pattern > 3.5) {\npattern = top >= 50.0 ? 3.0 : (top >= 18.0 ? (seed < 0.3 ? 3.0 : 2.0) : 1.0);\n}\nfloat bayWidth = facadeBayWidth(pattern);\n\nfloat bays = wallLength > 0.0 ? floor(wallLength / bayWidth + 0.5) : 1.0;\nfloat along = vFacadeUv.x / (wallLength > 0.0 ? wallLength / max(bays, 1.0) : bayWidth);\nfloat bay = floor(along);\nfloat groundFloor = base < 0.5 && top >= 10.0 ? floorHeight * 1.35 : 0.0;\nfloat storeys = floor((top - 0.8 - base - groundFloor) / floorHeight);\nfloat storey = (height - base - groundFloor) / floorHeight;\nbool onGroundFloor = height < base + groundFloor;\nfloat floorIndex = onGroundFloor ? -1.0 : floor(storey);\nfloat onFloor = onGroundFloor ? 1.0 : step(0.0, floorIndex) * step(floorIndex + 0.5, storeys);\nfloat windowLayout = onGroundFloor ? ${WINDOW_LAYOUTS.length-1}.0 : pattern - 1.0;\nfloat upStorey = onGroundFloor ? (height - base) / max(groundFloor, 1e-3) : storey;\n\n\nfloat window = texture(windowProfiles, vec3(along, 0.5, windowLayout * 2.0)).r\n* texture(windowProfiles, vec3(upStorey, 0.5, windowLayout * 2.0 + 1.0)).r * onFloor;\n\n\n\n\nfloat bayAveraged = smoothstep(0.3, 0.7, fwidth(along));\nfloat storeyAveraged = smoothstep(0.3, 0.7, fwidth(storey));\nfloat distant = max(bayAveraged, storeyAveraged);\n\n\nfloat panesSharp = 1.0 - smoothstep(0.08, 0.25, max(fwidth(along), fwidth(storey)));\nfloat metresPerPixel = max(fwidth(vFacadeUv.x), fwidth(vFacadeUv.y));\n\nif (vFacadeKind.x > 0.5) {\nvec3 roof = mix(roofColor, wall * 0.8, roofFollowsWalls);\nalbedo = roof * (0.97 + 0.06 * facadeHash(vec3(floor(vFacadeUv / 3.0), building)));\nreturn;\n}\n\n\nfloat occlusion = mix(0.7, 1.0, smoothstep(0.0, 12.0, height));\nalbedo = wall * occlusion;\nif (pattern < 0.5 || top < 2.5 || bays < 1.0) return;\n\nvec3 windowSeed = vec3(bay, floorIndex, building);\nvec3 glass = windowColor * mix(0.85 + 0.3 * facadeHash(windowSeed), 1.0, distant);\n\nvec3 between = pattern > 2.5 ? mix(wall, windowColor, 0.45) * occlusion : albedo;\nfloat strength = window * facadeIntensity;\nalbedo = mix(between, glass, strength);\n\nvec3 wallNormal = normalize(vSceneNormal);\n\nvec3 wallAlong = vec3(-wallNormal.y, wallNormal.x, 0.0);\n\nvec2 tilt = (vec2(facadeHash(windowSeed + 5.3), facadeHash(windowSeed + 8.9)) - 0.5) * vec2(PANE_TILT, PANE_LIFT) * panesSharp;\nvec3 normal = normalize(wallNormal + tilt.x * wallAlong + vec3(0.0, 0.0, tilt.y));\nfloat eyeDistance = distance(eyePosition, vScenePosition);\nvec3 toEye = (eyePosition - vScenePosition) / eyeDistance;\nvec3 reflected = reflect(-toEye, normal);\n\nfloat mirror = reflectivity * (pattern > 2.5 ? 1.0 : 0.57) * strength;\nfloat reflectance = mirror * glassFresnel(normal, toEye);\n\nalbedo *= 1.0 - reflectance;\nemissive += mirroredWorld(reflected, wallNormal, wallAlong, vFacadeUv, wall, building, top, metresPerPixel, eyeDistance)\n* reflectance;\n\nsunReflection = sunColor * pow(max(dot(reflected, sunDirection), 0.0), GLINT_SHARPNESS) * GLINT_STRENGTH * mirror\n+ mirroredSun(reflected) * reflectance;\n\nfloat litWindow = 1.0 - step(litFraction, facadeHash(windowSeed + 13.7));\n\nfloat litFloor = min(1.0, litFraction * (0.1 + 1.8 * facadeHash(vec3(-1.0, floorIndex, building))));\nfloat lit = mix(mix(litWindow, litFloor, bayAveraged), litFraction, storeyAveraged);\n\nfloat glow = mix(mix(0.65 + 0.35 * facadeHash(windowSeed + 3.1), 0.2, bayAveraged), 0.15, storeyAveraged);\nemissive += litColor * litIntensity * lit * strength * glow;\nalbedo *= 1.0 - 0.6 * lit * strength;\n}\n`)(),toVector=(e,t=new Vector3)=>{const i=setCssColor(new Color,e);return t.set(i.r,i.g,i.b)},FacadeMaterial=class extends MeshLambertMaterial{facadeUniforms={wallColors:{value:Array.from({length:GROUP_COLOR_COUNT},()=>new Vector3(1,1,1))},roofColor:{value:new Vector3(1,1,1)},roofFollowsWalls:{value:1},windowColor:{value:new Vector3},litColor:{value:new Vector3},litFraction:{value:0},litIntensity:{value:0},facadeIntensity:{value:1},floorHeight:{value:3.4},facadePattern:{value:PATTERN_INDEX.mixed},skyColor:{value:new Vector3(1,1,1)},skyIntensity:{value:.45},reflectivity:{value:.7},sunDirection:{value:new Vector3(0,0,1)},sunColor:{value:new Vector3(1,1,1)},eyePosition:{value:new Vector3},windowProfiles:{value:createWindowProfiles()}};constructor(){super(),this.onBeforeCompile=e=>{Object.assign(e.uniforms,this.facadeUniforms),e.vertexShader=e.vertexShader.replace("#include <common>",`#include <common>\n${VERTEX_DECLARATIONS$1}`).replace("#include <begin_vertex>",`#include <begin_vertex>\n${VERTEX_ASSIGNMENTS$1}`),e.fragmentShader=e.fragmentShader.replace("#include <common>",`#include <common>\n${FRAGMENT_DECLARATIONS$1}`).replace("#include <map_fragment>","#include <map_fragment>\nvec3 facadeEmissive;\nvec3 glassSunReflection;\napplyFacade(diffuseColor.rgb, facadeEmissive, glassSunReflection);").replace("#include <emissivemap_fragment>","#include <emissivemap_fragment>\ntotalEmissiveRadiance += facadeEmissive;").replace("#include <lights_fragment_end>",`#include <lights_fragment_end>\n${SUN_IN_THE_GLASS}`)}}setLook(e){const t=this.facadeUniforms;e.wallColorsByGroup.forEach((e,i)=>toVector(e,t.wallColors.value[i])),toVector(e["roofs.color"],t.roofColor.value),t.roofFollowsWalls.value=e.roofsFollowWalls?1:0,toVector(e["windows.color"],t.windowColor.value),toVector(e["litWindows.color"],t.litColor.value),t.litFraction.value=e["litWindows.fraction"],t.litIntensity.value=1.4*e["litWindows.intensity"],t.facadeIntensity.value=e["facade.intensity"],t.floorHeight.value=e["facade.floorHeightMeters"],t.facadePattern.value=PATTERN_INDEX[e["facade.pattern"]],toVector(e["ambientLight.color"],t.skyColor.value),t.skyIntensity.value=e["ambientLight.intensity"],t.reflectivity.value=e["reflections.intensity"],towardsSun(e,t.sunDirection.value),toVector(e["light.color"],t.sunColor.value).multiplyScalar(e["light.intensity"]),setMaterialOpacity(this,e.opacity)}setEyePosition(e){this.facadeUniforms.eyePosition.value.copy(e)}},BuildingsLayer=class{landmarksOf;id;type="custom";renderingMode="3d";source={id:"vectorTiles",layer:"buildings"};map;renderer;look;filter={withoutLandmarks:!1};origin;frame=0;scene=new Scene;camera=new Camera;buildings=new Group;landmarks=new Group;material=new FacadeMaterial;depthOnly=new MeshBasicMaterial({colorWrite:!1});shadowsOnly=new MeshBasicMaterial({colorWrite:!1,depthWrite:!1});sun=new DirectionalLight;sky=new HemisphereLight;groundReach={value:5e3};ground=new Mesh(new PlaneGeometry(1,1),this.groundMaterial());tiles=/* @__PURE__ */new Map;pending=[];extrusion;constructor(e,t=()=>{}){this.landmarksOf=t,this.id=e,this.sky.position.set(0,0,1),this.sun.castShadow=!0,this.sun.shadow.bias=-4e-4,this.sun.shadow.normalBias=.4,this.ground.receiveShadow=!0,this.ground.renderOrder=1,this.landmarks.matrixAutoUpdate=!1,this.scene.add(this.buildings,this.landmarks,this.sun,this.sun.target,this.sky,this.ground)}setLook(e){this.look=e,this.material.setLook(e),setCssColor(this.sun.color,e["light.color"]),this.sun.intensity=e["light.intensity"]*Math.PI,setCssColor(this.sky.color,e["ambientLight.color"]),this.sky.groundColor.copy(this.sky.color).multiplyScalar(.45),this.sky.intensity=e["ambientLight.intensity"]*Math.PI,this.sun.shadow.intensity=e["shadows.intensity"],this.ground.visible=e["shadows.visible"]}onAdd(e,t){this.map=e,this.renderer??=new WebGLRenderer({canvas:e.getCanvas(),context:t,antialias:!0}),this.renderer.autoClear=!1,this.renderer.shadowMap.type=PCFSoftShadowMap;const i=Math.min(4096,this.renderer.capabilities.maxTextureSize);this.sun.shadow.mapSize.set(i,i)}render(e,t){const{map:i,renderer:n,look:a}=this;if(!i||!n||!a?.visible)return;const o=t.defaultProjectionData.mainMatrix,r=this.landmarksOf(),s=r?.prepareForBuildings(o,this.material.facadeUniforms);if(this.buildings.visible=i.getZoom()>=a.minZoom,this.landmarks.visible=void 0!==s,!this.buildings.visible&&!s)return;this.frame++;const l=void 0!==s;l!==this.filter.withoutLandmarks&&(this.filter={withoutLandmarks:l},this.pending=[],this.extrusion=void 0);const d=this.updateOrigin(i);this.buildings.visible&&this.updateTiles(i,d),r&&s&&this.placeLandmarks(r,s,d),setCameraProjection(this.camera,localFrameMatrix(o,d.position,{centerLatitude:i.getCenter().lat})),this.material.setEyePosition(this.eyePosition()),this.updateSun(i,d,a),n.shadowMap.enabled!==a["shadows.visible"]&&(n.shadowMap.enabled=a["shadows.visible"],this.scene.traverse(e=>{if(isMesh(e))for(const t of[e.material].flat())t.needsUpdate=!0})),n.resetState(),n.setViewport(0,0,e.drawingBufferWidth,e.drawingBufferHeight);const c=[{group:this.buildings,translucent:a.opacity<1,use:e=>this.useBuildingsPass(e)}];r&&s&&c.push({group:this.landmarks,translucent:s.translucent,use:e=>r.useMaterials(e)}),c.some(({translucent:e})=>e)?this.renderTranslucent(n,c):n.render(this.scene,this.camera)}renderTranslucent(e,t){const i=t.filter(e=>e.translucent),n=t.filter(e=>!e.translucent),a=n.map(({group:e})=>e.visible),o=this.ground.visible;if(this.ground.visible=!1,n.length){for(const e of i)e.use("shadows");e.render(this.scene,this.camera);for(const{group:e}of n)e.visible=!1}e.shadowMap.autoUpdate=!1;for(const r of i)r.use("depth");e.render(this.scene,this.camera),this.ground.visible=o,e.shadowMap.autoUpdate=!n.length;for(const r of i)r.use("color");e.render(this.scene,this.camera),n.forEach(({group:e},t)=>{e.visible=a[t]}),e.shadowMap.autoUpdate=!0}useBuildingsPass(e){const t={color:this.material,depth:this.depthOnly,shadows:this.shadowsOnly}[e];for(const{mesh:i}of this.tiles.values())i.material=t}placeLandmarks(e,t,i){e.tiles.parent!==this.landmarks&&this.landmarks.add(e.tiles);const n=i.metresPerMercator*MERCATOR_UNITS_PER_EPSG3857_METER,a=this.toScene(i,.5+t.origin.x*MERCATOR_UNITS_PER_EPSG3857_METER,.5-t.origin.y*MERCATOR_UNITS_PER_EPSG3857_METER);this.landmarks.matrix.makeScale(n,n,1).setPosition(a.x,a.y,0),this.landmarks.matrixWorldNeedsUpdate=!0}toScene(e,t,i){return new Vector2((t-e.x)*e.metresPerMercator,(e.y-i)*e.metresPerMercator)}updateOrigin(e){const t=e.getCenter(),i=MercatorCoordinate.fromLngLat(t);if(this.origin&&this.toScene(this.origin,i.x,i.y).length()<2e4)return this.origin;const n=this.origin;return this.origin={x:i.x,y:i.y,position:t.toArray(),metresPerMercator:Math.cos(MathUtils.degToRad(t.lat))/MERCATOR_UNITS_PER_EPSG3857_METER},n&&this.carryTiles(n,this.origin),this.pending=[],this.extrusion=void 0,this.origin}carryTiles(e,t){const i=t.metresPerMercator/e.metresPerMercator,n=this.toScene(t,e.x,e.y);for(const{mesh:a}of this.tiles.values())a.position.set(a.position.x*i+n.x,a.position.y*i+n.y,0),a.scale.set(a.scale.x*i,a.scale.y*i,1)}updateTiles(e,t){const i=((e,t,i,n)=>{const a=e.style?.tileManagers?.[t],o=/* @__PURE__ */new Map;for(const r of a?.getRenderableIds()??[]){const e=a?.getTileByID(r);if(!e?.latestFeatureIndex?.rawTileData)continue;const{x:t,y:s,z:l}=e.tileID.canonical,{wrap:d}=e.tileID,c=`${l}/${t}/${s}/${d}`;o.has(c)||o.set(c,{key:c,x:t,y:s,z:l,wrap:d,read:()=>readBuildings(e,i,n)})}return[...o.values()]})(e,this.source.id,this.source.layer,this.filter),n=new Set(i.map(({key:e})=>e));this.queueTiles(i,n,t);const a=performance.now()+(e.isMoving()?4:8);for(;this.pending.length&&performance.now()<a;){const e=this.pending[0];if(this.extrusion?.key!==e.key&&(this.extrusion={key:e.key,run:this.startExtrusion(e,t)}),!this.extrusion.run.extrudeUntil(a))break;this.pending.shift();const i=this.tiles.get(e.key);i&&this.removeTileMesh(i.mesh),this.tiles.set(e.key,{mesh:this.addTileMesh(this.extrusion.run),lastSeen:this.frame,withoutLandmarks:this.filter.withoutLandmarks,origin:t}),this.extrusion=void 0}this.pending.length&&e.triggerRepaint();for(const[o,{mesh:r}]of this.tiles)r.visible=n.has(o);this.evictStaleTiles()}queueTiles(e,t,i){const n=new Set(this.pending.map(({key:e})=>e));for(const a of e){const e=this.tiles.get(a.key);e&&(e.lastSeen=this.frame),e?.withoutLandmarks===this.filter.withoutLandmarks&&e.origin===i||n.has(a.key)||this.pending.push(a)}this.pending=this.pending.filter(({key:e})=>t.has(e))}startExtrusion(e,t){const{footprints:i,extent:n}=e.read(),a=2**e.z,o=this.toScene(t,e.wrap+e.x/a,e.y/a);return new BuildingsExtrusion(i,{extent:n,originX:o.x,originY:o.y,metresPerUnit:t.metresPerMercator/(a*n)})}addTileMesh(e){const t=new Mesh(e.toGeometry(),this.material);return t.castShadow=!0,t.receiveShadow=!0,this.buildings.add(t),t}removeTileMesh(e){this.buildings.remove(e),e.geometry.dispose()}evictStaleTiles(){if(this.tiles.size<=96)return;const e=[...this.tiles].sort(([,e],[,t])=>e.lastSeen-t.lastSeen);for(const[t,{mesh:i}]of e.slice(0,this.tiles.size-96))i.visible||(this.removeTileMesh(i),this.tiles.delete(t))}eyePosition(){const e=new Vector4(0,0,1,0).applyMatrix4(this.camera.projectionMatrixInverse);return 0===e.w?new Vector3:new Vector3(e.x/e.w,e.y/e.w,e.z/e.w)}groundMaterial(){const e=new ShadowMaterial({opacity:.55,depthWrite:!1});return e.onBeforeCompile=e=>{e.uniforms.groundReach=this.groundReach,e.vertexShader=e.vertexShader.replace("#include <common>","#include <common>\nvarying vec2 vGroundUv;").replace("#include <begin_vertex>","#include <begin_vertex>\nvGroundUv = uv;"),e.fragmentShader=e.fragmentShader.replace("#include <common>","#include <common>\nuniform float groundReach;\nvarying vec2 vGroundUv;").replace("#include <fog_fragment>","gl_FragColor.a *= 1.0 - smoothstep(4000.0, 5000.0, length(vGroundUv * 2.0 - 1.0) * groundReach);\n#include <fog_fragment>")},e}updateSun(e,t,i){const n=MercatorCoordinate.fromLngLat(e.getCenter()),a=this.toScene(t,n.x,n.y);this.sun.target.position.set(a.x,a.y,0),this.sun.position.set(a.x,a.y,0).addScaledVector(towardsSun(i),8e3),this.sun.updateMatrixWorld(),this.sun.target.updateMatrixWorld();const{clientWidth:o,clientHeight:r}=e.getCanvas(),s=((e,t)=>{const i=e.getPitch(),n=t/2/Math.tan(MathUtils.degToRad(e.getVerticalFieldOfView())/2)*Math.min(.85*Math.tan(MathUtils.degToRad(90-i)),Math.tan(MathUtils.degToRad(89.25-i)));return Math.max(0,t/2-n)})(e,r),l=[[0,s],[o,s],[o,r],[0,r]].map(([i,n])=>{const o=MercatorCoordinate.fromLngLat(e.unproject([i,n]));return this.toScene(t,o.x,o.y).sub(a).clampLength(0,5e3).add(a)}),{shadow:d}=this.sun;d.updateMatrices(this.sun);const c=new Box2;for(const p of l){const e=new Vector3(p.x,p.y,0).applyMatrix4(d.camera.matrixWorldInverse);c.expandByPoint(new Vector2(e.x,e.y))}c.expandByScalar(150);const h=c.getSize(new Vector2).divideScalar(100).ceil().multiplyScalar(100),m=h.clone().divide(d.mapSize),u=(new Vector3).applyMatrix4(d.camera.matrixWorldInverse),f=c.min.clone().sub(u).divide(m).floor().multiply(m).add(u);d.camera.left=f.x,d.camera.right=f.x+h.x,d.camera.bottom=f.y,d.camera.top=f.y+h.y,d.camera.near=1,d.camera.far=16e3,d.camera.updateProjectionMatrix();const g=Math.max(...l.map(e=>e.distanceTo(a)))+150;this.groundReach.value=g,this.ground.position.set(a.x,a.y,.05),this.ground.scale.set(2*g,2*g,1)}},LAYER_ID="tomtom-3d-buildings",Buildings3D=class{map;buildingsLayer;config;renderedLook;styling;occludedLabels=/* @__PURE__ */new Set;styleOrder=[];constructor(e,t={}){this.map=e,this.config=t,this.buildingsLayer=new BuildingsLayer(LAYER_ID,()=>landmarksOn.get(e)),buildings3DLookOn.set(e,()=>{const e=this.look();return e.visible?e:void 0}),this.render(),this.map.addStyleChangeHandler({onStyleChanged:()=>this.install()}),this.map.mapLibreMap.on("styledata",()=>{this.map.mapReady&&!sameLook(this.look(),this.renderedLook)?this.render():this.styling&&this.placeLabels()}),whenMapReady(e,()=>this.install())}get layer(){return this.buildingsLayer}getConfig(){return structuredClone(this.config)}applyConfig(e){this.config=e,this.render()}updateConfig(e){this.applyConfig({...this.config,...e})}resetConfig(){this.applyConfig({})}isVisible(){return!1!==this.config.visible}setVisible(e){this.updateConfig({visible:e})}_knobValue(e){return this.look()[e]}_setKnobValues(e){this.applyConfig(configWithKnobs(this.config,e))}_resetKnobValue(e){this.applyConfig(configWithoutKnob(this.config,e))}install(){const e=this.map.mapLibreMap,t=e.getLayer("3D - Building");t?.source&&t.sourceLayer&&(this.buildingsLayer.source={id:t.source,layer:t.sourceLayer}),e.getLayer(LAYER_ID)||(this.occludedLabels.clear(),e.addLayer(this.buildingsLayer,t?"3D - Building":e.getLayersOrder().find(t=>"symbol"===e.getLayer(t)?.type))),this.render()}look(){const e=this.map.mapLibreMap,t=this.map.mapReady&&e.getLayer("3D - Building")?e.getPaintProperty("3D - Building","fill-extrusion-color"):void 0;return((e,t)=>{const i=e.preset??"auto",n=PRESETS["auto"===i?t.style:i],a=t=>knobValueIn(e,t)??n[t],o=e.walls?.color??n["walls.color"],r=o?oneColorForEveryGroup(o):t.styleColors??oneColorForEveryGroup("hsl(38, 6%, 90%)"),s=e.roofs?.color??n["roofs.color"],l=r[BUILDING_GROUPS.length];return{visible:e.visible??!0,preset:i,opacity:a("opacity"),minZoom:a("minZoom"),"facade.pattern":a("facade.pattern"),"facade.intensity":a("facade.intensity"),"facade.floorHeightMeters":a("facade.floorHeightMeters"),"walls.color":l,"roofs.color":s??l,"windows.color":a("windows.color"),"reflections.intensity":a("reflections.intensity"),"litWindows.color":a("litWindows.color"),"litWindows.fraction":a("litWindows.fraction"),"litWindows.intensity":a("litWindows.intensity"),"light.direction":a("light.direction"),"light.altitude":a("light.altitude"),"light.color":a("light.color"),"light.intensity":a("light.intensity"),"ambientLight.color":a("ambientLight.color"),"ambientLight.intensity":a("ambientLight.intensity"),"shadows.visible":a("shadows.visible"),"shadows.intensity":a("shadows.intensity"),"roadLabels.occluded":a("roadLabels.occluded"),"pois.occluded":a("pois.occluded"),wallColorsByGroup:r,roofsFollowWalls:void 0===s}})(this.config,{style:(i=this.map.getStyleInput(),("string"==typeof i?i:i?.id)??"streetLight"),styleColors:groupColorsOfPaint(t)});var i}render(){const e=this.look();this.renderedLook=e,this.buildingsLayer.setLook(e),restyleLandmarksOn.get(this.map)?.(),this.map.mapReady&&(this.map.mapLibreMap.getLayer("3D - Building")&&LayerFilterComposer.for(this.map).setClause("3D - Building","landmarks3d.buildings3D",!e.visible&&void 0),e.visible&&(e["roadLabels.occluded"]||e["pois.occluded"])&&(this.styling??=StylingFoundationsModule.get(this.map)),(this.styling||this.occludedLabels.size)&&this.placeLabels(),this.map.mapLibreMap.triggerRepaint())}async placeLabels(){const e=await this.styling,t=this.renderedLook,i=this.map.mapLibreMap;if(!e||!t||!i.getLayer(LAYER_ID))return;const n=(i,n)=>t.visible&&n?e.layers.query({group:i}).layerIds:[],a=/* @__PURE__ */new Set([...n("roadLabels",t["roadLabels.occluded"]),...n("pois",t["pois.occluded"])]),o=i.getLayersOrder(),r=o.indexOf(LAYER_ID);[...this.occludedLabels].some(e=>o.indexOf(e)>r)&&this.occludedLabels.clear(),this.restoreLabels(a),this.occludeLabels(a)}restoreLabels(e){const t=this.map.mapLibreMap;for(const i of this.occludedLabels){if(e.has(i))continue;this.occludedLabels.delete(i);const n=this.styleOrder.slice(this.styleOrder.indexOf(i)+1).find(e=>!this.occludedLabels.has(e)&&t.getLayer(e));t.getLayer(i)&&t.moveLayer(i,n)}}occludeLabels(e){const t=this.map.mapLibreMap,i=t.getLayersOrder(),n=i.indexOf(LAYER_ID);for(const a of e){const e=i.indexOf(a);if(!(this.occludedLabels.has(a)||e<n)){if(this.occludedLabels.size){if(!this.styleOrder.includes(a)){const t=this.styleOrder.indexOf(i[e+1]);this.styleOrder.splice(t<0?this.styleOrder.length:t,0,a)}}else this.styleOrder=[...i];this.occludedLabels.add(a),t.moveLayer(a,LAYER_ID)}}}},UNIT_RANGE={min:0,max:1,step:.05,bounds:"hard"},withIds=e=>Object.keys(e).map(t=>({id:t,...e[t]})),facadePatterns=["mixed","residential","office","glass","plain"],buildingsPresets=/* @__PURE__ */(()=>["auto",...standardStyleIDs])(),buildings3DKnobCatalogue=/* @__PURE__ */withIds({visible:{kind:"toggle",description:"The 3D buildings.",default:!0},preset:{kind:"enum",description:"Look every unset knob takes: a standard style's, or auto, which follows the map's standard style.",options:buildingsPresets,default:"auto"},opacity:{kind:"number",description:"Opacity of the buildings, and of the landmarks left unset among them, 0 to 1.",range:UNIT_RANGE},minZoom:{kind:"number",description:"Lowest zoom the buildings are drawn at, and the landmarks left unset among them.",range:{min:13,max:22,step:1,bounds:"hard"}},"facade.pattern":{kind:"enum",description:"How windows are laid out: mixed (by building height), residential, office, glass (curtain walls) or plain (no windows).",options:facadePatterns},"facade.intensity":{kind:"number",description:"How strongly the windows show on the walls, and the landmarks' own texture among the buildings while their texture is detail, 0 (plain walls) to 1.",range:UNIT_RANGE},"facade.floorHeightMeters":{kind:"number",description:"Height of one storey, which spaces the rows of windows. The ground floor is a third taller.",range:{min:2.5,max:6,step:.1,bounds:"hard-min"}},"walls.color":{kind:"color",description:"Colour of the walls. Unset: the map style's 3D building colour of each kind of building, following the map colours that restyle them, and the colour of the buildings of no named kind is the one reported. Landmarks left unset among the buildings take it too."},"roofs.color":{kind:"color",description:"Colour of the roofs. Unset: a shade darker than the walls of each building, and the colour reported is the walls' one."},"windows.color":{kind:"color",description:"Colour of the window glass."},"reflections.intensity":{kind:"number",description:"How much the window glass mirrors the street, the facades across it and the sky, and catches the sun, 0 (matte) to 1. Glass curtain walls reflect the most, landmarks a little; the sky's colour is the ambient light's.",range:UNIT_RANGE},"litWindows.color":{kind:"color",description:"Colour of the windows lit from inside."},"litWindows.fraction":{kind:"number",description:"Share of the windows lit from inside, 0 to 1. The dark presets light some.",range:UNIT_RANGE},"litWindows.intensity":{kind:"number",description:"Brightness of the lit windows, 0 to 1. Pair it with the map effects bloom for a night glow.",range:UNIT_RANGE},"light.direction":{kind:"number",description:"Direction the light comes from, in degrees clockwise from north. Shadows fall the opposite way.",range:{min:0,max:359,step:1,bounds:"hard"}},"light.altitude":{kind:"number",description:"Height of the light above the horizon, in degrees (90 = overhead); lower casts longer shadows.",range:{min:5,max:90,step:1,bounds:"hard"}},"light.color":{kind:"color",description:"Colour of the light: the sun on light presets, the moon on dark ones."},"light.intensity":{kind:"number",description:"Strength of the light, 0 to 1.",range:UNIT_RANGE},"ambientLight.color":{kind:"color",description:"Colour of the light from the sky, which also tints the reflections in the glass."},"ambientLight.intensity":{kind:"number",description:"Strength of the light from the sky, 0 to 1, which lights the walls in shade.",range:UNIT_RANGE},"shadows.visible":{kind:"toggle",description:"Shadows the buildings and the landmarks among them cast, on each other and on the ground."},"shadows.intensity":{kind:"number",description:"Darkness of the shadows, 0 to 1.",range:UNIT_RANGE},"roadLabels.occluded":{kind:"toggle",description:"Road names draw under the buildings: hidden wherever a building covers them, they give way to the labels above them."},"pois.occluded":{kind:"toggle",description:"The style's POIs draw under the buildings: hidden wherever a building covers them, still keeping other labels off, they give way to the labels above them."}}),buildings3DKnobIds=/* @__PURE__ */buildings3DKnobCatalogue.map(({id:e})=>e),ZOOM_RANGE={min:0,max:22,step:1,bounds:"hard"},landmarkTextureUses=["mask","detail","color"],landmarks3DKnobCatalogue=/* @__PURE__ */withIds({visible:{kind:"toggle",description:"The landmark models.",default:!0},color:{kind:"color",description:"Colour the landmarks are shaded in. Unset: the base map's 3D buildings' colour, following the map colours that restyle them."},texture:{kind:"enum",description:"What the landmarks' textures add to their silhouette: mask (nothing), detail (their light and shade over the color) or color (their own colours, in place of the color). Unset: mask, or detail while a Buildings3D draws.",options:landmarkTextureUses},opacity:{kind:"number",description:"Opacity of the landmarks, 0 to 1. Unset: the base map's 3D buildings' opacity.",range:UNIT_RANGE},verticalGradient:{kind:"toggle",description:"Whether the landmarks' walls darken towards the ground. Unset: as the base map's 3D buildings do. No effect while a Buildings3D draws, whose walls have no gradient."},minZoom:{kind:"number",description:"Lowest zoom the landmarks are drawn at. Unset: the base map's 3D buildings' one.",range:ZOOM_RANGE},maxZoom:{kind:"number",description:"Highest whole zoom level the landmarks are drawn at, up to the next one. Unset: the base map's 3D buildings' one, or 22 while a Buildings3D draws.",range:ZOOM_RANGE}}),landmarks3DKnobIds=/* @__PURE__ */landmarks3DKnobCatalogue.map(({id:e})=>e),buildLandmarksTileURL=()=>{const{commonBaseURL:e,apiKey:t}=TomTomConfig.instance.get();return`${e}/maps/orbis/display/3d/landmarks/tile/{z}/{x}/{y}?${t?`key=${t}&`:""}apiVersion=2`},STREET_LIGHT_LOOK={visible:!0,color:"hsl(38, 6%, 90%)",texture:"mask",opacity:.7,verticalGradient:!0,minZoom:10,maxZoom:22},textureUseIndexOf=e=>landmarkTextureUses.indexOf(e),LANDMARK_TEXTURE_GLSL=/* @__PURE__ */(()=>`\nuniform int textureUse;\n${landmarkTextureUses.map((e,t)=>`const int TEXTURE_${e.toUpperCase()} = ${t};`).join("\n")}\nconst vec3 LANDMARK_LUMA = vec3(0.2126, 0.7152, 0.0722);\n\n\nvec3 landmarkTextureMean(sampler2D source, vec2 uv) {\nvec4 mean = textureLod(source, uv, 16.0);\nreturn mean.rgb / max(mean.a, 0.05);\n}\n\n\n\nfloat landmarkTextureDetail(vec4 texel, vec3 mean) {\nreturn clamp(dot(texel.rgb, LANDMARK_LUMA) / max(dot(mean, LANDMARK_LUMA), 1e-3), 0.3, 1.8);\n}\n`)(),VERTEX_SHADER="\nattribute float fillExtrusionGradient;\nvarying vec3 vWorldNormal;\nvarying float vGradient;\n#ifdef USE_ALPHA_MASK\nvarying vec2 vUv;\n#endif\n\nvoid main() {\nvWorldNormal = normalize(mat3(modelMatrix) * normal);\nvGradient = fillExtrusionGradient;\n#ifdef USE_ALPHA_MASK\nvUv = uv;\n#endif\ngl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n}\n",ALPHA_MASK_FRAGMENT_CHUNK="\n#ifdef USE_ALPHA_MASK\nuniform sampler2D landmarkMap;\nuniform float alphaMaskCutoff;\nvarying vec2 vUv;\n#endif\n",ALPHA_MASK_MAIN_CHUNK="\n#ifdef USE_ALPHA_MASK\nvec4 landmarkTexel = texture2D(landmarkMap, vUv);\nif (landmarkTexel.a < alphaMaskCutoff) {\ndiscard;\n}\n#endif\n",FRAGMENT_SHADER=/* @__PURE__ */(()=>`\nuniform vec3 diffuseColor;\nuniform vec3 lightPosition;\nuniform float lightIntensity;\nuniform vec3 lightColor;\nuniform float layerOpacity;\nuniform float verticalGradient;\nvarying vec3 vWorldNormal;\nvarying float vGradient;\n${ALPHA_MASK_FRAGMENT_CHUNK}\n${LANDMARK_TEXTURE_GLSL}\n\nvoid main() {\n${ALPHA_MASK_MAIN_CHUNK}\nvec3 paint = diffuseColor;\nfloat colorValue = dot(diffuseColor, LANDMARK_LUMA);\n#ifdef USE_ALPHA_MASK\nif (textureUse != TEXTURE_MASK) {\nvec3 mean = landmarkTextureMean(landmarkMap, vUv);\nif (textureUse == TEXTURE_COLOR) {\npaint = sRGBTransferOETF(vec4(landmarkTexel.rgb, 1.0)).rgb;\ncolorValue = dot(sRGBTransferOETF(vec4(mean, 1.0)).rgb, LANDMARK_LUMA);\n} else {\npaint *= landmarkTextureDetail(landmarkTexel, mean);\n}\n}\n#endif\nvec3 normal = normalize(vWorldNormal);\n\n\nif (!gl_FrontFacing) {\nnormal = -normal;\n}\n\n\n\nvec3 flattened = vec3(normal.xy, 0.0);\nvec3 wallNormal = flattened / max(length(flattened), 1e-5);\nfloat upness = smoothstep(0.4, 0.8, normal.z);\nnormal = normalize(mix(wallNormal, vec3(0.0, 0.0, 1.0), upness));\nvec3 color = paint + vec3(0.03);\nfloat directional = clamp(dot(normal, lightPosition), 0.0, 1.0);\ndirectional = mix(1.0 - lightIntensity, max(1.0 - colorValue + lightIntensity, 1.0), directional);\nif (abs(normal.y) > 0.001) {\ndirectional *=\n(1.0 - verticalGradient) +\nverticalGradient * clamp(vGradient, mix(0.7, 0.98, 1.0 - lightIntensity), 1.0);\n}\nvec3 shaded = clamp(\ncolor * directional * lightColor,\nmix(vec3(0.0), vec3(0.3), vec3(1.0) - lightColor),\nvec3(1.0)\n);\ngl_FragColor = vec4(shaded, 1.0) * layerOpacity;\n}\n`)(),DEFAULT_LIGHT_POSITION=/* @__PURE__ */new Vector3(.2875,-.498,.996),parsedColor=/* @__PURE__ */new Color,srgbColor=/* @__PURE__ */new Color,FillExtrusionMaterial=class extends ShaderMaterial{constructor(e){super({uniforms:{diffuseColor:{value:new Vector3(1,1,1)},lightPosition:{value:DEFAULT_LIGHT_POSITION.clone()},lightIntensity:{value:.5},lightColor:{value:new Vector3(1,1,1)},layerOpacity:{value:1},verticalGradient:{value:1},textureUse:{value:textureUseIndexOf("mask")},...e&&{landmarkMap:{value:e.map},alphaMaskCutoff:{value:e.cutoff}}},...e&&{defines:{USE_ALPHA_MASK:""}},vertexShader:VERTEX_SHADER,fragmentShader:FRAGMENT_SHADER,side:e?DoubleSide:FrontSide,transparent:!0,blending:CustomBlending,blendSrc:OneFactor,blendDst:OneMinusSrcAlphaFactor})}copyShadingFrom(e){this.uniforms.diffuseColor.value.copy(e.uniforms.diffuseColor.value),this.uniforms.textureUse.value=e.uniforms.textureUse.value,this.uniforms.lightPosition.value.copy(e.uniforms.lightPosition.value),this.uniforms.lightIntensity.value=e.uniforms.lightIntensity.value,this.uniforms.lightColor.value.copy(e.uniforms.lightColor.value),this.uniforms.layerOpacity.value=e.uniforms.layerOpacity.value,this.uniforms.verticalGradient.value=e.uniforms.verticalGradient.value}setTextureUse(e){this.uniforms.textureUse.value=textureUseIndexOf(e)}setDiffuseColor(e){setCssColor(parsedColor,e).getRGB(srgbColor,SRGBColorSpace),this.uniforms.diffuseColor.value.set(srgbColor.r,srgbColor.g,srgbColor.b)}setLayerOpacity(e){this.uniforms.layerOpacity.value=e}setVerticalGradient(e){this.uniforms.verticalGradient.value=e?1:0}setLight(e,t,i,n){const a=Math.cos(t),o=Math.sin(t);this.uniforms.lightPosition.value.set(e.x*a-e.y*o,e.x*o+e.y*a,e.z),this.uniforms.lightIntensity.value=i,this.uniforms.lightColor.value.set(n.r,n.g,n.b)}},FillExtrusionDepthMaterial=class extends ShaderMaterial{constructor(e){super({...e&&{uniforms:{landmarkMap:{value:e.map},alphaMaskCutoff:{value:e.cutoff}},defines:{USE_ALPHA_MASK:""}},vertexShader:VERTEX_SHADER,fragmentShader:`\n${ALPHA_MASK_FRAGMENT_CHUNK}\nvoid main() {\n${ALPHA_MASK_MAIN_CHUNK}\ngl_FragColor = vec4(0.0);\n}\n`,side:e?DoubleSide:FrontSide,colorWrite:!1})}},FRAGMENT_DECLARATIONS=/* @__PURE__ */(()=>`\nuniform float detailIntensity;\nvarying vec3 vLandmarkPosition;\nvarying vec3 vLandmarkNormal;\n${GLASS_GLSL}\n${LANDMARK_TEXTURE_GLSL}\n\nconst float LANDMARK_REFLECTIVITY = 0.6;\n`)(),LandmarkFacadeMaterial=class extends MeshLambertMaterial{detailIntensity={value:1};textureUse={value:textureUseIndexOf("detail")};constructor(e,t){super({map:t?.map??null,alphaTest:t?.cutoff??0,side:t?DoubleSide:FrontSide}),this.onBeforeCompile=t=>{Object.assign(t.uniforms,e,{detailIntensity:this.detailIntensity,textureUse:this.textureUse}),t.vertexShader=t.vertexShader.replace("#include <common>","#include <common>\n\nvarying vec3 vLandmarkPosition;\nvarying vec3 vLandmarkNormal;\n").replace("#include <begin_vertex>","#include <begin_vertex>\n\nvLandmarkPosition = (modelMatrix * vec4(transformed, 1.0)).xyz;\nvLandmarkNormal = mat3(modelMatrix) * objectNormal;\n"),t.fragmentShader=t.fragmentShader.replace("#include <common>",`#include <common>\n${FRAGMENT_DECLARATIONS}`).replace("#include <map_fragment>","\nfloat landmarkGlass = 0.5;\n#ifdef USE_MAP\nvec4 landmarkTexel = texture2D(map, vMapUv);\ndiffuseColor.a *= landmarkTexel.a;\nif (textureUse != TEXTURE_MASK) {\nfloat detail = landmarkTextureDetail(landmarkTexel, landmarkTextureMean(map, vMapUv));\ndiffuseColor.rgb = textureUse == TEXTURE_COLOR\n? landmarkTexel.rgb\n: diffuseColor.rgb * mix(1.0, detail, detailIntensity);\nlandmarkGlass = 1.0 - smoothstep(0.6, 1.2, detail);\n}\n#endif\nvec3 landmarkNormal = normalize(vLandmarkNormal) * (gl_FrontFacing ? 1.0 : -1.0);\nvec3 landmarkToEye = normalize(eyePosition - vLandmarkPosition);\nvec3 landmarkReflected = reflect(-landmarkToEye, landmarkNormal);\nfloat landmarkReflectance = reflectivity * LANDMARK_REFLECTIVITY * mix(0.3, 1.0, landmarkGlass)\n* (1.0 - smoothstep(0.5, 0.9, abs(landmarkNormal.z)))\n* glassFresnel(landmarkNormal, landmarkToEye);\nvec3 landmarkMirrored = mix(mirroredStreet(), mirroredSky(landmarkReflected), smoothstep(-0.05, 0.05, landmarkReflected.z));\ndiffuseColor.rgb *= 1.0 - landmarkReflectance;\nvec3 glassSunReflection = mirroredSun(landmarkReflected) * landmarkReflectance;\n").replace("#include <emissivemap_fragment>","#include <emissivemap_fragment>\ntotalEmissiveRadiance += landmarkMirrored * landmarkReflectance;").replace("#include <lights_fragment_end>",`#include <lights_fragment_end>\n${SUN_IN_THE_GLASS}`)}}setLook(e){setCssColor(this.color,e.color),this.textureUse.value=textureUseIndexOf(e.texture),this.detailIntensity.value=e.detailIntensity,setMaterialOpacity(this,e.opacity)}},CREASE_ANGLE_RADIANS=Math.PI/6,ModelsSource=class{type="models";id;minzoom;maxzoom;map;tiles;scene;loadedTiles=/* @__PURE__ */new Set;accessDenied=!1;sceneOrigin=null;onTileLoaded;ktx2Loader;transcoderReady;gltfLoader;specification;withCredentials;coveringTileKeys=/* @__PURE__ */new Set;constructor(e,t){this.id=e,this.minzoom=t.minzoom??0,this.maxzoom=t.maxzoom??22,this.tiles=t.tiles,this.specification=t,this.withCredentials=t.withCredentials??!1,this.scene=new Group,this.ktx2Loader=new KTX2Loader(new LoadingManager).setCrossOrigin("anonymous").setTranscoderPath(t.transcoderPath??""),this.gltfLoader=(new GLTFLoader).setKTX2Loader(this.ktx2Loader).setMeshoptDecoder(MeshoptDecoder)}onAdd(e,t){this.map=e,this.ktx2Loader.detectSupport(t)}updateTiles(){if(0===this.tiles.length)return;const e=this.coveringTiles();this.coveringTileKeys=new Set(e.map(e=>e.key));for(const t of e)this.loadTile(t);this.showCoveringTilesOnly()}showCoveringTilesOnly(){for(const e of this.scene.children)e.visible=this.coveringTileKeys.has(e.userData.key)}coveringTiles(){const e={tileSize:this.map._camera.transform.tileSize,minzoom:this.minzoom,maxzoom:this.maxzoom,terrain:this.map.terrain};return this.map.coveringTiles(e)}loadTile(e){if(this.loadedTiles.has(e.key))return;this.loadedTiles.add(e.key);const t=e.canonical.url(this.tiles,this.map.getPixelRatio(),this.specification.scheme);this.fetchTile(t).then(t=>{t&&(prepareTileMeshes(t),this.rebaseToSceneOrigin(t),t.userData={isTile:!0,key:e.key},t.visible=this.coveringTileKeys.has(e.key),this.scene.add(t),this.map.triggerRepaint(),this.onTileLoaded?.(t,e.key))}).catch(t=>{console.warn(`Problem with loading ${e.toString()}: ${t?.message??"unknown"}`)})}rebaseToSceneOrigin(e){const t=[];if(e.traverse(e=>{isMesh(e)&&t.push(e)}),0===t.length)return;const i=t[0].position,n={x:Math.round(i.x),y:Math.round(i.y)};if(this.sceneOrigin){if(Math.hypot(i.x-this.sceneOrigin.x,i.y-this.sceneOrigin.y)>1e5){const e=n.x-this.sceneOrigin.x,t=n.y-this.sceneOrigin.y;this.scene.traverse(i=>{isMesh(i)&&(i.position.x-=e,i.position.y-=t)}),this.sceneOrigin=n}}else this.sceneOrigin=n;for(const a of t)a.position.x-=this.sceneOrigin.x,a.position.y-=this.sceneOrigin.y}async fetchTile(e){const t=await fetch(e,this.withCredentials?{credentials:"include"}:void 0);if(204===t.status||404===t.status)return null;if(403===t.status&&"InvalidReferer"!==await(async e=>(await e.json().catch(()=>{}))?.detailedError?.code)(t))throw this.accessDenied=!0,new Error("tile request failed with 403: Orbis 3D Landmarks is in Private Preview (https://docs.tomtom.com/legal/private-preview), and the API key needs access to it: request it from TomTom Sales at https://www.tomtom.com/contact-sales/?source_app=docs-portal&source_product=map-display-api-3d");if(!t.ok)throw new Error(`tile request failed with ${t.status}`);const i=await t.arrayBuffer();this.transcoderReady??=(async e=>{if(void 0!==this.specification.transcoderPath)return;const{resolveBundledTranscoderUrl:t}=await(import("./bundledTranscoder-CUVU7Ihm.js"));e.setURLModifier(t)})(this.ktx2Loader.manager),await this.transcoderReady;const{scene:n}=await this.gltfLoader.parseAsync(i,LoaderUtils.extractUrlBase(e));return n}},prepareTileMeshes=e=>{e.traverse(e=>{if(!isMesh(e))return;const t=e.material;t.alphaTest=.1,t.side=DoubleSide,e.userData.originalMaterial=t,e.castShadow=!0,e.receiveShadow=!0,e.geometry=toCreasedNormals(e.geometry,CREASE_ANGLE_RADIANS),bakeGradientAttribute(e)})},bakeGradientAttribute=e=>{const t=e.geometry,i=t.getAttribute("position");t.computeBoundingBox();const n=t.boundingBox?.max.z??0,a=n>0?Math.sqrt(n/150)/n:0,o=new Float32Array(i.count);for(let r=0;r<i.count;r++)o[r]=i.getZ(r)*a;t.setAttribute("fillExtrusionGradient",new BufferAttribute(o,1))},alphaMaskOf=e=>{const t=e.userData.originalMaterial;return t?.map?{map:t.map,cutoff:t.alphaTest}:void 0},ModelsLayer=class{id;type="custom";renderingMode="3d";renderer;scene;camera;tiles;directionalLight=new DirectionalLight(16777215,.5);ambientLight=new AmbientLight(16777215,.1);map;source;minzoom=0;maxzoom=22;visible=!0;diffuseColor="#ffffff";fillExtrusionMaterial=new FillExtrusionMaterial;depthPrepassMaterial=new FillExtrusionDepthMaterial;maskedFillExtrusionMaterials=/* @__PURE__ */new Map;facadeMaterials=/* @__PURE__ */new Map;buildingsLight;glass;opacity=1;textureUse="mask";tilesMainMatrix=/* @__PURE__ */new Float64Array(16);tilesStale=!0;markTilesStale=()=>{this.tilesStale=!0};constructor(e,t){this.id=e.id,this.source=new ModelsSource(this.id,t),this.tiles=this.source.scene,this.updateProperties(e)}updateProperties(e){this.visible="none"!==e.layout?.visibility,this.diffuseColor=e.paint?.["models-base-color"]??"#ffffff",this.minzoom=e.minzoom??0,this.maxzoom=e.maxzoom??22}setDirectionalLight(e,t,i){this.directionalLight.position.setFromSphericalCoords(e,MathUtils.degToRad(t),MathUtils.degToRad(i))}onAdd(e,t){this.map=e,this.scene=new Scene,this.tiles=this.source.scene,this.camera=new Camera,this.setDirectionalLight(1.15,90,0),this.scene.add(this.directionalLight,this.ambientLight),this.scene.add(this.tiles),this.renderer=new WebGLRenderer({canvas:e.getCanvas(),context:t,antialias:!0}),this.renderer.autoClear=!1,this.source.onAdd(e,this.renderer),this.tilesStale=!0,e.off("data",this.markTilesStale),e.on("data",this.markTilesStale)}render(e,t){!this.buildingsLight&&this.prepareFrame(t.defaultProjectionData.mainMatrix)&&(this.tiles.parent!==this.scene&&this.scene.add(this.tiles),this.syncLighting(),this.alignCameraToMap(t),this.renderer.resetState(),this.needsTranslucentPrepass()&&(this.useMaterials("depth"),this.renderer.render(this.scene,this.camera)),this.applyMaterials(),this.renderer.render(this.scene,this.camera))}prepareForBuildings(e,t){if(this.buildingsLight&&this.map&&!this.source.accessDenied&&this.prepareFrame(e))return t!==this.glass&&(this.facadeMaterials.forEach(e=>e.dispose()),this.facadeMaterials.clear(),this.glass=t),this.applyMaterials(),{origin:this.sceneOrigin,translucent:this.opacity<1}}useMaterials(e){if("depth"!==e){this.applyMaterials();const t="color"===e;return void this.facadeMaterials.forEach(e=>{e.colorWrite=t,e.depthWrite=t})}this.tiles.traverse(e=>{isMesh(e)&&(e.material=this.maskedFillExtrusionVariant(e)?.depth??this.depthPrepassMaterial)})}prepareFrame(e){const t=this.map._camera.transform.tileZoom,i=Math.max(this.minzoom,this.source.minzoom);return this.tiles.visible=this.visible&&t>=i&&t<=this.maxzoom,!!this.tiles.visible&&(this.updateTilesWhenStale(e),this.groundLandmarksOnTerrain(),!0)}updateTilesWhenStale(e){(this.tilesMainMatrix.some((t,i)=>t!==e[i])||this.tilesStale)&&(this.tilesMainMatrix.set(e),this.tilesStale=!1,this.source.updateTiles())}groundLandmarksOnTerrain(){for(const e of this.tiles.children)e.visible&&e.traverse(e=>{isMesh(e)&&this.groundMeshOnTerrain(e)})}groundMeshOnTerrain(e){const t=this.terrainSamplePoints(e);if(!t)return;let i=null;for(const n of t){const t=this.map.queryTerrainElevation(n);if(null===t)return void(e.position.z=0);(null===i||t<i)&&(i=t)}null!==i&&(e.position.z=i-.5)}terrainSamplePoints(e){let t=e.userData.terrainSamplePoints;if(!t){e.geometry.boundingBox||e.geometry.computeBoundingBox();const i=e.geometry.boundingBox;if(!i||i.isEmpty())return null;const n=e.position.x+this.sceneOrigin.x,a=e.position.y+this.sceneOrigin.y,o=(i.min.x+i.max.x)/2,r=(i.min.y+i.max.y)/2;t=[[o,r],[i.min.x,i.min.y],[i.min.x,i.max.y],[i.max.x,i.min.y],[i.max.x,i.max.y],[o,i.min.y],[o,i.max.y],[i.min.x,r],[i.max.x,r]].map(([e,t])=>mercatorMetresToLngLat(n+e,a+t)),e.userData.terrainSamplePoints=t}return t}alignCameraToMap(e){const t=localFrameMatrix(e.defaultProjectionData.mainMatrix,mercatorMetresToLngLat(this.sceneOrigin.x,this.sceneOrigin.y),{units:"mercatorMeters",centerLatitude:this.map.getCenter().lat});setCameraProjection(this.camera,t)}get sceneOrigin(){return this.source.sceneOrigin??{x:0,y:0}}needsTranslucentPrepass(){return this.fillExtrusionMaterial.uniforms.layerOpacity.value<1}setOpacity(e){this.opacity=e,this.forEachFillExtrusionMaterial(t=>t.setLayerOpacity(e))}setBuildingsLight(e){this.buildingsLight=e}setVerticalGradient(e){this.forEachFillExtrusionMaterial(t=>t.setVerticalGradient(e))}setTextureUse(e){this.textureUse=e,this.forEachFillExtrusionMaterial(t=>t.setTextureUse(e))}getMaterial(e){return this.maskedFillExtrusionVariant(e)?.color??this.fillExtrusionMaterial}maskedFillExtrusionVariant(e){const t=alphaMaskOf(e);if(!t)return null;let i=this.maskedFillExtrusionMaterials.get(t.map);return i||(i={color:new FillExtrusionMaterial(t),depth:new FillExtrusionDepthMaterial(t)},i.color.copyShadingFrom(this.fillExtrusionMaterial),this.maskedFillExtrusionMaterials.set(t.map,i)),i}forEachFillExtrusionMaterial(e){e(this.fillExtrusionMaterial),this.maskedFillExtrusionMaterials.forEach(t=>e(t.color))}syncLighting(){const e=this.map,t=e.style?.light,i=t?.properties,n=t?.getCartesianPosition?.();if(i&&n)try{const t=i.get("intensity");this.directionalLight.intensity=t*Math.PI,this.ambientLight.intensity=(1-t)*Math.PI;const a={x:-n[0],y:n[1],z:n[2]};this.directionalLight.position.set(a.x,a.y,a.z);const o="viewport"===i.get("anchor")?-(e._camera.transform.bearingInRadians??0):0,r=i.get("color");this.forEachFillExtrusionMaterial(e=>e.setLight(a,o,t,r))}catch{}}applyMaterials(){const{buildingsLight:e,glass:t}=this;if(e&&t){const i={color:this.diffuseColor,texture:this.textureUse,detailIntensity:e["facade.intensity"],opacity:this.opacity};return this.tiles.traverse(e=>{isMesh(e)&&(e.material=this.facadeMaterialOf(e,t))}),void this.facadeMaterials.forEach(e=>e.setLook(i))}this.forEachFillExtrusionMaterial(e=>e.setDiffuseColor(this.diffuseColor)),this.tiles.traverse(e=>{isMesh(e)&&(e.material=this.getMaterial(e))})}facadeMaterialOf(e,t){const i=alphaMaskOf(e),n=i?.map??null;let a=this.facadeMaterials.get(n);return a||(a=new LandmarkFacadeMaterial(t,i),this.facadeMaterials.set(n,a)),a}},NO_LANDMARK_FILTER_CLAUSE=["!",["coalesce",["get","has_landmark"],!1]],Landmarks3D=class{map;layerID="orbis-3d-landmarks";basemapBuildingLayerID="3D - Building";modelsLayer;config;renderedLook;constructor(e,{withCredentials:t,transcoderPath:i,...n}={}){this.map=e,this.config=n,restyleLandmarksOn.set(e,()=>this.render());const a={id:this.layerID,type:"models",source:this.layerID},o={type:"models",tiles:[buildLandmarksTileURL()],minzoom:15,maxzoom:15,withCredentials:t??isProxyCredentialsMode(),transcoderPath:i};this.modelsLayer=new ModelsLayer(a,o),landmarksOn.set(e,this.modelsLayer),this.render(),this.map.addCustomLayer(this.modelsLayer,{beforeLayerConfig:"poi"}),this.map.addStyleChangeHandler({onStyleChanged:()=>this.install()}),this.map.mapLibreMap.on("styledata",()=>{this.map.mapReady&&!sameLook(this.look(),this.renderedLook)&&this.render()}),whenMapReady(e,()=>this.install())}get layer(){return this.modelsLayer}getConfig(){return structuredClone(this.config)}applyConfig(e){this.config=e,this.render()}updateConfig(e){this.applyConfig({...this.config,...e})}resetConfig(){this.applyConfig({})}isVisible(){return!1!==this.config.visible}setVisible(e){this.updateConfig({visible:e})}_knobValue(e){return this.look()[e]}_setKnobValues(e){this.applyConfig(configWithKnobs(this.config,e))}_resetKnobValue(e){this.applyConfig(configWithoutKnob(this.config,e))}install(){this.excludeLandmarkBuildingsFromBasemap(),this.modelsLayer.source.onTileLoaded=()=>{this.look().opacity<1&&this.render()},this.render()}excludeLandmarkBuildingsFromBasemap(){LayerFilterComposer.for(this.map).setClause(this.basemapBuildingLayerID,"landmarks3d.buildings",NO_LANDMARK_FILTER_CLAUSE)}readBuildingsLook(){const e=buildings3DLookOn.get(this.map)?.();if(e)return{color:e["walls.color"],texture:"detail",opacity:e.opacity,verticalGradient:!1,minZoom:e.minZoom};const t=this.map.mapLibreMap,i=t.getLayer(this.basemapBuildingLayerID);if(!i)return{};const n=e=>t.getPaintProperty(this.basemapBuildingLayerID,e),a=groupColorsOfPaint(n("fill-extrusion-color"))?.at(-1),o=n("fill-extrusion-opacity"),r=n("fill-extrusion-vertical-gradient");return{...a&&{color:a},..."number"==typeof o&&{opacity:o},..."boolean"==typeof r&&{verticalGradient:r},...void 0!==i.minzoom&&{minZoom:i.minzoom},...void 0!==i.maxzoom&&{maxZoom:i.maxzoom}}}look(){const e=this.map.mapReady?this.readBuildingsLook():{};return((e,t)=>{const i={...STREET_LIGHT_LOOK,...t},n=t=>e[t]??i[t];return{visible:n("visible"),color:n("color"),texture:n("texture"),opacity:n("opacity"),verticalGradient:n("verticalGradient"),minZoom:n("minZoom"),maxZoom:n("maxZoom")}})(this.config,e)}render(){const e=this.look();this.renderedLook=e,this.modelsLayer.visible=e.visible,this.modelsLayer.minzoom=e.minZoom,this.modelsLayer.maxzoom=e.maxZoom,this.modelsLayer.diffuseColor=e.color,this.modelsLayer.setTextureUse(e.texture),this.modelsLayer.setOpacity(e.opacity),this.modelsLayer.setVerticalGradient(e.verticalGradient),this.modelsLayer.setBuildingsLight(buildings3DLookOn.get(this.map)?.()),this.map.mapReady&&this.map.mapLibreMap.triggerRepaint()}};export{Buildings3D,Landmarks3D,ModelsLayer,ModelsSource,buildLandmarksTileURL,buildings3DKnobCatalogue,buildings3DKnobIds,buildingsPresets,facadePatterns,landmarkTextureUses,landmarks3DKnobCatalogue,landmarks3DKnobIds};
@@ -1,7 +1,7 @@
1
1
  [
2
2
  {
3
3
  "name": "maplibre-gl",
4
- "version": "6.13.0",
4
+ "version": "6.15.0",
5
5
  "license": "BSD-3-Clause",
6
6
  "bundled": false,
7
7
  "description": "BSD licensed community fork of mapbox-gl, a WebGL interactive maps library",
package/package.json CHANGED
@@ -1,28 +1,29 @@
1
1
  {
2
2
  "name": "@tomtom-org/maps-sdk-plugin-landmarks-3d",
3
3
  "author": "TomTom International B.V.",
4
- "license": "See in LICENSE.txt",
5
- "version": "0.0.13",
4
+ "license": "SEE LICENSE IN LICENSE.txt",
5
+ "version": "0.2.0",
6
6
  "type": "module",
7
7
  "description": "Plugin to render TomTom Orbis 3D Landmarks (GLB tiles) on a TomTomMap with Three.js",
8
8
  "types": "dist/index.d.ts",
9
+ "sideEffects": false,
9
10
  "peerDependencies": {
10
- "@tomtom-org/maps-sdk": ">=0.64.0 <1.0.0 || >=1.0.0-rc.0 <1.0.0",
11
- "maplibre-gl": "^6.13.0",
11
+ "@tomtom-org/maps-sdk": "^1.0.0-rc.4",
12
+ "maplibre-gl": "^6.15.0",
12
13
  "three": "^0.170.0"
13
14
  },
14
15
  "devDependencies": {
15
16
  "@playwright/test": "1.60.0",
16
17
  "@tsconfig/recommended": "^1.0.13",
17
- "@types/node": "^26.6.4",
18
+ "@types/node": "^26.6.5",
18
19
  "@types/three": "^0.170.0",
19
- "@vitest/coverage-v8": "^5.0.3",
20
- "rolldown": "^1.2.13",
20
+ "@vitest/coverage-v8": "^5.0.5",
21
+ "rolldown": "^1.2.14",
21
22
  "typescript": "^6.0.3",
22
- "vite": "8.3.3",
23
- "vitest": "^5.0.3",
23
+ "vite": "^8.3.4",
24
+ "vitest": "^5.0.5",
24
25
  "@testing/core-utils": "0.0.0",
25
- "@tomtom-org/maps-sdk": "1.0.0-rc.2"
26
+ "@tomtom-org/maps-sdk": "1.0.0-rc.4"
26
27
  },
27
28
  "files": [
28
29
  "dist",
@@ -39,8 +40,8 @@
39
40
  }
40
41
  },
41
42
  "scripts": {
42
- "build": "vite build --config ../plugin-vite-config.ts",
43
- "build:watch": "vite build --watch --config ../plugin-vite-config.ts",
43
+ "build": "vite build --config vite.lib.config.ts",
44
+ "build:watch": "vite build --watch --config vite.lib.config.ts",
44
45
  "test": "vitest run",
45
46
  "test:coverage": "vitest run --coverage",
46
47
  "test:e2e": "playwright test --config e2e-tests/playwright.config.ts",