WME RA Util

Providing basic utility for RA adjustment without the need to delete & recreate

  1. // ==UserScript==
  2. // @name WME RA Util
  3. // @namespace https://greasyfork.org/users/30701-justins83-waze
  4. // @version 0.3.6
  5. // @description Providing basic utility for RA adjustment without the need to delete & recreate
  6. // @include https://www.waze.com/editor/*
  7. // @include https://www.waze.com/*/editor/*
  8. // @include https://beta.waze.com/*
  9. // @exclude https://www.waze.com/user/editor*
  10. // @require https://greasyfork.org/scripts/24851-wazewrap/code/WazeWrap.js
  11. // @author JustinS83
  12. // @grant none
  13. // @license GPLv3
  14. // ==/UserScript==
  15.  
  16. /* global W */
  17. /* global WazeWrap */
  18.  
  19. /*
  20. Todo:
  21. -diameter change
  22.  
  23.  
  24. non-normal RA color:#FF8000
  25. normal RA color:#4cc600
  26. major axis color #fedc98
  27. */
  28. (function () {
  29.  
  30. var RAUtilWindow = null;
  31. var UpdateSegmentGeometry;
  32. var MoveNode, MultiAction;
  33.  
  34. //var totalActions = 0;
  35. var _settings;
  36.  
  37. function bootstrap(tries) {
  38. tries = tries || 1;
  39.  
  40. if (window.W &&
  41. window.W.map &&
  42. window.W.model &&
  43. window.require &&
  44. WazeWrap) {
  45.  
  46. init();
  47.  
  48. } else if (tries < 1000) {
  49. setTimeout(function () { bootstrap(tries++); }, 200);
  50. }
  51. }
  52.  
  53. bootstrap();
  54.  
  55.  
  56. function init() {
  57.  
  58. /** Place break here **/
  59. /* debugger; */
  60.  
  61. UpdateSegmentGeometry = require('Waze/Action/UpdateSegmentGeometry');
  62. MoveNode = require("Waze/Action/MoveNode");
  63. MultiAction = require("Waze/Action/MultiAction");
  64.  
  65. RAUtilWindow = document.createElement('div');
  66. RAUtilWindow.id = "RAUtilWindow";
  67. RAUtilWindow.style.position = 'fixed';
  68. RAUtilWindow.style.visibility = 'hidden';
  69. RAUtilWindow.style.top = '15%';
  70. RAUtilWindow.style.left = '25%';
  71. RAUtilWindow.style.width = '244px'; //390px
  72. RAUtilWindow.style.zIndex = 100;
  73. RAUtilWindow.style.backgroundColor = '#BEDCE5';
  74. RAUtilWindow.style.borderWidth = '3px';
  75. RAUtilWindow.style.borderStyle = 'solid';
  76. RAUtilWindow.style.borderRadius = '10px';
  77. RAUtilWindow.style.boxShadow = '5px 5px 10px Silver';
  78. RAUtilWindow.style.padding = '4px';
  79.  
  80. var alertsHTML = '<div id="header" style="padding: 4px; background-color:#4cc600; font-weight: bold; text-align:center;">Roundabout Utility <a data-toggle="collapse" href="#divWrappers" id="collapserLink" style="float:right"><span id="collapser" style="cursor:pointer;border:thin outset black;padding:2px;" class="fa fa-caret-square-o-up"></a></span></div>';
  81. alertsHTML += '<div id="divWrappers" class="collapse in">';
  82. alertsHTML += '<div id="contentShift" style="padding: 4px; background-color:White; display:inline-block; border-style:solid; border-width:1px; margin-right:5px;">';
  83. alertsHTML += 'Shift amount</br><input type="text" name="shiftAmount" id="shiftAmount" size="1" style="border: 1px solid #000000" value="1"/> meter(s)&nbsp;';
  84.  
  85. alertsHTML += '<div id="controls" style="padding: 4px;">';
  86.  
  87. alertsHTML += '<table style="table-layout:fixed; width:60px; height:84px; margin-left:auto;margin-right:auto;">';
  88. alertsHTML += '<tr style="width:20px;height:28px;">';
  89. alertsHTML += '<td align="center"></td>';
  90. alertsHTML += '<td align="center">';
  91. //Single Shift Buttons
  92. alertsHTML += '<span id="RAShiftUpBtn" style="cursor:pointer;font-size:14px;border:thin outset black;padding:2px;">';//margin-left:23px;">';
  93. alertsHTML += '<i class="fa fa-angle-up"> </i>';
  94. alertsHTML += '<span id="UpBtnCaption" style="font-weight: bold;"></span>';
  95. alertsHTML += '</span>';
  96. alertsHTML += '</td>';
  97. alertsHTML += '<td align="center"></td>';
  98. alertsHTML += '</tr>';
  99.  
  100. alertsHTML += '<tr style="width:20px;height:28px;">';
  101. alertsHTML += '<td align="center">';
  102. alertsHTML += '<span id="RAShiftLeftBtn" style="cursor:pointer;font-size:14px;border:thin outset black;padding:2px;padding-right:4px;">';//position:relative;padding:2px;padding-left:3px;padding-right:3px;margin-left:0px;top:10px;">';
  103. alertsHTML += '<i class="fa fa-angle-left"> </i>';
  104. alertsHTML += '<span id="LeftBtnCaption" style="font-weight: bold;"></span>';
  105. alertsHTML += '</span>';
  106. alertsHTML += '</td>';
  107.  
  108. alertsHTML += '<td align="center"></td>';
  109.  
  110. alertsHTML += '<td align="center">';
  111. alertsHTML += '<span id="RAShiftRightBtn" style="cursor:pointer;font-size:14px;border:thin outset black;padding:2px;padding-left:4px;">';//position:relative;padding:2px;padding-left:3px;padding-right:3px;top:10px;margin-left:15px;">';
  112. alertsHTML += '<i class="fa fa-angle-right"> </i>';
  113. alertsHTML += '<span id="RightBtnCaption" style="font-weight: bold;"></span>';
  114. alertsHTML += '</span>';
  115. alertsHTML += '</td>';
  116. alertsHTML += '</tr>';
  117.  
  118. alertsHTML += '<tr style="width:20px;height:28px;">';
  119. alertsHTML += '<td align="center"></td>';
  120.  
  121. alertsHTML += '<td align="center">';
  122. alertsHTML += '<span id="RAShiftDownBtn" style="cursor:pointer;font-size:14px;border:thin outset black;padding:2px;">';//;position:relative;top:20px;margin-left:17px;">';
  123. alertsHTML += '<i class="fa fa-angle-down"> </i>';
  124. alertsHTML += '<span id="DownBtnCaption" style="font-weight: bold;"></span>';
  125. alertsHTML += '</span>';
  126. alertsHTML += '</td>';
  127.  
  128. alertsHTML += '<td align="center"></td>';
  129. alertsHTML += '</tr>';
  130. alertsHTML += '</table>';
  131. alertsHTML += '</div></div>';
  132.  
  133.  
  134. //***************** Rotation **************************
  135. alertsHTML += '<div id="contentRotate" style="padding: 4px; background-color:White; display:inline-block; border-style:solid; border-width:1px; margin-right:5px;">';
  136. alertsHTML += 'Rotation amount</br><input type="text" name="rotationAmount" id="rotationAmount" size="1" style="border: 1px solid #000000" value="1"/> degree(s)&nbsp;';
  137. alertsHTML += '<div id="rotationControls" style="padding: 4px;">';
  138. alertsHTML += '<table style="table-layout:fixed; width:60px; height:84px; margin-left:auto; margin-right:auto;">';
  139. alertsHTML += '<tr style="width:20px;height:28px;">';
  140. alertsHTML += '<td align="center">';
  141. alertsHTML += '<span id="RARotateLeftBtn" style="cursor:pointer;font-size:14px;border:thin outset black;padding:2px;">';//margin-left:23px;">';
  142. alertsHTML += '<i class="fa fa-undo"> </i>';
  143. alertsHTML += '<span id="RotateLeftBtnCaption" style="font-weight: bold;"></span>';
  144. alertsHTML += '</span>';
  145. alertsHTML += '</td>';
  146.  
  147. alertsHTML += '<td align="center">';
  148. alertsHTML += '<span id="RARotateRightBtn" style="cursor:pointer;font-size:14px;border:thin outset black;padding:2px;">';//margin-left:23px;">';
  149. alertsHTML += '<i class="fa fa-repeat"> </i>';
  150. alertsHTML += '<span id="RotateRightBtnCaption" style="font-weight: bold;"></span>';
  151. alertsHTML += '</span>';
  152. alertsHTML += '</td>';
  153. alertsHTML += '</tr></table>';
  154. alertsHTML += '</div></div>';
  155.  
  156. //***************** Horizontal stretch ************************** *//
  157. alertsHTML += '<div id="contentLongStretch" style="padding: 4px; background-color:White; display:inline-block; border-style:solid; border-width:1px; margin-right:5px;">';
  158. alertsHTML += 'Horizontal stretch</br><input type="text" name="xStretchAmount" id="HorizStretchAmount" size="1" style="border: 1px solid #000000" value="1"/> meter(s)&nbsp;';
  159.  
  160. alertsHTML += '<div id="controls" style="padding: 4px;">';
  161.  
  162. alertsHTML += '<table style="table-layout:fixed; width:60px; height:84px; margin-left:auto;margin-right:auto;">';
  163. //Single Stretch Buttons
  164.  
  165. alertsHTML += '<tr style="width:20px;height:28px;">';
  166. alertsHTML += '<td align="center">';
  167. alertsHTML += '<span id="RAStretchHorizBtnPlus" style="cursor:pointer;font-size:14px;border:thin outset black;padding:2px;padding-right:4px;">';//position:relative;padding:2px;padding-left:3px;padding-right:3px;margin-left:0px;top:10px;"+';
  168. alertsHTML += '<i class="fa fa-plus"> </i>';
  169. alertsHTML += '<span id="PlusBtnCaption" style="font-weight: bold;"></span>';
  170. alertsHTML += '</span>';
  171. alertsHTML += '</td>';
  172.  
  173. alertsHTML += '<td align="center">';
  174. alertsHTML += '<span id="RAStretchHorizBtnMinus" style="cursor:pointer;font-size:14px;border:thin outset black;padding:2px;padding-left:4px;">';//position:relative;padding:2px;padding-left:3px;padding-right:3px;top:10px;margin-left:15px;"-';
  175. alertsHTML += '<i class="fa fa-minus"> </i>';
  176. alertsHTML += '<span id="MinusBtnCaption" style="font-weight: bold;"></span>';
  177. alertsHTML += '</span>';
  178. alertsHTML += '</td>';
  179. alertsHTML += '</tr>';
  180.  
  181. alertsHTML += '</table>';
  182. alertsHTML += '</div></div>';
  183.  
  184.  
  185. //***************** Vertical stretch ************************** *//
  186. alertsHTML += '<div id="contentLatStretch" style="padding: 4px; background-color:White; display:inline-block; border-style:solid; border-width:1px; margin-right:5px;">';
  187. alertsHTML += 'Vertical stretch</br><input type="text" name="xStretchAmount" id="VertStretchAmount" size="1" style="border: 1px solid #000000" value="1"/> meter(s)&nbsp;';
  188.  
  189. alertsHTML += '<div id="controls" style="padding: 4px;">';
  190.  
  191. alertsHTML += '<table style="table-layout:fixed; width:60px; height:84px; margin-left:auto;margin-right:auto;">';
  192. //Single Stretch Buttons
  193.  
  194. alertsHTML += '<tr style="width:20px;height:14px;">';
  195. alertsHTML += '<td align="center">';
  196. alertsHTML += '<span id="RAStretchVertBtnPlus" style="cursor:pointer;font-size:14px;border:thin outset black;padding:2px;padding-right:4px;">';//position:relative;padding:2px;padding-left:3px;padding-right:3px;margin-left:0px;top:10px;"+';
  197. alertsHTML += '<i class="fa fa-plus"> </i>';
  198. alertsHTML += '<span id="PlusBtnCaption" style="font-weight: bold;"></span>';
  199. alertsHTML += '</span>';
  200. alertsHTML += '</td>';
  201. alertsHTML += '</tr>';
  202.  
  203. alertsHTML += '<tr style="width:20px;height:14px;">';
  204. alertsHTML += '<td align="center">';
  205. alertsHTML += '<span id="RAStretchVertBtnMinus" style="cursor:pointer;font-size:14px;border:thin outset black;padding:2px;padding-left:4px;">';//position:relative;padding:2px;padding-left:3px;padding-right:3px;top:10px;margin-left:15px;"-';
  206. alertsHTML += '<i class="fa fa-minus"> </i>';
  207. alertsHTML += '<span id="MinusBtnCaption" style="font-weight: bold;"></span>';
  208. alertsHTML += '</span>';
  209. alertsHTML += '</td>';
  210. alertsHTML += '</tr>';
  211.  
  212. alertsHTML += '</table>';
  213. alertsHTML += '</div></div>';
  214.  
  215.  
  216.  
  217. //********************* Diameter change ******************
  218. /*
  219. alertsHTML += '<div id="diameterChange" style="padding: 4px; padding-top:11px; background-color:White; display:inline-block; border-style:solid; border-width:1px; height:152px; text-align:center;" >';
  220. alertsHTML += 'Change diameter</br></br>';
  221. alertsHTML += '<div id="DiameterChangeControls" style="padding: 4px;">';
  222.  
  223. alertsHTML += '<table style="table-layout:fixed; height:84px; margin-left:auto;margin-right:auto;">';
  224. alertsHTML += '<tr style="width:20px;height:28px;">';
  225. alertsHTML += '<td align="center">';
  226. alertsHTML += '<span id="diameterChangeDecreaseBtn" style="cursor:pointer;font-size:14px;border:thin outset black;padding:2px;">';//margin-left:23px;">';
  227. alertsHTML += '<i class="fa fa-minus"> </i>';
  228. alertsHTML += '<span id="diameterChangeDecreaseCaption" style="font-weight: bold;"></span>';
  229. alertsHTML += '</span>';
  230. alertsHTML += '</td>';
  231.  
  232. alertsHTML += '<td align="center" width="105">';
  233. alertsHTML += '<input type="text" name="diameterChangeAmount" id="diameterChangeAmount" size="1" style="border: 1px solid #000000" value="1"/> meter(s)&nbsp;';
  234. alertsHTML += '</td>';
  235.  
  236. alertsHTML += '<td align="center">';
  237. alertsHTML += '<span id="diameterChangeIncreaseBtn" style="cursor:pointer;font-size:14px;border:thin outset black;padding:2px;">';//margin-left:23px;">';
  238. alertsHTML += '<i class="fa fa-plus"> </i>';
  239. alertsHTML += '<span id="diameterChangeIncreaseCaption" style="font-weight: bold;"></span>';
  240. alertsHTML += '</span>';
  241. alertsHTML += '</td>';
  242. alertsHTML += '</tr></table>';
  243.  
  244. alertsHTML += '</div></div>';*/
  245. alertsHTML += '</div></div>'; //Close divWrapers & outer div
  246.  
  247.  
  248.  
  249. RAUtilWindow.innerHTML = alertsHTML;
  250. document.body.appendChild(RAUtilWindow);
  251.  
  252. document.getElementById('RAShiftLeftBtn').addEventListener('click', RAShiftLeftBtnClick, false);
  253. document.getElementById('RAShiftRightBtn').addEventListener('click', RAShiftRightBtnClick, false);
  254. document.getElementById('RAShiftUpBtn').addEventListener('click', RAShiftUpBtnClick, false);
  255. document.getElementById('RAShiftDownBtn').addEventListener('click', RAShiftDownBtnClick, false);
  256.  
  257. document.getElementById('RARotateLeftBtn').addEventListener('click', RARotateLeftBtnClick, false);
  258. document.getElementById('RARotateRightBtn').addEventListener('click', RARotateRightBtnClick, false);
  259.  
  260. document.getElementById('RAStretchHorizBtnPlus').addEventListener('click', RAStretchHLeftBtnClick, false);
  261. document.getElementById('RAStretchHorizBtnMinus').addEventListener('click', RAStretchHRightBtnClick, false);
  262.  
  263. document.getElementById('RAStretchVertBtnPlus').addEventListener('click', RAStretchVTopBtnClick, false);
  264. document.getElementById('RAStretchVertBtnMinus').addEventListener('click', RAStretchVBottomBtnClick, false);
  265.  
  266. //document.getElementById('diameterChangeDecreaseBtn').addEventListener('click', diameterChangeDecreaseBtnClick, false);
  267. //document.getElementById('diameterChangeIncreaseBtn').addEventListener('click', diameterChangeIncreaseBtnClick, false);
  268.  
  269. $('#shiftAmount').keypress(function (event) {
  270. if ((event.which != 46 || $(this).val().indexOf('.') != -1) && (event.which < 48 || event.which > 57)) {
  271. event.preventDefault();
  272. }
  273. });
  274.  
  275. $('#rotationAmount').keypress(function (event) {
  276. if ((event.which != 46 || $(this).val().indexOf('.') != -1) && (event.which < 48 || event.which > 57)) {
  277. event.preventDefault();
  278. }
  279. });
  280.  
  281. $('#collapserLink').click(function () {
  282. if ($('#collapser').attr('class') == "fa fa-caret-square-o-down") {
  283. $("#collapser").removeClass("fa-caret-square-o-down");
  284. $("#collapser").addClass("fa-caret-square-o-up");
  285. }
  286. else {
  287. $("#collapser").removeClass("fa-caret-square-o-up");
  288. $("#collapser").addClass("fa-caret-square-o-down");
  289. }
  290. saveSettingsToStorage();
  291. });
  292.  
  293. window.Waze.selectionManager.events.register("selectionchanged", null, checkDisplayTool);
  294. //W.model.actionManager.events.register("afterundoaction",null, undotriggered);
  295. //W.model.actionManager.events.register("afterclearactions",null,actionsCleared);
  296.  
  297. var loadedSettings = $.parseJSON(localStorage.getItem("WME_RAUtil"));
  298. var defaultSettings = {
  299. divTop: "15%",
  300. divLeft: "25%",
  301. Expanded: true
  302. };
  303. _settings = loadedSettings ? loadedSettings : defaultSettings;
  304.  
  305. $('#RAUtilWindow').css('left', _settings.divLeft);
  306. $('#RAUtilWindow').css('top', _settings.divTop);
  307.  
  308. if (!_settings.Expanded) {
  309. $("#divWrappers").removeClass("in");
  310. $("#divWrappers").addClass("collapse");
  311. $("#collapser").removeClass("fa-caret-square-o-up");
  312. $("#collapser").addClass("fa-caret-square-o-down");
  313. }
  314. }
  315.  
  316. function saveSettingsToStorage() {
  317. if (localStorage) {
  318. var settings = {
  319. divTop: "15%",
  320. divLeft: "25%",
  321. Expanded: true
  322. };
  323.  
  324. settings.divLeft = $('#RAUtilWindow').css('left');
  325. settings.divTop = $('#RAUtilWindow').css('top');
  326. settings.Expanded = $("#collapser").attr('class').indexOf("fa-caret-square-o-up") > -1;
  327. localStorage.setItem("WME_RAUtil", JSON.stringify(settings));
  328. }
  329. }
  330.  
  331. /*
  332. function undotriggered(){
  333. checkSaveChanges();
  334. }
  335.  
  336. function actionsCleared(){
  337. //checkSaveChanges();
  338. totalActions = 0;
  339. }
  340. */
  341.  
  342. function checkDisplayTool() {
  343. if (W.selectionManager.hasSelectedItems() && Waze.selectionManager.selectedItems[0].model.type === 'segment') {
  344. if (!AllSelectedSegmentsRA() || W.selectionManager.selectedItems.length === 0)
  345. $('#RAUtilWindow').css({ 'visibility': 'hidden' });
  346. else {
  347. $('#RAUtilWindow').css({ 'visibility': 'visible' });
  348. if (typeof jQuery.ui !== 'undefined')
  349. $('#RAUtilWindow').draggable({ //Gotta nuke the height setting the dragging inserts otherwise the panel cannot collapse
  350. stop: function (event, ui) {
  351. $('#RAUtilWindow').css("height", "");
  352. saveSettingsToStorage();
  353. }
  354. });
  355. //checkSaveChanges();
  356. checkAllEditable(WazeWrap.Model.getAllRoundaboutSegmentsFromObj(W.selectionManager.selectedItems[0]));
  357. }
  358. }
  359. else {
  360. $('#RAUtilWindow').css({ 'visibility': 'hidden' });
  361. if (typeof jQuery.ui !== 'undefined')
  362. $('#RAUtilWindow').draggable({
  363. stop: function (event, ui) {
  364. $('#RAUtilWindow').css("height", "");
  365. saveSettingsToStorage();
  366. }
  367. });
  368. }
  369. }
  370.  
  371.  
  372. //var pendingChanges = false;
  373. /**
  374. Returns false if there are pending changes, true if no changes need saved.
  375. */
  376. /*function checkSaveChanges(){
  377. var $RASaveChanges = $('#RAUtilSaveChanges');
  378. if(W.model.actionManager.index >= 0 && (totalActions === 0 && (W.model.actionManager.actions.length > 0))){
  379. if($RASaveChanges.length === 0){
  380. $RASaveChanges = $('<div>', {id:'RAUtilSaveChanges', style:'color:red'});
  381. $RASaveChanges.text('You must save your changes before using this utility.');
  382. $('#RAUtilWindow').append($RASaveChanges);
  383. pendingChanges = true;
  384. }
  385. }
  386. else
  387. {
  388. $RASaveChanges.remove();
  389. pendingChanges = false;
  390. }
  391. }
  392. */
  393.  
  394. function checkAllEditable(RASegs) {
  395. var $RAEditable = $('#RAEditable');
  396. var allEditable = true;
  397. var segObj, fromNode, toNode;
  398.  
  399. for (i = 0; i < RASegs.length; i++) {
  400. segObj = W.model.segments.get(RASegs[i]);
  401. fromNode = segObj.getFromNode();
  402. toNode = segObj.getToNode();
  403.  
  404. if (segObj !== "undefined") {
  405. if (fromNode && fromNode !== "undefined" && !fromNode.areConnectionsEditable())
  406. allEditable = false;
  407. else if (toNode && toNode !== "undefined" && !toNode.areConnectionsEditable())
  408. allEditable = false;
  409. var toConnected, fromConnected;
  410.  
  411. if (toNode) {
  412. toConnected = toNode.attributes.segIDs;
  413. for (j = 0; j < toConnected.length; j++) {
  414. if (W.model.segments.get(toConnected[j]) !== "undefined")
  415. if (W.model.segments.get(toConnected[j]).hasClosures())
  416. allEditable = false;
  417. }
  418. }
  419.  
  420. if (fromNode) {
  421. fromConnected = fromNode.attributes.segIDs;
  422. for (j = 0; j < fromConnected.length; j++) {
  423. if (W.model.segments.get(fromConnected[j]) !== "undefined")
  424. if (W.model.segments.get(fromConnected[j]).hasClosures())
  425. allEditable = false;
  426. }
  427. }
  428. }
  429. }
  430. if (allEditable) {
  431. $RAEditable.remove();
  432. }
  433. else {
  434. if ($RAEditable.length === 0) {
  435. $RAEditable = $('<div>', { id: 'RAEditable', style: 'color:red' });
  436. $RAEditable.text('One or more segments are locked above your rank or have a closure.');
  437. $('#RAUtilWindow').append($RAEditable);
  438. }
  439. }
  440. return allEditable;
  441. }
  442.  
  443. function AllSelectedSegmentsRA() {
  444. for (i = 0; i < W.selectionManager.selectedItems.length; i++) {
  445. if (W.selectionManager.selectedItems[i].model.attributes.id < 0 || !WazeWrap.Model.isRoundaboutSegmentID(W.selectionManager.selectedItems[i].model.attributes.id))
  446. return false;
  447. }
  448. return true;
  449. }
  450.  
  451. function ShiftSegmentNodesLat(segObj, latOffset) {
  452. var RASegs = WazeWrap.Model.getAllRoundaboutSegmentsFromObj(segObj);
  453. if (checkAllEditable(RASegs)) {
  454. var gps;
  455. var newGeometry = segObj.geometry.clone();
  456. var originalLength = segObj.geometry.components.length;
  457. var multiaction = new MultiAction();
  458. multiaction.setModel(W.model);
  459.  
  460. for (i = 0; i < RASegs.length; i++) {
  461. segObj = W.model.segments.get(RASegs[i]);
  462. newGeometry = segObj.geometry.clone();
  463. originalLength = segObj.geometry.components.length;
  464. for (j = 1; j < originalLength - 1; j++) {
  465. gps = WazeWrap.Geometry.ConvertTo4326(segObj.geometry.components[j].x, segObj.geometry.components[j].y);
  466. gps.lat += latOffset;
  467. newGeometry.components.splice(j, 0, new OL.Geometry.Point(segObj.geometry.components[j].x, WazeWrap.Geometry.ConvertTo900913(segObj.geometry.components[j].x, gps.lat).lat));
  468. newGeometry.components.splice(j + 1, 1);
  469. }
  470. newGeometry.components[0].calculateBounds();
  471. newGeometry.components[originalLength - 1].calculateBounds();
  472. multiaction.doSubAction(new UpdateSegmentGeometry(segObj, segObj.geometry, newGeometry));
  473. //W.model.actionManager.add(new UpdateSegmentGeometry(segObj, segObj.geometry, newGeometry));
  474.  
  475. var node = W.model.nodes.objects[segObj.attributes.toNodeID];
  476. if (segObj.attributes.revDirection)
  477. node = W.model.nodes.objects[segObj.attributes.fromNodeID];
  478. var newNodeGeometry = node.geometry.clone();
  479. gps = WazeWrap.Geometry.ConvertTo4326(node.attributes.geometry.x, node.attributes.geometry.y);
  480. gps.lat += latOffset;
  481. newNodeGeometry.y = WazeWrap.Geometry.ConvertTo900913(node.geometry.x, gps.lat).lat;
  482. newNodeGeometry.calculateBounds();
  483.  
  484. var connectedSegObjs = {};
  485. var emptyObj = {};
  486. for (var j = 0; j < node.attributes.segIDs.length; j++) {
  487. var segid = node.attributes.segIDs[j];
  488. connectedSegObjs[segid] = W.model.segments.get(segid).geometry.clone();
  489. }
  490. //W.model.actionManager.add(new MoveNode(segObj, segObj.geometry, newNodeGeometry, connectedSegObjs, i));
  491. multiaction.doSubAction(new MoveNode(node, node.geometry, newNodeGeometry, connectedSegObjs, emptyObj));
  492. //W.model.actionManager.add(new MoveNode(node, node.geometry, newNodeGeometry));
  493. //totalActions +=2;
  494. }
  495. W.model.actionManager.add(multiaction);
  496. }
  497. }
  498.  
  499. function ShiftSegmentsNodesLong(segObj, longOffset) {
  500. var RASegs = WazeWrap.Model.getAllRoundaboutSegmentsFromObj(segObj);
  501. if (checkAllEditable(RASegs)) {
  502. var gps, newGeometry, originalLength;
  503. var multiaction = new MultiAction();
  504. multiaction.setModel(W.model);
  505.  
  506. //Loop through all RA segments & adjust
  507. for (i = 0; i < RASegs.length; i++) {
  508. segObj = W.model.segments.get(RASegs[i]);
  509. newGeometry = segObj.geometry.clone();
  510. originalLength = segObj.geometry.components.length;
  511. for (j = 1; j < originalLength - 1; j++) {
  512. gps = WazeWrap.Geometry.ConvertTo4326(segObj.geometry.components[j].x, segObj.geometry.components[j].y);
  513. gps.lon += longOffset;
  514. newGeometry.components.splice(j, 0, new OL.Geometry.Point(WazeWrap.Geometry.ConvertTo900913(gps.lon, segObj.geometry.components[j].y).lon, segObj.geometry.components[j].y));
  515. newGeometry.components.splice(j + 1, 1);
  516. }
  517. newGeometry.components[0].calculateBounds();
  518. newGeometry.components[originalLength - 1].calculateBounds();
  519. //W.model.actionManager.add(new UpdateSegmentGeometry(segObj, segObj.geometry, newGeometry));
  520. multiaction.doSubAction(new UpdateSegmentGeometry(segObj, segObj.geometry, newGeometry));
  521.  
  522. var node = W.model.nodes.objects[segObj.attributes.toNodeID];
  523. if (segObj.attributes.revDirection)
  524. node = W.model.nodes.objects[segObj.attributes.fromNodeID];
  525.  
  526. var newNodeGeometry = node.geometry.clone();
  527. gps = WazeWrap.Geometry.ConvertTo4326(node.attributes.geometry.x, node.attributes.geometry.y);
  528. gps.lon += longOffset;
  529. newNodeGeometry.x = WazeWrap.Geometry.ConvertTo900913(gps.lon, node.geometry.y).lon;
  530. newNodeGeometry.calculateBounds();
  531.  
  532. var connectedSegObjs = {};
  533. var emptyObj = {};
  534. for (var j = 0; j < node.attributes.segIDs.length; j++) {
  535. var segid = node.attributes.segIDs[j];
  536. connectedSegObjs[segid] = W.model.segments.get(segid).geometry.clone();
  537. }
  538. //W.model.actionManager.add(new MoveNode(node, node.geometry, newNodeGeometry));
  539. multiaction.doSubAction(new MoveNode(node, node.geometry, newNodeGeometry, connectedSegObjs, emptyObj));
  540. //totalActions +=2;
  541. }
  542. W.model.actionManager.add(multiaction);
  543. }
  544. }
  545.  
  546. function rotatePoints(origin, points, angle) {
  547. console.log("Origin: " + origin);
  548. console.log("Point: " + points[0]);
  549. var lineFeature = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LineString(points), null, null);
  550. lineFeature.geometry.rotate(angle, new OpenLayers.Geometry.Point(origin.lon, origin.lat));
  551. console.log(new OpenLayers.Geometry.Point(origin.lon, origin.lat).distanceTo(points[0]));
  552. console.log(lineFeature.geometry.components[0]);
  553. return lineFeature.geometry.components.clone();
  554. }
  555.  
  556. function RotateRA(segObj, angle) {
  557. var RASegs = WazeWrap.Model.getAllRoundaboutSegmentsFromObj(segObj);
  558. var raCenter = W.model.junctions.objects[segObj.model.attributes.junctionID].geometry.coordinates;
  559.  
  560. if (checkAllEditable(RASegs)) {
  561. var gps, newGeometry, originalLength;
  562. var multiaction = new MultiAction();
  563. multiaction.setModel(W.model);
  564.  
  565. //Loop through all RA segments & adjust
  566. for (i = 0; i < RASegs.length; i++) {
  567. segObj = W.model.segments.get(RASegs[i]);
  568. newGeometry = segObj.geometry.clone();
  569. originalLength = segObj.geometry.components.length;
  570.  
  571. var center = WazeWrap.Geometry.ConvertTo900913(raCenter[0], raCenter[1]);
  572.  
  573. //Find extreme low and high and set left and right to reverse
  574. var extremelow = WazeWrap.Geometry.ConvertTo900913(-180, -89);
  575. var extremehigh = WazeWrap.Geometry.ConvertTo900913(180, 90);
  576.  
  577. var left = extremehigh.lon;
  578. var right = extremelow.lon;
  579.  
  580. var segPoints = [];
  581. //Have to copy the points manually (can't use .clone()) otherwise the geometry rotation modifies the geometry of the segment itself and that hoses WME.
  582. for (j = 0; j < originalLength; j++) {
  583.  
  584. var newX = segObj.geometry.components[j].x;
  585. var newY = segObj.geometry.components[j].y;
  586.  
  587. if (newX < left)
  588. left = newX;
  589.  
  590. if (newX > right)
  591. right = newX;
  592.  
  593. segPoints.push(new OL.Geometry.Point(newX, newY));
  594. }
  595.  
  596. var newPoints = rotatePoints(center, segPoints, angle);
  597.  
  598. for (j = 1; j < originalLength - 1; j++) {
  599. newGeometry.components.splice(j, 0, new OL.Geometry.Point(newPoints[j].x, newPoints[j].y));
  600. newGeometry.components.splice(j + 1, 1);
  601. }
  602.  
  603. newGeometry.components[0].calculateBounds();
  604. newGeometry.components[originalLength - 1].calculateBounds();
  605. //W.model.actionManager.add(new UpdateSegmentGeometry(segObj, segObj.geometry, newGeometry));
  606. multiaction.doSubAction(new UpdateSegmentGeometry(segObj, segObj.geometry, newGeometry));
  607.  
  608. //**************Rotate Nodes******************
  609. var node = W.model.nodes.objects[segObj.attributes.toNodeID];
  610. if (segObj.attributes.revDirection)
  611. node = W.model.nodes.objects[segObj.attributes.fromNodeID];
  612.  
  613. var nodePoints = [];
  614. var newNodeGeometry = node.geometry.clone();
  615.  
  616. nodePoints.push(new OL.Geometry.Point(node.attributes.geometry.x, node.attributes.geometry.y));
  617. nodePoints.push(new OL.Geometry.Point(node.attributes.geometry.x, node.attributes.geometry.y)); //add it twice because lines need 2 points
  618.  
  619. gps = rotatePoints(center, nodePoints, angle);
  620.  
  621. newNodeGeometry.x = gps[0].x;
  622. newNodeGeometry.y = gps[0].y;
  623.  
  624. newNodeGeometry.calculateBounds();
  625. //W.model.actionManager.add(new MoveNode(node, node.geometry, newNodeGeometry));
  626. multiaction.doSubAction(new MoveNode(node, node.geometry, newNodeGeometry));
  627. //totalActions +=2;
  628. }
  629. W.model.actionManager.add(multiaction);
  630. }
  631. }
  632.  
  633. function StretchHorizRA(segObj, horizstretch, vertstretch) {
  634. var RASegs = WazeWrap.Model.getAllRoundaboutSegmentsFromObj(segObj);
  635. var raCenter = W.model.junctions.objects[segObj.model.attributes.junctionID].geometry.coordinates;
  636.  
  637. if (checkAllEditable(RASegs)) {
  638. var gps, newGeometry, originalLength;
  639. var multiaction = new MultiAction();
  640. multiaction.setModel(W.model);
  641. //Find extreme low and high and set left and right to reverse
  642. var extremelow = WazeWrap.Geometry.ConvertTo900913(-180, -89);
  643. var extremehigh = WazeWrap.Geometry.ConvertTo900913(180, 90);
  644.  
  645. var left = extremehigh.lon;
  646. var right = extremelow.lon;
  647. var top = extremelow.lat;
  648. var bottom = extremehigh.lat;
  649. var centroidX = -1.00000000;
  650. var centroidY = -1.00000000;
  651. var longOffset = -1.00000000;
  652. var longOffsetFactor = -1.00000000;
  653. var latOffset = -1.00000000;
  654. var latOffsetFactor = -1.00000000;
  655.  
  656. //loop through all RA segments to determine high and low
  657.  
  658. for (i = 0; i < RASegs.length; i++) {
  659. segObj = W.model.segments.get(RASegs[i]);
  660. originalLength = segObj.geometry.components.length;
  661.  
  662. for (j2 = 0; j2 < originalLength; j2++) {
  663.  
  664. var newX1 = segObj.geometry.components[j2].x;
  665. var newY1 = segObj.geometry.components[j2].y;
  666.  
  667. if (newX1 < left)
  668. left = newX1;
  669.  
  670. if (newX1 > right)
  671. right = newX1;
  672.  
  673. if (newY1 < bottom)
  674. bottom = newY1;
  675.  
  676. if (newY1 > top)
  677. top = newY1;
  678.  
  679. }
  680.  
  681. }
  682.  
  683. centroidX = (left + right) / 2;
  684. centroidY = (top + bottom) / 2;
  685. //Loop through all RA segments & adjust
  686. for (i = 0; i < RASegs.length; i++) {
  687.  
  688. segObj = W.model.segments.get(RASegs[i]);
  689. newGeometry = segObj.geometry.clone();
  690. originalLength = segObj.geometry.components.length;
  691. for (j1 = 1; j1 < originalLength - 1; j1++) {
  692. // Calculate horizontal stretch, varies on distance from center of roundbout
  693. longOffsetFactor = ((segObj.geometry.components[j1].x - centroidX) / (right - centroidX));
  694. latOffsetFactor = ((segObj.geometry.components[j1].y - centroidY) / (top - centroidY));
  695. gps = WazeWrap.Geometry.ConvertTo4326(segObj.geometry.components[j1].x, segObj.geometry.components[j1].y);
  696. gps.lon += horizstretch * longOffsetFactor / 2;
  697. gps.lat += vertstretch * latOffsetFactor / 2;
  698. //newGeometry.components.splice(j1,0, new OL.Geometry.Point(WazeWrap.Geometry.ConvertTo900913(gps.lon, segObj.geometry.components[j1].y).lon, segObj.geometry.components[j1].y));
  699. newGeometry.components.splice(j1, 0, new OL.Geometry.Point(WazeWrap.Geometry.ConvertTo900913(gps.lon, gps.lat).lon, WazeWrap.Geometry.ConvertTo900913(gps.lon, gps.lat).lat));
  700. newGeometry.components.splice(j1 + 1, 1);
  701. }
  702. newGeometry.components[0].calculateBounds();
  703. newGeometry.components[originalLength - 1].calculateBounds();
  704. //W.model.actionManager.add(new UpdateSegmentGeometry(segObj, segObj.geometry, newGeometry));
  705. multiaction.doSubAction(new UpdateSegmentGeometry(segObj, segObj.geometry, newGeometry));
  706.  
  707. var node = W.model.nodes.objects[segObj.attributes.toNodeID];
  708. if (segObj.attributes.revDirection)
  709. node = W.model.nodes.objects[segObj.attributes.fromNodeID];
  710.  
  711. var newNodeGeometry = node.geometry.clone();
  712. gps = WazeWrap.Geometry.ConvertTo4326(node.attributes.geometry.x, node.attributes.geometry.y);
  713. gps.lon += horizstretch * longOffsetFactor / 2;
  714. gps.lat += vertstretch * latOffsetFactor / 2;
  715. newNodeGeometry.x = WazeWrap.Geometry.ConvertTo900913(gps.lon, gps.lat).lon;
  716. newNodeGeometry.y = WazeWrap.Geometry.ConvertTo900913(gps.lon, gps.lat).lat;
  717. newNodeGeometry.calculateBounds();
  718.  
  719. var connectedSegObjs = {};
  720. var emptyObj = {};
  721. for (var j = 0; j < node.attributes.segIDs.length; j++) {
  722. var segid = node.attributes.segIDs[j];
  723. connectedSegObjs[segid] = W.model.segments.get(segid).geometry.clone();
  724. }
  725. //W.model.actionManager.add(new MoveNode(node, node.geometry, newNodeGeometry));
  726. multiaction.doSubAction(new MoveNode(node, node.geometry, newNodeGeometry, connectedSegObjs, emptyObj));
  727. //totalActions +=2;
  728. }
  729.  
  730.  
  731. W.model.actionManager.add(multiaction);
  732. }
  733. }
  734.  
  735. function ChangeDiameter(segObj, amount) {
  736. var RASegs = WazeWrap.Model.getAllRoundaboutSegmentsFromObj(segObj);
  737. var raCenter = W.model.junctions.objects[segObj.model.attributes.junctionID].geometry.coordinates;
  738.  
  739. if (checkAllEditable(RASegs)) {
  740. var gps, newGeometry, originalLength;
  741.  
  742. var center = WazeWrap.Geometry.ConvertTo900913(raCenter[0], raCenter[1]);
  743. //Loop through all RA segments & adjust
  744. for (i = 0; i < RASegs.length; i++) {
  745. segObj = W.model.segments.get(RASegs[i]);
  746. newGeometry = segObj.geometry.clone();
  747. originalLength = segObj.geometry.components.length;
  748. for (j = 1; j < originalLength - 1; j++) {
  749. gps = WazeWrap.Geometry.ConvertTo4326(segObj.geometry.components[j].x, segObj.geometry.components[j].y);
  750. var k = Math.atan2(origin.y - gps.lat, origin.x - gps.lon);
  751.  
  752. //gps.lon += longOffset;
  753. //newGeometry.components.splice(j,0, new OL.Geometry.Point(WazeWrap.Geometry.ConvertTo900913(gps.lon, segObj.geometry.components[j].y).lon, segObj.geometry.components[j].y));
  754. //newGeometry.components.splice(j+1,1);
  755. }
  756. newGeometry.components[0].calculateBounds();
  757. newGeometry.components[originalLength - 1].calculateBounds();
  758. W.model.actionManager.add(new UpdateSegmentGeometry(segObj, segObj.geometry, newGeometry));
  759.  
  760. /*
  761. var node = W.model.nodes.objects[segObj.attributes.toNodeID];
  762. if(segObj.attributes.revDirection)
  763. node = W.model.nodes.objects[segObj.attributes.fromNodeID];
  764.  
  765. var newNodeGeometry = node.geometry.clone();
  766. gps = WazeWrap.Geometry.ConvertTo4326(node.attributes.geometry.x, node.attributes.geometry.y);
  767. gps.lon += longOffset;
  768. newNodeGeometry.x = WazeWrap.Geometry.ConvertTo900913(gps.lon, node.geometry.y).lon;
  769. newNodeGeometry.calculateBounds();
  770. W.model.actionManager.add(new MoveNode(node, node.geometry, newNodeGeometry));
  771. totalActions +=2;
  772. */
  773. }
  774. }
  775. }
  776.  
  777. function diameterChangeDecreaseBtnClick(e) {
  778. e.stopPropagation();
  779. var segObj = W.selectionManager.selectedItems[0];
  780. ChangeDiameter(segObj, -$('#diameterChangeAmount').val());
  781. }
  782.  
  783. function diameterChangeIncreaseBtnClick(e) {
  784. e.stopPropagation();
  785. var segObj = W.selectionManager.selectedItems[0];
  786. ChangeDiameter(segObj, $('#diameterChangeAmount').val());
  787. }
  788.  
  789. function RARotateLeftBtnClick(e) {
  790. e.stopPropagation();
  791. var segObj = W.selectionManager.selectedItems[0];
  792. RotateRA(segObj, $('#rotationAmount').val());
  793. }
  794.  
  795. function RARotateRightBtnClick(e) {
  796. e.stopPropagation();
  797.  
  798. var segObj = W.selectionManager.selectedItems[0];
  799. RotateRA(segObj, -$('#rotationAmount').val());
  800. }
  801.  
  802. //Horizontal stretch
  803. function RAStretchHLeftBtnClick(e) {
  804. e.stopPropagation();
  805.  
  806. var segObj = W.selectionManager.selectedItems[0];
  807. var convertedCoords = WazeWrap.Geometry.ConvertTo4326(segObj.geometry.components[0].x, segObj.geometry.components[0].y);
  808. var gpsOffsetAmount = WazeWrap.Geometry.CalculateLongOffsetGPS($('#HorizStretchAmount').val(), convertedCoords.lon, convertedCoords.lat);
  809.  
  810. StretchHorizRA(segObj, gpsOffsetAmount, 0);
  811. }
  812.  
  813. //Horizontal contract
  814. function RAStretchHRightBtnClick(e) {
  815. e.stopPropagation();
  816.  
  817. var segObj = W.selectionManager.selectedItems[0];
  818. var convertedCoords = WazeWrap.Geometry.ConvertTo4326(segObj.geometry.components[0].x, segObj.geometry.components[0].y);
  819. var gpsOffsetAmount = WazeWrap.Geometry.CalculateLongOffsetGPS(-$('#HorizStretchAmount').val(), convertedCoords.lon, convertedCoords.lat);
  820.  
  821. StretchHorizRA(segObj, gpsOffsetAmount, 0);
  822. }
  823.  
  824. //Verical stretch
  825. function RAStretchVTopBtnClick(e) {
  826. e.stopPropagation();
  827.  
  828. var segObj = W.selectionManager.selectedItems[0];
  829. var convertedCoords = WazeWrap.Geometry.ConvertTo4326(segObj.geometry.components[0].x, segObj.geometry.components[0].y);
  830. var gpsOffsetAmount = WazeWrap.Geometry.CalculateLongOffsetGPS($('#VertStretchAmount').val(), convertedCoords.lon, convertedCoords.lat);
  831.  
  832. StretchHorizRA(segObj, 0, gpsOffsetAmount);
  833. }
  834.  
  835. //vertical contract
  836. function RAStretchVBottomBtnClick(e) {
  837. e.stopPropagation();
  838.  
  839. var segObj = W.selectionManager.selectedItems[0];
  840. var convertedCoords = WazeWrap.Geometry.ConvertTo4326(segObj.geometry.components[0].x, segObj.geometry.components[0].y);
  841. var gpsOffsetAmount = WazeWrap.Geometry.CalculateLongOffsetGPS(-$('#VertStretchAmount').val(), convertedCoords.lon, convertedCoords.lat);
  842.  
  843. StretchHorizRA(segObj, 0, gpsOffsetAmount);
  844. }
  845.  
  846. //Left
  847. function RAShiftLeftBtnClick(e) {
  848. // this traps the click to prevent it falling through to the underlying area name element and potentially causing the map view to be relocated to that area...
  849. e.stopPropagation();
  850.  
  851. //if(!pendingChanges){
  852. var segObj = W.selectionManager.selectedItems[0];
  853. var convertedCoords = WazeWrap.Geometry.ConvertTo4326(segObj.geometry.components[0].x, segObj.geometry.components[0].y);
  854. var gpsOffsetAmount = WazeWrap.Geometry.CalculateLongOffsetGPS(-$('#shiftAmount').val(), convertedCoords.lon, convertedCoords.lat);
  855. ShiftSegmentsNodesLong(segObj, gpsOffsetAmount);
  856. //}
  857. }
  858. //Right
  859. function RAShiftRightBtnClick(e) {
  860. // this traps the click to prevent it falling through to the underlying area name element and potentially causing the map view to be relocated to that area...
  861. e.stopPropagation();
  862.  
  863. //if(!pendingChanges){
  864. var segObj = W.selectionManager.selectedItems[0];
  865. var convertedCoords = WazeWrap.Geometry.ConvertTo4326(segObj.model.geometry.components[0].x, segObj.model.geometry.components[0].y);
  866. var gpsOffsetAmount = WazeWrap.Geometry.CalculateLongOffsetGPS($('#shiftAmount').val(), convertedCoords.lon, convertedCoords.lat);
  867. ShiftSegmentsNodesLong(segObj, gpsOffsetAmount);
  868. //}
  869. }
  870. //Up
  871. function RAShiftUpBtnClick(e) {
  872. // this traps the click to prevent it falling through to the underlying area name element and potentially causing the map view to be relocated to that area...
  873. e.stopPropagation();
  874.  
  875. //if(!pendingChanges){
  876. var segObj = W.selectionManager.selectedItems[0];
  877. var gpsOffsetAmount = WazeWrap.Geometry.CalculateLatOffsetGPS($('#shiftAmount').val(), WazeWrap.Geometry.ConvertTo4326(segObj.geometry.components[0].x, segObj.geometry.components[0].y));
  878. ShiftSegmentNodesLat(segObj, gpsOffsetAmount);
  879. //}
  880. }
  881. //Down
  882. function RAShiftDownBtnClick(e) {
  883. // this traps the click to prevent it falling through to the underlying area name element and potentially causing the map view to be relocated to that area...
  884. e.stopPropagation();
  885.  
  886. //if(!pendingChanges){
  887. var segObj = W.selectionManager.selectedItems[0];
  888. var gpsOffsetAmount = WazeWrap.Geometry.CalculateLatOffsetGPS(-$('#shiftAmount').val(), WazeWrap.Geometry.ConvertTo4326(segObj.geometry.components[0].x, segObj.geometry.components[0].y));
  889. ShiftSegmentNodesLat(segObj, gpsOffsetAmount);
  890. //}
  891. }
  892. })();
  893.  
  894. // JavaScript source code