WME Junction Angle Info Discussion View history

Revision as of 19:09, 13 February 2014 by Dbraughlr (talk | contribs) ((new) code from AlanOfTheBerg)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
   // ==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.$;
      //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);