WME Junction Angle Info Discussion View history

Revision as of 19:24, 13 February 2014 by Dbraughlr (talk | contribs)
    // ==UserScript==
    // @name WME Junction Angle info
    // @namespace http://pyrczak.pl/
    // @description Show the angle between two selected (and connected) segments
    // @include         https://*.waze.com/*/editor/*
    // @include         https://*.waze.com/editor/*
    // @include         https://*.waze.com/map-editor/*
    // @include         https://*.waze.com/beta_editor/*
    // @include         https://editor-beta.waze.com/*
    // @version 1.5.7.3
    // @grant none
    // @copyright                2013 Michael Wikberg <michael@wikberg.fi>
    // @license CC-BY-NC-SA
    // ==/UserScript==

    /**
    * Copyright 2013 Michael Wikberg <michael@wikberg.fi>
    *
    * Fixed for new WME: 2014 Paweł Pyrczak <support@pyrczak.pl>
    *
    */
    function run_ja() {


    var junctionangle_version = "1.5.7.3";
    var junctionangle_debug = 1;        //0: no output, 1: basic info, 2: debug 3: crazy debug
    var ja_wazeModel, ja_wazeMap, $;
    var ja_features = [];

            var ja_wazeMap = {};
            var ja_wazeModel = {};
            var ja_loginManager = {};
            var ja_selectionManager = {};
            var ja_OpenLayers = {};


    function junctionangle_bootstrap() {
            var bGreasemonkeyServiceDefined = false;

           
            // not needed
            /*
             
            try
            {
                    if (typeof Components.interfaces.gmIGreasemonkeyService === "object")
                    {
                            bGreasemonkeyServiceDefined = true;
                    }
            }
            catch (err)
            {
                    //Ignore.
            }
            if ( typeof unsafeWindow === "undefined" || ! bGreasemonkeyServiceDefined)
            {
                    unsafeWindow = ( function ()
                    {
                            var dummyElem = document.createElement('p');
                            dummyElem.setAttribute ('onclick', 'return window;');
                            return dummyElem.onclick ();
                    } ) ();
            }
           
            */
            /* begin running the code! */
            setTimeout(ja_startcode, 500);
    }


    function ja_startcode() {
           // 
       try {
          if ((typeof window.Waze.map != undefined)  && (undefined != typeof window.Waze.map.events.register) && (undefined != typeof window.Waze.selectionManager.events.register ) && (undefined != typeof window.Waze.loginManager.events.register) ) {
             setTimeout(junctionangle_init, 500);
          } else {
             setTimeout(ja_startcode, 1000);
          }
       } catch(err) {
             setTimeout(ja_startcode, 1000);
       }

    }


    function ja_log(ja_log_msg, ja_log_level) {
           return true;
           
            if(ja_log_level <= junctionangle_debug) {
                    if(typeof ja_log_msg == "object") {
                            //ja_log(arguments.callee.caller.toString(), ja_log_level);
                           // console.log(ja_log_msg);
                    }
                    else {
                            //console.log("WME Junction Angle: " + ja_log_msg);
                    }
            }
    }

    function junctionangle_init()
    {


       ja_wazeMap = window.Waze.map;
       ja_wazeModel = window.Waze.model;
       ja_loginManager = window.Waze.loginManager;
       ja_selectionManager = window.Waze.selectionManager;
       ja_OpenLayers = window.OpenLayers;
       //get jQuery support (not needed now)
       //$ = window.$;
       I18n.translations.en.layers.name["WMEJunctionAngles"] = "WME Junction Angles";
       ja_wazeMap.addLayer(ja_mapLayer);

       //selected nodes changed
       ja_selectionManager.events.register("selectionchanged", null, ja_calculate);
       
       //probably unnecessary
       //map is moved or resized
       //ja_wazeMap.events.register("moveend", null, ja_calculate);

       //mouse button released (FIXME: wanted to listen to "segment or node moved", but could not find a suitable event...)
       // FIXED
       //ja_wazeMap.events.register("mouseup", null, ja_calculate);
       ja_wazeModel.segments.events.on({
          "objectschanged": ja_calculate,
          "objectsremoved": ja_calculate,
       });
       ja_wazeModel.nodes.events.on({
          "objectschanged": ja_calculate,
          "objectsremoved": ja_calculate,
       });

       //HTML changes after login. Better do init again.
       ja_loginManager.events.register("afterloginchanged", null, junctionangle_init);
           
            /**
             * Make some style settings
             */
             var ja_style = new ja_OpenLayers.Style({
                    fillColor: "#ffcc88",
                    strokeColor: "#ff9966",
                    strokeWidth: 2,
                    label: "${angle}",
                    fontWeight: "bold",
                    pointRadius: 10,
                    fontSize: "10px"
            }, {
                    rules: [
                            new window.OpenLayers.Rule({
                                    symbolizer: {
                                    }
                            }),
                            new window.OpenLayers.Rule({
                                    filter: new window.OpenLayers.Filter.Comparison({
                                             type: window.OpenLayers.Filter.Comparison.EQUAL_TO,
                                             property: "ja_type",
                                             value: "junction"
                                     }),
                                    symbolizer: {
                                            pointRadius: 13,
                                            fontSize: "12px",
                                            fillColor: "#4cc600",
                                            strokeColor: "#183800"
                                    }
                            })
                    ]
            });

            //try to see if we already have a layer
            if(window.Waze.map.getLayersByName("Junction Angles").length > 0) {
           
            } else {
                // Create a vector layer and give it your style map.
                ja_mapLayer = new ja_OpenLayers.Layer.Vector("Junction Angles", {
                   displayInLayerSwitcher: true,
                   uniqueName: "JunctionAngles",
                   shortcutKey: "S+j",
                   accelerator: "toggleJunctionAngles",

                   styleMap: new ja_OpenLayers.StyleMap(ja_style)
              });

                    ja_wazeMap.addLayer(ja_mapLayer);
                    ja_log("version " + junctionangle_version + " loaded.", 0);
                   
                    ja_log(ja_wazeMap,3);
                    ja_log(ja_wazeModel,3);
                    ja_log(ja_loginManager,3);
                    ja_log(ja_selectionManager,3);
                    ja_log(ja_mapLayer,3);
                    ja_log(ja_OpenLayers,3);

                    //try to resize the layer selection box... Apparently the only (easy) way is to actually override the CSS
                    //No longer needed. Commented out.
                    //var newSwitcherStyle = $('<style>.WazeControlLayerSwitcher:hover {background-color: #FFFFFF; max-height: 390px; width: 200px;}</style>');
                    //$('html > head').append(newSwitcherStyle);
            }
    }

    function ja_calculate()
    {
            //clear old info
            ja_mapLayer.destroyFeatures();

            //try to show all angles for all selected segments
            if(ja_selectionManager.selectedItems.length == 0) return 1;
            ja_log("Checking junctions for " + ja_selectionManager.selectedItems.length + " segments", 1);
            var ja_nodes = [];

            for(i = 0; i < ja_selectionManager.selectedItems.length; i++) {
                    ja_log(ja_selectionManager.selectedItems[i],3);
                    switch(ja_selectionManager.selectedItems[i].type) {
                            case "node":
                                    ja_nodes.push(ja_selectionManager.selectedItems[i].fid);
                                    break;
                            case "segment":
                    //segments selected?
                                    if(ja_selectionManager.selectedItems[i].attributes.fromNodeID != null &&
                                            ja_nodes.indexOf(ja_selectionManager.selectedItems[i].attributes.fromNodeID) == -1) {
                                            ja_nodes.push(ja_selectionManager.selectedItems[i].attributes.fromNodeID);
                                    }
                                    if(ja_nodes.indexOf(ja_selectionManager.selectedItems[i].attributes.toNodeID != null &&
                                            ja_nodes.indexOf(ja_selectionManager.selectedItems[i].attributes.toNodeID) == -1)) {
                                            ja_nodes.push(ja_selectionManager.selectedItems[i].attributes.toNodeID);
                                    }
                                    break;
                            default:
                                    ja_log("Found unknown item type: " + ja_selectionManager.selectedItems[i].type,1);
                    }
            }

            ja_features = [];

            for(i = 0; i < ja_nodes.length; i++) {
                    node = ja_wazeModel.nodes.get(ja_nodes[i]);
                    if(node == null || !node.hasOwnProperty('attributes')) {
                            //Oh oh.. should not happen?
                            ja_log(ja_nodes,2)
                            ja_log(ja_wazeModel,3)
                            ja_log(ja_wazeModel.nodes,3)
                            continue;
                    }
                    //check connected segments
                    segments = node.attributes.segIDs;
                    ja_log(node,2);
                   
                    //ignore of we have less than 2 segments
                    if(segments.length <= 1) {
                            ja_log("Found only " + segments.length + " connected segments at " + ja_nodes[i] + ", not calculating anything...", 2);
                            continue;
                    }
                   
                    ja_log("Calculating angles for " + segments.length + " segments", 2);
                   
                    angles = new Array();
                    selected_segments = 0;

                    for(j = 0; j < segments.length; j++) {
                            s = ja_wazeModel.segments.get(segments[j]);
                            a = ja_getAngle(ja_nodes[i], s);
                            ja_log("j: " + j + "; Segment " + segments[j] + " angle is " + a, 3);
                            angles[j] = new Array(a, segments[j], s != null ? s.isSelected() : false);
                            if(s != null ? s.isSelected() : false) selected_segments++;
                    }

                    ja_log(angles,2);
                    //sort angle data (ascending)
                    angles.sort(function(a,b){return a[0] - b[0]});
                    ja_log(angles,3);
                    ja_log(selected_segments,3);

                    switch (ja_wazeMap.zoom) {
                            case 9:
                                    ja_label_distance = 4;
                                    break;
                            case 8:
                                    ja_label_distance = 8;
                                    break;
                            case 7:
                                    ja_label_distance = 15;
                                    break;
                            case 6:
                                    ja_label_distance = 25;
                                    break;
                            case 5:
                                    ja_label_distance = 40;
                                    break;
                            case 4:
                                    ja_label_distance = 80;
                                    break;
                            case 3:
                                    ja_label_distance = 140;
                                    break;
                            case 2:
                                    ja_label_distance = 300;
                                    break;
                            case 1:
                                    ja_label_distance = 400;
                                    break;
                    }
                    ja_log("zoom: " + ja_wazeMap.zoom + " -> distance: " + ja_label_distance, 2);
                   
                    //if we have two connected segments selected, do some magic to get the turn angle only =)
                    if(selected_segments == 2) {
                            ja_selected = [];
                            ja_extra_space_multiplier = 1;
                           
                            for(j = 0; j < angles.length; j++) {
                                    if(angles[j][2]) {
                                            ja_selected.push(angles[j]);
                                    }
                            }
                           
                            a = ((ja_selected[1][0] - ja_selected[0][0]) + 360) % 360;
                            ha = (360 + (ja_selected[0][0]+ja_selected[1][0])/2) % 360;

                            ja_log(a,3);
                            if(a < 60) {
                                    ja_log("Sharp angle", 2);
                                    ja_extra_space_multiplier = 2;
                            }

                            if(a > 180) {
                                    //a2 = a - 180;
                                    ha = ha + 180;
                            }

                           
                            ja_log("Angle between " + ja_selected[0][1] + " and " + ja_selected[1][1] + " is " + a + " and position for label should be at " + ha, 3);

                            //put the angle point
                            ja_features.push(new ja_OpenLayers.Feature.Vector(
                                    new ja_OpenLayers.Geometry.Point(
                                            node.geometry.x + (ja_extra_space_multiplier * ja_label_distance * Math.cos((ha*Math.PI)/180)),
                                            node.geometry.y + (ja_extra_space_multiplier * ja_label_distance * Math.sin((ha*Math.PI)/180))
                                            )
                                            , { angle: Math.round(Math.abs(180 - a))+"°", ja_type: "junction" }
                            ));
                    }
                    else {
                            //get all segment angles
                            for(j = 0; j < angles.length; j++) {
                                    a = (360 + (angles[(j+1)%angles.length][0] - angles[j][0])) % 360;
                                    ha = (360 + ((a/2) + angles[j][0])) % 360;
                                   
                                    ja_log("Angle between " + angles[j][1] + " and " + angles[(j+1)%angles.length][1] + " is " + a + " and position for label should be at " + ha, 3);
                                    //push the angle point
                                    ja_features.push(new ja_OpenLayers.Feature.Vector(
                                            new ja_OpenLayers.Geometry.Point(
                                                    node.geometry.x + (ja_label_distance * Math.cos((ha*Math.PI)/180)), node.geometry.y + (ja_label_distance * Math.sin((ha*Math.PI)/180))
                                                    )
                                                    , { angle: Math.round(a)+"°", ja_type: "generic" }
                                    ));
                            }
                    }
            }

            ja_log(ja_features, 2);
            //Update the displayed angles
            ja_mapLayer.addFeatures(ja_features);
    }

    function ja_points_equal(point1, point2) {
            return (point1.x == point2.x && point1.y == point2.y);
    }

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

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

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

    function ja_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 ja_getAngle(ja_node, ja_segment) {
            if(ja_node == null || ja_segment == null) return null;
            if(ja_segment.attributes.fromNodeID == ja_node) {
                    ja_dx = ja_get_second_point(ja_segment).x - ja_get_first_point(ja_segment).x;
                    ja_dy = ja_get_second_point(ja_segment).y - ja_get_first_point(ja_segment).y;
            } else {
                    ja_dx = ja_get_next_to_last_point(ja_segment).x - ja_get_last_point(ja_segment).x;
                    ja_dy = ja_get_next_to_last_point(ja_segment).y - ja_get_last_point(ja_segment).y;
            }
            ja_log(ja_node + " / " + ja_segment + ": dx:" + ja_dx + ", dy:" + ja_dy);
            ja_angle = Math.atan2(ja_dy,ja_dx);
            return (360+(ja_angle*180/Math.PI))%360;
    }

    junctionangle_bootstrap();


    }

    var DLscript = document.createElement("script");
    DLscript.textContent =run_ja.toString() + ' \n' + 'run_ja();';
    DLscript.setAttribute("type","application/javascript");
    document.body.appendChild(DLscript);