UNPKG

maplibre-gl

Version:

BSD licensed community fork of mapbox-gl, a WebGL interactive maps library

97 lines (87 loc) 4.94 kB
import {mat4} from 'gl-matrix'; import {EXTENT} from '../../data/extent'; import {clamp, degreesToRadians, MAX_VALID_LATITUDE, zoomScale} from '../../util/util'; import {MercatorCoordinate, mercatorXfromLng, mercatorYfromLat, mercatorZfromAltitude} from '../mercator_coordinate'; import Point from '@mapbox/point-geometry'; import type {UnwrappedTileIDType} from '../transform_helper'; import type {LngLat} from '../lng_lat'; /* * The maximum angle to use for the Mercator horizon. This must be less than 90 * to prevent errors in `MercatorTransform::_calcMatrices()`. It shouldn't be too close * to 90, or the distance to the horizon will become very large, unnecessarily increasing * the number of tiles needed to render the map. */ export const maxMercatorHorizonAngle = 89.25; /** * Returns mercator coordinates in range 0..1 for given coordinates inside a specified tile. * @param inTileX - X coordinate in tile units - range [0..EXTENT]. * @param inTileY - Y coordinate in tile units - range [0..EXTENT]. * @param canonicalTileID - Tile canonical ID - mercator X, Y and zoom. * @returns Mercator coordinates of the specified point in range [0..1]. */ export function tileCoordinatesToMercatorCoordinates(inTileX: number, inTileY: number, canonicalTileID: {x: number; y: number; z: number}): MercatorCoordinate { const scale = 1.0 / (1 << canonicalTileID.z); return new MercatorCoordinate( inTileX / EXTENT * scale + canonicalTileID.x * scale, inTileY / EXTENT * scale + canonicalTileID.y * scale ); } /** * Returns LngLat for given in-tile coordinates and tile ID. * @param inTileX - X coordinate in tile units - range [0..EXTENT]. * @param inTileY - Y coordinate in tile units - range [0..EXTENT]. * @param canonicalTileID - Tile canonical ID - mercator X, Y and zoom. */ export function tileCoordinatesToLocation(inTileX: number, inTileY: number, canonicalTileID: {x: number; y: number; z: number}): LngLat { return tileCoordinatesToMercatorCoordinates(inTileX, inTileY, canonicalTileID).toLngLat(); } /** * Convert from LngLat to world coordinates (Mercator coordinates scaled by world size). * @param worldSize - Mercator world size computed from zoom level and tile size. * @param lnglat - The location to convert. * @returns Point */ export function projectToWorldCoordinates(worldSize: number, lnglat: LngLat): Point { const lat = clamp(lnglat.lat, -MAX_VALID_LATITUDE, MAX_VALID_LATITUDE); return new Point( mercatorXfromLng(lnglat.lng) * worldSize, mercatorYfromLat(lat) * worldSize); } /** * Convert from world coordinates (mercator coordinates scaled by world size) to LngLat. * @param worldSize - Mercator world size computed from zoom level and tile size. * @param point - World coordinate. * @returns LngLat */ export function unprojectFromWorldCoordinates(worldSize: number, point: Point): LngLat { return new MercatorCoordinate(point.x / worldSize, point.y / worldSize).toLngLat(); } /** * Calculate pixel height of the visible horizon in relation to map-center (e.g. height/2), * multiplied by a static factor to simulate the earth-radius. * The calculated value is the horizontal line from the camera-height to sea-level. * @returns Horizon above center in pixels. */ export function getMercatorHorizon(transform: {pitch: number; cameraToCenterDistance: number}): number { return transform.cameraToCenterDistance * Math.min(Math.tan(degreesToRadians(90 - transform.pitch)) * 0.85, Math.tan(degreesToRadians(maxMercatorHorizonAngle - transform.pitch))); } export function calculateTileMatrix(unwrappedTileID: UnwrappedTileIDType, worldSize: number): mat4 { const canonical = unwrappedTileID.canonical; const scale = worldSize / zoomScale(canonical.z); const unwrappedX = canonical.x + Math.pow(2, canonical.z) * unwrappedTileID.wrap; const worldMatrix = mat4.identity(new Float64Array(16) as any); mat4.translate(worldMatrix, worldMatrix, [unwrappedX * scale, canonical.y * scale, 0]); mat4.scale(worldMatrix, worldMatrix, [scale / EXTENT, scale / EXTENT, 1]); return worldMatrix; } export function cameraMercatorCoordinateFromCenterAndRotation(center: LngLat, elevation: number, pitch: number, bearing: number, distance: number): MercatorCoordinate { const centerMercator = MercatorCoordinate.fromLngLat(center, elevation); const mercUnitsPerMeter = mercatorZfromAltitude(1, center.lat); const dMercator = distance * mercUnitsPerMeter; const dzMercator = dMercator * Math.cos(degreesToRadians(pitch)); const dhMercator = Math.sqrt(dMercator * dMercator - dzMercator * dzMercator); const dxMercator = dhMercator * Math.sin(degreesToRadians(-bearing)); const dyMercator = dhMercator * Math.cos(degreesToRadians(-bearing)); return new MercatorCoordinate(centerMercator.x + dxMercator, centerMercator.y + dyMercator, centerMercator.z + dzMercator); }