WME Select Same Type Roads

This script add functionnality to select and modify roads

目前為 2018-03-18 提交的版本,檢視 最新版本

// ==UserScript==
// @name WME Select Same Type Roads
// @author buchet37
// @namespace https://gf.qytechs.cn/users/4062
// @description This script add functionnality to select and modify roads
// @match https://world.waze.com/editor*
// @match https://www.waze.com/editor*
// @match https://world.waze.com/map-editor*
// @match https://www.waze.com/map-editor*
// @include https://*.waze.com/editor*
// @include https://*.waze.com/*/editor*
// @include https://*.waze.com/map-editor*
// @include https://*.waze.com/beta_editor*
// @include https://descarte*.waze.com/beta*
// @include https://editor-beta.waze.com*
// @grant      none
// @version         4.9.22
// ==/UserScript==

// Based on Street to River ( http://userscripts.org/scripts/show/122049 )
// Thanks to alcolo47 (some functions are based on WME Extented Tools)
// Thanks to gdu1971, bgodette, Timbones for part of code
// Adapted by buchet37 for "Select Same Type Road"

// Mini howto:
// 1) install this script as greasemonkey script or chrome extension
// 2) Select 2 segments
// 3) Click the "Select Roads A<=>B" button
// The script will select all same type road between A and B with a limit of 50 segments

var WME_SSTR_version = "4.9.22" ;

if ('undefined' == typeof __RTLM_PAGE_SCOPE_RUN__) {
  (function page_scope_runner() {
    // If we're _not_ already running in the page, grab the full source
    // of this script.
    var my_src = "(" + page_scope_runner.caller.toString() + ")();";

    // Create a script node holding this script, plus a marker that lets us
    //F know we are running in the page scope (not the Greasemonkey sandbox).
    // Note that we are intentionally *not* scope-wrapping here.
    var script = document.createElement('script');
    script.setAttribute("type", "text/javascript");
    script.textContent = "var __RTLM_PAGE_SCOPE_RUN__ = true;\n" + my_src;

    // Insert the script node into the page, so it will run, and immediately
    // remove it to clean up.  Use setTimeout to force execution "outside" of
    // the user script scope completely.
    setTimeout(function() {
					document.body.appendChild(script);
          document.body.removeChild(script);
        }, 0);
  })();

  // Stop running, because we know Greasemonkey actually runs us in
  // an anonymous wrapper.
  return;
}

