Repository

js/Mobilizing/input/GPSUtils.js

import * as _Math from '../core/util/Math';

const _STATICS = {};
_STATICS.zoom = 1;
_STATICS.worldSize = 512 * (Math.pow(2, _STATICS.zoom));

/**
* Some GPS coordinates convertion tools to use maps in Mobilizing.js
*/
export default class GPSUtils {

    /**
    * Converts longitude and latitude coords (from an OpenStreetMap map) into absolute pixels coords. This method don't calculate the pixels coords within a given map bound's! Use getCoordinateInMap for this.
    * @static
    *
    * @param {Number} longitute longitute
    * @param {Number} latitude latitude
    * @param {Number} zoom the zoom factor fo this map
    */
    static getPixelsCoordsFromOSMLngLat(longitute, latitude, zoom) {
        if (zoom) {
            _STATICS.zoom = zoom;
            _STATICS.worldSize = 512 * (Math.pow(2, _STATICS.zoom));
        }

        return { x: GPSUtils.lngX(longitute), y: GPSUtils.latY(latitude) };
    }

    /**
    * Compute GPS coordinates into pixels x, y coordinates in a map. Here, we adopt the OSM standard for mappinp. Therefore, you should generate your bitmap earth map with a tool using OSM tiles (like MapBox, TileMill). You should give the zoom factor and the map bounds (in lognititude and latitude) to this method for the calculation to be effective
    * @static
    *
    * @param {Number} longitute
    * @param {Number} latitude
    * @param {Number} zoom zoom factor fo this map
    * @param {Array} mapCoord MapBox/TileMill map coords array, like [-180,-85.0511,180,85.0511]
    * @param {Number} mapWidth the map width in pixels
    * @param {Number} mapHeight the map height in pixels
    */
    static getCoordinateInMap(longitute, latitude, mapCoord, mapWidth, mapHeight, zoom) {
        if (zoom) {
            _STATICS.zoom = zoom;
        }
        //construct local variable to simplify expressions writing
        const leftLong = mapCoord[0];
        const bottomLat = mapCoord[1];

        const rightLong = mapCoord[2];
        const topLat = mapCoord[3];

        //construct the corners pixel coordinates
        const topRight = GPSUtils.getPixelsCoordsFromOSMLngLat(rightLong, topLat);
        const topLeft = GPSUtils.getPixelsCoordsFromOSMLngLat(leftLong, topLat);

        const bottomRight = GPSUtils.getPixelsCoordsFromOSMLngLat(rightLong, bottomLat);
        // let bottomLeft = GPSUtils.getPixelsCoordsFromOSMLngLat(leftLong, bottomLat);

        const absCoord = GPSUtils.getPixelsCoordsFromOSMLngLat(longitute, latitude);

        const coords = {
            x: _Math.map(absCoord.x, topRight.x, topLeft.x, mapWidth / 2, -mapHeight / 2),
            y: _Math.map(absCoord.y, topRight.y, bottomRight.y, mapWidth / 2, -mapHeight / 2)
        };

        return coords;
    }

    /**
     * latitude to absolute x coord
     * @static
     *
     * @param {Number} lon
     * @return {Number} pixel coordinate
     */
    static lngX(lng) {
        return (180 + lng) * _STATICS.worldSize / 360;
    }

    /**
     * latitude to absolute y coord
     * @static
     * @method latY
     * @param {Number} lat
     * @return {Number} pixel coordinate
     */
    static latY(lat) {
        const y = 180 / Math.PI * Math.log(Math.tan(Math.PI / 4 + lat * Math.PI / 360));
        return (180 - y) * _STATICS.worldSize / 360;
    }

    static xLng(x) {
        return x * 360 / _STATICS.worldSize - 180;
    }
    static yLat(y) {
        const y2 = 180 - y * 360 / _STATICS.worldSize;
        return 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90;
    }

    /**
    * Convert GPS coords to cartesian coords. NB : this algorithm is adapted to three.js geoms!
    * @static
    *
    * @param {Number} longitude
    * @param {Number} latitude
    * @param {Number} radius
    * @return {Object} {x, y, z} coordinates
    */
    static getPolarFromLngLat(longitude, latitude, radius) {
        const lng = _Math.degToRad(longitude + 180);
        const lat = _Math.degToRad(90 - latitude);

        const x = -(radius * Math.cos(lng) * Math.sin(lat));
        const y = radius * Math.cos(lat);
        const z = radius * Math.sin(lat) * Math.sin(lng);

        return { x, y, z };
    }
}