🏠 Home 

WME Street to River PLUS (mod)

This script create a new river landmark in waze map editor (WME). It transforms the the geometry of a new unsaved street to a polygon.


Install this script?
  1. // ==UserScript==
  2. // @name WME Street to River PLUS (mod)
  3. // @description This script create a new river landmark in waze map editor (WME). It transforms the the geometry of a new unsaved street to a polygon.
  4. // @namespace https://greasyfork.org/users/160654-waze-ukraine
  5. // @grant none
  6. // @version 2024.06.30.001
  7. // @match https://beta.waze.com/*editor*
  8. // @match https://www.waze.com/*editor*
  9. // @exclude https://www.waze.com/*user/*editor/*
  10. // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAc9SURBVHja7J3NSxxJFMDnmD8gVxECg3PwZEBIDsIu8RI9RQhD7oGF3M0HODiHmBxkYRIvwbASsgZnmxBh1I4OiiLGQMIgmw1mD6tLxDGZkCBh4y4TofYyNamU3dNV3####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
  11. // @require https://update.greasyfork.org/scripts/450160/1218867/WME-Bootstrap.js
  12. // ==/UserScript==
  13. // Based on WME Street to river
  14. // Mini howto:
  15. // 1) install this script as greasemonkey script or chrome extension
  16. // 2) draw a new street but do not save the street
  17. // 3) add and apply a street name to define the rivers name and the the width of the river
  18. // Example: "20m Spree" creates a 20 meters width river named "Spree"
  19. // 4) Select the helper street
  20. // 5) Click the "Street to river" button
  21. // 4) Delete the helper street
  22. // 5) Edit the new landmark as you like
  23. //
  24. // Updated by: Eduardo Carvajal
  25. /* jshint esversion: 11 */
  26. /* global W */
  27. /* global I18n */
  28. /* global OpenLayers */
  29. /* global $ */
  30. /* global require */
  31. console.warn('Remove this line, when WME-Bootstrap will fix its syntax. now it causes script error on load, details https://stackoverflow.com/questions/42036349/uncaught-typeerror-intermediate-value-is-not-a-function');
  32. (function () {
  33. const version = GM_info.script.version;
  34. //const unused = 0;
  35. const idWidth = 1;
  36. const idTitle = 2;
  37. const idStreetToRiver = 3;
  38. const idUnlimitedSize = 4;
  39. const idNoUsavedStreet = 5;
  40. const idAllSegmentsInside = 6;
  41. const idMultipleSegmentsInside = 7;
  42. const idStreetToOther = 8;
  43. const idStreetToForest = 9;
  44. const idDeleteSegment = 10;
  45. function streetToRiver_bootstrap() {
  46. $(document)
  47. .on('bootstrap.wme', function () {
  48. streetToRiver_init()
  49. })
  50. }
  51. function streetToRiver_init() {
  52. const defaultWidth = 15;
  53. var scriptLanguage = "us";
  54. var langText;{
  55. var Config = [{
  56. handler: 'WME-Street-to-River_other',
  57. title: "Other",
  58. func: function (ev) {
  59. doPOI(ev, "OTHER");
  60. },
  61. key: -1,
  62. arg: {
  63. type: "OTHER"
  64. }
  65. },
  66. ];
  67. for (var i = 0; i < Config.length; ++i) {
  68. WMEKSRegisterKeyboardShortcut('WME-Street-to-River', 'WME-Street-to-River', Config[i].handler, Config[i].title, Config[i].func, Config[i].key, Config[i].arg);
  69. }
  70. WMEKSLoadKeyboardShortcuts('WME-Street-to-River');
  71. window.addEventListener("beforeunload", function () {
  72. WMEKSSaveKeyboardShortcuts('WME-Street-to-River');
  73. }, false);
  74. }
  75. function insertButtons() {
  76. if (W.selectionManager.getSelectedFeatures().length === 0)
  77. return;
  78. var btn0 = $('<wz-button size="sm" color="submit" title="' + getString(idTitle) + '">' + getString(idStreetToOther) + '</wz-button>');
  79. btn0.click(doOther);
  80. var btn1 = $('<wz-button size="sm" color="submit" title="' + getString(idTitle) + '">' + getString(idStreetToRiver) + '</wz-button>');
  81. btn1.click(doRiver);
  82. var btn2 = $('<wz-button size="sm" color="submit" title="' + getString(idTitle) + '">' + getString(idStreetToForest) + '</wz-button>');
  83. btn2.click(doForest);
  84. const widthValues = [1, 2, 3, 5, 8, 10, 11, 12, 13, 15, 17, 20, 25, 30, 40, 50, 80, 100, 120, 150, 180, 200];
  85. var selRiverWidth = $('<wz-select name="riverWidth" />');
  86. for (let w = 0; w < widthValues.length; w++) {
  87. selRiverWidth.append($(`<wz-option value="${widthValues[w]}">${widthValues[w]}</wz-option>`));
  88. }
  89. selRiverWidth.change(function () {
  90. setLastRiverWidth(this.value);
  91. });
  92. var lastRiverWidth = getLastRiverWidth(defaultWidth);
  93. console_log("Last river width: " + lastRiverWidth);
  94. selRiverWidth.val(lastRiverWidth);
  95. var chk = $('<wz-checkbox title="' + getString(idUnlimitedSize) + '" name="_isUnlimitedSize" >' + getString(idUnlimitedSize) + '</wz-checkbox>');
  96. chk.prop("checked", getLastIsUnlimitedSize(false));
  97. chk.change(function () {
  98. setLastIsUnlimitedSize(this.checked);
  99. });
  100. var chkDel = $('<wz-checkbox name="_isDeleteSegment" >' + getString(idDeleteSegment) + '</wz-checkbox>');
  101. chkDel.prop("checked", getLastIsDeleteSegment(true));
  102. chkDel.change(function () {
  103. setLastIsDeleteSegment(this.checked);
  104. });
  105. var cnt = $('<div class="form-group" />');
  106. var label = $('<wz-label><a href="https://github.com/waze-ua/wme-street-to-river-plus-mod" target="_blank">Street to River+ (Mod) v' + version + '</a></wz-label>');
  107. cnt.append(label);
  108. var divGroup1 = $('<div class="controls-container" />');
  109. divGroup1.append($('<wz-label html-for>' + getString(idWidth) + '</wz-label>'));
  110. divGroup1.append(selRiverWidth);
  111. var divGroup2 = $('<div class="controls-container" />');
  112. divGroup2.append(chk);
  113. divGroup2.append(chkDel);
  114. var divGroup3 = $('<div class="controls-container" />');
  115. divGroup3.append(btn0);
  116. divGroup3.append(btn1);
  117. divGroup3.append(btn2);
  118. cnt.append(divGroup1);
  119. cnt.append(divGroup2);
  120. cnt.append(divGroup3);
  121. $("#segment-edit-general form.attributes-form").after(cnt);
  122. console_log("Street to River Language: " + scriptLanguage);
  123. console_log("Street to river PLUS initialized");
  124. }
  125. function doPOI(ev, typ) {
  126. var convertOK;
  127. var foundSelectedSegment = false;
  128. var isUnlimitedSize = getLastIsUnlimitedSize(false);
  129. var isDeleteSegment = getLastIsDeleteSegment(true);
  130. // 2014-01-09: Search for helper street. If found create or expand a river
  131. for (var s = W.selectionManager.getSelectedFeatures().length - 1; s >= 0; s--) {
  132. var sel = W.selectionManager.getSelectedFeatures()[s]._wmeObject;
  133. if (sel.type == "segment") {
  134. // found segment
  135. foundSelectedSegment = true;
  136. convertOK = convertToLandmark(sel, typ, isUnlimitedSize);
  137. if (convertOK && isDeleteSegment) {
  138. var wazeActionDeleteSegment = require("Waze/Action/DeleteSegment");
  139. W.model.actionManager.add(new wazeActionDeleteSegment(sel));
  140. }
  141. }
  142. }
  143. if (!foundSelectedSegment) {
  144. alert(getString(idNoUsavedStreet));
  145. }
  146. }
  147. function doRiver(ev) {
  148. doPOI(ev, "RIVER_STREAM");
  149. }
  150. function doForest(ev) {
  151. doPOI(ev, "FOREST_GROVE");
  152. }
  153. function doOther(ev) {
  154. doPOI(ev, "OTHER");
  155. }
  156. function CalcRL(components) {
  157. var count = components.length;
  158. var j = count - 1;
  159. var area = 0;
  160. for (var i = 0; i < count; ++i) {
  161. area += (components[i].y * components[j].x) - (components[i].x * components[j].y);
  162. j = i;
  163. }
  164. return area < 0 ? 1 : -1; // 1 - по часовой, -1 - против часовой
  165. }
  166. function uniq(a) {
  167. var seen = {};
  168. return a.filter(function (item) {
  169. return seen.hasOwnProperty(item) ? false : (seen[item] = true);
  170. });
  171. }
  172. // 2014-01-09: Base on selected helper street creates or expand an existing river/railway
  173. function convertToLandmark(sel, lmtype, isUnlimitedSize) {
  174. var i;
  175. var leftPa,
  176. rightPa,
  177. leftPb,
  178. rightPb;
  179. var prevLeftEq,
  180. prevRightEq;
  181. var street = getStreet(sel);
  182. var displacement = getDisplacement(street);
  183. // create place with a minimum area 100m2
  184. // for simple segments only (A-B)
  185. if (sel.geometry.components.length === 2) {
  186. var segLength = 0;
  187. var minArea = 100;
  188. var pt = [];
  189. pt[0] = sel.geometry.components[0];
  190. pt[1] = sel.geometry.components[1];
  191. var seg = new OpenLayers.Geometry.LineString(pt);
  192. segLength = seg.getGeodesicLength(W.map.getProjectionObject());
  193. // if small area is expected
  194. if (minArea / displacement > segLength) {
  195. if (segLength <= Math.sqrt(minArea)) {
  196. // create a minimum square
  197. var line = Math.sqrt(minArea);
  198. var segScale = line / segLength;
  199. displacement = line / 1.18;
  200. pt[1].resize(segScale, pt[0], 1);
  201. } else {
  202. // adjust displacement (width)
  203. displacement = minArea / segLength;
  204. }
  205. }
  206. }
  207. var streetVertices = sel.geometry.getVertices();
  208. var polyPoints = null;
  209. var firstPolyPoint = null;
  210. var secondPolyPoint = null;
  211. var wazeActionUpdateFeatureGeometry = require("Waze/Action/UpdateFeatureGeometry");
  212. var wazefeatureVectorLandmark = require("Waze/Feature/Vector/Landmark");
  213. var wazeActionAddLandmark = require("Waze/Action/AddLandmark");
  214. var wazeActionDeleteObject = require("Waze/Action/DeleteObject");
  215. var wazeActionUpdateFeatureAddress = require("Waze/Action/UpdateFeatureAddress");
  216. console_log("Street vertices: " + streetVertices.length);
  217. // 2013-10-13: Is new street inside an existing river?
  218. var bAddNew = !0;
  219. var riverLandmark = null;
  220. var repo = W.model.venues;
  221. var rrr,
  222. donorLandmark = null;
  223. for (var t in repo.objects) {
  224. riverLandmark = repo.objects[t];
  225. if (riverLandmark.attributes.categories[0] === lmtype) {
  226. console_log("riverLandmark.attributes.id=" + riverLandmark.attributes.id);
  227. console_log("streetVertices.length=" + streetVertices.length);
  228. console_log("streetVertices[0]=" + streetVertices[0]);
  229. console_log("streetVertices[streetVertices.length - 1]=" + streetVertices[streetVertices.length - 1]);
  230. // 2014-06-27: Verify if the landmark object has containsPoint function
  231. if ("function" === typeof riverLandmark.geometry.containsPoint) {
  232. if (riverLandmark.geometry.containsPoint(streetVertices[0])) {
  233. bAddNew = false; // Street is inside an existing river
  234. console_log("rrr=" + riverLandmark.attributes.id);
  235. rrr = riverLandmark;
  236. // break;
  237. }
  238. if (riverLandmark.geometry.containsPoint(streetVertices[streetVertices.length - 1])) {
  239. // bAddNew = false; // Street is inside an existing river
  240. console_log("donorLandmark=" + riverLandmark.attributes.id);
  241. donorLandmark = riverLandmark;
  242. // break;
  243. }
  244. }
  245. }
  246. }
  247. riverLandmark = rrr;
  248. // 2013-10-13: Ignore vertices inside river
  249. var bIsOneVerticeStreet = false;
  250. var firstStreetVerticeOutside = 0;
  251. if (!bAddNew) {
  252. console_log("Expanding an existing river");
  253. while (firstStreetVerticeOutside < streetVertices.length) {
  254. if (!riverLandmark.geometry.containsPoint(streetVertices[firstStreetVerticeOutside]))
  255. break;
  256. firstStreetVerticeOutside += 1;
  257. }
  258. if (firstStreetVerticeOutside === streetVertices.length) {
  259. alert(getString(idAllSegmentsInside));
  260. return false;
  261. }
  262. bIsOneVerticeStreet = firstStreetVerticeOutside === (streetVertices.length - 1);
  263. if (bIsOneVerticeStreet) {
  264. console_log("It's one vertice street");
  265. }
  266. if (firstStreetVerticeOutside > 1) {
  267. alert(getString(idMultipleSegmentsInside));
  268. return false;
  269. }
  270. console_log("First street vertice outside river:" + firstStreetVerticeOutside);
  271. }
  272. // 2013-10-13: Add to polyPoints river polygon
  273. console_log("River polygon: Create");
  274. var first;
  275. if (bAddNew)
  276. first = 0;
  277. else
  278. first = firstStreetVerticeOutside - 1;
  279. for (i = first; i < streetVertices.length - 1; i++) {
  280. var pa = streetVertices[i];
  281. var pb = streetVertices[i + 1];
  282. // fix for incorrect scale calculation, as distanceTo() returns units, but displacement is in meters
  283. // old:
  284. //var scale = (pa.distanceTo(pb) + displacement) / pa.distanceTo(pb);
  285. // new:
  286. //TODO optimize this, convert displacement into map units for easier scale calculation
  287. var points = [pa, pb];
  288. var ls = new OpenLayers.Geometry.LineString(points);
  289. var len = ls.getGeodesicLength(W.map.getProjectionObject());
  290. var scale = (len + displacement / 2) / len;
  291. leftPa = pa.clone();
  292. leftPa.resize(scale, pb, 1);
  293. rightPa = leftPa.clone();
  294. leftPa.rotate(90, pa);
  295. rightPa.rotate(-90, pa);
  296. leftPb = pb.clone();
  297. leftPb.resize(scale, pa, 1);
  298. rightPb = leftPb.clone();
  299. leftPb.rotate(-90, pb);
  300. rightPb.rotate(90, pb);
  301. var leftEq = getEquation({
  302. 'x1': leftPa.x,
  303. 'y1': leftPa.y,
  304. 'x2': leftPb.x,
  305. 'y2': leftPb.y
  306. });
  307. var rightEq = getEquation({
  308. 'x1': rightPa.x,
  309. 'y1': rightPa.y,
  310. 'x2': rightPb.x,
  311. 'y2': rightPb.y
  312. });
  313. if (polyPoints === null) {
  314. polyPoints = [leftPa, rightPa];
  315. } else {
  316. var li = intersectX(leftEq, prevLeftEq);
  317. var ri = intersectX(rightEq, prevRightEq);
  318. if (li && ri) {
  319. // 2013-10-17: Is point outside river?
  320. if (i >= firstStreetVerticeOutside) {
  321. polyPoints.unshift(li);
  322. polyPoints.push(ri);
  323. // 2013-10-17: Is first point outside river? -> Save it for later use
  324. if (i == firstStreetVerticeOutside) {
  325. firstPolyPoint = li.clone();
  326. secondPolyPoint = ri.clone();
  327. polyPoints = [li, ri];
  328. }
  329. }
  330. } else {
  331. // 2013-10-17: Is point outside river?
  332. if (i >= firstStreetVerticeOutside) {
  333. polyPoints.unshift(leftPb.clone());
  334. polyPoints.push(rightPb.clone());
  335. // 2013-10-17: Is first point outside river? -> Save it for later use
  336. if (i == firstStreetVerticeOutside) {
  337. firstPolyPoint = leftPb.clone();
  338. secondPolyPoint = rightPb.clone();
  339. polyPoints = [leftPb, rightPb];
  340. }
  341. }
  342. }
  343. }
  344. prevLeftEq = leftEq;
  345. prevRightEq = rightEq;
  346. // 2013-06-03: Is Waze limit reached?
  347. if ((polyPoints.length > 50) && !isUnlimitedSize) {
  348. break;
  349. }
  350. }
  351. if (bIsOneVerticeStreet) {
  352. firstPolyPoint = leftPb.clone();
  353. secondPolyPoint = rightPb.clone();
  354. polyPoints = [leftPb, rightPb];
  355. console_log("One vertice river:" + polyPoints.length);
  356. } else {
  357. polyPoints.push(rightPb);
  358. polyPoints.push(leftPb);
  359. }
  360. console_log("River polygon: done");
  361. // 2014-01-09: Create or expand an existing river?
  362. if (bAddNew) {
  363. // 2014-01-09: Add new river
  364. // 2014-01-09: Create new river's Polygon
  365. var polygon = new OpenLayers.Geometry.Polygon(new OpenLayers.Geometry.LinearRing(polyPoints));
  366. // 2014-10-08: Creates river's Landmark
  367. //FIX (?????? Start)
  368. // riverLandmark = new wazefeatureVectorLandmark();
  369. var ldk = {};
  370. ldk.geoJSONGeometry = W.userscripts.toGeoJSONGeometry (polygon);
  371. riverLandmark = new wazefeatureVectorLandmark(ldk);
  372. //FIX (?????? End)
  373. riverLandmark.geometry = polygon;
  374. riverLandmark.attributes.categories.push(lmtype);
  375. // 2014-01-09: Add river's name base on Street Name
  376. if (street && street.attributes.name) {
  377. riverLandmark.attributes.name = street.attributes.name.replace(/^\d+(m|м|ft)\s*/, ''); // TODO make localizable
  378. }
  379. // 2014-10-08: Add new Landmark to Waze Editor
  380. var riverLandmark_o = new wazeActionAddLandmark(riverLandmark);
  381. W.model.actionManager.add(riverLandmark_o);
  382. try {
  383. W.selectionManager.setSelectedModels([riverLandmark]);
  384. } catch (err) {
  385. // Ignore error:
  386. // Uncaught TypeError: Cannot read properties of undefined (reading 'children')
  387. // at Object.WMETB_FPnewSelectionAvailable (FancyPermalink.min.js:216:184)
  388. // at v (third_party-45fe9aba9d649e1fe91a.js.gz:2:1169484)
  389. console_log(err)
  390. }
  391. if (lmtype !== "OTHER") {
  392. console_log("bAddNew");
  393. let address = riverLandmark.getAddress().attributes;
  394. console_log(address);
  395. let newAddressAtts = {
  396. streetName: null,
  397. emptyStreet: true,
  398. cityName: null,
  399. emptyCity: true,
  400. stateID: address.state.attributes.id,
  401. countryID: address.country.attributes.id
  402. };
  403. W.model.actionManager.add(new wazeActionUpdateFeatureAddress(riverLandmark, newAddressAtts, {
  404. streetIDField: 'streetID'
  405. }));
  406. }
  407. } else {
  408. // 2014-01-09: Expand an existing river
  409. var originalGeometry = riverLandmark.geometry.clone();
  410. if (donorLandmark) // если есть донор
  411. {
  412. let undoGeometry = riverLandmark.geometry.clone();
  413. var undoGeometryDonor = donorLandmark.geometry.clone();
  414. var components = riverLandmark.geometry.components[0].components;
  415. var componentsDonor = donorLandmark.geometry.components[0].components;
  416. //window.donorLandmark=donorLandmark;
  417. //window.riverLandmark=riverLandmark;
  418. // куда закручен массив?
  419. var componentsRL = CalcRL(components);
  420. var componentsDonorRL = CalcRL(componentsDonor);
  421. console_log("src=" + componentsRL + ", donor=" + componentsDonorRL);
  422. // найти индекс ближайшей точки к началу сегмента
  423. var dist = 1000000000;
  424. var p1 = [0, 0],
  425. p2 = [0, 0]; // индексы ближайших точек
  426. for (let i1 = 0; i1 < components.length; i1++) {
  427. var d1 = Math.sqrt(Math.pow(Math.abs(components[i1].x - streetVertices[0].x), 2) + Math.pow(Math.abs(components[i1].y - streetVertices[0].y), 2));
  428. if (d1 < dist) {
  429. dist = d1;
  430. p1[0] = i1;
  431. if (componentsRL > 0)
  432. p1[1] = i1 === 0 ? components.length - 1 : i1 - 1;
  433. else
  434. p1[1] = i1 == components.length - 1 ? 0 : i1 + 1;
  435. }
  436. }
  437. console_log("p1=" + p1 + ", dist=" + dist);
  438. // ищем индекс во втором ПОИ, откуда начинать вставку.
  439. dist = 1000000000;
  440. for (let i1 = 0; i1 < componentsDonor.length; i1++) {
  441. let d1 = Math.sqrt(Math.pow(Math.abs(componentsDonor[i1].x - streetVertices[streetVertices.length - 1].x), 2) + Math.pow(Math.abs(componentsDonor[i1].y - streetVertices[streetVertices.length - 1].y), 2));
  442. if (d1 < dist) {
  443. dist = d1;
  444. p2[0] = i1;
  445. if (componentsDonorRL > 0)
  446. p2[1] = i1 === 0 ? componentsDonor.length - 1 : i1 - 1;
  447. else
  448. p2[1] = i1 == componentsDonor.length - 1 ? 0 : i1 + 1;
  449. }
  450. }
  451. console_log("p2=" + p2 + ", dist=" + dist);
  452. var componentsNew = components.slice();
  453. componentsNew.length = 0;
  454. // добавляем источник
  455. for (let i1 = 0; i1 <= p1[0]; ++i1)
  456. componentsNew.push(components[i1]);
  457. // добавляем донора
  458. if (componentsRL < 0) {
  459. if (componentsDonorRL < 0) {
  460. // добавляем донора по кругу
  461. for (let i1 = p2[0]; i1 < componentsDonor.length; ++i1)
  462. componentsNew.push(componentsDonor[i1]);
  463. // ...остаток донора
  464. for (let i1 = 0; i1 < p2[0]; ++i1)
  465. componentsNew.push(componentsDonor[i1]);
  466. } else {
  467. // добавляем донора по кругу
  468. for (let i1 = p2[0]; i1 >= 0; --i1)
  469. componentsNew.push(componentsDonor[i1]);
  470. // ...остаток донора
  471. for (let i1 = componentsDonor.length - 1; i1 > p2[0]; --i1)
  472. componentsNew.push(componentsDonor[i1]);
  473. }
  474. } else {
  475. if (componentsDonorRL < 0) {
  476. // добавляем донора по кругу
  477. for (let i1 = p2[0]; i1 >= 0; --i1)
  478. componentsNew.push(componentsDonor[i1]);
  479. // ...остаток донора
  480. for (let i1 = componentsDonor.length - 1; i1 > p2[0]; --i1)
  481. componentsNew.push(componentsDonor[i1]);
  482. } else {
  483. // добавляем донора по кругу
  484. for (let i1 = p2[0]; i1 < componentsDonor.length; ++i1)
  485. componentsNew.push(componentsDonor[i1]);
  486. // ...остаток донора
  487. for (let i1 = 0; i1 < p2[0]; ++i1)
  488. componentsNew.push(componentsDonor[i1]);
  489. }
  490. }
  491. // добавляем источник
  492. for (let i1 = p1[0] + 1; i1 < components.length; ++i1)
  493. componentsNew.push(components[i1]);
  494. //window.componentsNew=componentsNew
  495. // обновляемся
  496. riverLandmark.geometry.components[0].components = uniq(componentsNew);
  497. W.model.actionManager.add(new wazeActionUpdateFeatureGeometry(riverLandmark, W.model.venues, W.userscripts.toGeoJSONGeometry(undoGeometry), W.userscripts.toGeoJSONGeometry(riverLandmark.geometry)));
  498. W.model.actionManager.add(new wazeActionDeleteObject(donorLandmark, W.model.venues, W.userscripts.toGeoJSONGeometry(undoGeometryDonor), W.userscripts.toGeoJSONGeometry(donorLandmark.geometry)));
  499. return true;
  500. }
  501. var riverVertices = riverLandmark.geometry.getVertices();
  502. console_log("Total river vertices:" + riverVertices.length);
  503. // 2013-06-01: Adjust first street vertice in case of a 2 vertice river
  504. if (firstStreetVerticeOutside === 0)
  505. firstStreetVerticeOutside = 1;
  506. // 2013-06-01: Find on selected river, the nearest point from the beginning of road
  507. var distance = 0;
  508. var minDistance = 100000;
  509. var indexNearestPolyPoint = 0;
  510. for (i = 0; i < polyPoints.length; i++) {
  511. distance = polyPoints[i].distanceTo(streetVertices[firstStreetVerticeOutside]);
  512. if (distance < minDistance) {
  513. minDistance = distance;
  514. indexNearestPolyPoint = i;
  515. }
  516. }
  517. console_log("polyPoints.length: " + polyPoints.length);
  518. console_log("indexNearestPolyPoint: " + indexNearestPolyPoint);
  519. var indexNearestRiverVertice = 0;
  520. var nextIndex;
  521. minDistance = 100000;
  522. for (i = 0; i < riverVertices.length; i++) {
  523. nextIndex = getNextIndex(i, riverVertices.length, +1);
  524. if (isIntersectingLines(riverVertices[i], riverVertices[nextIndex], streetVertices[0], streetVertices[1])) {
  525. distance = polyPoints[indexNearestPolyPoint].distanceTo(riverVertices[i]);
  526. if (distance < minDistance) {
  527. minDistance = distance;
  528. indexNearestRiverVertice = i;
  529. }
  530. }
  531. }
  532. console_log("indexNearestRiverVertice: " + indexNearestRiverVertice);
  533. var nextRiverVertice = getNextIndex(indexNearestRiverVertice, riverVertices.length, 1);
  534. // 2013-06-01: Is river's Polygon clockwise or counter-clockwise?
  535. console_log("nextRiverVertice: " + nextRiverVertice);
  536. console_log("firstPolyPoint:" + firstPolyPoint);
  537. console_log("secondPolyPoint:" + secondPolyPoint);
  538. var inc = 1;
  539. var incIndex = 0;
  540. if (isIntersectingLines(riverVertices[indexNearestRiverVertice], firstPolyPoint, riverVertices[nextRiverVertice], secondPolyPoint)) {
  541. //inc = -1;
  542. console_log("Lines intersect: clockwise polygon");
  543. inc = +1;
  544. incIndex = 1;
  545. } else {
  546. inc = +1;
  547. console_log("Lines doesn't intersect: counter-clockwise polygon");
  548. }
  549. // 2013-06-03: Update river's polygon (add new vertices)
  550. //var indexLastPolyPoint = getNextIndex(index, polyPoints.length, -inc);
  551. var indexNextVertice = 1;
  552. var index = polyPoints.length / 2 - 1;
  553. if (bIsOneVerticeStreet)
  554. index += 1;
  555. for (i = 0; i < polyPoints.length; i++) {
  556. if (!originalGeometry.containsPoint(polyPoints[index])) {
  557. // 2014-01-09: Save's old Landmark
  558. let undoGeometry = riverLandmark.geometry.clone();
  559. // 2014-01-09: Add a new point to existing river landmark
  560. riverLandmark.geometry.components[0].addComponent(polyPoints[index], indexNearestRiverVertice + indexNextVertice);
  561. // 2014-01-09: Update river landmark on Waze editor
  562. // 2014-09-30: Gets UptdateFeatureGeometry
  563. W.model.actionManager.add(new wazeActionUpdateFeatureGeometry(riverLandmark, W.model.venues, W.userscripts.toGeoJSONGeometry(undoGeometry), W.userscripts.toGeoJSONGeometry(riverLandmark.geometry)));
  564. //delete undoGeometry;
  565. console_log("Added: " + index);
  566. indexNextVertice += incIndex;
  567. }
  568. index = getNextIndex(index, polyPoints.length, inc);
  569. }
  570. // 2013-06-03: Notify Waze that current river's geometry change.
  571. //Waze.model.actionManager.add(new Waze.Action.UpdateFeatureGeometry(riverLandmark,Waze.model.landmarks,originalGeometry,riverLandmark.geometry));
  572. //delete originalGeometry;
  573. if (lmtype !== "OTHER") {
  574. console_log("!bAddNew");
  575. let address = riverLandmark.getAddress().attributes;
  576. console_log(address);
  577. let newAddressAtts = {
  578. streetName: null,
  579. emptyStreet: true,
  580. cityName: null,
  581. emptyCity: true,
  582. stateID: address.state.attributes.id,
  583. countryID: address.country.attributes.id
  584. };
  585. W.model.actionManager.add(new wazeActionUpdateFeatureAddress(riverLandmark, newAddressAtts, {
  586. streetIDField: 'streetID'
  587. }));
  588. }
  589. }
  590. return true;
  591. }
  592. // 2013-06-02: Returns TRUE if line1 intersects lines2
  593. function isIntersectingLines(pointLine1From, pointLine1To, pointLine2From, pointLine2To) {
  594. var segment1;
  595. var segment2;
  596. // 2013-06-02: OpenLayers.Geometry.segmentsIntersect requires that start and end are ordered so that x1 < x2.
  597. if (pointLine1From.x <= pointLine1To.x)
  598. segment1 = {
  599. 'x1': pointLine1From.x,
  600. 'y1': pointLine1From.y,
  601. 'x2': pointLine1To.x,
  602. 'y2': pointLine1To.y
  603. };
  604. else
  605. segment1 = {
  606. 'x1': pointLine1To.x,
  607. 'y1': pointLine1To.y,
  608. 'x2': pointLine1From.x,
  609. 'y2': pointLine1From.y
  610. };
  611. if (pointLine2From.x <= pointLine2To.x)
  612. segment2 = {
  613. 'x1': pointLine2From.x,
  614. 'y1': pointLine2From.y,
  615. 'x2': pointLine2To.x,
  616. 'y2': pointLine2To.y
  617. };
  618. else
  619. segment2 = {
  620. 'x1': pointLine2To.x,
  621. 'y1': pointLine2To.y,
  622. 'x2': pointLine2From.x,
  623. 'y2': pointLine2From.y
  624. };
  625. return OpenLayers.Geometry.segmentsIntersect(segment1, segment2, !1);
  626. }
  627. // 2013-06-02: Returns TRUE if polygon's direction is clockwise. FALSE -> counter-clockwise
  628. // Based on: http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of-polygon-points-are-in-clockwise-order
  629. /*
  630. function isClockwise(vertices,index,count){
  631. var total=0;
  632. var nextIndex;
  633. if(count > vertices.length)
  634. count = vertices.length;
  635. for(var i=0; i < vertices.length-1; i++){
  636. nextIndex = getNextIndex(index,vertices.length,+1);
  637. total += (vertices[nextIndex].x-vertices[index].x) * (vertices[nextIndex].y+vertices[index].y);
  638. index = nextIndex;
  639. }
  640. return total>=0;
  641. }
  642. */
  643. // 2013-06-01: Increment/decrement index by 1
  644. function getNextIndex(index, length, inc) {
  645. var next = index + inc;
  646. if (next == length)
  647. next = 0;
  648. if (next < 0)
  649. next = length - 1;
  650. return next;
  651. }
  652. function getEquation(segment) {
  653. if (segment.x2 == segment.x1)
  654. return {
  655. 'x': segment.x1
  656. };
  657. var slope = (segment.y2 - segment.y1) / (segment.x2 - segment.x1);
  658. var offset = segment.y1 - (slope * segment.x1);
  659. return {
  660. 'slope': slope,
  661. 'offset': offset
  662. };
  663. }
  664. //
  665. // line A: y = ax + b
  666. // line B: y = cx + b
  667. //
  668. // x = (d - b) / (a - c)
  669. function intersectX(eqa, eqb) {
  670. if ("number" == typeof eqa.slope && "number" == typeof eqb.slope) {
  671. if (eqa.slope == eqb.slope)
  672. return null;
  673. var ix = (eqb.offset - eqa.offset) / (eqa.slope - eqb.slope);
  674. var iy = eqa.slope * ix + eqa.offset;
  675. return new OpenLayers.Geometry.Point(ix, iy);
  676. } else if ("number" == typeof eqa.x) {
  677. return new OpenLayers.Geometry.Point(eqa.x, eqb.slope * eqa.x + eqb.offset);
  678. } else if ("number" == typeof eqb.y) {
  679. return new OpenLayers.Geometry.Point(eqb.x, eqa.slope * eqb.x + eqa.offset);
  680. }
  681. return null;
  682. }
  683. function getStreet(segment) {
  684. if (!segment.attributes.primaryStreetID)
  685. return null;
  686. var street = segment.model.streets.getObjectById(segment.attributes.primaryStreetID);
  687. return street;
  688. }
  689. function getDisplacement(street) {
  690. if (!street)
  691. return getLastRiverWidth(defaultWidth);
  692. if (!street.attributes.name)
  693. return getLastRiverWidth(defaultWidth);
  694. if (street.attributes.name.match(/^(\d+)(m|м)\b/)) // TODO make localizable
  695. return parseInt(RegExp.$1);
  696. if (street.attributes.name.match(/^(\d+)ft\b/)) // TODO make localizable
  697. return parseInt(RegExp.$1) * 0.3048;
  698. return getLastRiverWidth(defaultWidth);
  699. }
  700. // 2013-06-09: Save current river Width
  701. function setLastRiverWidth(riverWidth) {
  702. if (typeof(Storage) !== "undefined") {
  703. // 2013-06-09: Yes! localStorage and sessionStorage support!
  704. sessionStorage.riverWidth = Number(riverWidth);
  705. } else {
  706. // Sorry! No web storage support..
  707. console_log("No web storage support");
  708. }
  709. }
  710. // 2013-06-09: Returns last saved river width
  711. function getLastRiverWidth(defaultRiverWidth) {
  712. if (typeof(Storage) !== "undefined") {
  713. // 2013-06-09: Yes! localStorage and sessionStorage support!
  714. if (sessionStorage.riverWidth)
  715. return Number(sessionStorage.riverWidth);
  716. else
  717. return Number(defaultRiverWidth); // Default river width
  718. } else {
  719. // Sorry! No web storage support..
  720. return Number(defaultRiverWidth); // Default river width
  721. }
  722. }
  723. // 2013-10-20: Save current unlimited size preference
  724. function setLastIsUnlimitedSize(isUnlimitedSize) {
  725. if (typeof(Storage) !== "undefined") {
  726. // 2013-06-09: Yes! localStorage and sessionStorage support!
  727. sessionStorage.isUnlimitedSize = Number(isUnlimitedSize);
  728. } else {
  729. // Sorry! No web storage support..
  730. console_log("No web storage support");
  731. }
  732. }
  733. // 2013-10-20: Returns last saved unlimited size preference
  734. function getLastIsUnlimitedSize(defaultValue) {
  735. if (typeof(Storage) !== "undefined") {
  736. // 2013-10-20: Yes! localStorage and sessionStorage support!
  737. if (sessionStorage.isUnlimitedSize)
  738. return Number(sessionStorage.isUnlimitedSize);
  739. else
  740. return Number(defaultValue); // Default preference
  741. } else {
  742. // Sorry! No web storage support..
  743. return Number(defaultValue); // Default preference
  744. }
  745. }
  746. // 2013-10-20: Save current unlimited size preference
  747. function setLastIsDeleteSegment(isDeleteSegment) {
  748. if (typeof(Storage) !== "undefined") {
  749. // 2013-06-09: Yes! localStorage and sessionStorage support!
  750. sessionStorage.isDeleteSegment = Number(isDeleteSegment);
  751. } else {
  752. // Sorry! No web storage support..
  753. console_log("No web storage support");
  754. }
  755. }
  756. // 2013-10-20: Returns last saved unlimited size preference
  757. function getLastIsDeleteSegment(defaultValue) {
  758. if (typeof(Storage) !== "undefined") {
  759. // 2013-10-20: Yes! localStorage and sessionStorage support!
  760. if (sessionStorage.isDeleteSegment)
  761. return Number(sessionStorage.isDeleteSegment);
  762. else
  763. return Number(defaultValue); // Default preference
  764. } else {
  765. // Sorry! No web storage support..
  766. return Number(defaultValue); // Default preference
  767. }
  768. }
  769. // 2014-06-05: Returns WME interface language
  770. function getLanguage() {
  771. var wmeLanguage;
  772. var urlParts;
  773. urlParts = location.pathname.split("/");
  774. wmeLanguage = urlParts[1].toLowerCase();
  775. if (wmeLanguage === "editor")
  776. wmeLanguage = "us";
  777. return wmeLanguage;
  778. }
  779. // 2014-06-05: Returns WME interface language
  780. /*
  781. function isBetaEditor(){
  782. var wmeEditor = location.host.toLowerCase();
  783. return wmeEditor==="editor-beta.waze.com";
  784. }
  785. */
  786. // 2014-06-05: Translate text to different languages
  787. function intLanguageStrings() {
  788. switch (getLanguage()) {
  789. case "es": // 2014-06-05: Spanish
  790. case "es-419":
  791. langText = new Array("", "Ancho (metros)", "Cree una nueva calle, selecciónela y oprima este botón.", "Calle a Río", "Tamaño ilimitado",
  792. "¡No se encontró una calle sin guardar!", "Todos los segmentos de la calle adentro del río. No se puede continuar.",
  793. "Múltiples segmentos de la calle dentro del río. No se puede continuar", "Other", "Forest", "Delete segment");
  794. break;
  795. case "fr": // 2014-06-05: French
  796. langText = new Array("", "Largura (mètres)", "Crie uma nova rua, a selecione e clique neste botão.", "Rue á rivière", "Taille illimitée (dangereux)",
  797. "Pas de nouvelle rue non enregistré trouvée!", "Tous les segments de la rue dans la rivière. Vous ne pouvez pas continuer.",
  798. "Plusieurs segments de rues à l'intérieur de la rivière. Vous ne pouvez pas continuer.", "Other", "Forest", "Delete segment");
  799. break;
  800. case "ru": // 2014-06-05: Russian
  801. langText = new Array("", "Ширина (в метрах)", "Создайте новую дорогу (не сохраняйте), выберите ее и нажмите эту кнопку.", "Река", "Вся длина",
  802. "Не выделено ни одной не сохраненной дороги!", "Все сегменты дороги находятся внутри реки. Преобразование невозможно.",
  803. "Слишком много сегментов дороги находится внутри реки. Преобразование невозможно.", "Контур", "Лес", "Удалить сегмент");
  804. break;
  805. case "uk": // 2018-05-03: Ukrainian
  806. langText = new Array("", "Ширина (в метрах)", "Створіть нову дорогу (не зберігайте і не знімайте виділення) та натисніть цю кнопку.", "Ріка", "Безлімітна довжина (небезпечно)",
  807. "Не виділено жодної збереженої дороги!", "Усі сегменти дороги знаходяться всередині ріки. Перетворення неможливе.",
  808. "Занадто багато сегментів дороги знаходяться всередині ріки. Перетворення неможливе.", "Контур", "Ліс", "Видалити сегмент");
  809. break;
  810. case "hu": // 2014-07-02: Hungarian
  811. langText = new Array("", "Szélesség (méter)", "Hozzon létre egy új utcát, válassza ki, majd kattintson erre a gombra.", "Utcából folyó", "Korlátlan méretű (nem biztonságos)",
  812. "Nem található nem mentett és kiválasztott új utca!", "Az útszakasz a folyón belül található! Nem lehet folytatni.",
  813. "Minden útszakasz a folyón belül található! Nem lehet folytatni.", "Other", "Forest", "Delete segment");
  814. break;
  815. case "cs": // 2014-07-03: Czech
  816. langText = new Array("", "Šířka (metrů)", "Vytvořte osu řeky, vyberte segment a stiskněte toto tlačítko.", "Silnice na řeku", "Neomezená šířka (nebezpečné)",
  817. "Nebyly vybrány žádné neuložené segmenty!", "Všechny segmenty jsou uvnitř řeky! Nelze pokračovat.",
  818. "Uvnitř řeky je více segmentů! Nelze pokračovat.", "Other", "Forest", "Delete segment");
  819. break;
  820. case "pl": // 2014-11-08: Polish - By Zniwek
  821. langText = new Array("", "Szerokość (w metrach)", "Stwórz ulicę, wybierz ją i kliknij ten przycisk.", "Ulica w Rzekę", "Nieskończony rozmiar (niebezpieczne)",
  822. "Nie znaleziono nowej i niezapisanej ulicy!", "Wszystkie segmenty ulicy wewnątrz rzeki. Nie mogę kontynuować.",
  823. "Wiele segmentów ulicy wewnątrz rzeki. Nie mogę kontynuować.", "Other", "Forest", "Delete segment");
  824. break;
  825. case "pt-br": // 2015-04-05: Portuguese - By esmota
  826. langText = new Array("", "Largura (metros)", "Criar uma nova rua, selecione e clique neste botão.", "Rua para Rio", "Comprimento ilimitado (instável)",
  827. "Nenhuma nova rua, sem salvar, selecionada!", "Todos os segmentos de rua estão dentro de um rio. Nada a fazer.",
  828. "Múltiplos segmentos de rua dentro de um rio. Impossível continuar.", "Other", "Forest", "Delete segment");
  829. break;
  830. default: // 2014-06-05: English
  831. langText = new Array("", "Width (in meters)", "Create a new street, select and click this button.", "River", "Unlimited size (unsafe)",
  832. "No unsaved and selected new street found!", "All street segments inside river. Cannot continue.",
  833. "Multiple street segments inside river. Cannot continue.", "Other", "Forest", "Delete segment");
  834. }
  835. }
  836. // 2014-06-05: Returns the translated string to current language, if the language is not recognized assumes English
  837. function getString(stringID) {
  838. return langText[stringID];
  839. }
  840. function console_log(msg) {
  841. //if (console.log)
  842. // 2013-05-19: Alternate method to validate console object
  843. if (typeof console != "undefined")
  844. console.log(msg);
  845. }
  846. // 2014-06-05: Get interface language
  847. scriptLanguage = getLanguage();
  848. intLanguageStrings();
  849. W.selectionManager.events.register(
  850. 'selectionchanged',
  851. null,
  852. insertButtons
  853. )
  854. //$(document)
  855. //.on('segment.wme', (event, element, model) => {
  856. // insertButtons()
  857. //})
  858. }
  859. streetToRiver_bootstrap();
  860. // from: https://greasyfork.org/ru/scripts/16071-wme-keyboard-shortcuts (modify)
  861. /*
  862. when adding shortcuts each shortcut will need a unique name
  863. the command to add links is WMERegisterKeyboardShortcut(ScriptName, ShortcutsHeader, NewShortcut, ShortcutDescription, FunctionToCall, ShortcutKeysObj) {
  864. ScriptName: This is the name of your script used to track all of your shortcuts on load and save.
  865. ScriptName: replace 'WMEAwesome' with your scripts name such as 'SomeOtherScript'
  866. ShortcutsHeader: this is the header that will show up in the keyboard editor
  867. NewShortcut: This is the name of the shortcut and needs to be unique from all of the other shortcuts, from other scripts, and WME
  868. ShortcutDescription: This will show up as the text next to your shortcut
  869. FunctionToCall: this is the name of your function that will be called when the keyboard shortcut is presses
  870. ShortcutKeysObj: the is the object representing the keys watched set this to '-1' to let the users specify their own shortcuts.
  871. ShortcutKeysObj: The alt, shift, and ctrl keys are A=alt, S=shift, C=ctrl. for short cut to use "alt shift ctrl and l" the object would be 'ASC+l'
  872. */
  873. function WMEKSRegisterKeyboardShortcut(a, b, c, d, e, f, g) {
  874. try {
  875. I18n.translations[I18n.locale].keyboard_shortcuts.groups[a].members.length
  876. } catch (c) {
  877. W.accelerators.Groups[a] = [],
  878. W.accelerators.Groups[a].members = [],
  879. I18n.translations[I18n.locale].keyboard_shortcuts.groups[a] = [],
  880. I18n.translations[I18n.locale].keyboard_shortcuts.groups[a].description = b,
  881. I18n.translations[I18n.locale].keyboard_shortcuts.groups[a].members = []
  882. }
  883. if (e && "function" == typeof e) {
  884. I18n.translations[I18n.locale].keyboard_shortcuts.groups[a].members[c] = d,
  885. W.accelerators.addAction(c, {
  886. group: a
  887. });
  888. var i = "-1",
  889. j = {};
  890. j[i] = c,
  891. W.accelerators._registerShortcuts(j),
  892. null !== f && (j = {}, j[f] = c, W.accelerators._registerShortcuts(j)),
  893. W.accelerators.events.register(c, null, function () {
  894. e(g)
  895. })
  896. } else
  897. alert("The function " + e + " has not been declared")
  898. }
  899. function WMEKSLoadKeyboardShortcuts(a) {
  900. if (console.log("WMEKSLoadKeyboardShortcuts(" + a + ")"), localStorage[a + "KBS"])
  901. for (var b = JSON.parse(localStorage[a + "KBS"]), c = 0; c < b.length; c++)
  902. try {
  903. W.accelerators._registerShortcuts(b[c])
  904. } catch (a) {
  905. console.log(a)
  906. }
  907. }
  908. function WMEKSSaveKeyboardShortcuts(a) {
  909. console.log("WMEKSSaveKeyboardShortcuts(" + a + ")");
  910. var b = [];
  911. for (var c in W.accelerators.Actions) {
  912. var d = "";
  913. if (W.accelerators.Actions[c].group == a) {
  914. W.accelerators.Actions[c].shortcut ? (W.accelerators.Actions[c].shortcut.altKey === !0 && (d += "A"), W.accelerators.Actions[c].shortcut.shiftKey === !0 && (d += "S"), W.accelerators.Actions[c].shortcut.ctrlKey === !0 && (d += "C"), "" !== d && (d += "+"), W.accelerators.Actions[c].shortcut.keyCode && (d += W.accelerators.Actions[c].shortcut.keyCode)) : d = "-1";
  915. var e = {};
  916. e[d] = W.accelerators.Actions[c].id,
  917. b[b.length] = e
  918. }
  919. }
  920. localStorage[a + "KBS"] = JSON.stringify(b)
  921. }
  922. /* ********************************************************** */
  923. })();