GeoUtils

Spherical geometry utility class for WME scripts

Ten skrypt nie powinien być instalowany bezpośrednio. Jest to biblioteka dla innych skyptów do włączenia dyrektywą meta // @require https://update.greasyfork.org/scripts/571719/1785947/GeoUtils.js

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Greasemonkey lub Violentmonkey.

You will need to install an extension such as Tampermonkey to install this script.

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Violentmonkey.

Aby zainstalować ten skrypt, wymagana będzie instalacja rozszerzenia Tampermonkey lub Userscripts.

You will need to install an extension such as Tampermonkey to install this script.

Aby zainstalować ten skrypt, musisz zainstalować rozszerzenie menedżera skryptów użytkownika.

(Mam już menedżera skryptów użytkownika, pozwól mi to zainstalować!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Musisz zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

(Mam już menedżera stylów użytkownika, pozwól mi to zainstalować!)

// ==UserScript==
// @name         GeoUtils
// @description  Spherical geometry utility class for WME scripts
// @author       Anton Shevchuk
// @license      MIT License
// @version      0.0.1
// @match        *://*/*
// @grant        none
// @namespace    https://greasyfork.org/users/227648
// ==/UserScript==

(function () {
    'use strict';

    /**
     * A utility class for spherical geometry (geodesy).
     * Assumes points are [longitude, latitude] in degrees.
     */
    class GeoUtils {
        static _toRadians(degrees) {
            return degrees * (Math.PI / 180);
        }
        static _toDegrees(radians) {
            return radians * (180 / Math.PI);
        }
        static _normalizeAngle(degrees) {
            return (degrees + 540) % 360 - 180;
        }
        static getBearing(pA, pB) {
            const latA = GeoUtils._toRadians(pA[1]);
            const lonA = GeoUtils._toRadians(pA[0]);
            const latB = GeoUtils._toRadians(pB[1]);
            const lonB = GeoUtils._toRadians(pB[0]);
            const deltaLon = lonB - lonA;
            const y = Math.sin(deltaLon) * Math.cos(latB);
            const x = Math.cos(latA) * Math.sin(latB) -
                Math.sin(latA) * Math.cos(latB) * Math.cos(deltaLon);
            const bearingRad = Math.atan2(y, x);
            return (GeoUtils._toDegrees(bearingRad) + 360) % 360;
        }
        static findAngle(p1, p2, p3) {
            const bearing21 = GeoUtils.getBearing(p2, p1);
            const bearing23 = GeoUtils.getBearing(p2, p3);
            let angle = Math.abs(bearing21 - bearing23);
            if (angle > 180) {
                angle = 360 - angle;
            }
            return angle;
        }
        static getDistance(pA, pB) {
            return GeoUtils.getAngularDistance(pA, pB) * 6371000;
        }
        static getAngularDistance(pA, pB) {
            const latA = GeoUtils._toRadians(pA[1]);
            const lonA = GeoUtils._toRadians(pA[0]);
            const latB = GeoUtils._toRadians(pB[1]);
            const lonB = GeoUtils._toRadians(pB[0]);
            const deltaLat = latB - latA;
            const deltaLon = lonB - lonA;
            const a = Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2) +
                Math.cos(latA) * Math.cos(latB) *
                    Math.sin(deltaLon / 2) * Math.sin(deltaLon / 2);
            return 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        }
        static getDestination(startPoint, bearing, distanceRad) {
            const lat1 = GeoUtils._toRadians(startPoint[1]);
            const lon1 = GeoUtils._toRadians(startPoint[0]);
            const brng = GeoUtils._toRadians(bearing);
            const d = distanceRad;
            const lat2 = Math.asin(Math.sin(lat1) * Math.cos(d) +
                Math.cos(lat1) * Math.sin(d) * Math.cos(brng));
            const lon2 = lon1 + Math.atan2(Math.sin(brng) * Math.sin(d) * Math.cos(lat1), Math.cos(d) - Math.sin(lat1) * Math.sin(lat2));
            const lon2Deg = GeoUtils._toDegrees(lon2);
            const lat2Deg = GeoUtils._toDegrees(lat2);
            return [(lon2Deg + 540) % 360 - 180, lat2Deg];
        }
        static findIntersection(pA, pB, pC, angle) {
            if (angle % 180 === 0) {
                return null;
            }
            const angleRad = GeoUtils._toRadians(angle);
            const bearingAB = GeoUtils.getBearing(pA, pB);
            const bearingAC = GeoUtils.getBearing(pA, pC);
            const angleA_rad = GeoUtils._toRadians(bearingAC - bearingAB);
            const distb_rad = GeoUtils.getAngularDistance(pA, pC);
            if (distb_rad < 1e-12) {
                return null;
            }
            const cot_b = 1.0 / Math.tan(distb_rad);
            const cot_D = 1.0 / Math.tan(angleRad);
            const X = cot_b;
            const Y = Math.cos(angleA_rad);
            const Z = Math.sin(angleA_rad) * cot_D;
            const R = Math.hypot(X, Y);
            const phi = Math.atan2(Y, X);
            const sin_c_minus_phi = Z / R;
            if (Math.abs(sin_c_minus_phi) > 1) {
                return null;
            }
            const distAD_rad = phi + Math.asin(sin_c_minus_phi);
            return GeoUtils.getDestination(pA, bearingAB, distAD_rad);
        }
        static findRightAngleIntersection(pA, pB, pC) {
            const angleA_deg = GeoUtils.findAngle(pB, pA, pC);
            const angleA_rad = GeoUtils._toRadians(angleA_deg);
            const distAC_rad = GeoUtils.getAngularDistance(pA, pC);
            const tan_c = Math.cos(angleA_rad) * Math.tan(distAC_rad);
            const distAD_rad = Math.abs(Math.atan(tan_c));
            const bearingAC_deg = GeoUtils.getBearing(pA, pC);
            const bearingAB_deg = GeoUtils.getBearing(pA, pB);
            const angleCAB_raw_diff = GeoUtils._normalizeAngle(bearingAC_deg - bearingAB_deg);
            let bearingAD_deg;
            if (angleCAB_raw_diff >= 0) {
                bearingAD_deg = GeoUtils._normalizeAngle(bearingAC_deg - angleA_deg);
            }
            else {
                bearingAD_deg = GeoUtils._normalizeAngle(bearingAC_deg + angleA_deg);
            }
            return GeoUtils.getDestination(pA, bearingAD_deg, distAD_rad);
        }
    }

    Object.assign(window, { GeoUtils });

})();