| 
									
										
										
										
											2024-01-28 05:10:13 +01:00
										 |  |  | import { RasterLayerPolygon } from "../../Models/RasterLayers" | 
					
						
							|  |  |  | import { Polygon } from "geojson" | 
					
						
							|  |  |  | import { RasterLayerProperties } from "../../Models/RasterLayerProperties" | 
					
						
							|  |  |  | import { BBox } from "../../Logic/BBox" | 
					
						
							|  |  |  | import { Utils } from "../../Utils" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export class BingRasterLayerProperties implements Partial<RasterLayerProperties> { | 
					
						
							|  |  |  |     private static singleton: BingRasterLayerProperties | "error" | 
					
						
							|  |  |  |     name = "Bing Maps Aerial" | 
					
						
							|  |  |  |     id = "Bing" | 
					
						
							|  |  |  |     type = "bing" | 
					
						
							|  |  |  |     category = "photo" | 
					
						
							|  |  |  |     min_zoom = 1 | 
					
						
							|  |  |  |     max_zoom = 22 | 
					
						
							|  |  |  |     best = false | 
					
						
							|  |  |  |     attribution = { | 
					
						
							|  |  |  |         url: "https://www.bing.com/maps", | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     url: string | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private constructor(url: string) { | 
					
						
							|  |  |  |         this.url = url | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public static async get(): Promise<BingRasterLayerProperties | "error"> { | 
					
						
							|  |  |  |         if (BingRasterLayerProperties.singleton === undefined) { | 
					
						
							|  |  |  |             try { | 
					
						
							|  |  |  |                 const url = await this.getEndpoint() | 
					
						
							|  |  |  |                 BingRasterLayerProperties.singleton = new BingRasterLayerProperties(url) | 
					
						
							|  |  |  |             } catch (e) { | 
					
						
							|  |  |  |                 BingRasterLayerProperties.singleton = "error" | 
					
						
							|  |  |  |                 console.error(e) | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return BingRasterLayerProperties.singleton | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private static async getEndpoint() { | 
					
						
							|  |  |  |         console.log("Getting bing endpoint") | 
					
						
							|  |  |  |         // Key by 'pietervdvn@outlook.com' from https://www.bingmapsportal.com/Application
 | 
					
						
							|  |  |  |         // Inspired by https://github.com/zlant/parking-lanes/pull/159
 | 
					
						
							|  |  |  |         const key = "An0vKZ4r_PZx820sn3seuPKjd1Vyc5WE3s1b-qN4HCgI-Nr6QR83aLOQ-3fbFl08" | 
					
						
							|  |  |  |         const url = `https://dev.virtualearth.net/REST/v1/Imagery/Metadata/AerialOSM?include=ImageryProviders&uriScheme=https&key=${key}` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Get the image tiles template:
 | 
					
						
							|  |  |  |         const metadata = await Utils.downloadJson(url) | 
					
						
							|  |  |  |         // FYI:
 | 
					
						
							|  |  |  |         // "imageHeight": 256, "imageWidth": 256,
 | 
					
						
							|  |  |  |         // "imageUrlSubdomains": ["t0","t1","t2","t3"],
 | 
					
						
							|  |  |  |         // "zoomMax": 21,
 | 
					
						
							| 
									
										
										
										
											2024-09-11 17:31:38 +02:00
										 |  |  |         const imageryResource = metadata["resourceSets"][0].resources[0] | 
					
						
							| 
									
										
										
										
											2024-01-28 05:10:13 +01:00
										 |  |  |         const template = new URL(imageryResource.imageUrl) | 
					
						
							|  |  |  |         // Add tile image strictness param (n=)
 | 
					
						
							|  |  |  |         // • n=f -> (Fail) returns a 404
 | 
					
						
							|  |  |  |         // • n=z -> (Empty) returns a 200 with 0 bytes (no content)
 | 
					
						
							|  |  |  |         // • n=t -> (Transparent) returns a 200 with a transparent (png) tile
 | 
					
						
							|  |  |  |         if (!template.searchParams.has("n")) template.searchParams.append("n", "f") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // FYI: `template` looks like this but partly encoded
 | 
					
						
							|  |  |  |         // https://ecn.{subdomain}.tiles.virtualearth.net/tiles/a{quadkey}.jpeg?g=14107&pr=odbl&n=z
 | 
					
						
							|  |  |  |         const subdomains = ["t0", "t1", "t2", "t3"] | 
					
						
							|  |  |  |         const index = Math.floor(Math.random() * subdomains.length) | 
					
						
							|  |  |  |         return template.toString().replace("{subdomain}", subdomains[index]) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export class BingRasterLayer implements RasterLayerPolygon { | 
					
						
							|  |  |  |     private static singleton: RasterLayerPolygon | "error" | 
					
						
							|  |  |  |     readonly type: "Feature" = "Feature" | 
					
						
							|  |  |  |     readonly geometry: Polygon = BBox.global.asGeometry() | 
					
						
							|  |  |  |     readonly id = "bing" | 
					
						
							|  |  |  |     readonly properties: RasterLayerProperties | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     constructor(properties: RasterLayerProperties) { | 
					
						
							|  |  |  |         this.properties = properties | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public static async get(): Promise<RasterLayerPolygon | "error"> { | 
					
						
							|  |  |  |         if (BingRasterLayer.singleton === undefined) { | 
					
						
							|  |  |  |             const properties = await BingRasterLayerProperties.get() | 
					
						
							|  |  |  |             if (properties === "error") { | 
					
						
							|  |  |  |                 BingRasterLayer.singleton = "error" | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 BingRasterLayer.singleton = new BingRasterLayer(properties) | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return BingRasterLayer.singleton | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |