WME Roundabout Angles

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

目前为 2014-10-01 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name WME Roundabout Angles
  3. // @namespace http://userscripts.org/scripts/show/440831
  4. // @description Draws angles for typical roundabout and overlays helper line to adjust geometry of roundabout.
  5. // @include https://www.waze.com/editor/*
  6. // @include https://www.waze.com/*/editor/*
  7. // @include https://editor-beta.waze.com/*
  8. // @version 1.04
  9. // @grant none
  10. // @copyright 2014 wlodek76
  11. // ==/UserScript==
  12.  
  13. var wmech_version = "1.04"
  14.  
  15. //---------------------------------------------------------------------------------------
  16. function bootstrapRoundaboutAngles()
  17. {
  18. var bGreasemonkeyServiceDefined = false;
  19.  
  20. try {
  21. bGreasemonkeyServiceDefined = (typeof Components.interfaces.gmIGreasemonkeyService === "object");
  22. }
  23. catch (err) { /* Ignore */ }
  24.  
  25. if (typeof unsafeWindow === "undefined" || ! bGreasemonkeyServiceDefined) {
  26. unsafeWindow = ( function () {
  27. var dummyElem = document.createElement('p');
  28. dummyElem.setAttribute('onclick', 'return window;');
  29. return dummyElem.onclick();
  30. }) ();
  31. }
  32.  
  33. /* begin running the code! */
  34. setInterval(DrawRoundaboutAngles, 500);
  35. }
  36. //---------------------------------------------------------------------------------------
  37. function DrawRoundaboutAngles()
  38. {
  39. drc_wazeMap = unsafeWindow.Waze.map;
  40. drc_wazeModel = unsafeWindow.Waze.model;
  41. drc_OpenLayers = unsafeWindow.OpenLayers;
  42. if (drc_wazeMap == null) return;
  43. if (drc_wazeModel == null) return;
  44. if (drc_OpenLayers == null) return;
  45.  
  46. var layers = drc_wazeMap.getLayersBy("uniqueName","__DrawRoundaboutAngles");
  47. if(layers.length > 0) {
  48. var drc_layer = layers[0];
  49. if (drc_layer.visibility == false) {
  50. drc_layer.removeAllFeatures();
  51. return;
  52. }
  53.  
  54. if (Waze.map.zoom < 6) {
  55. drc_layer.removeAllFeatures();
  56. return;
  57. }
  58. }
  59.  
  60. drc_features = [];
  61. var rids = [];
  62. for (var iseg in Waze.model.segments.objects) {
  63. var isegment = Waze.model.segments.get(iseg);
  64. var iattributes = isegment.attributes;
  65. var iline = isegment.geometry.id;
  66.  
  67. var irid = iattributes.junctionID;
  68. var p = rids.indexOf(irid);
  69. if (iline !== null && irid !== null && p==-1) {
  70. rids.push(irid);
  71. var nodes = new Array();
  72. var nodes_x = new Array();
  73. var nodes_y = new Array();
  74.  
  75. for (var jseg in Waze.model.segments.objects) {
  76. var jsegment = Waze.model.segments.get(jseg);
  77. var jattributes = jsegment.attributes;
  78. var jrid = jattributes.junctionID;
  79.  
  80. if (jrid == irid) {
  81. nodes.push(jattributes.fromNodeID);
  82. nodes.push(jattributes.toNodeID);
  83. }
  84. }
  85. for (var inode in Waze.model.nodes.objects) {
  86. var node = Waze.model.nodes.get(inode);
  87. var p = nodes.indexOf(node.fid);
  88. if (p >= 0) {
  89. nodes_x.push(node.geometry.x);
  90. nodes_y.push(node.geometry.y);
  91. }
  92. }
  93. var sr_x = 0;
  94. var sr_y = 0;
  95. var radius = 0;
  96. var numNodes = nodes_x.length;
  97. if (nodes_x.length >= 3) {
  98. //-----------throw short segments
  99. while (nodes_x.length > 4) {
  100. var id = 0;
  101. var dmin = 99999999;
  102. for(var i=0; i<nodes_x.length; i++) {
  103. for(var j=0; j<nodes_x.length; j++) {
  104. if (i == j) continue;
  105. var x1 = nodes_x[i];
  106. var y1 = nodes_y[i];
  107. var x2 = nodes_x[j];
  108. var y2 = nodes_y[j];
  109. var dx = x1 - x2;
  110. var dy = y1 - y2;
  111. var d = dx*dx + dy*dy;
  112. if (d < dmin) { dmin = d; id = i; }
  113. }
  114. }
  115. nodes_x.splice(id, 1);
  116. nodes_y.splice(id, 1);
  117. }
  118. //-----------simple approximation of centre point calculated from three first points
  119. var ax = nodes_x[0];
  120. var ay = nodes_y[0];
  121. var bx = nodes_x[1];
  122. var by = nodes_y[1];
  123. var cx = nodes_x[2];
  124. var cy = nodes_y[2];
  125. var x1 = (bx + ax) * 0.5;
  126. var y11 = (by + ay) * 0.5;
  127. var dy1 = bx - ax;
  128. var dx1 = -(by - ay);
  129. var x2 = (cx + bx) * 0.5;
  130. var y2 = (cy + by) * 0.5;
  131. var dy2 = cx - bx;
  132. var dx2 = -(cy - by);
  133. sr_x = (y11 * dx1 * dx2 + x2 * dx1 * dy2 - x1 * dy1 * dx2 - y2 * dx1 * dx2)/ (dx1 * dy2 - dy1 * dx2);
  134. sr_y = (sr_x - x1) * dy1 / dx1 + y11;
  135. var dx = ax - sr_x;
  136. var dy = ay - sr_y;
  137. radius = Math.sqrt(dx*dx + dy*dy);
  138. var angles = [];
  139.  
  140. for(var i=0; i<nodes_x.length; i++) {
  141. var dx = nodes_x[i] - sr_x;
  142. var dy = nodes_y[i] - sr_y;
  143. var angle = Math.atan2(dy, dx);
  144. angle = (360.0 + (angle * 180.0 / Math.PI));
  145. if (angle < 0.0) angle += 360.0;
  146. if (angle > 360.0) angle -= 360.0;
  147. angles.push(angle);
  148. }
  149. //---------sorting angles for calulating angle difference between two segments
  150. angles = angles.sort(function(a,b) { return a - b; });
  151. angles.push( angles[0] + 360.0);
  152. angles = angles.sort(function(a,b) { return a - b; });
  153. //console.log(angles);
  154.  
  155. var drc_point = new drc_OpenLayers.Geometry.Point(sr_x, sr_y );
  156. var drc_circle = new drc_OpenLayers.Geometry.Polygon.createRegularPolygon( drc_point, radius, 256 );
  157. var drc_feature = new drc_OpenLayers.Feature.Vector(drc_circle, {labelText: "", labelColor: "#000000" } );
  158. drc_features.push(drc_feature);
  159.  
  160. if (numNodes == 3 || numNodes == 4) {
  161. for(var i=0; i<nodes_x.length; i++) {
  162. var ix = nodes_x[i];
  163. var iy = nodes_y[i];
  164. var startPt = new drc_OpenLayers.Geometry.Point( sr_x, sr_y );
  165. var endPt = new drc_OpenLayers.Geometry.Point( ix, iy );
  166. var line = new drc_OpenLayers.Geometry.LineString([startPt, endPt]);
  167. var style = {strokeColor:"#0040FF", strokeWidth:2};
  168. var fea = new drc_OpenLayers.Feature.Vector(line, {}, style);
  169. drc_features.push(fea);
  170. }
  171. var angles_int = [];
  172. var angles_float = [];
  173. var angles_sum = 0;
  174. for(var i=0; i<angles.length - 1; i++) {
  175. var ang = angles[i+1] - angles[i+0];
  176. if (ang < 0) ang += 360.0;
  177. if (ang < 0) ang += 360.0;
  178. if (ang < 135.0) {
  179. ang = ang - 90.0;
  180. }
  181. else {
  182. ang = ang - 180.0;
  183. }
  184. angles_sum += parseInt(ang);
  185. angles_float.push( ang );
  186. angles_int.push( parseInt(ang) );
  187. }
  188. if (angles_sum > 45) angles_sum -= 90;
  189. if (angles_sum > 45) angles_sum -= 90;
  190. if (angles_sum > 45) angles_sum -= 90;
  191. if (angles_sum > 45) angles_sum -= 90;
  192. if (angles_sum < -45) angles_sum += 90;
  193. if (angles_sum < -45) angles_sum += 90;
  194. if (angles_sum < -45) angles_sum += 90;
  195. if (angles_sum < -45) angles_sum += 90;
  196. if (angles_sum != 0) {
  197. for(var i=0; i<angles_int.length; i++) {
  198. var a = angles_int[i];
  199. var af = angles_float[i] - angles_int[i];
  200. if ( (a < 10 || a > 20) && (af < -0.5 || af > 0.5) ) {
  201. angles_int[i] += -angles_sum;
  202. break;
  203. }
  204. }
  205. }
  206.  
  207. for(var i=0; i<angles.length - 1; i++) {
  208. var arad = (angles[i+0] + angles[i+1]) * 0.5 * Math.PI / 180.0;
  209. var ex = sr_x + Math.cos (arad) * radius * 0.5;
  210. var ey = sr_y + Math.sin (arad) * radius * 0.5;
  211. var angint = angles_int[i];
  212. var kolor = "#004000";
  213. if (angint <= -15 || angint >= 15) kolor = "#FF0000";
  214. var pt = new OpenLayers.Geometry.Point(ex, ey);
  215. drc_features.push(new OpenLayers.Feature.Vector( pt, {labelText: (angint + "°"), labelColor: kolor } ));
  216. }
  217. }
  218. else {
  219. for(var i=0; i<3; i++) {
  220. var ix = nodes_x[i];
  221. var iy = nodes_y[i];
  222. var startPt = new drc_OpenLayers.Geometry.Point( sr_x, sr_y );
  223. var endPt = new drc_OpenLayers.Geometry.Point( ix, iy );
  224. var line = new drc_OpenLayers.Geometry.LineString([startPt, endPt]);
  225. var style = {strokeColor:"#0040FF", strokeWidth:2};
  226. var fea = new drc_OpenLayers.Feature.Vector(line, {}, style);
  227. drc_features.push(fea);
  228. }
  229. }
  230. var p1 = new drc_OpenLayers.Geometry.Point( nodes_x[0], nodes_y[0] );
  231. var p2 = new drc_OpenLayers.Geometry.Point( sr_x, sr_y );
  232. var line = new OpenLayers.Geometry.LineString([p1, p2]);
  233. var geo_radius = line.getGeodesicLength(new OpenLayers.Projection("EPSG:900913"));
  234. var diam = geo_radius * 2.0;
  235. var pt = new OpenLayers.Geometry.Point(sr_x, sr_y);
  236. drc_features.push(new OpenLayers.Feature.Vector( pt, {labelText: (diam.toFixed(0) + "m"), labelColor: "#000000" } ));
  237. }
  238. }
  239.  
  240. }
  241. var layers = drc_wazeMap.getLayersBy("uniqueName","__DrawRoundaboutAngles");
  242. if(layers.length > 0) {
  243. var drc_layer = layers[0];
  244. drc_layer.removeAllFeatures();
  245. drc_layer.addFeatures(drc_features);
  246. } else {
  247.  
  248. var drc_style = new drc_OpenLayers.Style({
  249. fillOpacity: 0.0,
  250. strokeOpacity: 1.0,
  251. fillColor: "#FF40C0",
  252. strokeColor: "#0040FF",
  253. strokeWidth: 10,
  254. fontWeight: "bold",
  255. pointRadius: 0,
  256. label : "${labelText}",
  257. fontFamily: "Tahoma, Courier New",
  258. labelOutlineColor: "#FFFFFF",
  259. labelOutlineWidth: 4,
  260. fontColor: "${labelColor}",
  261. fontSize: "10px"
  262. });
  263.  
  264. var drc_mapLayer = new drc_OpenLayers.Layer.Vector("Roundabout Angles", {
  265. displayInLayerSwitcher: true,
  266. uniqueName: "__DrawRoundaboutAngles",
  267. styleMap: new drc_OpenLayers.StyleMap(drc_style)
  268. });
  269. I18n.translations.en.layers.name["__DrawRoundaboutAngles"] = "Roundabout Angles";
  270. drc_wazeMap.addLayer(drc_mapLayer);
  271. drc_mapLayer.setVisibility(false);
  272. }
  273. }
  274. //---------------------------------------------------------------------------------------
  275. bootstrapRoundaboutAngles();