@polygonjs/plugin-mapbox
Version:
Mapbox plugin for the 3D engine https://polygonjs.com
133 lines (110 loc) • 4.24 kB
text/typescript
// 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;