WME Bad Junction Angle Info

Shows "Bad Angle Infos" of all Junctions in the editing area

目前为 2021-10-27 提交的版本。查看 最新版本

// ==UserScript==
// @name          WME Bad Junction Angle Info
// @description   Shows "Bad Angle Infos" of all Junctions in the editing area
// @include       /^https:\/\/(www|beta)\.waze\.com\/(?!user\/)(.{2,6}\/)?editor.*$
// @require       https://gf.qytechs.cn/scripts/24851-wazewrap/code/WazeWrap.js
// @version       1.9.0
// @grant         none
// @namespace     https://wms.kbox.at/
// @copyright     2021 Gerhard; 2018 seb-d59, 2016 Michael Wikberg <[email protected]>
// @license       CC-BY-NC-SA
// @icon          data:image/png;base64,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
// ==/UserScript==

/**
 * This script is based on the code from "WME Junction angle Info".
 * Thanks for the great work to the authors of the original script:
 */
/**
 * Copyright 2016 Michael Wikberg <[email protected]>
 * WME Junction Angle Info extension is licensed under a Creative Commons
 * Attribution-NonCommercial-ShareAlike 3.0 Unported License.
 *
 * Contributions by:
 *	2014 Paweł Pyrczak "tkr85" <[email protected]>
 *	2014 "AlanOfTheBerg" <[email protected]>
 *	2014 "berestovskyy" <?>
 *	2015 "FZ69617" <?>
 *	2015 "wlodek76" <?>
 *	2016 Sergey Kuznetsov "WazeRus" <[email protected]> (Russian translation)
 *	2016 "MajkiiTelini" <?> Czech translation
 *	2016 "witoco" <?> (Latin-American Spanish translation)
 *	2017 "seb-d59" (Check override instruction and French translation)  <https://www.waze.com/forum/memberlist.php?mode=viewprofile&u=16863068>
 *  2019 thank to Sapozhnik for the Ukrainian (український) translation
 */

/*jshint eqnull:true, nonew:true, nomen:true, curly:true, latedef:true, unused:strict, noarg:true, loopfunc:true */
/*jshint trailing:true, forin:true, noempty:true, maxparams:7, maxerr:100, eqeqeq:true, strict:true, undef:true */
/*jshint bitwise:true, newcap:true, immed:true, onevar:true, browser:true, nonbsp:true, freeze:true */
/*global I18n, $*/
/* global _ */
/* global W */
/* global WazeWrap */