function selectSameTypeRoad() {

	var defaultWidth = "15 m";  //Default Width is equal to 15m

	// *****************   COMPATIBILITY WITH NEW EDITOR   ***********
	var WazeActionAddLandmark = require("Waze/Action/AddLandmark");
	var WazeActionAddOrGetCity = require("Waze/Action/AddOrGetCity");
	var WazeActionAddOrGetStreet = require("Waze/Action/AddOrGetStreet");
	//var WazeActionCreateObject = require("Waze/Action/CreateObject");
	var WazeActionCreateRoundabout = require ("Waze/Action/CreateRoundabout");
	var WazeActionDeleteSegment = require ("Waze/Action/DeleteSegment");
	//var WazeActionModifyConnection = require ("Waze/Action/ModifyConnection");
	var WazeActionMultiAction = require ("Waze/Action/MultiAction");
	var WazeActionUpdateObject = require("Waze/Action/UpdateObject");
	var WazeActionUpdateSegmentGeometry = require("Waze/Action/UpdateSegmentGeometry");
	var WazeFeatureVectorLandmark = require("Waze/Feature/Vector/Landmark");

  // *****************************************************************

	setTimeout (function () {insertButton();}, 10001);		//tempo
	
	function insertButton() {

		if(document.getElementById('WME_SSTR_All') != null) return;
		var WME_SSTR_ALL1 = create_WME_SSTR_ALL ();
			
	// ******* Mise en place des buttons      
		var WME_SSTR_ALL_Flag = false, myDialogBoxFlag = false;
		
		function put_WME_SSTR_ALL() {        // wait for 'sidebar'
		   if (document.getElementById('segment-edit-general')!=null) {
		   //if (document.getElementById('sidebar')!=null) {
					 $("#segment-edit-general").append(WME_SSTR_ALL1);
					 WME_SSTR_ALL_Flag = true;
				}
		   else {
					setTimeout (function () {put_WME_SSTR_ALL();}, 1001);
				}
		}
     
		put_WME_SSTR_ALL();
		
		// Boite d'alerte
		var myAlertBoxFlag = false;
		function put_myAlertBox() {
			if (document.getElementById('search')!=null) {
				if (document.getElementById('WME_JCB_AlertBox')==null) {
					var myAlertBox = $('<div id="WME_JCB_AlertBox" class="form-control search-query" style="opacity : 0.8;display :none;  height: auto;min-height: 30px; position: absolute;top :16px; margin-left: 350px; margin-right: auto; "/>');	
					var myAlertTxt = $('<div id="WME_JCB_AlertTxt" style=" opacity : 1;display:inline;padding:0px 0px">City ID/');
					myAlertBox.append(myAlertTxt);
					$("#search").append(myAlertBox);
				 }
				myAlertBoxFlag = true;
			}
			else {setTimeout (function () {put_myAlertBox();}, 501);}
		}
		put_myAlertBox();

		function start_init_WME_SSTR() {         // si tous les boutons sont chargés on démarre le script
			if (WME_SSTR_ALL_Flag && myAlertBoxFlag) {
				init_WME_SSTR();
			}
			else {setTimeout(function () {start_init_WME_SSTR();}, 501);}
		}
		start_init_WME_SSTR();
		return;
    }
	

  function put_WME_SSTR_button () {
	  if(document.getElementById('WME_SSTR_All') != null) return ;
	  if (W.selectionManager.selectedItems.length != 0 &&
		    W.selectionManager.selectedItems[0].model.type == "segment") {                       // s'il y aune selection de segment active
		  	  var WME_SSTR_ALL1 = create_WME_SSTR_ALL ();
			  	if (document.getElementById('segment-edit-general')!=null) {
		  		  $("#segment-edit-general").append(WME_SSTR_ALL1);           //on met le menu et on intilise les check box
					  if (localStorage['WME_SSTR_enable']=='true') {								// restaure old Values (if exist)
						  document.getElementById ('WME_SSTR_enable').checked = 1;}
					  if (localStorage['WME_SSTR_Smth']=='true') {
							document.getElementById ('WME_SSTR_SmthRvr').checked = 1;}
				  }
				  else {
						setTimeout (function () {put_WME_SSTR_button();}, 1001);  //autrement on attend
				  }
	  }
		return;
  }
	
	function create_WME_SSTR_ALL () {
		var chk1 = $('<Label style="font-weight:normal"><input type="checkbox"; style="vertical-align: middle;margin: 0px;" id="WME_SSTR_enable"	title="Enable or Disable WME SSTR">On-Off   </input></Label>');
		var chk2 = $('<Label style="font-weight:normal"><input type="checkbox"; style="vertical-align: middle;margin: 0px;" id="WME_SSTR_SmthRvr" title="Check for smoothing">Smooth</input></Label>');
		var url1 = $('<div style="font-size:12px;display: inline;"> <u><i><a href="https://gf.qytechs.cn/scripts/4715-wme-select-same-type-roads" target="_blank">Select Same Type Road ' + WME_SSTR_version+ '</a></i></u>');

		var btn1 = $('<button class="btn btn-default" style="padding:0px 8px; height:22px" title="Select 1 or more segments and click this button">Select Same Type Roads</button>');
		var btn2 = $('<button class="btn btn-default" style="padding:0px 8px; height:22px; margin-right:5px;" title="Select adjacent segment from node A">A =></button>');
		var btn3 = $('<button class="btn btn-default" style="padding:0px 8px; height:22px" title="Select adjacent segment from node B">B =></button>');
		var btn4 = $('<button class="btn btn-default" style="padding:0px 8px; height:22px" title="Start from segment 1 to join Segment 2 (if possible)">1 => 2</button>');
		var btn7 = $('<button class="btn btn-default" style="padding:0px 10px; height:22px; margin-right:5px; " title="Create a River from Street Geometry">Street => River</button>');
		var btn8 = $('<button class="btn btn-default" style="padding:0px 10px; height:22px" title="Select road(s) to make an Overall Landmark">Do Landmark</button>');
		var btn10= $('<button class="btn btn-default" style="padding:0px 10px; height:22px" title="Make a new roundabout from 1 segment of an old one">Redo Roundabout</button>');
		var btn12= $('<button class="btn btn-default" style="padding:0px 10px; height:22px; margin-right:5px; " title="click this button to suppress road geometry">Clear Road Geometry</button>');
		var btn13= $('<button class="btn btn-default" style="padding:0px 10px; height:22px" title="click this button to allow "All drives" and "All Turns" on selected roads)">All drives on Selection</button>');

		btn1.click	(select_same_type_roads);
		btn2.click	(Side_A);
		btn3.click	(Side_B);
		btn4.click	(select_AB);
		btn7.click	(Street_River);
		btn8.click	(Roads_to_Interchange);
		btn10.click (Redo_RoundAbout);
		btn12.click (Clear_Road_Geometry);
		btn13.click (All_drives_on_Selection);
		chk1.click (manage_WME_SSTR);
		chk2.click (manageSmoothRiver);
		
		WME_SSTR_ALL = $ ('<div id="WME_SSTR_All" style="height: auto;padding:2px 5px 2px 5px;margin:5px 0px 30px 0px;width:285px; border-width:3px; border-style:double;border-color: SkyBlue; border-radius:10px"/>');

		var cnt0 = $('<section id="WME_SSTR_lnk"		style="padding-top:2px"/>'); cnt0.append(chk1);cnt0.append(" ");cnt0.append(url1);
		var cnt1 = $('<section id="WME_SSTR"				style="padding-top:2px; margin-right:5px; display:inline;"/>'); cnt1.append(btn1);
		var cnt2 = $('<section id="WME_SSTR_Side"		/>'); cnt2.append(btn2);cnt2.append(btn3);
		var cnt3 = $('<section id="WME_SSTR_12"			/>'); cnt3.append(btn4);
		var cnt4 = $('<section id="WME_SSTR_River"	style="padding-top:5px"/>'); cnt4.append(btn7); cnt4.append(chk2);
		var cnt6 = $('<section id="WME_SSTR_Ldmk"		style="padding-top:5px"/>'); cnt6.append(btn8);
		var cnt7 = $('<section id="WME_SSTR_Rdt"		style="padding-top:5px; padding-bottom:5px"/>'); cnt7.append(btn10);
		var cnt8 = $('<section id="WME_SSTR_CrgAds"	style="padding-top:5px"/>'); cnt8.append(btn12); 
		// cnt8.append(btn13);

		WME_SSTR_ALL.append(cnt0);
		WME_SSTR_ALL.append(cnt1);
		WME_SSTR_ALL.append(cnt2);
		WME_SSTR_ALL.append(cnt3);
		WME_SSTR_ALL.append(cnt4);
		WME_SSTR_ALL.append(cnt6);
		WME_SSTR_ALL.append(cnt7);
		WME_SSTR_ALL.append(cnt8);

		return WME_SSTR_ALL;
	}
	
	function Clear_Road_Geometry(ev) {
		if (W.selectionManager.selectedItems.length!=0) {
			if (confirm ("Do you want to clear the geometry for selected segments") ) {
				for (var i = 0; i < W.selectionManager.selectedItems.length; i++) {
					var seg = W.selectionManager.selectedItems[i].model;
					if (seg.type == "segment") {
						var newGeo = seg.geometry.clone();
						newGeo.components.splice(1,newGeo.components.length -2);														// on garde le 1er et le dernier point
						newGeo.components[0].calculateBounds();
						newGeo.components[1].calculateBounds();
						W.model.actionManager.add (new WazeActionUpdateSegmentGeometry (seg,seg.geometry,newGeo));
					}
				}
			}
		}
	}
	
	function All_drives_on_Selection(ev) {
		if (W.selectionManager.selectedItems.length!=0) {
			var action = [];
			var nodeToAllowed = [];
			var selectRoadIDs = [];
			for (var i = 0; i < W.selectionManager.selectedItems.length; i++) {
				var seg = W.selectionManager.selectedItems[i].model;
				if (seg != null && seg.type == "segment" && !seg.attributes.locked && seg.attributes.junctionID == null) {
				selectRoadIDs.push (seg.getID());
				action.push (new WazeActionUpdateObject( seg, {fwdDirection: true, revDirection: true}));		// pass to two ways
					if (W.model.nodes.objects[seg.attributes.fromNodeID]!= null) {																			// store node A
						nodeToAllowed.push (seg.attributes.fromNodeID);	}
					if (W.model.nodes.objects[seg.attributes.toNodeID]!= null) {																				// store node B
						nodeToAllowed.push (seg.attributes.toNodeID);}
				}
			}
			nodeToAllowed = areTwice (nodeToAllowed);																						// on ne traite que les segments inttermédiaires
			for (var l = 0; l < nodeToAllowed.length; l++) {
				var node = W.model.nodes.objects[nodeToAllowed[l]];
				var roadIDs =	node.attributes.segIDs;
				for (var j = 0; j < roadIDs.length; j++) {
					for (var k = 0; k < roadIDs.length; k++) {
						if (roadIDs[j]!= roadIDs[k] && isInArray (roadIDs[j],selectRoadIDs) && isInArray (roadIDs[k],selectRoadIDs)) {
							action.push (new WazeActionModifyConnection(roadIDs[j], node, roadIDs[k], true));
						}
					}
				}
			}
			if (action.length !=0) { W.model.actionManager.add (new WazeActionMultiAction(action));}
//alert ("On va au bout");
		}
	}

	function areTwice (myArray) {
		var myNewArray = [];
		if (myArray.length > 0) {
			for (var i = 0; i < myArray.length-1; i++) {
				for (var j = i+1; j < myArray.length; j++) {
					if (myArray [i] == myArray[j]) {
						myNewArray.push(myArray [i]);
					}
				}
			}
			return delete_multi_Ids(myNewArray);
		}
		else {
			return (myArray);
		}
	}
	
	function Redo_RoundAbout (ev) {
		var selectedGood = (W.selectionManager.selectedItems.length!=0);
		if (selectedGood) {
			var listRoadIds = [];
			if (W.selectionManager.selectedItems[0].model.attributes.junctionID !=null) {			// si c'est un rdt , on selectionne tout le rdt
				var sel = W.selectionManager.selectedItems[0].model;
				var junc = W.model.junctions.objects[sel.attributes.junctionID];
//alert (junc);
				listRoadIds = junc.segIDs;
				}
			else {
				for (var i = 0; i < W.selectionManager.selectedItems.length; i++) {								// sinon on prend tous les egments selectionnés
					var sel = W.selectionManager.selectedItems[i].model;
					listRoadIds.push (sel.getID());
				}
			}
			var oldRdt = extract_rdt (listRoadIds);

			if (oldRdt.higherRank == false) {
				var action = [];
				for (var j = 0; j < oldRdt.listRoadIds.length; j++) {
					var seg = W.model.segments.objects[oldRdt.listRoadIds[j]];
					W.model.actionManager.add (new WazeActionDeleteSegment(seg));																// ******* Delete old Roundabout
				}

				for (var i = 0; i < oldRdt.listAdjRoadIds.length; i++) {
					var seg = W.model.segments.objects[oldRdt.listAdjRoadIds[i].id];
					var newGeo = seg.geometry.clone();
					if (oldRdt.listAdjRoadIds[i].sideConnect == "A") {
						var index1 =0;
						var index2 =1;
						var nodeEnd = W.model.nodes.objects [seg.attributes.toNodeID];
					}
					else {
						var index1 = newGeo.components.length-1;
						var index2 = newGeo.components.length-2;
						var nodeEnd = W.model.nodes.objects [seg.attributes.fromNodeID];
					}

					if (nodeEnd !=null && onScreen(nodeEnd) && nodeEnd.attributes.segIDs.length <2) {
						W.model.actionManager.add (new WazeActionUpdateObject(seg, {fwdDirection: true, revDirection: true}));} 			// dead-end is always two ways roads	
					if (!seg.attributes.fwdDirection && !seg.attributes.revDirection) {																								// unknown roads are fixed to two ways roads
						W.model.actionManager.add (new WazeActionUpdateObject(seg, {fwdDirection: true, revDirection: true}));}

					var deltaX = newGeo.components[index1].x - newGeo.components[index2].x;
					var deltaY = newGeo.components[index1].y - newGeo.components[index2].y;
					var angle = angleDeg (deltaX,deltaY);
					var meanExt = 0.10 * (oldRdt.dim.rx + oldRdt.dim.ry);
					newGeo.components[index1].x = newGeo.components[index1].x + meanExt* Math.cos(convertDegRad(angle));
					newGeo.components[index1].y = newGeo.components[index1].y + meanExt* Math.sin(convertDegRad(angle));
					newGeo.components[index1].calculateBounds(); 
					W.model.actionManager.add(new WazeActionUpdateSegmentGeometry (seg,seg.geometry,newGeo));
				}
				var action1 = new WazeActionCreateRoundabout(oldRdt.dim);				// créé le nouveau rdt sur les bases géométrique de l'ancien
				W.model.actionManager.add (action1);

				var rbtRoadIds = W.model.junctions.objects[action1.roundaboutSegments[0].attributes.junctionID].segIDs;  //recup Id segments
				newRdt = searchNewRdt (rbtRoadIds,oldRdt.primaryStreetID);									
				var action2 = [];
				for (var k = 0; k < rbtRoadIds.length; k++) {
					var road = W.model.segments.objects[rbtRoadIds[k]];
					W.model.actionManager.add(new WazeActionUpdateObject(road, {
								roadType: newRdt.roadtype, level: oldRdt.level, lockRank: "0", primaryStreetID: oldRdt.primaryStreetID} ));
				}
				//Waze.model.actionManager.add(new WazeActionMultiAction(action2));
				select (rbtRoadIds);
			}
			else {
				alert ("Your ranking is not higher\nto redo this roundabout");
			}
		}
		else {
			alert ("Incorrect Selection : \n\nOne segment must be selected \nOr It is not Roundabout Segment");
		}
	}

	function onScreen(obj){
    if (obj.geometry){
      return(W.map.getExtent().intersectsBounds(obj.geometry.getBounds()));}
    return false;
	}

	function searchNewRdt (listRdtSegIds,StreetID) {
		var roadpriority = [];
			roadpriority [1]  = 0; 	//"Streets"
			roadpriority [2]  = 1; 	//"Primary Street"
			roadpriority [3]  = 3;  //"Freeways"
			roadpriority [4]  = 2;	//"Ramps"
			roadpriority [6]  = 3;	//"Major Highway"
			roadpriority [7]  = 2;	//"Minor Highway"
			roadpriority [8]  = 0;	//"Dirt roads"
			roadpriority [18] = 0;  //"Railroad"
			roadpriority [19] = 0;	//"Runway/Taxiway"
			roadpriority [20] = 0;  //"Parking Lot Road"
			roadpriority [5]  = 0; 	//"Walking Trails"
			roadpriority [10] = 0;  //"Pedestrian Bw"
			roadpriority [16] = 0;	//"Stairway"
			roadpriority [17] = 0;  //"Private Road"
			roadpriority [21] = 0;  //"Service Road"

		var priorityToRoadtype = [];
			priorityToRoadtype [0] = 1; 	//"Streets"
			priorityToRoadtype [1] = 2; 	//"Primary Street"
			priorityToRoadtype [2] = 7;	//"Minor Highway"
			priorityToRoadtype [3]= 6;	//"Major Highway"

		var compteur = [0,0,0,0];																						//array for number of roads by type
		var listRdtNodeIds = [];

		for (var i = 0; i < listRdtSegIds.length; i++) {
			var road = W.model.segments.objects[listRdtSegIds[i]];
			if (road != null) {
				listRdtNodeIds.push (road.attributes.fromNodeID);
				listRdtNodeIds.push (road.attributes.toNodeID);
			}
		}
		listRdtNodeIds = delete_multi_Ids (listRdtNodeIds);

		var usedNodeIDs = [];
		usedNodeIDs.push.apply (usedNodeIDs,listRdtNodeIds);
		var rdt = {};
		var action = [];
		for (var j = 0; j <listRdtNodeIds.length; j++) {															// Search connected Segments
			var node = W.model.nodes.objects[listRdtNodeIds[j]];
			if (node != null) {
				var nbSegs = node.attributes.segIDs.length;
				for (var k = 0; k < nbSegs;k++) {
					var road = W.model.segments.objects[node.attributes.segIDs[k]];
					if ((road != null) && (notInArray (road.getID(),listRdtSegIds))) {	
 						if (road.attributes.roadType == 3 ) {
								W.model.actionManager.add (new WazeActionUpdateObject(road, {roadType: 6}));}	// Freeways are not allowed in roundabout
						if (notInArray(road.attributes.roadType,([1,2,3,4,6,7]))) {	
								W.model.actionManager.add (new WazeActionUpdateObject(road, {roadType: 1}));}		// Road type on roundabout should be at least "Street"
						if (road.attributes.primaryStreetID == null && StreetID != null) {
								W.model.actionManager.add(new WazeActionUpdateObject(road, {primaryStreetID: StreetID}));	}		// Unnamed Roads are named as the rdt
						if (notInArray(road.attributes.fromNodeID,usedNodeIDs) ||  notInArray(road.attributes.toNodeID,usedNodeIDs)) {
							compteur [roadpriority[road.attributes.roadType]] ++;
							usedNodeIDs.push (usedNodeIDs, road.attributes.fromNodeID);
							usedNodeIDs.push (usedNodeIDs, road.attributes.toNodeID);
						}
					}	
				}
			}
		}

		rdt.roadtype = priorityToRoadtype [0];
		var foundMax = false;
		for (var k = 3; k > 0; k --) {
			if (compteur[k] > 1) {
				rdt.roadtype = priorityToRoadtype [k];
				break;
				}
			else {
				compteur [k-1] = compteur[k-1] + compteur[k];
			}
		}
//alert ("fin du new rdt")
		if (action.length !=0) {W.model.actionManager.add ( new WazeActionMultiAction(action));}				// do modifications if there are 
		return rdt;
	}

	function extract_rdt (listIDs) {
		var rdt = {};
		rdt.listAdjRoadIds = [];
		rdt.higherRank = false;
		rdt.listRoadIds = listIDs;
		rdt.listNodeIds = [];
		var xmin =  10000000000000; var ymin = xmin;
		var xmax = -10000000000000; var ymax = xmax;
		for (var i = 0; i<listIDs.length;i++) {
			var road = W.model.segments.objects[listIDs[i]];
			if (road != null) {
				rdt.listNodeIds.push (road.attributes.fromNodeID);													//stocke les nodes
				rdt.listNodeIds.push (road.attributes.toNodeID);
				rdt.higherRank = rdt.higherRank || road.isLockedByHigherRank();							// stocke si on a les droits
				for (var j = 0; j < road.geometry.components.length;j++) {									//extrait les dimensions du rdt
					var pt = road.geometry.components[j];
					xmin = Math.min(xmin,pt.x); xmax = Math.max(xmax,pt.x);
					ymin = Math.min(ymin,pt.y); ymax = Math.max(ymax,pt.y);
				}
			}
		}

		var ray_X = Math.min (parseInt(144),(xmax-xmin)/2);
		var ray_Y = Math.min (parseInt(144),(ymax-ymin)/2);
		if (Math.abs (ray_X - ray_Y) < (0.15 * ray_X)) {							// if diam x near diam y => Circle with mean value
			rdt.dim = {rx: (ray_X+ray_Y)/2, ry: (ray_X+ray_Y)/2};}
		else {
			rdt.dim = {rx: ray_X, ry: ray_Y};}
		rdt.dim.center = {x:((xmin+xmax)/2),y:((ymin+ymax)/2)};
		rdt.dim.bounds = new OpenLayers.Bounds(
		rdt.dim.center.x - rdt.dim.rx, rdt.dim.center.y - rdt.dim.ry, rdt.dim.center.x+rdt.dim.rx, rdt.dim.center.y +rdt.dim.ry);

		rdt.listNodeIds = delete_multi_Ids(rdt.listNodeIds);													//extrait les node du rdt
		rdt.level = -5;	
		var roadIDs =[];
		for (var i = 0; i <rdt.listNodeIds.length; i++) {															// Search connected Segments
			var node = W.model.nodes.objects[rdt.listNodeIds[i]];
			if (node != null) {
				var nbSegs = node.attributes.segIDs.length;
				roadIDs = roadIDs.concat(node.attributes.segIDs);								  				//collect roadsIds connect to rdt
				for (var j=0; j<nbSegs;j++) {
					var road = W.model.segments.objects[node.attributes.segIDs[j]];
					if ((road != null) && (notInArray (road.getID(),listIDs))) {
						rdt.higherRank = rdt.higherRank || road.isLockedByHigherRank();				// test if locked at higher rank
						rdt.level = Math.max (rdt.level,road.attributes.level +1);					//calcule le future level
						if (isInArray (road.attributes.fromNodeID,rdt.listNodeIds)) {
							rdt.listAdjRoadIds.push ({id:road.getID(),sideConnect :"A"});
						}				
						if (isInArray (road.attributes.toNodeID,rdt.listNodeIds)) {
							rdt.listAdjRoadIds.push ({id:road.getID(),sideConnect :"B"});
						}					
					}	
				}
			}
		}
		// ************** Récupère la ville **********
		roadIDs = delete_multi_Ids(roadIDs);
		var cityName = [];
		for (var i = 0; i <roadIDs.length; i++) {	
			var sel = W.model.segments.objects[roadIDs[i]];
			var streetID = sel.attributes.primaryStreetID;
			if (streetID && W.model.streets.objects[streetID]) {
				var street = W.model.streets.objects[streetID];
				if (street.cityID && W.model.cities.objects[street.cityID]) {
				  var city = W.model.cities.objects[street.cityID];
					if (city && city.name !="") {
						cityName.push(city.name);
					}
				}
			}
		}
//alert(cityName)
		cityName = delete_multi_Ids(cityName);
		if (cityName.length!=1) {cityName[0]='';}
		rdt.primaryStreetID = SearchPrimaryID (streetID, cityName[0], "");
		return rdt;
	}

	function SearchCityID (country_ID, state_ID, cityName) {
		var	fattr = {countryID: country_ID, stateID: state_ID, name : cityName };
// afficheObjet (fattr);
		var city = W.model.cities.getByAttributes(fattr);
    if (city.length === 0) {
      myAlert ("Create new city: "+cityName);
			var state = W.model.states.objects[state_ID];
			var country = W.model.countries.objects[country_ID];

			var f = new WazeActionAddOrGetCity(state,country,cityName);
			W.model.actionManager.add(f);
			return f.city.getID();
    }
    if (city.length === 1) {return city[0].getID();}
    if (city.length > 1) {
      myAlert ("Problems with cityID : "+city.length+" cities with same name. Please save and redo");
      return null;
    }
    return null;
  }

	function SearchPrimaryID (oldStreetID,newCityName,newStreetName) {
		var oldStreet = W.model.streets.objects[oldStreetID];
    var oldCity   = W.model.cities.objects[oldStreet.cityID];
    var newCityID = SearchCityID (oldCity.countryID, oldCity.stateID, newCityName);
		if (newCityID == null) {return null;}
    if (newStreetName == null) {newStreetName = "";}
    var emptyst = (newStreetName =="");
    var fattr = {cityID: newCityID, isEmpty: emptyst};
    if (emptyst == false) {fattr.name = newStreetName;}
    var st = W.model.streets.getByAttributes(fattr);

		if (st.length === 0) {					// la rue n'existe pas
			myAlert ("Create new street: "+newCityName+"  "+newStreetName);
			var newCity = W.model.cities.objects[newCityID];
			var a = new WazeActionAddOrGetStreet(newStreetName,newCity,emptyst);
			W.model.actionManager.add(a);
			return a.street.getID();
    }
    if (st.length === 1) {return st[0].getID();}
    if (st.length > 1) {
      myAlert ("Problems with StreetID : "+st.length+" streets with same name. Please save and redo");
      return null;
    }
		return null;
  }

	function Roads_to_Interchange(ev) {
		var foundSelectedSegment = false;
		var selectedGood = (W.selectionManager.selectedItems.length>0);
		var roadIds = [];
		for (var i = 0; i<W.selectionManager.selectedItems.length;i++) { 					// Test if selection are segment
			var sel = W.selectionManager.selectedItems[i].model;
			selectedGood = ((selectedGood) && (sel.type == "segment"));
			if ((selectedGood)&& (sel.attributes.junctionID!=null)) {						// if it is a roundabout we add all Rdt segs 
				var jId = sel.attributes.junctionID;
				var junc = W.model.junctions.objects[jId];
				roadIds.push.apply (roadIds,junc.segIDs);									// we add all segment of the roundabout
			}
			if (selectedGood) {	roadIds.push ( sel.getID());}								// stocke les segments
		}
		if ((selectedGood) &&( roadIds.length != 0)) {
			roadIds = delete_multi_Ids (roadIds);											// delete double roads
			var totalPoints = [];
			var name;
			var leftEnv = [];
			var rightEnv = [];
			var typeLandmak;
			leftEnv.push ({x: 100000000000000,y:2000000000});
			var yMax = -100000000000;
//alert (roadIds);
			for (var k = 0; k<roadIds.length;k++) { 
				var sel = W.model.segments.objects[roadIds[k]];
//alert (sel.getID());
				if (name == null) {name = getStreet(sel).name;}
				if (typeLandmak == null) {
					switch (sel.attributes.roadType) {
						case 1: //"Streets"
						case 2: //"Primary Street"
						case 3: //"Freeways"
						case 4: //"Ramps"
						case 6: //"Major Highway"
						case 7: //"Minor Highway"
							//typeLandmak = ["JUNCTION_INTERCHANGE"]; break;// Jonction/interchange
							typeLandmak = "JUNCTION_INTERCHANGE"; break;// Jonction/interchange
						case 8: //"Dirt roads"
						case 18: //"Railroad"
						case 19: //"Runway/Taxiway"
						case 20: //"Parking Lot Road"
							typeLandmak = "PARKING_LOT"; break;						// ParkingLot
						case 5: //"Walking Trails"
						case 10: //"Pedestrian Bw"
						case 16: //"Stairway"
						case 17: //"Private Road"
						case 21: //"Service Road"
							typeLandmak = "PARK"; break;												// Park	
					}
				}

				for (var j = 0; j < sel.geometry.components.length;j++) {
					totalPoints.push (sel.geometry.components[j].clone());
					if (leftEnv[0].y > sel.geometry.components[j].y) {									// Stocke le Y mini
						leftEnv[0]  = sel.geometry.components[j].clone();
						rightEnv[0] = sel.geometry.components[j].clone();
					}
					if (sel.geometry.components[j].y > yMax) { yMax = sel.geometry.components[j].y;}
				}
			}

			while ( rightEnv[rightEnv.length-1].y <yMax) {												// traitement de la voie droite
				var anglemin = 190;
				for (var i = 0; i<totalPoints.length;i++) {
					if (totalPoints[i].y > rightEnv[rightEnv.length-1].y) {
						var deltaX = totalPoints[i].x - rightEnv[rightEnv.length-1].x;
						if (deltaX !=0) {
							var deltaY = totalPoints[i].y - rightEnv[rightEnv.length-1].y;
							var angle = angleDeg( deltaX , deltaY);
							if (angle < anglemin) {
								anglemin = angle;
								var iMin = i;
							}
						}
					}
				} 
				rightEnv.push (totalPoints[iMin]);
			}

			while ( leftEnv[leftEnv.length-1].y <yMax) {													// traitement de la voie droite
				var anglemax = 0;
				for (var i = 0; i<totalPoints.length;i++) {
					if (totalPoints[i].y > leftEnv[leftEnv.length-1].y) {
						var deltaX = totalPoints[i].x - leftEnv[leftEnv.length-1].x;
						if (deltaX !=0) {
							var deltaY = totalPoints[i].y - leftEnv[leftEnv.length-1].y;
							var angle = angleDeg( deltaX , deltaY);
							if (angle > anglemax) {
								anglemax = angle;
								var iMax = i;
							}
						}
					}
				} 
				leftEnv.push (totalPoints[iMax]);
			}

			leftEnv.shift(); leftEnv.pop();																//On ote le premier et le dernier point( communs avec droite)			
			rightEnv.push.apply (rightEnv,leftEnv.reverse ());						//on ajoute la partie Gauche
			var dummy = doLandmark (rightEnv,name,typeLandmak);						// make the landmark
			alert("Successfully created Landmark");}
		else {
			alert("Incorrect Selection : \n\nOne segment must be selected \nOr It is not RoundAbout Segment");
		}
	}

	function doLandmark (geometry,nameLandmak,typeLandmark) {
		var polyPoints = null;
		for (var i = 0; i<geometry.length;i++) {
			if (polyPoints == null) {
				polyPoints = [geometry[i]]; 
				var ri = new OpenLayers.Geometry.Point(geometry[i].x, geometry[i].y);
				polyPoints.push(ri);
				}
			else {
				var ri = new OpenLayers.Geometry.Point(geometry[i].x, geometry[i].y);
				polyPoints.push(ri);
			}
		}
		var polygon = new OpenLayers.Geometry.Polygon(new OpenLayers.Geometry.LinearRing(polyPoints));
		var landmark = new WazeFeatureVectorLandmark();
		landmark.geometry = polygon;
		landmark.attributes.name = nameLandmak;
		landmark.attributes.categories [0] = typeLandmark;
		var what = W.model.actionManager.add(new WazeActionAddLandmark(landmark));
	//	activateLayer ("landmarks", true );
		return true; 
	}

	function Street_River (ev) {
		var selectedGood = (W.selectionManager.selectedItems.length==1);
		var sel = W.selectionManager.selectedItems[0].model;
		selectedGood = selectedGood && (sel.type == "segment") && (sel.attributes.roadType != "18");
		if (selectedGood) {
			var offset = getDisplacement();																						// valeur en mètres
			if (offset == null) {
				return;}
			var name = getStreet(sel).name;
			var points = StreetToLandmark (sel, offset); 
			var dummy = doLandmark (points,name,"RIVER_STREAM");	// river	
			alert("Successfully created a River Landmark");}
		else {
			alert("Incorrect Selection : \n\nOne segment must be selected \nOr It is not Street Segment");
		}
	}

	function getDisplacement() {
		var scale = 1.44449796;																				// Scale mètres => coordonnées waze			
		var width = prompt ("Enter new Width or leave it to old value ",defaultWidth);
		if (width == null) {
			return null; }
		else {
			if (width.match("m","g")) {
				width =parseInt(width);
				if (width < 1) {width = 1;}					//minimum width equal to 1m
				if (width >100) {width = 100;}		  //maximum width equal to 100m
				defaultWidth=width+" m";
				return width * scale / 2;			
			}
			if (width.match("ft","g")) {
				width =parseInt(width);
				if (width < 3) {width =3;}					//minimum width equal to 3 ft
				if (width > 300) {width =300;}			//maximum width equal to 300 ft
				defaultWidth=width+" ft";
				return width * 0.3048 * scale /2;
			}
			width=15;
			defaultWidth="15 m";
			return width * scale / 2;
		}
  }

	function StreetToLandmark (seg,offset) {
		var decal = decalage (seg.geometry.components, offset);
		if (document.getElementById ('WME_SSTR_SmthRvr').checked == 1) {	
			decal.dir = optGeometry (decal.dir);
			decal.sym = optGeometry (decal.sym);
			decal.dir = b_spline (decal.dir);												// creation des B - splines X & Y
			decal.sym = b_spline (decal.sym);
			decal.dir = sup_unneed (decal.dir);											// delete aligned points
			decal.sym = sup_unneed (decal.sym);											// delete aligned points
		}
		decal.dir.push.apply  (decal.dir,decal.sym.reverse());		// on rajoute le trajet retour
		return decal.dir;
	}

	function sup_unneed (decal) {
		for (var phase = 0; phase < 3; phase ++) {
			var decal1 = [];
			decal1 [0] = decal [0];
			for (var i = 1; i< decal.length-2; i++) {
				if ((decal1[decal1.length-1].x != decal[i+1].x) && (decal[i+1].x != decal[i+2].x)) {															// non vertical => can calculate Atan				
				var angle1 = ((decal1[decal1.length-1].y  - decal[i+1].y) / (decal1[decal1.length-1].x - decal[i+1].x));
					var angle2 = ((decal[i+1].y - decal[i+2].y) / (decal[i+1].x - decal[i+2].x));
					var length1 = longueur (decal1[decal1.length-1].x,decal1[decal1.length-1].y,decal[i+1].x,decal[i+1].y);
					if (testUnneed (angle1,angle2,length1,phase)) {
						decal1.push (decal[i+1]);
					}
				}
				else {
					decal1.push (decal[i+1]);
				}
			}
			decal1.push (decal[decal.length-1]);
			decal = decal1;
		}
		return decal1;
	}

	function testUnneed (angle1,angle2,longueur,phase) {
		var deltaAngle = Math.abs (AtanDeg (angle1) - AtanDeg (angle2));	
		switch (phase) {
			case 0: if ((deltaAngle < 45) && (longueur < 10))	{return false;}; break;
			case 1: if ((deltaAngle < 1 ) && (longueur >= 10) && (longueur < 250)) {return false;}; break;
			case 2: if ((deltaAngle < 2 ) && (longueur >= 10) && (longueur < 50 )) {return false;}; break;
		}
		return true;
	}

	function optGeometry ( line) {
		var opt = [];
		opt[0] = line[0].clone();
		for (var i = 1; i< line.length; i++) {
			var deltaX = line[i].x-line[i-1].x;
			var deltaY = line[i].y-line[i-1].y;
			opt.push ({x: line[i-1].x + deltaX * 0.33, y: line[i-1].y + deltaY * 0.33}); // add 2 extra control points
			opt.push ({x: line[i-1].x + deltaX * 0.66, y: line[i-1].y + deltaY * 0.66});		
			opt.push ({x: line[i].x, y: line[i].y});
		}
		return opt;
	}

	function decalage (geom,offset) {	
		var decal = {};
		decal.dir = [];																					// décalage d'un coté
		decal.sym = [];																					// décalage de l'autre
		decal.dir[0] = geom[0].clone();
		decal.sym[0] = geom[0].clone();
		if (Math.abs(geom[1].x - geom[0].x) < 0.1) {geom[1].x = geom[0].x+0.1;}															// traitement de la verticalité
		var deltaX = geom[1].x - geom[0].x;
		var deltaY = geom[1].y - geom[0].y;
		var angle = Math.atan (deltaY/deltaX);	
		decal.dir[0].x = geom[0].x - sign (deltaX) * offset * Math.sin (angle);
		decal.dir[0].y = geom[0].y + sign (deltaX) * offset * Math.cos (angle);
		decal.sym[0].x = geom[0].x + sign (deltaX) * offset * Math.sin (angle);
		decal.sym[0].y = geom[0].y - sign (deltaX) * offset * Math.cos (angle);

		var aprev = deltaY / deltaX;
		var b = geom[0].y - aprev * geom[0].x;										// y = ax+b

		var off1 = sign(deltaX) *  offset / Math.cos (angle);
		var bprev = b + off1;	var bprev1 = b - off1;
		for (var i = 1; i < geom.length-1; i++) {
			if (Math.abs(geom[i+1].x - geom[i].x)< 0.1) {geom[i+1].x = geom[i].x+0.1;}															// traitement de la verticalité
			deltaX = geom[i+1].x - geom[i].x; 
			deltaY = geom[i+1].y - geom[i].y;
			var anext = deltaY / deltaX;
			b = geom[i].y - anext * geom[i].x;
			angle = Math.atan (deltaY/deltaX);
			off1 = sign(deltaX) * offset / Math.cos (angle);
			var bnext = b + off1;	var bnext1 = b - off1;

			var x1 = -(bprev - bnext) / (aprev - anext);
			var x2 = -(bprev1 - bnext1) / (aprev - anext);
			decal.dir.push ({x: x1, y: (aprev * x1 + bprev)});											// décalage d'un coté
			decal.sym.push ({x: x2, y: (aprev * x2 + bprev1)});										  // décalage de l'autre coté

			aprev = anext;
			bprev = bnext;	bprev1 = bnext1;
		}
																																							// derniers point
		decal.dir.push ({x: (geom[i].x - sign(deltaX) * offset * Math.sin (angle)),y: (geom[i].y + sign(deltaX) * offset * Math.cos (angle))});  
		decal.sym.push ({x: (geom[i].x + sign(deltaX) * offset * Math.sin (angle)),y: (geom[i].y - sign(deltaX) * offset * Math.cos (angle))});
		return decal;
	}

	function b_spline (ligne) {
		var ligne1 = [];
		ligne1 [0] = ligne [0];
		for (var j = 1; j < ligne.length-2;j++) {
			var t = 4; 																															// nombre de sous-segments
			for (var i = 0; i < 1;i+=1/t) {
				var x1 = ((1-i)*(1-i)*(1-i)*ligne[j-1].x + (3*i*i*i -6*i*i +4)*ligne[j].x + (-3*i*i*i +3*i*i +3*i +1)*ligne[j+1].x + i*i*i*ligne[j+2].x)/6;
				var y1 = ((1-i)*(1-i)*(1-i)*ligne[j-1].y + (3*i*i*i -6*i*i +4)*ligne[j].y + (-3*i*i*i +3*i*i +3*i +1)*ligne[j+1].y + i*i*i*ligne[j+2].y)/6;
				ligne1.push ({x: (x1), y: (y1)});
			}
		}
		ligne1.push( ligne[ligne.length-1] );
		return ligne1;
	}

	function getStreet(segment) {
		if (!segment.attributes.primaryStreetID)
      return null;
    var street = segment.model.streets.get(segment.attributes.primaryStreetID);
    return street;
  }

  function select_same_type_roads(ev) {
		var nbRoad = W.selectionManager.selectedItems.length;
		var selectedGood = true;																									// selection must have 1 or 2 items
		for (var i = 0; i<nbRoad;i++) { 																					// Test if selection are segment
			var sel = W.selectionManager.selectedItems[i].model;
			selectedGood = ((selectedGood) && (sel.type == "segment"));
		}

		if (selectedGood) {
			var Select_IDs =[];                     											  //tableau de stockage des Routes electionnées
			for (var j = 0; j < nbRoad; j++) {
				var sel = W.selectionManager.selectedItems[j].model;
				if (sel.attributes.junctionID!=null) {															  // It's un roundabout
					var jId = sel.attributes.junctionID;
					var junc = W.model.junctions.objects[jId];
					Select_IDs.push.apply(Select_IDs,junc.segIDs);}											// Add to pervious selected Ids
				else {
					var roadFrom = sel.attributes.fromNodeID;
					var nodeFrom = W.model.nodes.objects[roadFrom];										// recherche à partir du premier noeud
					var segList = searchRoad(nodeFrom,sel,"0");					
					Select_IDs.push.apply(Select_IDs,segList.IDs);											// Add to pervious selected Ids
					var roadTo =  sel.attributes.toNodeID;
					var nodeTo = W.model.nodes.objects[roadTo];												// recherche à partir du deuxième noeud					
					var segList = searchRoad(nodeTo,sel,"0");			
					Select_IDs.push.apply(Select_IDs,segList.IDs);											// Add to pervious selected Ids
				}
			}
			select (Select_IDs);
		}
		if (!selectedGood) { alert("You must select road(s)");}
  }

	function Side_A(ev) {
		var nbRoad = W.selectionManager.selectedItems.length;
		var sel = W.selectionManager.selectedItems[0].model;
		if ((nbRoad == 1) && (sel.type == "segment")) {						
			var roadFrom = sel.attributes.fromNodeID;
			var nodeFrom = W.model.nodes.objects[roadFrom];												// recherche à partir du noeud A
			var segList = searchRoad(nodeFrom,sel,"0");
			select (segList.IDs);
			}
		else {
			alert ("One segment (and only one)\nmust be selected");
		}	
	}

	function Side_B(ev) {
		var nbRoad = W.selectionManager.selectedItems.length;
		var sel = W.selectionManager.selectedItems[0].model;
		if ((nbRoad == 1) && (sel.type == "segment")) {						
			var roadTo =  sel.attributes.toNodeID;
			var nodeTo = W.model.nodes.objects[roadTo];															// recherche à partir du noeud	A					
			var segList = searchRoad(nodeTo,sel,"0");
			select (segList.IDs);}
		else {
			alert ("One segment (and only one)\nmust be selected");
		}	
	}

	function select_AB(ev)  {
		var nbRoad = W.selectionManager.selectedItems.length;															// **** Validate selection *****
		var selectedGood = (nbRoad == 2);																													// selection must have 2 items
		if (selectedGood) {
			var sel = W.selectionManager.selectedItems[0].model;
			var sel1 = W.selectionManager.selectedItems[1].model;
			selectedGood = ((sel.type == "segment") && (sel1.type == "segment"));											// Test if selection are segment
			selectedGood = ((selectedGood) && (sel.attributes.roadType == sel1.attributes.roadType));	// Test if selection have same road Type
		}
		if (selectedGood) {
			var lengthMin = 1000000;
			var goodTrip = [];
			var select1 = select_12(sel,sel1);
			if (select1[select1.length-1] == sel1.getID()) {																								// on a trouvé un chemin dans ce sens
				goodTrip = select1;
				lengthMin = lengthTrip (select1);	
				}
			var select2 = select_12(sel1,sel);
			
			if ((select2[select2.length-1] == sel.getID()) && (lengthTrip (select2) < lengthMin)){					// on a trouvé un chemin dans ce sens
					goodTrip = select2;
					lengthMin = lengthTrip (select2);
			}
			var nodeTrip1 = nodeFromTrip (select1);																												// ******* search for Common Nodes
			var nodeTrip2 = nodeFromTrip (select2);
			var CommonNode = [];	
			for (var m = 0; m < nodeTrip1.length; m++) {
				if (isInArray (nodeTrip1[m],nodeTrip2)) {
					CommonNode.push (nodeTrip1[m]);
				}
			}

			if (CommonNode.length !=0) {																																								
				for (var i = 0; i < CommonNode.length; i++) {
					var select3 = [];
					var road = W.model.segments.objects[select1[0]];
					for (var j = 0; ((road.attributes.fromNodeID != CommonNode[i]) && (road.attributes.toNodeID != CommonNode[i])); j++) {
						select3.push (road.getID());
						road = W.model.segments.objects[select1[j]];
					}
					select3.push (road.getID());
					road = W.model.segments.objects[select2[0]];
					for (var k = 0; ((road.attributes.fromNodeID != CommonNode[i]) && (road.attributes.toNodeID != CommonNode[i])); k++) {
						select3.push (road.getID());
						road = W.model.segments.objects[select2[k]];
					}
					select3.push (road.getID());
					select3 = delete_multi_Ids (select3);
					if (lengthTrip (select3) <lengthMin) {
						goodTrip = select3;
						lengthMin = lengthTrip (goodTrip);
					}
				}
			}

			if (lengthMin != 1000000) {																								// a path was found
				goodTrip = addRoundabout (goodTrip);																		// Add roundabout segments
				goodTrip = addAlternativePaths (goodTrip);															// add alternative simple way like fork in roundabaout
				select (goodTrip);}		// make the selection		
			else {
				alert("No Path found"); 	
			}
		}
		else { alert("You must select 2 roads \nwith the same type"); 
		}
	}

	function addAlternativePaths (trip) {
		var alternativeSegs = [];
		var listNodeIDs = nodeFromTrip (trip);																			// list of nodesIds of the trip
		var road = W.model.segments.objects[trip[0]];
		var roadtype	= road.attributes.roadType;
		for (var i = 0; i < listNodeIDs.length;i++) {
			var node = W.model.nodes.objects[listNodeIDs[i]];
			var nodeSegIdList = node.attributes.segIDs;
			for (var j = 0; j < nodeSegIdList.length;j++) {
				var road1 = W.model.segments.objects[nodeSegIdList[j]];
				if ((road1 != null) && (road1.attributes.roadType == roadtype) && (isInArray (road1.attributes.fromNodeID,listNodeIDs)) && (isInArray (road1.attributes.toNodeID,listNodeIDs))) {
					alternativeSegs.push (road1.getID());
				}
			}
		}
		if (alternativeSegs.length != 0 ) {
			trip.push.apply(trip,alternativeSegs);
			trip = delete_multi_Ids (trip);
		}
		return trip;
	}

	function addRoundabout (trip) {
		var roundaboutSegs = [];
		for (var i = 0; i < trip.length;i++) {
			var road = W.model.segments.objects[trip[i]];
			if (road.attributes.junctionID!=null) {															  // It's un roundabout
				var jId = road.attributes.junctionID;
				var junc = W.model.junctions.objects[jId];
				roundaboutSegs.push.apply(roundaboutSegs,junc.attributes.segIDs);								// prepare to add roundabout to select
			}
		}
		if (roundaboutSegs.length != 0 ) {
			trip.push.apply(trip,roundaboutSegs);
			trip = delete_multi_Ids (trip);
		}
		return trip;
	}

	function nodeFromTrip (Trip) {
		var node =[];
		for (var i = 0; i < Trip.length; i++) {
			var road = W.model.segments.objects[Trip[i]];
			node.push (road.attributes.fromNodeID);
			node.push (road.attributes.toNodeID);
		}
		node = delete_multi_Ids (node);
		return node;
	}

	function lengthTrip (listRoadID) {
		var length= 0;
		for (var i = 0; i < listRoadID.length;i++) {
			var road = W.model.segments.objects[listRoadID[i]];
			length = length + road.attributes.length;
		}
		return length;
	}

	function select_12(startRoad,endRoad) {
		var Select_IDs =[];																								//tableau de stockage des Routes electionnées
		var endRoadFrom;
		var endRoadTo;
		if (endRoad.attributes.fromNodeID != null) {																	// Validate node for End Road 
			endRoadFrom = W.model.nodes.objects[endRoad.attributes.fromNodeID];}
		else {endRoadFrom = W.model.nodes.objects[endRoad.attributes.toNodeID];}
		if (endRoad.attributes.toNodeID != null) {
			endRoadTo = W.model.nodes.objects[endRoad.attributes.toNodeID];}
		else {endRoadTo = W.model.nodes.objects[endRoad.attributes.fromNodeID];}	
		var node = choiceStartNode (startRoad,endRoadFrom,endRoadTo);													// Choix du node de depart
		var segList = searchRoad(node,startRoad,endRoad.getID());
		Select_IDs.push.apply(Select_IDs,segList.IDs);				
//alert (Select_IDs);
		while ((segList.stop == "multiRoads") &&  (segList.roads.length >"1") && (Select_IDs.length < 50)) {							// Manage jonctions with same type road
			var BestNextNode  = searchBestNextNode (segList.node, segList.roads, endRoad);
			if ( BestNextNode.getID() != segList.node.getID() ) {																		// search road with best node
				for (var i = 0; i < segList.roads.length;i++) {
					var road = W.model.segments.objects[segList.roads[i]];
					if ((BestNextNode.getID() == road.attributes.fromNodeID) || (BestNextNode.getID() == road.attributes.toNodeID)) {
					var bestRoad = road;
					}
				}
				var segList = searchRoad (BestNextNode, bestRoad, endRoad.getID());
				Select_IDs.push.apply(Select_IDs, segList.IDs);}
			else {
				segList.stop = "none";
			}
		}
		return (Select_IDs);
	}		

	function searchBestNextNode (StartNode,listRoadID,endRoad) {
		var EndNode1 = W.model.nodes.objects[endRoad.attributes.fromNodeID];
		var EndNode2 = W.model.nodes.objects[endRoad.attributes.toNodeID];
		if (distance(StartNode,EndNode2) > distance(StartNode,EndNode1)) {					// determine de noeud de référence de fin
			var EndNode = EndNode1;}
		else {
			var EndNode = EndNode2;
		}
		var angleEnd = angle(StartNode, EndNode);
		var angleMin = 360;
		var BestNode;
		for (var i = 0; i < listRoadID.length;i++) {
			var road = W.model.segments.objects[listRoadID[i]];
			if (road.attributes.fromNodeID == StartNode.getID()) {												// determine de noeud à tester pour la fin du segment
				var node = W.model.nodes.objects[road.attributes.toNodeID];}
			else {
				var node = W.model.nodes.objects[road.attributes.fromNodeID];
			}
			var angle1 = Math.abs(angle (StartNode,node) - angleEnd);
			if (angle1 > 180 ) { angle1= 360 - angle1;}															// angle complémentaire
			if ( angle1 < angleMin ) {
				angleMin = angle1;
				BestNode = node;
			}
		}
		return BestNode;
	}

	//        **** Math functions *****
	function sign (x) {return (x < 0) ? (-1) : (1);}
	function AtanDeg ( x) {return ( 180 * Math.atan (x) / Math.PI );}
	function convertDegRad (angledeg) {return (Math.PI * (angledeg) / 180 );}
	function angle (node1,node2) {
		//var deltaX = (node2.geometry.x - node1.geometry.x);
		//var deltaY = (node2.geometry.y - node1.geometry.y);
		//return angleDeg (deltaX,deltaY);
		return angleDeg ((node2.geometry.x - node1.geometry.x),(node2.geometry.y - node1.geometry.y));
	}
	function angleDeg (deltaX,deltaY) {
		if (deltaX == 0) { return ( sign( deltaY ) * 90);}
		if (deltaX > 0 ) { return (AtanDeg( deltaY / deltaX));}
			else { return ((sign( deltaY )* 180) + AtanDeg( deltaY / deltaX));}
	}
	function longueur (x1,y1,x2,y2) {
		return (Math.sqrt (((x1-x2)*(x1-x2))+((y1-y2)*(y1-y2))));
	}
	//        **********************
	
	function select (Select_IDs)	{
		Select_IDs = delete_multi_Ids (Select_IDs)	;														// suppression des doublons
		var foundSegs =[];	
		for (var i = 0; i<Select_IDs.length;i++) {
			foundSegs.push(W.model.segments.objects[Select_IDs[i]]);					// créer la selection
		}	
		W.selectionManager.select(foundSegs); 
	}
	
	function delete_multi_Ids (myArray) {
		var myNewArray = [];
		if (myArray.length >0) {
			myNewArray[0]= myArray [0];
			for (var i = 0; i < myArray.length; i++) {
				if (notInArray (myArray [i],myNewArray)) {
					myNewArray.push(myArray [i]);
				}
			}
		}
		return myNewArray;
	}
	
  function minInArray (array) {
		if (array.length > 0) {
			var minimum = array [0];
			for (var i = 1; i < array.length; i++) {
				minimum = Math.min (minimum,array [i]);
			}
			return minimum;
		}
		else {return null;}
	}
	
	function isInArray (item,array)  {return array.indexOf(item) !== -1;}
  function notInArray (item,array) {return array.indexOf(item) === -1;}

	function searchRoad(node,roadStart,roadEndID) {
		var roadtype	= roadStart.attributes.roadType;
		var roadStartID = roadStart.getID();
		var roadID = roadStartID;
		var foundSegs  = {};												// object for return parameters
		foundSegs.IDs = [];
		foundSegs.roads = [];												//init array
		foundSegs.stop = "none";											//init Stop cause
		foundSegs.IDs.push(roadID);
		var nbSeg = 1;														//Number of searched segments	
		while ((nbSeg < 50) && (roadID != roadEndID)) {
			var nodeSegIdList = node.attributes.segIDs;						// list of road connected to node
			var sameTypeRoad = [];
			for (var i = 0; i < nodeSegIdList.length;i++) { 
				var segID = nodeSegIdList [i];
				var seg1 =W.model.segments.objects[segID];
				if (seg1 == null ) return foundSegs;						// le segment n'est pas chargé en mémoire
				else {	
					if ((seg1.attributes.roadType == roadtype) && (seg1.getID() != roadID)) {
						sameTypeRoad.push(segID);
					}
				}			
			}

			if (sameTypeRoad.length !=1) {
				if (isInArray (roadEndID,sameTypeRoad)) {			// End Road is in the fork
					foundSegs.IDs.push(roadEndID);					// We add it and go away
					return foundSegs;
				}	
				sameTypeRoad = validate (sameTypeRoad);				// delete cul-de-sac
			}
			if (sameTypeRoad.length !=1) {							// not an unique segment (0,2 or more)
				foundSegs.stop = "multiRoads";
				foundSegs.roads = sameTypeRoad;
				foundSegs.node = node; 
				return foundSegs;}									// on retourne le tableau d'Ids s
			else {
				var roadID = sameTypeRoad[0];
				if (isInArray (roadID,foundSegs.IDs)) return foundSegs;		// we are in a lopp : we go away
				foundSegs.IDs.push(roadID);
				nbSeg = nbSeg + 1;
				var seg2 = W.model.segments.objects[roadID];
				if (node.getID() == seg2.attributes.fromNodeID) { var nodeID = seg2.attributes.toNodeID;}
					else { var nodeID = seg2.attributes.fromNodeID;}
				var node = W.model.nodes.objects[nodeID];

				if (node == null ) return foundSegs;											// It's a cul-de-sac : we go away
			}
		}
		return foundSegs;
	}

	function validate (sameTypeRoad) {
		var myNewSameTypeRoad  = [];
		for (var i = 0; i < sameTypeRoad.length; i++) {
			var sel = W.model.segments.objects[sameTypeRoad[i]];
			if ((sel.attributes.fromNodeID !=null) && (sel.attributes.toNodeID!=null)) { //it is not a cul-de-sac
				myNewSameTypeRoad.push (sameTypeRoad[i]);
			}
		}
		return myNewSameTypeRoad;
	}

	function choiceStartNode (road1,node3,node4) {
		var node1,node2;

		if (road1.attributes.fromNodeID != null) {																									// test of cul-de-sac & change node if it is
			node1 = W.model.nodes.objects[road1.attributes.fromNodeID];}
		else { node1 = W.model.nodes.objects[road1.attributes.toNodeID];}
		if (road1.attributes.toNodeID != null) {
			node2 = W.model.nodes.objects[road1.attributes.toNodeID];}
		else { node2 = W.model.nodes.objects[road1.attributes.fromNodeID];}

		var nodeStart = node1;
		var dist_min = distance (node1,node3);
		var dist = distance (node1,node4);
		if (dist < dist_min ) {dist_min=dist;}
		dist = distance (node2,node3);
		if (dist < dist_min ) { dist_min = dist; nodeStart = node2;}
		dist = distance (node2,node4);
		if (dist < dist_min ) { dist_min = dist; nodeStart = node2;}
		return nodeStart;
	}

	function distance (node1 , node2) {
		var dist = (node1.geometry.x - node2.geometry.x)*(node1.geometry.x - node2.geometry.x);
		dist = dist + (node1.geometry.y - node2.geometry.y)*(node1.geometry.y - node2.geometry.y);
		return Math.sqrt(dist);
	}

  function activateLayer (layerName, flag) {
    if (flag == true || flag == false) {
      var index = findLayerIndex (layerName);
      // switch (layerName.toUpperCase()) {
        // case "AERIALS":         index = 0; break;
        // case "CITIES":          index = 1; break;
        // case "GPS POINTS":      index = 2; break;
		// case "ROADS":           index = 3; break;
		// case "MAPCOMMENTS":     index = 4; break;
        // case "AREA MANAGERS":   index = 8; break;
        // case "LANDMARKS":       index = 9; break;
        // case "PLACES UPDATE":   index = 10;break;
        // case "JUNCTIONS":       index = 11;break;
        // case "SPEED CAMERAS":   index = 14;break;
        // case "MAP PROBLEMS":    index = 16;break;
        // case "UPDATE REQUESTS": index = 18;break;
        // case "EDITABLE AREAS":  index = 19;break;
        // case "CLOSURES":        index = 22;break;
      // }
      if (index != null) {
        var layerID = W.map.controls[0].map.layers[index].id;
        W.map.controls[0].map.getLayer(layerID).setVisibility(flag);
      }
    }
  }

  	function findLayerIndex (layerName) {
        var index ;
		var layers = W.map.controls[0].map.layers;
		for (var i = 0; i<layers.length; i++) {
            if (layers[i].uniqueName && layers[i].uniqueName.toUpperCase() == layerName.toUpperCase()) {
				index=i;
            }
        }
        return index;
    }

/*     function activateLayer2 (layerName, flag) {
		if (flag == true || flag == false) {
		  var index;
		  switch (layerName.toUpperCase()) {
			case "AERIALS":         index = 0; break;
			case "CITIES":          index = 1; break;
			case "GPS POINTS":      index = 2; break;
			case "ROADS":           index = 3; break;
			case "MAPCOMMENTS":     index = 4; break;
			case "AREA MANAGERS":   index = 8; break;
			case "LANDMARKS":       index = 9; break;
			case "PLACES UPDATE":   index = 10;break;
			case "JUNCTIONS":       index = 11;break;
			case "SPEED CAMERAS":   index = 14;break;
			case "MAP PROBLEMS":    index = 16;break;
			case "UPDATE REQUESTS": index = 18;break;
			case "EDITABLE AREAS":  index = 19;break;
			case "CLOSURES":        index = 22;break;
		  }
		  if (index != null) {
			var layerID = W.map.controls[0].map.layers[index].id;
			W.map.controls[0].map.getLayer(layerID).setVisibility(flag);
		  }
		}
	}
   */

	function afficheObjet (objet) {
		for (var e in objet) {alert("objet["+e+"] ="+ objet[e]+" !");}
	}

	function manage_WME_SSTR(ev) {

	//	$("#segment-edit-general").append(WME_SSTR_ALL);				//repositionne le menu 

		put_WME_SSTR_button();

//alert("B");		
			if(document.getElementById('WME_SSTR_All') != null) {;
				localStorage['WME_SSTR_enable'] = document.getElementById ('WME_SSTR_enable').checked == 1;	
				var road = [];
				for (var i = 0; i<W.selectionManager.selectedItems.length;i++) {
					var seg = W.selectionManager.selectedItems[i].model;
					if (seg != null && seg.type == "segment") { road.push(seg);}
				}
				effaceMenu ();
				if(document.getElementById ('WME_SSTR_enable').checked == 1) {	
					if (road.length == 1)  {
						document.getElementById ('WME_SSTR_Side').style.display = "inline";
						document.getElementById ('WME_SSTR_River').style.display = "block";}
					if (road.length >= 1) {
						document.getElementById ('WME_SSTR').style.display = "inline";
						document.getElementById ('WME_SSTR_Ldmk').style.display = "block";
						if (road[0].attributes.junctionID !=null) {
//							document.getElementById ('WME_SSTR_Rdt').style.display = "block";   //inhib redoRdt
						}
						if (W.loginManager.user.normalizedLevel >= 3) {
							document.getElementById ('WME_SSTR_CrgAds').style.display = "block";}
					}
					if (road.length == 2)  {
						document.getElementById ('WME_SSTR_12').style.display = "inline";
					}
				}
			}
		return;
	}

	function effaceMenu () {
		document.getElementById ('WME_SSTR').style.display = "none";
		document.getElementById ('WME_SSTR_Side').style.display = "none";
		document.getElementById ('WME_SSTR_12').style.display = "none";
		document.getElementById ('WME_SSTR_River').style.display = "none";
		document.getElementById ('WME_SSTR_Ldmk').style.display = "none";
		document.getElementById ('WME_SSTR_Rdt').style.display = "none";
		document.getElementById ('WME_SSTR_CrgAds').style.display = "none";
	}

	function manageSmoothRiver () {	
		localStorage['WME_SSTR_Smth'] = document.getElementById ('WME_SSTR_SmthRvr').checked == 1;	
		return;
	}

	function init_WME_SSTR() {
		if (localStorage['WME_SSTR_enable']=='true') {																				// restaure old Values (if exist)
			document.getElementById ('WME_SSTR_enable').checked = 1;}
		if (localStorage['WME_SSTR_Smth']=='true') {
			document.getElementById ('WME_SSTR_SmthRvr').checked = 1;
		}

	//	if (typeof(Waze.map) != "object" || typeof(require.modules) != "object") {
	//		myAlert("WME_SSTR : Waze.map not ready");
	//		setTimeout(init_WME_SSTR, 2001);}
	//	else {
			//Waze.selectionManager.events.register("selectionchanged", null, manage_WME_SSTR);
			
			W.selectionManager.events.register("selectionchanged", null, manage_WME_SSTR1);

		//	document.getElementById('WME_SSTR_enable').onclick = manage_WME_SSTR;
		//	document.getElementById('WME_SSTR_SmthRvr').onclick = manageSmoothRiver;
			effaceMenu();
			manage_WME_SSTR();
			myAlert("WME_SSTR initialized");

			console_log("Select Same Type Roads initialized");
		//}
	}

	function manage_WME_SSTR1 () {
		setTimeout(manage_WME_SSTR, 1001);
	}

  function myAlert (message) {
    if (document.getElementById('search')!=null && !document.getElementById ('WME_JCB_AlertTxt')) { 			// verif (et réafffichage) de l'alerteBox
			var myAlertBox = $('<div id="WME_JCB_AlertBox" class="form-control search-query" style="opacity : 0.8;display :none;  height: auto;min-height: 30px; position: absolute;top :16px; margin-left: 350px; margin-right: auto; "/>');	
			var myAlertTxt = $('<div id="WME_JCB_AlertTxt" style=" opacity : 1;display:inline;padding:0px 0px">City ID/');
			myAlertBox.append(myAlertTxt);
			$("#search").append(myAlertBox);
		}
		if (document.getElementById ('WME_JCB_AlertTxt')){
			var myMessage = document.getElementById ('WME_JCB_AlertTxt').innerHTML;
			var line = myMessage.split("<br>");
			if (line.length==1 && line[0]==""){ line[0]= message;}
				else { line.push (message);}
			document.getElementById ('WME_JCB_AlertTxt').innerHTML = line.join ("<br>");
			document.getElementById ('WME_JCB_AlertBox').style.display = "block";
			setTimeout(function() {endAlert();}, 3750 + 500*Math.random());
		}
	}

	function endAlert() {
		var myMessage = document.getElementById ('WME_JCB_AlertTxt').innerHTML;
		var line = myMessage.split("<br>");
		line.shift();
		document.getElementById ('WME_JCB_AlertTxt').innerHTML = line.join ("<br>");
		if (line.length ==0){
			document.getElementById ('WME_JCB_AlertBox').style.display = "none";
		}
	}

  function console_log(msg) {
    if (console) {
      console.log(msg);}
  }

}

selectSameTypeRoad();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址