import { GeoBox } from "../coordinates/GeoBox" ; import { GeoCoordinates } from "../coordinates/GeoCoordinates" ; import { GeoCoordinatesLike } from "../coordinates/GeoCoordinatesLike" ; import { Vector3Like } from "../math/Vector3Like" ; import { TileKey } from "./TileKey" ; import { TilingScheme } from "./TilingScheme" ; export const powerOfTwo = ( ( ) => { let val = 0.5 ; return new Array ( 53 ) . fill ( 0 ) . map ( ( ) => ( val *= 2 ) ) ; } ) ( ) ; export namespace TileKeyUtils { export function geoCoordinatesToTileKey ( tilingScheme , geoPoint , level ) { const projection = tilingScheme . projection ; const worldPoint = projection . projectPoint ( geoPoint ) ; return worldCoordinatesToTileKey ( tilingScheme , worldPoint , level ) ; } export function worldCoordinatesToTileKey ( tilingScheme , worldPoint , level ) { const projection = tilingScheme . projection ; const subdivisionScheme = tilingScheme . subdivisionScheme ; const cx = subdivisionScheme . getLevelDimensionX ( level ) ; const cy = subdivisionScheme . getLevelDimensionY ( level ) ; const { min , max } = projection . worldExtent ( 0 , 0 ) ; const worldSizeX = max . x - min . x ; const worldSizeY = max . y - min . y ; if ( worldPoint . x < min . x || worldPoint . x > max . x ) { return null ; } if ( worldPoint . y < min . y || worldPoint . y > max . y ) { return null ; } const column = Math . min ( cx - 1 , Math . floor ( ( cx * ( worldPoint . x - min . x ) ) / worldSizeX ) ) ; const row = Math . min ( cy - 1 , Math . floor ( ( cy * ( worldPoint . y - min . y ) ) / worldSizeY ) ) ; return TileKey . fromRowColumnLevel ( row , column , level ) ; } export function geoRectangleToTileKeys ( tilingScheme , geoBox , level ) { const wrap = ( value , lower , upper ) => { if ( value < lower ) { return upper - ( ( lower - value ) % ( upper - lower ) ) ; } return lower + ( ( value - lower ) % ( upper - lower ) ) ; } ; const clamp = ( x , minVal , maxVal ) => { return Math . min ( Math . max ( x , minVal ) , maxVal ) ; } ; const southWestLongitude = wrap ( geoBox . southWest . longitudeInRadians , - Math . PI , Math . PI ) ; const southWestLatitude = clamp ( geoBox . southWest . latitudeInRadians , - ( Math . PI * 0.5 ) , Math . PI * 0.5 ) ; const northEastLongitude = wrap ( geoBox . northEast . longitudeInRadians , - Math . PI , Math . PI ) ; const northEastLatitude = clamp ( geoBox . northEast . latitudeInRadians , - ( Math . PI * 0.5 ) , Math . PI * 0.5 ) ; const minTileKey = TileKeyUtils . geoCoordinatesToTileKey ( tilingScheme , GeoCoordinates . fromRadians ( southWestLatitude , southWestLongitude ) , level ) ; const maxTileKey = TileKeyUtils . geoCoordinatesToTileKey ( tilingScheme , GeoCoordinates . fromRadians ( northEastLatitude , northEastLongitude ) , level ) ; const columnCount = tilingScheme . subdivisionScheme . getLevelDimensionX ( level ) ; if ( ! minTileKey || ! maxTileKey ) { throw new Error ( "Invalid coordinates" ) ; } const minColumn = minTileKey . column ; let maxColumn = maxTileKey . column ; if ( southWestLongitude > northEastLongitude ) { if ( maxColumn !== minColumn ) { maxColumn += columnCount ; } else { maxColumn += columnCount - 1 ; } } const minRow = Math . min ( minTileKey . row , maxTileKey . row ) ; const maxRow = Math . max ( minTileKey . row , maxTileKey . row ) ; const keys = new Array < TileKey > ( ) ; for ( let row = minRow ; row <= maxRow ; ++ row ) { for ( let column = minColumn ; column <= maxColumn ; ++ column ) { keys . push ( TileKey . fromRowColumnLevel ( row , column % columnCount , level ) ) ; } } return keys ; } param tileKey - The unique  {@link @here/harp-geoutils#TileKey} *                  from which to compute the unique key.
     *  param offset - How much the given  {@link @here/harp-geoutils#TileKey} is offset
     *  param bitshift export function getKeyForTileKeyAndOffset ( tileKey , offset , bitshift = 4 ) { const shiftedOffset = getShiftedOffset ( offset , bitshift ) ; return tileKey . mortonCode ( ) + shiftedOffset ; } param key param bitshift export function extractOffsetAndMortonKeyFromKey ( key , bitshift = 4 ) { let offset = 0 ; let mortonCode = key ; let i = 0 ; for ( ; i < bitshift ; i ++ ) { const num = powerOfTwo [ 52 - i ] ; if ( mortonCode >= num ) { mortonCode -= num ; offset += powerOfTwo [ bitshift - 1 - i ] ; } } offset -= powerOfTwo [ bitshift - 1 ] ; return { offset , mortonCode } ; } param calculatedKey param bitshift export function getParentKeyFromKey ( calculatedKey , bitshift = 4 ) { const { offset , mortonCode } = extractOffsetAndMortonKeyFromKey ( calculatedKey , bitshift ) ; const parentTileKey = TileKey . fromMortonCode ( TileKey . parentMortonCode ( mortonCode ) ) ; return getKeyForTileKeyAndOffset ( parentTileKey , offset , bitshift ) ; } param offset param offsetBits function getShiftedOffset ( offset , offsetBits = 4 ) { let result = 0 ; const totalOffsetsToStore = powerOfTwo [ offsetBits ] ; offset += totalOffsetsToStore / 2 ; while ( offset < 0 ) { offset += totalOffsetsToStore ; } while ( offset >= totalOffsetsToStore ) { offset -= totalOffsetsToStore ; } for ( let i = 0 ; i < offsetBits && offset > 0 ; i ++ ) { if ( offset & 0x1 ) { result += powerOfTwo [ 53 - offsetBits + i ] ; } offset >>>= 1 ; } return result ; } }