function run_aja() {
    "use strict";

    //    var TURN_ANGLE = 45.50; //Turn vs. keep angle - based on map experiments (45.04 specified in Wiki).
    //    var GRAY_ZONE = 1.5; //Gray zone angle intended to prevent from irregularities observed on map.

    /*
     * First some variable and enumeration definitions
     */
    var junctionangle_version = "1.2.5";
    var name = "Bad Junction Angle Info";
    var junctionangle_debug = 0; //0: no output, 1: basic info, 2: debug 3: verbose debug, 4: insane debug
    var aja_last_restart = 0;
    var aja_roundabout_points = [];
    var aja_options = {};
    var aja_mapLayer;
    var scriptenabled = true;
    var pointSize = 12;
    var decimals = 2;

    /*
     * Main logic functions
     */

    function junctionangle_init() {
        // Register event listeners
        WazeWrap.Events.register('selectionchanged', null, aja_calculate);
        WazeWrap.Events.register('moveend', null, aja_calculate);
        WazeWrap.Events.register('afteraction', null, aja_calculate);
        WazeWrap.Events.register('moveend', null, aja_calculate);

        window.W.model.segments.on({
            "objectschanged": aja_calculate,
            "objectsremoved": aja_calculate
        });
        window.W.model.nodes.on({
            "objectschanged": aja_calculate,
            "objectsremoved": aja_calculate
        });

        window.W.map.getOLMap().events.register("zoomend", null, aja_calculate);
        window.W.map.getOLMap().events.register("move", null, aja_calculate);

        //Add support for translations. Default (and fallback) is "en".
        //Note, don't make typos in "acceleratorName", as it has to match the layer name (with whitespace removed)
        // to actually work. Took me a while to figure that out...
        I18n.translations[window.I18n.locale].layers.name.alljunction_angles = name;

        /**
         * Initialize BJAI OpenLayers vector layer
         */
        if (window.W.map.getLayersBy("uniqueName","alljunction_angles").length === 0) {

            // Create a vector layer and give it your style map.
            aja_mapLayer = new window.OpenLayers.Layer.Vector(name, {
                displayInLayerSwitcher: true,
                uniqueName: "alljunction_angles",
                shortcutKey: "S+j",
                accelerator: "toggle" + name.replace(/\s+/g,''),
                className: "alljunction-angles",
                styleMap: new window.OpenLayers.StyleMap(aja_style())
            });

            window.W.map.addLayer(aja_mapLayer);
            aja_log("version " + junctionangle_version + " loaded.", 0);

            aja_log(window.W.map, 3);
            aja_log(window.W.model, 3);
            aja_log(window.W.loginManager, 3);
            aja_log(window.W.selectionManager, 3);
            aja_log(aja_mapLayer, 3);
            aja_log(window.OpenLayers, 3);
        } else {
            aja_log("Oh, nice.. We already had a layer?", 3);
        }

        WazeWrap.Interface.AddLayerCheckbox("display", "Bad Junction Angle Info", true, LayerToggled);

        aja_apply();

        // MTE mode event
        // reload after changing WME units
        W.prefs.on('change:isImperial', function(){
            aja_apply();
        });

        aja_calculate();
    }

    function LayerToggled(checked){
        aja_mapLayer.setVisibility(checked);
        scriptenabled = checked;
    }

    function findLayer(partOf_id){
        var layer;
        for (var i=0; i < window.W.map.layers.length; i++){
            if (window.W.map.layers[i].id.search(partOf_id) != -1){
                layer={id: window.W.map.layers[i].id, name: window.W.map.layers[i].name, number : i};
                aja_log("Number: " + i + "; id : " + layer.id + "; name :" + layer.name ,3);
                return layer;
            }
        }
    }

    function testLayerZIndex(){
        // seb-d59:
        // Here i search the selection layer and i read the z-index
        // and put BJAI's layer under this one.
        var zIndex = 0;
        aja_mapLayer.setZIndex(500);
        // now selection layer has no name ...
        var layer = {}
        layer = findLayer("OpenLayers_Layer_Vector_RootContainer");
        var layerOBJ = window.W.map.layers[layer.number];
        //aja_log("id : " + layerOBJ.id + "; name :" + layerOBJ.name + " zIndex: " + layerOBJ.getZIndex() ,3);
        zIndex = parseInt(layerOBJ.getZIndex()) - 1 ;
        aja_mapLayer.setZIndex(zIndex);
        aja_log("aja_mapLayer new zIndex: " + aja_mapLayer.getZIndex() ,3);
    }

    function aja_calculate_real() {
        var aja_start_time = Date.now();
        var aja_nodes = [];
        var restart = false;
        aja_log("Actually calculating now", 2);
        aja_roundabout_points = [];
        aja_log(window.W.map, 3);
        if (typeof aja_mapLayer === 'undefined') {
            return;
        }
        //clear old info
        aja_mapLayer.destroyFeatures();

        testLayerZIndex();
        if (!scriptenabled) return;

        _.each(W.model.segments.getObjectArray(), s => {
            if(![5, 10, 16, 18, 19].includes(s.attributes.roadType)){
                let segmentsAtt = s.attributes;
                if (segmentsAtt.fromNodeID != null &&
                    aja_nodes.indexOf(segmentsAtt.fromNodeID) === -1) {
                    aja_nodes.push(segmentsAtt.fromNodeID);
                }
                if (segmentsAtt.toNodeID != null &&
                    aja_nodes.indexOf(segmentsAtt.toNodeID) === -1) {
                    aja_nodes.push(segmentsAtt.toNodeID);
                }
            }
        });
        aja_log(aja_nodes, 3);

        var aja_label_distance;
        /*
         * Define a base distance to markers, depending on the zoom level
         */
        switch (window.W.map.getOLMap().zoom) {
            case 22: //10:
                aja_label_distance = 2.8;
                break;
            case 21: //9:
                aja_label_distance = 4;
                break;
            case 20: //8:
                aja_label_distance = 8;
                break;
            case 19: //7:
                aja_label_distance = 15;
                break;
            case 18: //6:
                aja_label_distance = 25;
                break;
            case 17: //5:
                aja_label_distance = 40;
                break;
            case 16: //4:
                aja_label_distance = 80;
                break;
            case 15: //3:
                aja_label_distance = 150;
                break;
            case 14: //2:
                aja_label_distance = 300;
                break;
            case 13: //1:
                aja_label_distance = 400;
                break;
            default:
                aja_log("Unsupported zoom level: " + window.W.map.getOLMap().zoom + "!", 2);
        }

        aja_label_distance *= (1 + (0.2 * parseInt(decimals)));

        aja_log("zoom: " + window.W.map.getOLMap().zoom + " -> distance: " + aja_label_distance, 2);

        //Start looping through selected nodes
        for (var i = 0; i < aja_nodes.length; i++) {
            var node = getByID(window.W.model.nodes,aja_nodes[i]);
            var angles = [];
            var aja_selected_segments_count = 0;
            var aja_selected_angles = [];
            var a;

            if (node == null || !node.hasOwnProperty('attributes')) {
                //Oh oh.. should not happen? We want to use a node that does not exist
                aja_log("Oh oh.. should not happen?",2);
                aja_log(node, 2);
                aja_log(aja_nodes[i], 2);
                aja_log(window.W.model, 3);
                aja_log(window.W.model.nodes, 3);
                continue;
            }
            //check connected segments
            var aja_current_node_segments = node.attributes.segIDs;
            aja_log("Alle aja_current_node_segments",2);
            aja_log(aja_current_node_segments.length,2);
            aja_log(node, 2);

            // Remove non driveable Segments
            for( var ii = 0; ii < aja_current_node_segments.length; ii++){
                if([5, 10, 16, 18, 19].includes(window.W.model.segments.objects[aja_current_node_segments[ii]].attributes.roadType)){
                    aja_current_node_segments.splice(ii, 1);
                    ii--;
                }
            }
            aja_log(aja_current_node_segments.length,2);

            //ignore of we have less than 2 segments
            if (aja_current_node_segments.length <= 2) {
                aja_log("Found only " + aja_current_node_segments.length + " connected segments at " + aja_nodes[i] +
                        ", not calculating anything...", 2);
                continue;
            }
            aja_log("Mehr als 2 aja_current_node_segments",2);
            aja_log(aja_current_node_segments.length,2);


            aja_log("Calculating angles for " + aja_current_node_segments.length + " segments", 2);
            aja_log(aja_current_node_segments, 3);

            aja_current_node_segments.forEach(function (nodeSegment, j) {
                var s = window.W.model.segments.objects[nodeSegment];
                if(typeof s === 'undefined') {
                    //Meh. Something went wrong, and we lost track of the segment. This needs a proper fix, but for now
                    // it should be sufficient to just restart the calculation
                    aja_log("Failed to read segment data from model. Restarting calculations.", 1);
                    if(aja_last_restart === 0) {
                        aja_last_restart = new Date().getTime();
                        setTimeout(function(){aja_calculate();}, 500);
                    }
                    restart = true;
                }

                a = aja_getAngle(aja_nodes[i], s);
                aja_log("Segment " + nodeSegment + " angle is " + a, 2);
                angles[j] = [a, nodeSegment, s == null ? false : true];
                if (s == null ? false : true) {
                    aja_selected_segments_count++;
                }
            });

            if(restart) { return; }

            aja_log(angles, 2);

            var ha, point;
            //sort angle data (ascending)
            angles.sort(function (a, b) {
                return a[0] - b[0];
            });
            aja_log(angles, 3);
            aja_log(aja_selected_segments_count, 3);

            //get all segment angles

            for (var iii = 0; iii < angles.length - 1; iii++) {
                for (var jjj = iii + 1; jjj < angles.length; jjj++) {

                    a = (360 + (angles[(jjj) % angles.length][0] - angles[iii][0])) % 360;
                    if (a > 180) {
                        a = 360 - a;
                        ha = (360 + ((a / 2) + angles[jjj][0])) % 360;
                    } else {

                        ha = (360 + ((a / 2) + angles[iii][0])) % 360;
                    }
                    aja_log(a,3);

                    aja_log("Angle between " + angles[iii][1] + " and " + angles[(jjj) % angles.length][1] + " is " +
                            a + " and position for label should be at " + ha, 1);
                    //                    if (a < 10.26 || (a > 133 && a < 136 )) {
                    if ((a > 133 && a < 136 )) {
                        point = new window.OpenLayers.Geometry.Point(
                            node.geometry.x + (aja_label_distance * 1.25 * Math.cos((ha * Math.PI) / 180)),
                            node.geometry.y + (aja_label_distance * 1.25 * Math.sin((ha * Math.PI) / 180))
                        );
                        aja_draw_marker(point, node, aja_label_distance, a, ha);
                    }
                }
            }
        }

        aja_last_restart = 0;
        var aja_end_time = Date.now();
        aja_log("Calculation took " + String(aja_end_time - aja_start_time) + " ms", 2);
    }

    /*
     * Drawing functions
     */
    /**
     *
     * @param point Estimated point for marker
     * @param node Node the marker is for
     * @param aja_label_distance Arbitrary distance to be used in moving markers further away etc
     * @param a Angle to display
     * @param ha Angle to marker from node (FIXME: either point or ha is probably unnecessary)
     * @param withRouting true: show routing guessing markers, false: show "normal" angle markers
     * @param aja_junction_type If using routing, this needs to be set to the desired type
     */
    function aja_draw_marker(point, node, aja_label_distance, a, ha, withRouting, aja_junction_type) {

        //Try to estimate of the point is "too close" to another point
        //(or maybe something else in the future; like turn restriction arrows or something)
        //FZ69617: Exctract initial label distance from point
        var aja_tmp_distance = Math.abs(ha) % 180 < 45 || Math.abs(ha) % 180 > 135 ?
            (point.x - node.geometry.x) / (Math.cos((ha * Math.PI) / 180)) :
        (point.y - node.geometry.y) / (Math.sin((ha * Math.PI) / 180));
        aja_log("Starting distance estimation", 3);
        while(aja_mapLayer.features.some(function(feature){
            if(typeof feature.attributes.aja_type !== 'undefined' && feature.attributes.aja_type !== 'roundaboutOverlay') {
                //Arbitrarily chosen minimum distance.. Should actually use the real bounds of the markers,
                //but that didn't work out.. Bounds are always 0..
                if(aja_label_distance / 1.4 > feature.geometry.distanceTo(point)) {
                    aja_log(aja_label_distance / 1.5 > feature.geometry.distanceTo(point) + " is kinda close..", 3);
                    return true;
                }
            }
            return false;
        })) {
            //add 1/4 of the original distance and hope for the best =)
            aja_tmp_distance += aja_label_distance / 4;
            aja_log("setting distance to " + aja_tmp_distance, 2);
            point = new window.OpenLayers.Geometry.Point(
                node.geometry.x + (aja_tmp_distance * Math.cos((ha * Math.PI) / 180)),
                node.geometry.y + (aja_tmp_distance * Math.sin((ha * Math.PI) / 180))
            );
        }
        aja_log("Distance estimation done", 3);

        var anglePoint = new window.OpenLayers.Feature.Vector(
            point,
            { angle: aja_round(180 - a) + "°", aja_type: "generic" }
        );

        aja_log(anglePoint, 3);

        //Draw a line to the point
        aja_mapLayer.addFeatures([
            new window.OpenLayers.Feature.Vector(
                new window.OpenLayers.Geometry.LineString([node.geometry, point]),
                {},
                {strokeOpacity: 0.9, strokeWidth: 2.2, strokeDashstyle: "solid", strokeColor: "#ff9966"}
            )
        ]
                                );
        //push the angle point
        aja_mapLayer.addFeatures([anglePoint]);
    }

    function aja_get_first_point(segment) {
        return segment.geometry.components[0];
    }

    function aja_get_last_point(segment) {
        return segment.geometry.components[segment.geometry.components.length - 1];
    }

    function aja_get_second_point(segment) {
        return segment.geometry.components[1];
    }

    function aja_get_next_to_last_point(segment) {
        return segment.geometry.components[segment.geometry.components.length - 2];
    }

    //get the absolute angle for a segment end point
    function aja_getAngle(aja_node, aja_segment) {
        aja_log("node: " + aja_node, 2);
        aja_log("segment: " + aja_segment, 2);
        if (aja_node == null || aja_segment == null) { return null; }
        var aja_dx, aja_dy;
        if (aja_segment.attributes.fromNodeID === aja_node) {
            aja_dx = aja_get_second_point(aja_segment).x - aja_get_first_point(aja_segment).x;
            aja_dy = aja_get_second_point(aja_segment).y - aja_get_first_point(aja_segment).y;
        } else {
            aja_dx = aja_get_next_to_last_point(aja_segment).x - aja_get_last_point(aja_segment).x;
            aja_dy = aja_get_next_to_last_point(aja_segment).y - aja_get_last_point(aja_segment).y;
        }
        aja_log(aja_node + " / " + aja_segment + ": dx:" + aja_dx + ", dy:" + aja_dy, 2);
        var aja_angle = Math.atan2(aja_dy, aja_dx);
        return ((aja_angle * 180 / Math.PI)) % 360;
    }

    /**
     * Decimal adjustment of a number. Borrowed (with some modifications) from
     * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
     * aja_round(55.55); with 1 decimal // 55.6
     * aja_round(55.549); with 1 decimal // 55.5
     * aja_round(55); with -1 decimals // 60
     * aja_round(54.9); with -1 decimals // 50
     *
     * @param    {Number}    value    The number.
     * @returns    {Number}            The adjusted value.
     */
    function aja_round(value) {
        var aja_rounding = -parseInt(decimals);
        var valueArray;
        if (typeof aja_rounding === 'undefined' || +aja_rounding === 0) {
            return Math.round(value);
        }
        value = +value;
        // If the value is not a number or the exp is not an integer...
        if (isNaN(value) || !(typeof aja_rounding === 'number' && aja_rounding % 1 === 0)) {
            return NaN;
        }
        // Shift
        valueArray = value.toString().split('e');
        value = Math.round(+(valueArray[0] + 'e' + (valueArray[1] ? (+valueArray[1] - aja_rounding) : -aja_rounding)));
        // Shift back
        valueArray = value.toString().split('e');
        return +(valueArray[0] + 'e' + (valueArray[1] ? (+valueArray[1] + aja_rounding) : aja_rounding));
    }

    /*
     * WME interface helper functions
     */
    var aja_apply = function applyAJAOptions() {
        aja_log("Applying stored (or default) settings", 2);
        if(typeof window.W.map.getLayersBy("uniqueName","alljunction_angles")[0] === 'undefined') {
            aja_log("WME not ready yet, trying again in 400 ms", 2);
            setTimeout(function(){aja_apply();}, 400);
            return;
        }
        window.W.map.getLayersBy("uniqueName","alljunction_angles")[0].styleMap = aja_style();
        aja_calculate_real();
        aja_log(aja_options, 2);
    };

    var aja_reset = function resetAJAOptions() {
        aja_log("Resetting settings", 2);
        if(localStorage != null) {
            localStorage.removeItem("wme_bja_options");
        }
        aja_options = {};
        aja_apply();
        return false;
    };

    var aja_calculation_timer = {
        start: function() {
            aja_log("Starting timer", 2);
            this.cancel();
            var aja_calculation_timer_self = this;
            this.timeoutID = window.setTimeout(function(){aja_calculation_timer_self.calculate();}, 200);
        },

        calculate: function() {
            aja_calculate_real();
            delete this.timeoutID;
        },

        cancel: function() {
            if(typeof this.timeoutID === "number") {
                window.clearTimeout(this.timeoutID);
                aja_log("Cleared timeout ID : " + this.timeoutID, 2);
                delete this.timeoutID;
            }
        }
    };

    function aja_calculate() {
        aja_calculation_timer.start();
    }

    function aja_style() {
        aja_log("Point radius will be: " + (parseInt(pointSize, 10)) +
                (parseInt(decimals > 0 ? (4 * parseInt(decimals)).toString() : "0")), 2);
        return new window.OpenLayers.Style({
            fillColor: "#ffff00",
            strokeColor: "#ff9966",
            strokeWidth: 2,
            label: "${angle}",
            fontWeight: "bold",
            pointRadius: parseInt(pointSize, 10) +
            (parseInt(decimals) > 0 ? 4 * parseInt(decimals) : 0),
            fontSize: "10px"
        });
    }

    /*
     * Bootstrapping and logging
     */

    function aja_bootstrap(retries) {
        retries = retries || 0;
        //If Waze has not been defined in ~15 seconds, it probably won't work anyway. Might need tuning
        //for really slow devices?
        if (retries >= 30) {
            aja_log("Failed to bootstrap 30 times. Giving up.", 0);
            return;
        }

        try {
            //User logged in and WME ready
            if (
                !(document.querySelector('.list-unstyled.togglers .group') === null) &&
                aja_is_model_ready() &&
                aja_is_dom_ready() &&
                window.W.loginManager.isLoggedIn()) {
                setTimeout(function () {
                    junctionangle_init();
                }, 500);
            }
            //Some part of the WME was not yet fully loaded. Retry.
            else {
                setTimeout(function () {
                    aja_bootstrap(++retries);
                }, 500);
            }
        } catch (err) {
            aja_log(err, 1);
            setTimeout(function () {
                aja_bootstrap(++retries);
            }, 500);
        }
    }

    function aja_is_model_ready() {
        if(typeof window.W === 'undefined' || typeof window.W.map === 'undefined') {
            return false;
        } else {
            //return 'undefined' !== typeof window.W.map.events.register &&
            return 'undefined' !== typeof window.W.map.getOLMap().events.register &&
                'undefined' !== typeof window.W.selectionManager.events.register &&
                'undefined' !== typeof window.W.loginManager.events.register;
        }
    }

    function aja_is_dom_ready() {
        if(null === document.getElementById('user-info')) {
            return false;
        } else {
            return document.getElementById('user-info').getElementsByClassName('nav-tabs').length > 0 &&
                document.getElementById('user-info').getElementsByClassName('tab-content').length > 0;
        }
    }

    /**
     * Debug logging.
     * @param aja_log_msg
     * @param aja_log_level
     */
    function aja_log(aja_log_msg, aja_log_level) {
        if(typeof aja_log_level === 'undefined') { aja_log_level = 1; }
        if (aja_log_level <= junctionangle_debug) {
            if (typeof aja_log_msg === "object") {
                console.log(aja_log_msg);
            }
            else {
                console.log("WME Bad JAI: " + aja_log_msg);
            }
        }
    }

    function getByID(obj, id){
        if (typeof(obj.getObjectById) == "function"){
            return obj.getObjectById(id);
        }else if (typeof(obj.getObjectById) == "undefined"){
            return obj.get(id);
        }
    }

    aja_bootstrap();
}

//Dynamically create, add and run the script in the real page context. We really do need access to many of the objects...
var DLScript = document.createElement("script");
DLScript.textContent = '' +
    run_aja.toString() + ' \n' +
    'run_aja();';
DLScript.setAttribute("type", "application/javascript");
document.body.appendChild(DLScript);

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址