WME Simplify Place Geometry

Simplifies geometry of area places in WME

当前为 2015-02-23 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name WME Simplify Place Geometry
  3. // @description Simplifies geometry of area places in WME
  4. // @version 0.9
  5. // @author SAR85
  6. // @grant none
  7. // @include https://www.waze.com/editor/*
  8. // @include https://www.waze.com/*/editor/*
  9. // @include https://editor-beta.waze.com/*
  10. // @copyright SAR85 <flsar85@gmail.com>
  11. // @license CC BY-NC-SA
  12. // @namespace https://greasyfork.org/users/9321
  13. // ==/UserScript==
  14.  
  15. function simpBootstrap() {
  16. var bGreasemonkeyServiceDefined = false;
  17. try
  18. {
  19. if ("object" === typeof Components.interfaces.gmIGreasemonkeyService)
  20. {
  21. bGreasemonkeyServiceDefined = true;
  22. }
  23. }
  24. catch (err)
  25. {
  26. // Ignore.
  27. }
  28. if ( "undefined" === typeof unsafeWindow || ! bGreasemonkeyServiceDefined)
  29. {
  30. unsafeWindow = ( function ()
  31. {
  32. var dummyElem = document.createElement('p');
  33. dummyElem.setAttribute ('onclick', 'return window;');
  34. return dummyElem.onclick ();
  35. } ) ();
  36. }
  37. /* begin running the code! */
  38. window.setTimeout(simpInit, 2000);
  39. /*doesn't work in FF: $(document).ready(simpInit); */
  40. }
  41.  
  42. function addSimplifyFunc() {
  43. /*
  44. (c) 2013, Vladimir Agafonkin
  45. Simplify.js, a high-performance JS polyline simplification library
  46. mourner.github.io/simplify-js
  47. */
  48. (function () { 'use strict';
  49.  
  50. // to suit your point format, run search/replace for '.x' and '.y';
  51. // for 3D version, see 3d branch (configurability would draw significant performance overhead)
  52.  
  53. // square distance between 2 points
  54. function getSqDist(p1, p2) {
  55.  
  56. var dx = p1.x - p2.x,
  57. dy = p1.y - p2.y;
  58.  
  59. return dx * dx + dy * dy;
  60. }
  61.  
  62. // square distance from a point to a segment
  63. function getSqSegDist(p, p1, p2) {
  64.  
  65. var x = p1.x,
  66. y = p1.y,
  67. dx = p2.x - x,
  68. dy = p2.y - y;
  69.  
  70. if (dx !== 0 || dy !== 0) {
  71.  
  72. var t = ((p.x - x) * dx + (p.y - y) * dy) / (dx * dx + dy * dy);
  73.  
  74. if (t > 1) {
  75. x = p2.x;
  76. y = p2.y;
  77.  
  78. } else if (t > 0) {
  79. x += dx * t;
  80. y += dy * t;
  81. }
  82. }
  83.  
  84. dx = p.x - x;
  85. dy = p.y - y;
  86.  
  87. return dx * dx + dy * dy;
  88. }
  89. // rest of the code doesn't care about point format
  90.  
  91. // basic distance-based simplification
  92. function simplifyRadialDist(points, sqTolerance) {
  93.  
  94. var prevPoint = points[0],
  95. newPoints = [prevPoint],
  96. point;
  97.  
  98. for (var i = 1, len = points.length; i < len; i++) {
  99. point = points[i];
  100.  
  101. if (getSqDist(point, prevPoint) > sqTolerance) {
  102. newPoints.push(point);
  103. prevPoint = point;
  104. }
  105. }
  106.  
  107. if (prevPoint !== point) newPoints.push(point);
  108.  
  109. return newPoints;
  110. }
  111.  
  112. // simplification using optimized Douglas-Peucker algorithm with recursion elimination
  113. function simplifyDouglasPeucker(points, sqTolerance) {
  114.  
  115. var len = points.length,
  116. MarkerArray = typeof Uint8Array !== 'undefined' ? Uint8Array : Array,
  117. markers = new MarkerArray(len),
  118. first = 0,
  119. last = len - 1,
  120. stack = [],
  121. newPoints = [],
  122. i, maxSqDist, sqDist, index;
  123.  
  124. markers[first] = markers[last] = 1;
  125.  
  126. while (last) {
  127.  
  128. maxSqDist = 0;
  129.  
  130. for (i = first + 1; i < last; i++) {
  131. sqDist = getSqSegDist(points[i], points[first], points[last]);
  132.  
  133. if (sqDist > maxSqDist) {
  134. index = i;
  135. maxSqDist = sqDist;
  136. }
  137. }
  138.  
  139. if (maxSqDist > sqTolerance) {
  140. markers[index] = 1;
  141. stack.push(first, index, index, last);
  142. }
  143.  
  144. last = stack.pop();
  145. first = stack.pop();
  146. }
  147.  
  148. for (i = 0; i < len; i++) {
  149. if (markers[i]) newPoints.push(points[i]);
  150. }
  151.  
  152. return newPoints;
  153. }
  154.  
  155. // both algorithms combined for awesome performance
  156. function simplify(points, tolerance, highestQuality) {
  157.  
  158. if (points.length <= 1) return points;
  159.  
  160. var sqTolerance = tolerance !== undefined ? tolerance * tolerance : 1;
  161.  
  162. points = highestQuality ? points : simplifyRadialDist(points, sqTolerance);
  163. points = simplifyDouglasPeucker(points, sqTolerance);
  164.  
  165. return points;
  166. }
  167.  
  168. // export as AMD module / Node module / browser or worker variable
  169. if (typeof define === 'function' && define.amd) define(function() { return simplify; });
  170. else if (typeof module !== 'undefined') module.exports = simplify;
  171. else if (typeof self !== 'undefined') self.simplify = simplify;
  172. else window.simplify = simplify;
  173.  
  174. })();
  175. }
  176.  
  177. function simpInit() {
  178. /* HTML */
  179. var tab = '<li><a href="#sidepanel-simplifyarea" data-toggle="tab" id="simplifytab">Simplify Area</a></li>';
  180. var content = '<div class="tab-pane" id="sidepanel-simplifyarea"><h1 style="display: block; position:relative; margin-top: -10px; margin-bottom: 10px">Simplify Area Place Geometry</h1><hr><p>Simplification factor:</p><p>0<input type="range" id="simpE" step="1" min="1" max="100" defaultValue="50"></input>100</p><p>Press "j" to simplify the geometry of a selected area place.</p></div>';
  181. /* Initialize simplification library */
  182. addSimplifyFunc();
  183. /* Add HTML to page */
  184. $('h2 + ul.nav-tabs').append(tab);
  185. $('h2 + ul.nav-tabs + .tab-content').append(content);
  186. /* Shortcut key = j */
  187. $(document).keypress(function(e) {
  188. if (e.charCode == 106) simplifyFeatureGeometry($('#simpE').val());
  189. });
  190. console.log("WME Simplify Area Geometry Initialized");
  191. }
  192.  
  193. function simplifyFeatureGeometry(e) {
  194. if (!W.selectionManager.hasSelectedItems() || W.selectionManager.selectedItems[0].model.type !== "venue") return;
  195. var UpdateFeatureGeometry = require("Waze/Action/UpdateFeatureGeometry");
  196. var place = W.selectionManager.selectedItems[0];
  197. var placegeo = place.geometry.clone();
  198. var newgeo = placegeo.clone();
  199. newgeo.components[0].components = simplify(placegeo.components[0].components, e, false);
  200. if (newgeo.components[0].components.length < placegeo.components[0].components.length) {
  201. W.model.actionManager.add(new UpdateFeatureGeometry(place.model,W.model.venues,placegeo,newgeo));
  202. console.log("WME Simplify Area Geometry: " + place.model.attributes.name + " simplified from " + placegeo.components[0].components.length + " to " + newgeo.components[0].components.length + " geo nodes using factor " + e + ".");
  203. } else {
  204. console.log("Geo nodes cannot be simplified from " + placegeo.components[0].components.length + " to " + newgeo.components[0].components.length + ".");
  205. }
  206. }
  207.  
  208. simpBootstrap();