WME Roundabout Angles

Draws angles for typical roundabout and overlays helper line to adjust geometry of roundabout.

当前为 2014-10-01 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name                WME Roundabout Angles
// @namespace           http://userscripts.org/scripts/show/440831
// @description         Draws angles for typical roundabout and overlays helper line to adjust geometry of roundabout.
// @include             https://www.waze.com/editor/*
// @include             https://www.waze.com/*/editor/*
// @include             https://editor-beta.waze.com/*
// @version             1.04.1
// @grant               none
// @copyright           2014 wlodek76
// ==/UserScript==


/* Original wlodek76's version 1.04 adapted to WME v1.6-297 by FZ69617 */


var wmech_version = "1.04.1"

//---------------------------------------------------------------------------------------
function bootstrapRoundaboutAngles()
{
  var bGreasemonkeyServiceDefined = false;

  try {
    bGreasemonkeyServiceDefined = (typeof Components.interfaces.gmIGreasemonkeyService === "object");
  }
  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! */
    setInterval(DrawRoundaboutAngles, 500);
}
//---------------------------------------------------------------------------------------
function DrawRoundaboutAngles()
{
    drc_wazeMap = unsafeWindow.Waze.map;
    drc_wazeModel = unsafeWindow.Waze.model;
    drc_OpenLayers = unsafeWindow.OpenLayers;
    
    if (drc_wazeMap == null) return;
    if (drc_wazeModel == null) return;
    if (drc_OpenLayers == null) return;

    var layers = drc_wazeMap.getLayersBy("uniqueName","__DrawRoundaboutAngles");
    if(layers.length > 0) {
    	var drc_layer = layers[0];
        
        if (drc_layer.visibility == false) {
            drc_layer.removeAllFeatures();
            return;
        }

        if (Waze.map.zoom < 6) {
            drc_layer.removeAllFeatures();
            return;
        }
    }
    

    drc_features = [];
    
    var rids = [];
    
    for (var iseg in Waze.model.segments.objects) {
        var isegment = Waze.model.segments.get(iseg);
        var iattributes = isegment.attributes;
		var iline = isegment.geometry.id;

        var irid = iattributes.junctionID;
        
        var p = rids.indexOf(irid);
        
        if (iline !== null && irid != undefined && p==-1) {
            rids.push(irid);
            
            var nodes = new Array();
            var nodes_x = new Array();
            var nodes_y = new Array();

            for (var jseg in Waze.model.segments.objects) {
                var jsegment = Waze.model.segments.get(jseg);
                var jattributes = jsegment.attributes;
                var jrid = jattributes.junctionID;

                if (jrid == irid) {
                    nodes.push(jattributes.fromNodeID);
                    nodes.push(jattributes.toNodeID);
                }
            }
            
            for (var inode in Waze.model.nodes.objects) {
                var node = Waze.model.nodes.get(inode);
                var p = nodes.indexOf(node.attributes.id);
                if (p >= 0) {
                    nodes_x.push(node.geometry.x);
                    nodes_y.push(node.geometry.y);
            	}
            }
                    
            var sr_x   = 0;
            var sr_y   = 0;
            var radius = 0;
            var numNodes = nodes_x.length;
                              
            
            if (nodes_x.length >= 3) {
                
                //-----------throw short segments
                while (nodes_x.length > 4) {
                    var id = 0;
                    var dmin = 99999999;
                    for(var i=0; i<nodes_x.length; i++) {
                        for(var j=0; j<nodes_x.length; j++) {
                            if (i == j) continue;
                            
                            var x1 = nodes_x[i];
                            var y1 = nodes_y[i];
                            var x2 = nodes_x[j];
                            var y2 = nodes_y[j];
    
                            var dx = x1 - x2;
                            var dy = y1 - y2;
                            var d = dx*dx + dy*dy;
                            if (d < dmin) { dmin = d; id = i; }
                        }
                    }
                    
                    nodes_x.splice(id, 1);
                    nodes_y.splice(id, 1);
                }
                          
                //-----------simple approximation of centre point calculated from three first points
                var ax = nodes_x[0];
                var ay = nodes_y[0];
                var bx = nodes_x[1];
                var by = nodes_y[1];
                var cx = nodes_x[2];
                var cy = nodes_y[2];
                
                var x1 = (bx + ax) * 0.5;
                var y11 = (by + ay) * 0.5;
                var dy1 = bx - ax;
                var dx1 = -(by - ay);
                var x2 = (cx + bx) * 0.5;
                var y2 = (cy + by) * 0.5;
                var dy2 = cx - bx;
                var dx2 = -(cy - by);
                sr_x = (y11 * dx1 * dx2 + x2 * dx1 * dy2 - x1 * dy1 * dx2 - y2 * dx1 * dx2)/ (dx1 * dy2 - dy1 * dx2);
                sr_y = (sr_x - x1) * dy1 / dx1 + y11;
                
                var dx = ax - sr_x;
                var dy = ay - sr_y;
                radius = Math.sqrt(dx*dx + dy*dy); 
                
                var angles = [];

                for(var i=0; i<nodes_x.length; i++) {
                    
                    var dx = nodes_x[i] - sr_x;
                    var dy = nodes_y[i] - sr_y;
                    
                    var angle = Math.atan2(dy, dx);
                    angle = (360.0 + (angle * 180.0 / Math.PI));
                    if (angle < 0.0) angle += 360.0;
                    if (angle > 360.0) angle -= 360.0;
                    angles.push(angle);
                }
            
            
                //---------sorting angles for calulating angle difference between two segments
                angles = angles.sort(function(a,b) { return a - b; });
                angles.push( angles[0] + 360.0);
                angles = angles.sort(function(a,b) { return a - b; });
                //console.log(angles);
            

                
                var drc_point = new drc_OpenLayers.Geometry.Point(sr_x, sr_y );
                var drc_circle = new drc_OpenLayers.Geometry.Polygon.createRegularPolygon( drc_point, radius, 256 );
                var drc_feature = new drc_OpenLayers.Feature.Vector(drc_circle, {labelText: "", labelColor: "#000000" }  );
                drc_features.push(drc_feature);

                if (numNodes == 3 || numNodes == 4) {
                   for(var i=0; i<nodes_x.length; i++) {
                        var ix = nodes_x[i];
                        var iy = nodes_y[i];
                        var startPt   = new drc_OpenLayers.Geometry.Point( sr_x, sr_y );
                        var endPt     = new drc_OpenLayers.Geometry.Point( ix, iy );
                        var line      = new drc_OpenLayers.Geometry.LineString([startPt, endPt]);
                        var style     = {strokeColor:"#0040FF", strokeWidth:2};
                        var fea       = new drc_OpenLayers.Feature.Vector(line, {}, style);
                        drc_features.push(fea);
                   }
                    
                   var angles_int = [];
                   var angles_float = [];
                   var angles_sum = 0;
                    
                   for(var i=0; i<angles.length - 1; i++) {
                       
                       var ang = angles[i+1] - angles[i+0];
                       if (ang < 0) ang += 360.0;
                       if (ang < 0) ang += 360.0;
                       
                       if (ang < 135.0) {
                          ang = ang - 90.0;
                       }
                       else {
                          ang = ang - 180.0;
                       }
                    
                       angles_sum += parseInt(ang);
                       
                       angles_float.push( ang );
                       angles_int.push( parseInt(ang) );
                   }
            
                   if (angles_sum > 45) angles_sum -= 90;
                   if (angles_sum > 45) angles_sum -= 90;
                   if (angles_sum > 45) angles_sum -= 90;
                   if (angles_sum > 45) angles_sum -= 90;
                   if (angles_sum < -45) angles_sum += 90;
                   if (angles_sum < -45) angles_sum += 90;
                   if (angles_sum < -45) angles_sum += 90;
                   if (angles_sum < -45) angles_sum += 90;
            
                   if (angles_sum != 0) {
                       for(var i=0; i<angles_int.length; i++) {
                           var a = angles_int[i];
                           var af = angles_float[i] - angles_int[i];
                           if ( (a < 10 || a > 20) && (af < -0.5 || af > 0.5) )  {
                               angles_int[i] += -angles_sum;
                               break;
                           }
                       }
                   }

        
                   for(var i=0; i<angles.length - 1; i++) {
                       
                       var arad = (angles[i+0] + angles[i+1]) * 0.5 * Math.PI / 180.0;
                       var ex = sr_x + Math.cos (arad) * radius * 0.5;
                       var ey = sr_y + Math.sin (arad) * radius * 0.5;
                       
                       var angint = angles_int[i];
                       
                       var kolor = "#004000";
                       if (angint <= -15 || angint >= 15) kolor = "#FF0000";
                       
                       var pt = new OpenLayers.Geometry.Point(ex, ey);
                       drc_features.push(new OpenLayers.Feature.Vector( pt, {labelText: (angint + "°"), labelColor: kolor } ));
                   }
                }
                else {
                   for(var i=0; i<3; i++) {
                        var ix = nodes_x[i];
                        var iy = nodes_y[i];
                        var startPt   = new drc_OpenLayers.Geometry.Point( sr_x, sr_y );
                        var endPt     = new drc_OpenLayers.Geometry.Point( ix, iy );
                        var line      = new drc_OpenLayers.Geometry.LineString([startPt, endPt]);
                        var style     = {strokeColor:"#0040FF", strokeWidth:2};
                        var fea       = new drc_OpenLayers.Feature.Vector(line, {}, style);
                        drc_features.push(fea);
                   }               
                }
            
                var p1   = new drc_OpenLayers.Geometry.Point( nodes_x[0], nodes_y[0] );
                var p2   = new drc_OpenLayers.Geometry.Point( sr_x, sr_y );
                var line = new OpenLayers.Geometry.LineString([p1, p2]);
                var geo_radius = line.getGeodesicLength(new OpenLayers.Projection("EPSG:900913"));
            
                var diam = geo_radius * 2.0;
                var pt = new OpenLayers.Geometry.Point(sr_x, sr_y);
                drc_features.push(new OpenLayers.Feature.Vector( pt, {labelText: (diam.toFixed(0) + "m"), labelColor: "#000000" } ));
                
            }
        }

    }
        
    var layers = drc_wazeMap.getLayersBy("uniqueName","__DrawRoundaboutAngles");
    
    if(layers.length > 0) {
        var drc_layer = layers[0];
        drc_layer.removeAllFeatures();
       	drc_layer.addFeatures(drc_features);
    } else {

         var drc_style = new drc_OpenLayers.Style({
             	fillOpacity: 0.0,
             	strokeOpacity: 1.0,
                fillColor: "#FF40C0",
                strokeColor: "#0040FF",
                strokeWidth: 10,
                fontWeight: "bold",
                pointRadius: 0,
                label : "${labelText}",
                fontFamily: "Tahoma, Courier New",
                labelOutlineColor: "#FFFFFF",
                labelOutlineWidth: 4,
                fontColor: "${labelColor}",
                fontSize: "10px"
        });

        var drc_mapLayer = new drc_OpenLayers.Layer.Vector("Roundabout Angles", {
            displayInLayerSwitcher: true,
            uniqueName: "__DrawRoundaboutAngles",
            styleMap: new drc_OpenLayers.StyleMap(drc_style)
        });
        
        I18n.translations.en.layers.name["__DrawRoundaboutAngles"] = "Roundabout Angles";
        drc_wazeMap.addLayer(drc_mapLayer);
        drc_mapLayer.setVisibility(false);
    }
}
//---------------------------------------------------------------------------------------
bootstrapRoundaboutAngles();