| 
									
										
										
										
											2023-03-26 05:58:28 +02:00
										 |  |  | import { BBox } from "../Logic/BBox" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-10 20:56:59 +02:00
										 |  |  | export interface TileRange { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |     xstart: number | 
					
						
							|  |  |  |     ystart: number | 
					
						
							|  |  |  |     xend: number | 
					
						
							|  |  |  |     yend: number | 
					
						
							|  |  |  |     total: number | 
					
						
							| 
									
										
										
										
											2021-07-10 20:56:59 +02:00
										 |  |  |     zoomlevel: number | 
					
						
							| 
									
										
										
										
											2021-09-26 17:36:39 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export class Tiles { | 
					
						
							|  |  |  |     public static MapRange<T>(tileRange: TileRange, f: (x: number, y: number) => T): T[] { | 
					
						
							|  |  |  |         const result: T[] = [] | 
					
						
							| 
									
										
										
										
											2021-10-01 04:49:40 +02:00
										 |  |  |         const total = tileRange.total | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |         if (total > 100000) { | 
					
						
							| 
									
										
										
										
											2022-01-07 17:31:39 +01:00
										 |  |  |             throw `Tilerange too big (z is ${tileRange.zoomlevel}, total tiles needed: ${tileRange.total})` | 
					
						
							| 
									
										
										
										
											2021-10-01 04:49:40 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-09-26 17:36:39 +02:00
										 |  |  |         for (let x = tileRange.xstart; x <= tileRange.xend; x++) { | 
					
						
							|  |  |  |             for (let y = tileRange.ystart; y <= tileRange.yend; y++) { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                 const t = f(x, y) | 
					
						
							| 
									
										
										
										
											2021-09-26 17:36:39 +02:00
										 |  |  |                 result.push(t) | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         return result | 
					
						
							| 
									
										
										
										
											2021-09-26 17:36:39 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Calculates the tile bounds of the | 
					
						
							|  |  |  |      * @param z | 
					
						
							|  |  |  |      * @param x | 
					
						
							|  |  |  |      * @param y | 
					
						
							|  |  |  |      * @returns [[maxlat, minlon], [minlat, maxlon]] | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     static tile_bounds(z: number, x: number, y: number): [[number, number], [number, number]] { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         return [ | 
					
						
							|  |  |  |             [Tiles.tile2lat(y, z), Tiles.tile2long(x, z)], | 
					
						
							|  |  |  |             [Tiles.tile2lat(y + 1, z), Tiles.tile2long(x + 1, z)], | 
					
						
							|  |  |  |         ] | 
					
						
							| 
									
										
										
										
											2021-09-26 17:36:39 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |     static tile_bounds_lon_lat( | 
					
						
							|  |  |  |         z: number, | 
					
						
							|  |  |  |         x: number, | 
					
						
							|  |  |  |         y: number | 
					
						
							|  |  |  |     ): [[number, number], [number, number]] { | 
					
						
							|  |  |  |         return [ | 
					
						
							|  |  |  |             [Tiles.tile2long(x, z), Tiles.tile2lat(y, z)], | 
					
						
							|  |  |  |             [Tiles.tile2long(x + 1, z), Tiles.tile2lat(y + 1, z)], | 
					
						
							|  |  |  |         ] | 
					
						
							| 
									
										
										
										
											2021-09-26 17:36:39 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Returns the centerpoint [lon, lat] of the specified tile | 
					
						
							|  |  |  |      * @param z | 
					
						
							|  |  |  |      * @param x | 
					
						
							|  |  |  |      * @param y | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |     static centerPointOf(z: number, x: number, y: number): [number, number] { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         return [ | 
					
						
							|  |  |  |             (Tiles.tile2long(x, z) + Tiles.tile2long(x + 1, z)) / 2, | 
					
						
							|  |  |  |             (Tiles.tile2lat(y, z) + Tiles.tile2lat(y + 1, z)) / 2, | 
					
						
							|  |  |  |         ] | 
					
						
							| 
									
										
										
										
											2021-09-26 17:36:39 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-26 17:36:39 +02:00
										 |  |  |     static tile_index(z: number, x: number, y: number): number { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         return (x * (2 << z) + y) * 100 + z | 
					
						
							| 
									
										
										
										
											2021-09-26 17:36:39 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-26 17:36:39 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Given a tile index number, returns [z, x, y] | 
					
						
							|  |  |  |      * @param index | 
					
						
							|  |  |  |      * @returns 'zxy' | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     static tile_from_index(index: number): [number, number, number] { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         const z = index % 100 | 
					
						
							| 
									
										
										
										
											2021-09-26 17:36:39 +02:00
										 |  |  |         const factor = 2 << z | 
					
						
							|  |  |  |         index = Math.floor(index / 100) | 
					
						
							|  |  |  |         const x = Math.floor(index / factor) | 
					
						
							|  |  |  |         return [z, x, index % factor] | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Return x, y of the tile containing (lat, lon) on the given zoom level | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |     static embedded_tile(lat: number, lon: number, z: number): { x: number; y: number; z: number } { | 
					
						
							| 
									
										
										
										
											2023-04-06 01:33:08 +02:00
										 |  |  |         return { x: Tiles.lon2tile(lon, z), y: Tiles.lat2tile(lat, z), z } | 
					
						
							| 
									
										
										
										
											2021-09-26 17:36:39 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-26 05:58:28 +02:00
										 |  |  |     static tileRangeFrom(bbox: BBox, zoomlevel: number) { | 
					
						
							|  |  |  |         return Tiles.TileRangeBetween( | 
					
						
							|  |  |  |             zoomlevel, | 
					
						
							|  |  |  |             bbox.getNorth(), | 
					
						
							|  |  |  |             bbox.getWest(), | 
					
						
							|  |  |  |             bbox.getSouth(), | 
					
						
							|  |  |  |             bbox.getEast() | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |     static TileRangeBetween( | 
					
						
							|  |  |  |         zoomlevel: number, | 
					
						
							|  |  |  |         lat0: number, | 
					
						
							|  |  |  |         lon0: number, | 
					
						
							|  |  |  |         lat1: number, | 
					
						
							|  |  |  |         lon1: number | 
					
						
							|  |  |  |     ): TileRange { | 
					
						
							| 
									
										
										
										
											2021-09-26 17:36:39 +02:00
										 |  |  |         const t0 = Tiles.embedded_tile(lat0, lon0, zoomlevel) | 
					
						
							|  |  |  |         const t1 = Tiles.embedded_tile(lat1, lon1, zoomlevel) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const xstart = Math.min(t0.x, t1.x) | 
					
						
							|  |  |  |         const xend = Math.max(t0.x, t1.x) | 
					
						
							|  |  |  |         const ystart = Math.min(t0.y, t1.y) | 
					
						
							|  |  |  |         const yend = Math.max(t0.y, t1.y) | 
					
						
							|  |  |  |         const total = (1 + xend - xstart) * (1 + yend - ystart) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return { | 
					
						
							|  |  |  |             xstart: xstart, | 
					
						
							|  |  |  |             xend: xend, | 
					
						
							|  |  |  |             ystart: ystart, | 
					
						
							|  |  |  |             yend: yend, | 
					
						
							|  |  |  |             total: total, | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |             zoomlevel: zoomlevel, | 
					
						
							| 
									
										
										
										
											2021-09-26 17:36:39 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |     private static tile2long(x, z) { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         return (x / Math.pow(2, z)) * 360 - 180 | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private static tile2lat(y, z) { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         const n = Math.PI - (2 * Math.PI * y) / Math.pow(2, z) | 
					
						
							|  |  |  |         return (180 / Math.PI) * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n))) | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private static lon2tile(lon, zoom) { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         return Math.floor(((lon + 180) / 360) * Math.pow(2, zoom)) | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private static lat2tile(lat, zoom) { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         return Math.floor( | 
					
						
							|  |  |  |             ((1 - | 
					
						
							|  |  |  |                 Math.log(Math.tan((lat * Math.PI) / 180) + 1 / Math.cos((lat * Math.PI) / 180)) / | 
					
						
							|  |  |  |                     Math.PI) / | 
					
						
							|  |  |  |                 2) * | 
					
						
							|  |  |  |                 Math.pow(2, zoom) | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  | } |