UNPKG

@polygonjs/plugin-mapbox

Version:

Mapbox plugin for the 3D engine https://polygonjs.com

133 lines (110 loc) 4.24 kB
// THREE = require("../three97.js"); # Modified version to use 64-bit double precision floats for matrix math import {Vector3} from 'three'; import {Matrix4} from 'three'; import mapboxgl from 'mapbox-gl'; import {CoreMapboxConstants} from './Constants'; import {Number3} from '@polygonjs/polygonjs/dist/src/types/GlobalTypes'; const Constants = CoreMapboxConstants; export class CoreMapboxUtils { // @prettyPrintMatrix: (uglymatrix)-> // for (s=0;s<4;s++){ // quartet=[uglymatrix[s], // uglymatrix[s+4], // uglymatrix[s+8], // uglymatrix[s+12]]; // console.log(quartet.map(function(num){return num.toFixed(4)})) // } static makePerspectiveMatrix(fovy: number, aspect: number, near: number, far: number) { const out = new Matrix4(); const f = 1.0 / Math.tan(fovy / 2); const nf = 1 / (near - far); const newMatrix = [f / aspect, 0, 0, 0, 0, f, 0, 0, 0, 0, (far + near) * nf, -1, 0, 0, 2 * far * near * nf, 0]; out.elements = newMatrix; return out; } // #gimme radians // function radify(deg){ // if (typeof deg === 'object'){ // return deg.map(function(degree){ // return Math.PI*2*degree/360 // }) // } // else return Math.PI*2*deg/360 // } // #gimme degrees // function degreeify(rad){ // return 360*rad/(Math.PI*2) // } static projectToWorld(lnglat: Number3) { // Spherical mercator forward projection, re-scaling to WORLD_SIZE const projected = [ -Constants.MERCATOR_A * lnglat[0] * Constants.DEG2RAD * Constants.PROJECTION_WORLD_SIZE, -Constants.MERCATOR_A * Math.log(Math.tan(Math.PI * 0.25 + 0.5 * lnglat[1] * Constants.DEG2RAD)) * Constants.PROJECTION_WORLD_SIZE, ]; const pixelsPerMeter = this.projectedUnitsPerMeter(lnglat[1]); //z dimension let height = lnglat[2]; if (height == null) { height = 0; } projected.push(height * pixelsPerMeter); return new Vector3(projected[0], projected[1], projected[2]); } static projectedUnitsPerMeter(latitude: number): number { return Math.abs( (Constants.WORLD_SIZE * (1 / Math.cos((latitude * Math.PI) / 180))) / Constants.EARTH_CIRCUMFERENCE ); } static fromLL(lon: number, lat: number): [number, number] { // derived from https://gist.github.com/springmeyer/871897 const extent = 20037508.34; const x = (lon * extent) / 180; let y = Math.log(Math.tan(((90 + lat) * Math.PI) / 360)) / (Math.PI / 180); y = (y * extent) / 180; return [(x + extent) / (2 * extent), 1 - (y + extent) / (2 * extent)]; } static fromLLv(position: Vector3): Vector3 { const ll = this.fromLL(position.x, position.z); return new Vector3(ll[0], position.y, ll[1]); } // https://github.com/mapbox/mapbox-gl-js/blob/5bebe1cd725e9af0c6be25928bdbde468bebdf61/src/ui/control/scale_control.js#L61-L127 static get_distance(latlng1: mapboxgl.LngLat, latlng2: mapboxgl.LngLat) { // Uses spherical law of cosines approximation. const R = 6371000; const rad = Math.PI / 180, lat1 = latlng1.lat * rad, lat2 = latlng2.lat * rad, a = Math.sin(lat1) * Math.sin(lat2) + Math.cos(lat1) * Math.cos(lat2) * Math.cos((latlng2.lng - latlng1.lng) * rad); const maxMeters = R * Math.acos(Math.min(a, 1)); return maxMeters; } // https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Lon..2Flat._to_tile_numbers_3 static lnglat_to_tile_number(lng_deg: number, lat_deg: number, zoom: number) { const lat_rad = (lat_deg / 180) * Math.PI; const n = 2.0 ** zoom; const x = Math.floor(((lng_deg + 180.0) / 360.0) * n); const y = Math.floor(((1.0 - Math.log(Math.tan(lat_rad) + 1 / Math.cos(lat_rad)) / Math.PI) / 2.0) * n); return { x: x, y: y, }; } static tile_number_to_lnglat(xtile: number, ytile: number, zoom: number) { const n = 2.0 ** zoom; const lon_deg = (xtile / n) * 360.0 - 180.0; const lat_rad = Math.atan(Math.sinh(Math.PI * (1 - (2 * ytile) / n))); const lat_deg = 180.0 * (lat_rad / Math.PI); return { lat: lat_deg, lng: lon_deg, }; } } // module.exports.prettyPrintMatrix = prettyPrintMatrix; // module.exports.makePerspectiveMatrix = makePerspectiveMatrix; // module.exports.radify = radify; // module.exports.degreeify = degreeify;