WME Select Same Type Roads

This script add functionnality to select and modify roads

当前为 2023-12-12 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name WME Select Same Type Roads
// @author buchet37
// @namespace https://greasyfork.org/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*
// @match https://*.waze.com/editor*
// @match https://*.waze.com/*/editor*
// @match https://*.waze.com/map-editor*
// @match https://*.waze.com/beta_editor*
// @match https://descarte*.waze.com/beta*
// @match https://editor-beta.waze.com*
// @version         4.17.1
// ==/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

/* global require */
/* global $ */
/* global OpenLayers */
/* global W */
/* global I18n */

var WME_SSTR_version = "4.17.1" ;


// *************
// **  INIT   **
// *************
function SSTR_bootstrap() {
    if (typeof unsafeWindow === "undefined") {
        unsafeWindow = ( function () {
            var dummyElem = document.createElement('p');
            dummyElem.setAttribute('onclick', 'return window;');
            return dummyElem.onclick();
        }) ();
    }

    /* begin running the code! */
    //    log("starting");
    selectSameTypeRoad();
}

function selectSameTypeRoad() {
    if (W && W.map && W.model && 'undefined' != typeof require ) {start_selectSameTypeRoad(); }
    else { setTimeout(selectSameTypeRoad , 1000); }
}

function start_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");
    var WazeActionMoveNode = require("Waze/Action/MoveNode");

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

    setTimeout (function () {insertButton();}, 5001);		//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 ;
        //	  var selectedItems = W.selecti onManager.getSelectedFeatures();
        var selectedItems = getSelectedFeatures();
        if (selectedItems.length != 0 &&
            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;margin:0px 5px 0px 0px"><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://greasyfork.org/scripts/4715-wme-select-same-type-roads" target="_blank">Select Same Type Road ' + WME_SSTR_version+ '</a></i></u>');

        var btn1 = $('<button class="waze-btn waze-btn-small waze-btn-white" style="padding:0px 6px; height:20px;" title="Select 1 or more segments and click this button">Select Same Type Roads</button>');
        var btn2 = $('<button class="waze-btn waze-btn-small waze-btn-white" style="padding:0px 6px; height:20px; margin-right:5px;" title="Select adjacent segment from node A">A =></button>');
        var btn3 = $('<button class="waze-btn waze-btn-small waze-btn-white" style="padding:0px 6px; height:20px;" title="Select adjacent segment from node B">B =></button>');
        var btn4 = $('<button class="waze-btn waze-btn-small waze-btn-white" style="padding:0px 6px; height:20px;" title="Start from segment 1 to join Segment 2 (if possible)">1 => 2</button>');
        var btn7 = $('<button class="waze-btn waze-btn-small waze-btn-white" style="padding:0px 6px; height:20px; margin-right:5px; " title="Create a River from Street Geometry">Street => River</button>');
        var btn8 = $('<button class="waze-btn waze-btn-small waze-btn-white" style="padding:0px 6px; height:20px;" title="Select road(s) to make an Overall Landmark">Do Landmark</button>');
        var btn10= $('<button class="waze-btn waze-btn-small waze-btn-white" style="padding:0px 6px; height:20px; margin:2px;width:250px;" title="Make a new roundabout from 1 segment of an old one">Redo Roundabout</button>');
        var btn12= $('<button class="waze-btn waze-btn-small waze-btn-white" style="padding:0px 6px; height:20px; margin-right:5px; " title="click this button to suppress road geometry">Clear Road Geometry</button>');
        var btn13= $('<button class="waze-btn waze-btn-small waze-btn-white" style="padding:0px 6px; height:20px;" title="click this button to allow "All drives" and "All Turns" on selected roads)">All drives on Selection</button>');
        var btn14= $('<button class="waze-btn waze-btn-small waze-btn-white" style="font-size:20px; padding:0px 6px; height:auto; margin: 2px;" >&#11013</button>');
        var btn15= $('<button class="waze-btn waze-btn-small waze-btn-white" style="font-size:20px; padding:0px 6px; height:auto; margin: 2px;" >&#10145</button>');
        var btn16= $('<button class="waze-btn waze-btn-small waze-btn-white" style="font-size:20px; padding:0px 6px; height:auto; margin: 2px;" >&#11015</button>');
        var btn17= $('<button class="waze-btn waze-btn-small waze-btn-white" style="font-size:20px; padding:0px 6px; height:auto; margin: 2px;" >&#11014</button>');
        var btn18= $('<button class="waze-btn waze-btn-small waze-btn-white" style="font-size:20px; padding:0px 6px; height:auto; margin: 2px;" > -- </button>');
        var btn19= $('<button class="waze-btn waze-btn-small waze-btn-white" style="font-size:20px; padding:0px 6px; height:auto; margin: 2px;" > ++ </button>');
        var btn20= $('<button class="waze-btn waze-btn-small waze-btn-white" style="font-size:20px; padding:0px 6px; height:auto; margin: 2px;" >&#11119</button>');
        var btn21= $('<button class="waze-btn waze-btn-small waze-btn-white" style="font-size:20px; padding:0px 6px; height:auto; margin: 2px;" >&#11118</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_Rdt_zero);
        btn12.click (Clear_Road_Geometry);
        btn13.click (All_drives_on_Selection);
        chk1.click  (manage_WME_SSTR);
        chk2.click  (manageSmoothRiver);
        btn14.click (Redo_Rdt_Xmoins);btn15.click (Redo_Rdt_Xplus);btn16.click (Redo_Rdt_Ymoins);btn17.click (Redo_Rdt_Yplus);
        btn18.click (Redo_Rdt_Rmoins);btn19.click (Redo_Rdt_Rplus);btn20.click (Redo_Rdt_Rotmoins);btn21.click (Redo_Rdt_Rotplus);

        WME_SSTR_ALL = $ ('<div id="WME_SSTR_All"  style="height: auto;  padding:2px 2px 2px 5px;margin:5px 0px 0px -5px;width:295px; border-width:3px; border-style:double;border-color: SkyBlue; border-radius:10px"/>');

        var cnt0 = $('<section id="WME_SSTR_lnk" 	style="padding-top:2px; margin:2px;"/>'); cnt0.append(chk1);cnt0.append(" ");cnt0.append(url1);
        var cnt1 = $('<section id="WME_SSTR"		style="padding-top:2px; margin:2px; display:inline;"/>'); cnt1.append(btn1);
        var cnt2 = $('<section id="WME_SSTR_Side"	style="padding-top:2px; margin:2px;"/>'); cnt2.append(btn2);cnt2.append(btn3);
        var cnt3 = $('<section id="WME_SSTR_12"		style="padding-top:2px; margin:2px;"/>'); cnt3.append(btn4);
        var cnt4 = $('<section id="WME_SSTR_River"	style="padding-top:2px; margin:2px;"/>'); cnt4.append(btn7); cnt4.append(chk2);
        var cnt6 = $('<section id="WME_SSTR_Ldmk"	style="padding-top:2px; margin:2px;"/>'); cnt6.append(btn8);
        var cnt7_1 = $('<div style="padding-top:2px; margin:2px;"/>'); cnt7_1.append("&ensp;Move&emsp;",btn14,btn15,btn16,btn17);
        var cnt7_2 = $('<div style="padding-top:2px; margin:2px;"/>'); cnt7_2.append("&ensp;Strech&ensp;",btn18,btn19,btn20,btn21);
        var cnt7 = $('<section id="WME_SSTR_Rdt"	style="padding-top:2px; margin:2px;border-width:1px; border-style:solid;border-color: SkyBlue; border-radius:6px; background-color:#ebebeb"/>');
    //    cnt7.append(btn10,cnt7_1,cnt7_2);
        cnt7.append(cnt7_1,cnt7_2);
        var cnt8 = $('<section id="WME_SSTR_CrgAds"	style="padding-top:2px; margin:2px;"/>'); cnt8.append(btn12);
        // cnt8.append(btn13);
        // 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) {
        //		var selectedItems = W.selectionManager.getSelectedFeatures();
        var selectedItems = getSelectedFeatures();
        if (selectedItems.length!=0) {
            if (confirm ("Do you want to clear the geometry for selected segments") ) {
                for (var i = 0; i < selectedItems.length; i++) {
                    var seg = selectedItems[i].model;
                    if (seg.type == "segment") {
                        var geo = seg.clone().getGeometry();
                        geo.coordinates.splice(1,geo.coordinates.length-2); // on garde le 1er et le dernier point
                        W.model.actionManager.add (new WazeActionUpdateSegmentGeometry (seg,seg.getGeometry(),geo));
                    }
                }
            }
        }
    }

    function All_drives_on_Selection(ev) {
        //		var selectedItems = W.selectionManager.getSelectedFeatures();
        var selectedItems = getSelectedFeatures();
        if (selectedItems.length!=0) {
            var action = [];
            var nodeToAllowed = [];
            var selectRoadIDs = [];
            for (var i = 0; i < selectedItems.length; i++) {
                var seg = 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_Rdt_zero (ev)    {Redo_RoundAbout(0,0,0)};
    function Redo_Rdt_Xmoins (ev)  {move_RoundAbout1(-1,0,0,0)};
    function Redo_Rdt_Xplus (ev)   {move_RoundAbout1(1,0,0,0)};
    function Redo_Rdt_Ymoins (ev)  {move_RoundAbout1(0,-1,0,0)};
    function Redo_Rdt_Yplus (ev)   {move_RoundAbout1(0,1,0,0)};
    function Redo_Rdt_Rmoins (ev)  {move_RoundAbout1(0,0,-1,0)};
    function Redo_Rdt_Rplus (ev)   {move_RoundAbout1(0,0,1,0)};
    function Redo_Rdt_Rotmoins(ev) {move_RoundAbout1(0,0,0,1)};
    function Redo_Rdt_Rotplus (ev) {move_RoundAbout1(0,0,0,-1)};

    function move_RoundAbout(xdecal,ydecal,rstr,rot) {
        var rdt = getOldRdt();
        if (rdt) {
            var multiaction = new WazeActionMultiAction();
            multiaction.setModel(W.model);
            var decal_X = xdecal * 0.05 * rdt.width;
            var decal_Y = ydecal * 0.05 * rdt.height;
            for (var i = 0; i < rdt.nodes.length; i++) { // on decale les noeuds
                var node = W.model.nodes.objects[rdt.nodes[i]];
 //               var newGeo = node.geometry.clone();
                var newGeo = node.getOLGeometry().clone();
                var decal_R = decalageRadial(newGeo.x,newGeo.y,rdt,rstr,rot); // décalage radial (etire - repli
                newGeo.x = decal_R.x + decal_X;
                newGeo.y = decal_R.y + decal_Y;
                newGeo.calculateBounds();
                var connectedSegs = [];
                for(let m=0;m<node.attributes.segIDs.length;m++){
                    var segID = node.attributes.segIDs[m];
//                    connectedSegs[segID] = W.model.segments.objects[segID].geometry.clone();
                    connectedSegs[segID] = W.model.segments.objects[segID].getOLGeometry().clone();
                }
//                multiaction.doSubAction (new WazeActionMoveNode(node, node.geometry, newGeo, connectedSegs, {}));
                multiaction.doSubAction (new WazeActionMoveNode(node, node.getOLGeometry(), newGeo, connectedSegs, {}));
            }
            for (var j = 0; j < rdt.segs.length; j++) { // on decale les segments
                var seg = W.model.segments.objects[rdt.segs[j]];
//                var newGeo = seg.geometry.clone();
                var newGeo = seg.getOLGeometry().clone();
                for (var k = 1; k < newGeo.components.length-1; k++){
                    var decal_R = decalageRadial( newGeo.components[k].x, newGeo.components[k].y,rdt,rstr,rot); // décalage radial (etire - repli
                    newGeo.components[k].x = decal_R.x + decal_X;
                    newGeo.components[k].y = decal_R.y + decal_Y;
                    newGeo.components[k].calculateBounds();
                }
                newGeo.calculateBounds();
                multiaction.doSubAction (new WazeActionUpdateSegmentGeometry (seg,seg.getOLGeometry(),newGeo));
            }
            W.model.actionManager.add (multiaction);
        }
    }


    function move_RoundAbout1(xdecal,ydecal,rstr,rot) {
        var rdt = getOldRdt();
        if (rdt) {
            var multiaction = new WazeActionMultiAction();
            multiaction.setModel(W.model);
            var decal_X = xdecal * 0.05 * rdt.width;
            var decal_Y = ydecal * 0.05 * rdt.height;
            for (var i = 0; i < rdt.nodes.length; i++) { // on decale les noeuds
                var node = W.model.nodes.objects[rdt.nodes[i]];
                var geo = node.clone().getGeometry();
                var decal_R = decalageRadial(geo.coordinates[0],geo.coordinates[1],rdt,rstr,rot); // décalage radial (etire - repli
                geo.coordinates[0]= decal_R.x + decal_X;
                geo.coordinates[1]= decal_R.y + decal_Y;
                var connectedSegs = [];
                for(let m=0;m<node.attributes.segIDs.length;m++){
                    var segID = node.attributes.segIDs[m];
                    connectedSegs[segID] = W.model.segments.objects[segID].getGeometry();
                }
                multiaction.doSubAction (new WazeActionMoveNode(node, node.getGeometry(), geo, connectedSegs, {}));
            }
            for (var j = 0; j < rdt.segs.length; j++) { // on decale les segments
                var seg = W.model.segments.objects[rdt.segs[j]];
                var geo1 = seg.clone().getGeometry();
                for (var k = 1; k < geo1.coordinates.length-1; k++){
                    var decal_R1 = decalageRadial(geo1.coordinates[k][0],geo1.coordinates[k][1],rdt,rstr,rot); // décalage radial (etire - repli
                    geo1.coordinates[k][0]= decal_R1.x + decal_X;
                    geo1.coordinates[k][1]= decal_R1.y + decal_Y;
                }
                multiaction.doSubAction (new WazeActionUpdateSegmentGeometry (seg,seg.getGeometry(),geo1));
            }
            W.model.actionManager.add (multiaction);
        }
    }

    function decalageRadial (x,y,rdt,rstr,rot) { // avec passage en projection linéaire pour non deformation
        var center = openLayerTransform (rdt.center.x,rdt.center.y,"EPSG:4326","EPSG:900913");
        var point = openLayerTransform (x,y,"EPSG:4326","EPSG:900913");

        var deltaX = point.lon - center.lon;
        var deltaY = point.lat - center.lat;
        var angle = angleDeg (deltaX,deltaY) + 5 * rot; // rotation de +-5 °
        var oldRayon = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
        var newRayon = oldRayon + oldRayon * 0.05 * rstr; // etirement ou contraction
        var newPt = {};
        newPt.lon = center.lon + newRayon * Math.cos(convertDegRad(angle));
        newPt.lat = center.lat + newRayon * Math.sin(convertDegRad(angle));

        var point2 = openLayerTransform (newPt.lon,newPt.lat,"EPSG:900913","EPSG:4326");
        var pt = {}; pt.x = point2.lon; pt.y = point2.lat;
        return pt;
    }

    function openLayerTransform (x,y,from,to) {
        var point = new OpenLayers.LonLat(x,y);
        var projFrom = new OpenLayers.Projection(from);
        var projTo = new OpenLayers.Projection(to);
        return point.transform(projFrom, projTo);
    }

    function getOldRdt() {
        var selectedItems = W.selectionManager.getSegmentSelection().segments;
        if (selectedItems.length==0) {return null;}
        var junctionID = [];
        for (var i = 0; i < selectedItems.length; i++) {
            if (selectedItems[i].attributes.junctionID !=null) {
                junctionID.push(selectedItems[i].attributes.junctionID);
            }
        }
        junctionID = delete_multi_Ids(junctionID);
        if (junctionID.length!=1) {return null;} // il ya un rdt et un seul de selectionné
        var rdt ={}
        rdt.junctionID = junctionID[0];
        rdt.nodes = [];
        rdt.center = {};
        rdt.maxX = rdt.maxY = -10000000000000;
        rdt.minX = rdt.minY = 10000000000000;
        var junc = W.model.junctions.objects[rdt.junctionID];
        rdt.segs = junc.attributes.segIDs;
        for (var j = 0; j < rdt.segs.length; j++) {
            var seg = W.model.segments.objects[rdt.segs[j]];
            rdt.nodes.push(seg.attributes.fromNodeID);
            rdt.nodes.push(seg.attributes.toNodeID);
            var geo = seg.getGeometry().coordinates;
            for (var k = 0; k < geo.length; k++) { // recup geométrie
                if (geo[k][0] > rdt.maxX) {rdt.maxX = geo[k][0];}
                if (geo[k][1] > rdt.maxY) {rdt.maxY = geo[k][1];}
                if (geo[k][0] < rdt.minX) {rdt.minX = geo[k][0];}
                if (geo[k][1] < rdt.minY) {rdt.minY = geo[k][1];}
            }
        }
        rdt.nodes = delete_multi_Ids(rdt.nodes);
        rdt.width = rdt.maxX - rdt.minX;
        rdt.height= rdt.maxY - rdt.minY;
        rdt.center.x = (rdt.maxX + rdt.minX)/2;
        rdt.center.y = (rdt.maxY + rdt.minY)/2;
        return rdt;
    }

    function Redo_RoundAbout (xdecal,ydecal,rstr) {
        //        var selectedItems = W.selectionManager.getSelectedFeatures();
        var selectedItems = getSelectedFeatures();
        var selectedGood = (selectedItems.length!=0);

        if (selectedGood) {
            var listRoadIds = [];
            if (selectedItems[0].model.attributes.junctionID !=null) {			// si c'est un rdt , on selectionne tout le rdt
                var sel = selectedItems[0].model;
                var junc = W.model.junctions.objects[sel.attributes.junctionID];
                listRoadIds = junc.attributes.segIDs;
var geo = junc.clone().getGeometry();
afficheObjet(geo);
            }
            else {
                for (var ii = 0; ii < selectedItems.length; ii++) {								// sinon on prend tous les egments selectionnés
                    var sel1 = selectedItems[ii].model;
                    listRoadIds.push (sel1.getID());
                }
            }

            var oldRdt = extract_rdt (listRoadIds);
            var oldRdt1 = extract_rdt (listRoadIds);
            oldRdt.dim.center.x =oldRdt.dim.center.x + xdecal*0.05* oldRdt.dim.rx; // decalage
            oldRdt.dim.center.y =oldRdt.dim.center.y + ydecal*0.05* oldRdt.dim.ry;
            oldRdt.dim.rx =oldRdt.dim.rx + rstr*0.05* oldRdt.dim.rx;
            oldRdt.dim.ry =oldRdt.dim.ry + rstr*0.05* oldRdt.dim.ry;

            if (oldRdt.higherRank == false) {
                var action0 = [];
                for (var j = 0; j < oldRdt.listRoadIds.length; j++) {
                    var seg1 = W.model.segments.objects[oldRdt.listRoadIds[j]];															// ******* Delete old Roundabout
//                    action0.push (new WazeActionDeleteSegment(seg1)); // ******* Delete old Roundabout
 //                   W.model.actionManager.add (new WazeActionDeleteSegment(seg1)); // ******* 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();
                    var index1, index2, nodeEnd;
                    if (oldRdt.listAdjRoadIds[i].sideConnect == "A") {
                        index1 =0; index2 =1;
                        nodeEnd = W.model.nodes.objects [seg.attributes.toNodeID];
                    }
                    else {
                        index1 = newGeo.components.length-1; index2 = newGeo.components.length-2;
                        nodeEnd = W.model.nodes.objects [seg.attributes.fromNodeID];
                    }
                     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();
                  var geo = W.userscripts.toGeoJSONGeometry(newGeo);
//                    action0.push(new WazeActionUpdateSegmentGeometry (seg,seg.geometry,newGeo));
    //                W.model.actionManager.add (new WazeActionUpdateSegmentGeometry (seg,seg.getGeometry(),geo));
                }



alert("A");
         //       W.model.actionManager.add (new WazeActionMultiAction(action0));


              //  oldRdt1.dim.center
                var rdt = W.userscripts.toGeoJSONGeometry(oldRdt1.dim.center);
                oldRdt1.dim.center = rdt

   //             var action1 = new WazeActionCreateRoundabout(oldRdt.dim); // créé le nouveau rdt sur les bases géométrique de l'ancien
                var action1 = new WazeActionCreateRoundabout(oldRdt1.dim); // créé le nouveau rdt sur les bases géométrique de l'ancien
//                W.model.actionManager.add (action1);

return
                var rbtRoadIds = W.model.junctions.objects[action1.roundaboutSegments[0].attributes.junctionID].attributes.segIDs; //recup Id segments
                var newRdt = searchNewRdt (rbtRoadIds,oldRdt.primaryStreetID);

                var action2 = [];
                for (var k = 0; k < rbtRoadIds.length; k++) {
                    var road = W.model.segments.objects[rbtRoadIds[k]];
                    action2.push(new WazeActionUpdateObject(road, {roadType: newRdt.roadtype, level: oldRdt.level, primaryStreetID: oldRdt.primaryStreetID}));
                }

                W.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.getOLMap().getExtent().intersectsBounds(obj.geometry.getBounds()));}
        if (obj.getOLGeometry()){
            return(W.map.getOLMap().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 road1 = W.model.segments.objects[listRdtSegIds[i]];
            if (road1 != null) {
                listRdtNodeIds.push (road1.attributes.fromNodeID);
                listRdtNodeIds.push (road1.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 kk = 0; kk < nbSegs;kk++) {
                    var road = W.model.segments.objects[node.attributes.segIDs[kk]];
                    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];
            }
        }

        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 = 10000000000000;
        var xmax = -10000000000000;
        var ymax = -10000000000000;
        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);
                }
            }
        }
        rdt.listNodeIds = delete_multi_Ids(rdt.listNodeIds);						// elimine les noeuds en doublons

        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.level = 0;
        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 jj=0; jj<nbSegs;jj++) {
                    var road = W.model.segments.objects[node.attributes.segIDs[jj]];
                    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);					//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 cityIDs = [];
        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.attributes && street.attributes.cityID && W.model.cities.objects[street.attributes.cityID]) {
                    cityIDs.push(street.attributes.cityID);
                }
            }
        }

        cityIDs = delete_multi_Ids(cityIDs);
        if (cityIDs.length ===1) {
            var city =  W.model.cities.objects[cityIDs[0]];}
        else {
            var state_ID   = W.model.cities.objects[cityIDs[0]].attributes.stateID;
            var country_ID = W.model.cities.objects[cityIDs[0]].attributes.countryID;
            var city = searchCity(country_ID, state_ID, "");
        }
        var primaryStreet = searchPrimaryStreet("",city);
        rdt.primaryStreetID = primaryStreet.getID();
        return rdt;
    }

    function searchCity (country_ID, state_ID, 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);
        f.setModel();
        if (f.city.getID()<0) {myAlert ("Create new city: "+cityName+" in "+state.name);}
        return W.model.cities.objects[f.city.getID()];
    }

    function searchPrimaryStreet (streetName,city) {
        var a = new WazeActionAddOrGetStreet(streetName,city,(streetName == ""));
        W.model.actionManager.add(a);
        a.setModel();
        if (a.street.getID()<0) {myAlert ("Create new street: "+city.attributes.name+"  "+streetName);}
        return W.model.streets.objects[a.street.getID()];
    }

    function Roads_to_Interchange(ev) {
        var foundSelectedSegment = false;
        //		var selectedItems = W.selectionManager.getSelectedFeatures();
        var selectedItems = getSelectedFeatures();
        var selectedGood = (selectedItems.length>0);
        var roadIds = [];
        for (var i = 0; i<selectedItems.length;i++) { 					// Test if selection are segment
            var sel1 = selectedItems[i].model;
            selectedGood = ((selectedGood) && (sel1.type == "segment"));
            if ((selectedGood)&& (sel1.attributes.junctionID!=null)) {	// if it is a roundabout we add all Rdt segs
                var jId = sel1.attributes.junctionID;
                var junc = W.model.junctions.objects[jId];
                roadIds.push.apply (roadIds,junc.attributes.segIDs);	// we add all segment of the roundabout
            }
            if (selectedGood) {	roadIds.push ( sel1.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;

            for (var k = 0; k<roadIds.length;k++) {
                var sel = W.model.segments.objects[roadIds[k]];

                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;}
//                }

                for (var j = 0; j < sel.getOLGeometry().components.length;j++) {
                    totalPoints.push (sel.getOLGeometry().components[j].clone());
                    if (leftEnv[0].y > sel.getOLGeometry().components[j].y) {									// Stocke le Y mini
                        leftEnv[0]  = sel.getOLGeometry().components[j].clone();
                        rightEnv[0] = sel.getOLGeometry().components[j].clone();
                    }
                    if (sel.getOLGeometry().components[j].y > yMax) { yMax = sel.getOLGeometry().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 ldk = {};
        ldk.geoJSONGeometry = W.userscripts.toGeoJSONGeometry (polygon);
        var landmark = new WazeFeatureVectorLandmark(ldk);
//        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 selectedItems = W.selectionManager.getSelectedFeatures();
        var selectedItems = getSelectedFeatures();
        var selectedGood = (selectedItems.length==1);
        var sel = 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).attributes.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;																				// 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);
        var decal = decalage (seg.getOLGeometry().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 selectedItems = W.selectionManager.getSelectedFeatures();
        var selectedItems = getSelectedFeatures();
        var nbRoad = 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 = 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 = 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 selectedItems = W.selectionManager.getSelectedFeatures();
        var selectedItems = getSelectedFeatures();
        var nbRoad = selectedItems.length;
        var sel = 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 selectedItems = W.selectionManager.getSelectedFeatures();
        var selectedItems = getSelectedFeatures();
        var nbRoad = selectedItems.length;
        var sel = 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 selectedItems = W.selectionManager.getSelectedFeatures();
        var selectedItems = getSelectedFeatures();
        var nbRoad = selectedItems.length;															// **** Validate selection *****
        var selectedGood = (nbRoad == 2);															// selection must have 2 items
        if (selectedGood) {
            var sel = selectedItems[0].model;
            var sel1 = 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);
        W.selectionManager.setSelectedModels(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.getOLMap().controls[0].map.layers[index].id;
                W.map.getOLMap().controls[0].map.getLayer(layerID).setVisibility(flag);
            }
        }
    }

    function findLayerIndex (layerName) {
        var index ;
        var layers = W.map.getOLMap().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.getOLMap().controls[0].map.layers[index].id;
			W.map.getOLMap().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 = [];
            //				var selectedItems = W.selectionManager.getSelectedFeatures();
            var selectedItems = getSelectedFeatures();
            for (var i = 0; i<selectedItems.length;i++) {
                var seg = 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";
                    }
                    //                    if (W.loginManager.user.normalizedLevel >= 3) {
                    if (W.loginManager.user.attributes.rank >= 2) {
                        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;
        }
        W.selectionManager.events.register("selectionchanged", null, manage_WME_SSTR1);

        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) {
        console_log(message);
    }

    function myAlert_old (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 getSelectedFeatures() { // function de remplacement pour W.selectionManager.getSelectedFeatures() modifiée dans WME
        var selectedItems = W.selectionManager.getSegmentSelection().segments;
        var table = [];
        for (var i = 0; i < selectedItems.length; i++) {
            var obj = {};
            obj.model = selectedItems[i];
            table.push (obj);
        }
        return table;
    }

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

}

SSTR_bootstrap();