Get a sneak peek at whats next for Permanent Hazards on our April 7th Office Hours!
Post by Twister-UK
Another WME to OS update, improving the accuracy of the lat/lon to gridref conversion by performing the proper WGS84->OSGB36 transformation rather than simply assuming the two are equal...
Twister-UK
Waze Local Champs
Waze Local Champs
Posts: 4671
Answers: 2
Has thanked: 736 times
Been thanked: 4687 times
Send a message
Chris (not to be confused with Chris or Chris, or even Tim, Stu, or any of the other champs team...)
AM SE England & Shetland Islands, UK Local Champ, WME Beta Tester & ScriptMangler
WME/Livemap enhancement scripts @ GreasyFork


https://chizzum.com/greasemonkey/images/beta.pnghttps://chizzum.com/greasemonkey/images/s0400.pnghttps://chizzum.com/greasemonkey/images/c5s.png

Post by Twister-UK
Haven't put this one on userscripts.org, as it's a proof of concept release not intended for general use. The concept being evaluated here is the first version of my OS Locator lookup code, which may, possibly, lead to a point-n-click means of populating the road properties fields.

That's a probably optimistic, and definitely distant, goal. At present the code simply performs a basic grid ref comparison between the centrepoint of the WME map window and the bounding boxes defined in the OS data, and then lists all the matches it finds in the space below the map. This alone may be of some use in sanity-checking any existing road names, but it's really only intended to prove that we can pull, fairly quickly, the correct OS data into WME for the given map location.


Notes:

Not Chrome-compatible at present due to Chrome not implementing the Greasemonkey @require feature.

On installation, it downloads a pre-processed copy of the OS Locator dataset from my server - the file is 120MB so this may take some time... This data is cached locally as part of the installation process, and so it doesn't need to be downloaded each time the script runs.

All of the previous functionality of the script should still be present and work as before.


Code: Select all

// ==UserScript==
// @name                WME to OS link
// @namespace           http://greasemonkey.chizzum.com
// @description         Adds link to WME to open up various mapping sites at the same map location
// @include             https://world.waze.com/editor/*
// @include             https://world.waze.com/map-editor/*
// @include             https://descartesw.waze.com/beta/*
// @require             http://greasemonkey.chizzum.com/osl_10km.js
// @version             0.8
// ==/UserScript==

// Contains Ordnance Survey data Crown copyright and database right 2012
// Contents of the osl_10km.js file are derived under the Open Government Licence from the OS Locator dataset


//-----------------------------------------------------------------------------------------------------------------------------------------
// all code between here and the next ------------- marker line is a stripped down version of the original from Paul Dixon
//
// * GeoTools javascript coordinate transformations
// * http://files.dixo.net/geotools.html
// *
// * This file copyright (c)2005 Paul Dixon (paul@elphin.com)
// *
// * This program is free software; you can redistribute it and/or
// * modify it under the terms of the GNU General Public License
// * as published by the Free Software Foundation; either version 2
// * of the License, or (at your option) any later version.
// *
// * This program is distributed in the hope that it will be useful,
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// * GNU General Public License for more details.
// *
// * You should have received a copy of the GNU General Public License
// * along with this program; if not, write to the Free Software
// * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
// *
// * ---------------------------------------------------------------------------
// *
// * Credits
// *
// * The algorithm used by the script for WGS84-OSGB36 conversions is derived
// * from an OSGB spreadsheet (www.gps.gov.uk) with permission. This has been
// * adapted into Perl by Ian Harris, and into PHP by Barry Hunter. Conversion
// * accuracy is in the order of 7m for 90% of Great Britain, and should be
// * be similar to the conversion made by a typical GPSr
// *
// * See accompanying documentation for more information
// * http://files.dixo.net/geotools.html

var northings;
var eastings;
var latitude;
var longitude;

var helmX, helmY, helmZ;
var Pi = 3.14159265358979;

function wgs_to_osgb()
{
	LatLon_to_HelmXYZ();
   var latitude2  = XYZ_to_Lat();
	var longitude2 = Math.atan2(helmY , helmX) * (180 / Pi);
	LatLon_to_OSGrid(latitude2,longitude2);
}

function LatLon_to_HelmXYZ()
{
   var a = 6378137.0;
   var b = 6356752.313;
   var DX = -446.448;
   var DY = 125.157;
   var DZ = -542.060;
   var rotX = -0.1502;
   var rotY = -0.2470;
   var rotZ = -0.8421;
	var sfactor = 20.4894 * 0.000001;

   // perform initial lat-lon to cartesian coordinate translation
   var RadPHI = latitude * (Pi / 180);
   var RadLAM = longitude * (Pi / 180);
   var e2 = (Math.pow(a,2) - Math.pow(b,2)) / Math.pow(a,2);
   var V = a / (Math.sqrt(1 - (e2 * (  Math.pow(Math.sin(RadPHI),2)))));
   var cartX = V * (Math.cos(RadPHI)) * (Math.cos(RadLAM));
   var cartY = V * (Math.cos(RadPHI)) * (Math.sin(RadLAM));
   var cartZ = (V * (1 - e2)) * (Math.sin(RadPHI));

   // Compute Helmert transformed coordinates
	var RadX_Rot = (rotX / 3600) * (Pi / 180);
	var RadY_Rot = (rotY / 3600) * (Pi / 180);
	var RadZ_Rot = (rotZ / 3600) * (Pi / 180);
   helmX = (cartX + (cartX * sfactor) - (cartY * RadZ_Rot) + (cartZ * RadY_Rot) + DX);
	helmY = (cartX * RadZ_Rot) + cartY + (cartY * sfactor) - (cartZ * RadX_Rot) + DY;
	helmZ = (-1 * cartX * RadY_Rot) + (cartY * RadX_Rot) + cartZ + (cartZ * sfactor) + DZ;
}

function XYZ_to_Lat()
{
   var a = 6377563.396;
   var b = 6356256.910;
   var RootXYSqr = Math.sqrt(Math.pow(helmX,2) + Math.pow(helmY,2));
   var e2 = (Math.pow(a,2) - Math.pow(b,2)) / Math.pow(a,2);
   var PHI1 = Math.atan2(helmZ , (RootXYSqr * (1 - e2)) );
   var PHI = Iterate_XYZ_to_Lat(a, e2, PHI1, helmZ, RootXYSqr);
   return PHI * (180 / Pi);
}

function Iterate_XYZ_to_Lat(a, e2, PHI1, Z, RootXYSqr)
{
   var V = a / (Math.sqrt(1 - (e2 * Math.pow(Math.sin(PHI1),2))));
   var PHI2 = Math.atan2((Z + (e2 * V * (Math.sin(PHI1)))) , RootXYSqr);
   while (Math.abs(PHI1 - PHI2) > 0.000000001)
   {
      PHI1 = PHI2;
      V = a / (Math.sqrt(1 - (e2 * Math.pow(Math.sin(PHI1),2))));
      PHI2 = Math.atan2((Z + (e2 * V * (Math.sin(PHI1)))) , RootXYSqr);
   }
   return PHI2;
}

function Marc(bf0, n, PHI0, PHI)
{
   return bf0 * (((1 + n + ((5 / 4) * Math.pow(n,2)) + ((5 / 4) * Math.pow(n,3))) * (PHI - PHI0)) - (((3 * n) + (3 * Math.pow(n,2)) +
          ((21 / 8) * Math.pow(n,3))) * (Math.sin(PHI - PHI0)) * (Math.cos(PHI + PHI0))) + ((((15 / 8) * Math.pow(n,2)) + ((15 / 8) *
          Math.pow(n,3))) * (Math.sin(2 * (PHI - PHI0))) * (Math.cos(2 * (PHI + PHI0)))) - (((35 / 24) * Math.pow(n,3)) *
          (Math.sin(3 * (PHI - PHI0))) * (Math.cos(3 * (PHI + PHI0)))));
}

function LatLon_to_OSGrid(PHI, LAM)
{
   var a = 6377563.396;
   var b = 6356256.910;
   var e0 = 400000;
   var n0 = -100000;
   var f0 = 0.999601272;
   var PHI0 = 49.00000;
   var LAM0 = -2.00000;

   var RadPHI = PHI * (Pi / 180);
   var RadLAM = LAM * (Pi / 180);
   var RadPHI0 = PHI0 * (Pi / 180);
   var RadLAM0 = LAM0 * (Pi / 180);
   var af0 = a * f0;
   var bf0 = b * f0;
   var e2 = (Math.pow(af0,2) - Math.pow(bf0,2)) / Math.pow(af0,2);
   var n = (af0 - bf0) / (af0 + bf0);
   var nu = af0 / (Math.sqrt(1 - (e2 * Math.pow(Math.sin(RadPHI),2) )));
   var rho = (nu * (1 - e2)) / (1 - (e2 * Math.pow(Math.sin(RadPHI),2) ));
   var eta2 = (nu / rho) - 1;
   var p = RadLAM - RadLAM0;
   var M = Marc(bf0, n, RadPHI0, RadPHI);
   var I = M + n0;
   var II = (nu / 2) * (Math.sin(RadPHI)) * (Math.cos(RadPHI));
   var III = ((nu / 24) * (Math.sin(RadPHI)) * (Math.pow(Math.cos(RadPHI),3))) * (5 - (Math.pow(Math.tan(RadPHI),2)) + (9 * eta2));
   var IIIA = ((nu / 720) * (Math.sin(RadPHI)) * (Math.pow(Math.cos(RadPHI),5))) * (61 - (58 * (Math.pow(Math.tan(RadPHI),2))) + (Math.pow(Math.tan(RadPHI),4)));
   var IV = nu * (Math.cos(RadPHI));
   var V = (nu / 6) * ( Math.pow(Math.cos(RadPHI),3)) * ((nu / rho) - (Math.pow(Math.tan(RadPHI),2)));
   var VI = (nu / 120) * (Math.pow(Math.cos(RadPHI),5)) * (5 - (18 * (Math.pow(Math.tan(RadPHI),2))) + (Math.pow(Math.tan(RadPHI),4)) + (14 * eta2) - (58 * (Math.pow(Math.tan(RadPHI),2)) * eta2));
   eastings = Math.round(e0 + (p * IV) + (Math.pow(p,3) * V) + (Math.pow(p,5) * VI));
   northings = Math.round(I + (Math.pow(p,2) * II) + (Math.pow(p,4) * III) + (Math.pow(p,6) * IIIA));
}
//-----------------------------------------------------------------------------------------------------------------------------------------

function toOSGrid(lat, lon)
{
   latitude = lat;
   longitude = lon;
   wgs_to_osgb();

   // determine which 10km grid block contains the current WME centrepoint
   var eBlock = (Math.floor(eastings/10000)) * 10000;
   var nBlock = (Math.floor(northings/10000)) * 10000;
   // check to see if there's a corresponding array in the osl_10km data
   var evalstr = 'typeof locatorData_'+eBlock+'_'+nBlock;
   if(eval(evalstr) != "undefined")
   {
      // yes...  make a local copy to avoid having an eval() in each iteration of the loop
      evalstr = 'var blockData = locatorData_'+eBlock+'_'+nBlock;
      eval(evalstr);
      oslDiv.innerHTML = 'Potential names at '+eastings+','+northings+':<br>';
      for(var loop = 0;loop < blockData.length; loop++)
      {
         // for each entry in the array, test the centrepoint position to see if it lies within the bounding box for that entry
         // note that we allow a 10m tolerance on all sides of the box to allow for inaccuracies in the latlon->gridref conversion,
         // and to increase the chance of a successful match when the road runs E-W or N-S and thus has a long but narrow bounding box
         var locatorElements = blockData[loop].split(":");
         if((eastings>=parseInt(locatorElements[4])-10)&&(eastings<=parseInt(locatorElements[5])+10)&&(northings>=parseInt(locatorElements[6])-10)&&(northings<=parseInt(locatorElements[7])+10))
         {
            if(locatorElements[1].length > 0)
            {
               oslDiv.innerHTML += locatorElements[1];
               if(locatorElements[0].length > 0)
               {
                  oslDiv.innerHTML += " - ";
               }
            }
            oslDiv.innerHTML += locatorElements[0]+'<br>';
         }
      }
   }

   return '?e='+eastings+'&n='+northings;
}

function processPermalink()
{
   // extract current lat/lon & zoom level from the permalink URL
   var plsrc = document.getElementById("permalink-container").innerHTML;
   var zoompos = plsrc.indexOf("?zoom=");
   var latpos = plsrc.indexOf("&lat=");
   var lonpos = plsrc.indexOf("&lon=");
   var layerpos = plsrc.indexOf("&layers=");

   // does the URL contain all three parameters?
   if((zoompos != -1)&&(latpos != -1)&&(lonpos != -1)&&(layerpos != -1))
   {
      // yes, so extract them...
      var zoom = parseInt(plsrc.substr(zoompos+6,latpos-(zoompos+6)));

      // accommodate both the original permalink ordering of zoom, lat then lon, and the present
      // ordering (as of early July 2012) of zoom, lon then lat...
      if(latpos < lonpos)
      {
         var lat = plsrc.substr(latpos+9,lonpos-(latpos+9));
         var lon = plsrc.substr(lonpos+9,layerpos-(lonpos+9));
      }
      else
      {
         var lat = plsrc.substr(latpos+9,layerpos-(latpos+9));
         var lon = plsrc.substr(lonpos+9,latpos-(lonpos+9));
      }

      // compare the freshly extracted parameters against the persistent copies, and update the
      // links to OSMC & OSOD only if there's a change required - the newly-inserted <a> element
      // can't be clicked on until the insertion process is complete, and if we were to re-insert
      // it every 250ms then it'd spend a lot of its time giving the appearance of being clickable
      // but without actually doing anything...
      if((zoom != sessionStorage.zoom)||(lat != sessionStorage.lat)||(lon != sessionStorage.lon))
      {
         // update the persistent vars with the new position
         sessionStorage.zoom = zoom;
         sessionStorage.lat = lat;
         sessionStorage.lon = lon;

         // translate the zoom level between WME and Musical Chairs - this gives a pretty close match
         var mczoom = zoom + 12;
         if(mczoom > 18) mczoom = 18;
         // generate the Musical Chairs URL
         var osmc_url = 'http://ris.dev.openstreetmap.org/oslmusicalchairs/map?zoom='+mczoom+'&lat='+lat+'&lon='+lon+'&layers=B0TT&view_mode=pseudorandom';

         // translate the zoom level between WME and OpenData - the match here isn't quite so good...
         var odzoom = zoom + 5;
         if(odzoom < 6) odzoom = 6;
         if(odzoom > 10) odzoom = 10;
         // generate the OpenData URL - requires the support of os_opendata_fullheight.user.js
         var osod_url = 'http://www.ordnancesurvey.co.uk/oswebsite/opendata/viewer/'+toOSGrid(lat,lon)+'&z='+odzoom;

         // generate the Cartouche URL
         var cartouche_url = 'http://world.waze.com/cartouche_old/?zoom='+zoom+'&lon='+lon+'&lat='+lat;

         // translate the zoom level between WME and live map.  The only correlation is (WME)=[Live] (0 or 1)=[7], (2 or 3)=[8], (4 or more)=[9]
         var livemap_zoom = Math.floor(zoom/2)+7;
         if (livemap_zoom > 9 ) livemap_zoom = 9;
         var livemap_url = 'https://world.waze.com/livemap/?zoom='+livemap_zoom+'&lat='+lat+'&lon='+lon+'&layers=BTTTT';
         // Modify existing livemap link to reference current position in WME
         document.getElementById("livemap").href = livemap_url;
         document.getElementById("livemap").target = '_blank';

         // update the link URLs
         document.getElementById("_linkOSOD").href = osod_url;
         document.getElementById("_linkOSMC").href = osmc_url;
         document.getElementById("_linkCartouche").href = cartouche_url;

         // refresh any of the site tabs/windows we've checked for auto-tracking
         if(document.getElementById('_cbAutoTrackOSOD').checked == 1) window.open(osod_url,'_osopendata');
         if(document.getElementById('_cbAutoTrackOSMC').checked == 1) window.open(osmc_url,'_osmusicalchairs');
         if(document.getElementById('_cbAutoTrackCartouche').checked == 1) window.open(cartouche_url,'_cartouche');
      }
   }
}

// initialise persistent vars
sessionStorage.zoom = 0;
sessionStorage.lat = '';
sessionStorage.lon = '';

// get the colour attribute for the permalink, so that our new links are visually consistent
var pl_colour = document.defaultView.getComputedStyle(document.getElementById("map-footer"),"").getPropertyValue("color");
// create a new child div in the existing map footer div, so we don't have to borrow the bing attrinution one any more...
var mlcDiv = document.createElement('div');
var oslDiv = document.createElement('div');
mlcDiv.setAttribute('id','MapLinkControls');
// add the anchors and auto-track checkboxes for OS OpenData, Musical Chairs and Cartouche.  Note that the urls are blank at this stage,
// they'll be filled in as soon as we've done our first processPermalink() call
mlcDiv.innerHTML = '<a href="" id="_linkOSOD" target=_osopendata style="color:' + pl_colour +'">OS OpenData</a> <input type="checkbox" id="_cbAutoTrackOSOD"></input> | ';
mlcDiv.innerHTML += '<a href="" id="_linkOSMC" target=_osmusicalchairs style="color:' + pl_colour +'">OS Musical Chairs</a> <input type="checkbox" id="_cbAutoTrackOSMC"></input> | ';
mlcDiv.innerHTML += '<a href="" id="_linkCartouche" target=_cartouche style="color:' + pl_colour +'">Cartouche</a> <input type="checkbox" id="_cbAutoTrackCartouche"></input>';
mlcDiv.innerHTML += '<br>(Checkboxes enable auto-tracking)';
document.getElementById('map-footer').appendChild(mlcDiv);
document.getElementById('map-footer').appendChild(oslDiv);

// set up a check for new map co-ords every 250ms
setInterval(processPermalink,250);
Twister-UK
Waze Local Champs
Waze Local Champs
Posts: 4671
Answers: 2
Has thanked: 736 times
Been thanked: 4687 times
Send a message
Chris (not to be confused with Chris or Chris, or even Tim, Stu, or any of the other champs team...)
AM SE England & Shetland Islands, UK Local Champ, WME Beta Tester & ScriptMangler
WME/Livemap enhancement scripts @ GreasyFork


https://chizzum.com/greasemonkey/images/beta.pnghttps://chizzum.com/greasemonkey/images/s0400.pnghttps://chizzum.com/greasemonkey/images/c5s.png

Post by Twister-UK
The OS Locator data consists of a whole bunch of fields per road, with the road name and road number being two seperate fields, so it's simple to add the two together with a - seperator to get the Waze-preferred format. Other fields include locality data (city/town/village name and county/area name) which could also be useful... As far as upper/lower case and abbreviations go, I'll probably sort all of that out in the pre-processing stage rather than expect the script to get it correct on the fly - having all the abbreviations baked into the preprocessed data will, along with some other optimisations, also help bring the data size down a little.

Layout-wise, the goal is ultimately to have the potential names listed as clickable links in the road properties section of the WME screen - click the name to auto-populate the relevant properties fields, then move the mouse pointer up a bit to do whatever fine tuning is required. It might be possible to quickly relocate the current non-clickable output up there too, I haven't yet had a look at that part of the WME page layout to see how much work is involved.

From a targetting point of view, I'd like to have it perform the lookup when you click on an existing road segment rather than having it constantly doing lookups every time the map is dragged - not only would this improve overall performance, but it'd also mean you'd know exactly which location was being used for the search. Not so sure if this is easily doable since it'd mean intercepting the mouse click before WME gets its hands on it, and from what I've seen so far the WME code isn't the easiest to follow...


Anyway, it is very early days for this evolution of the script, so right now I'm just happy that the OS lookup is working for at least one other person!
Twister-UK
Waze Local Champs
Waze Local Champs
Posts: 4671
Answers: 2
Has thanked: 736 times
Been thanked: 4687 times
Send a message
Chris (not to be confused with Chris or Chris, or even Tim, Stu, or any of the other champs team...)
AM SE England & Shetland Islands, UK Local Champ, WME Beta Tester & ScriptMangler
WME/Livemap enhancement scripts @ GreasyFork


https://chizzum.com/greasemonkey/images/beta.pnghttps://chizzum.com/greasemonkey/images/s0400.pnghttps://chizzum.com/greasemonkey/images/c5s.png

Post by Twister-UK
What's new/changed...

-Now performs lookup when a segment is highlighted, provided no segments are selected
-Road names are now shown in correct upper/lower case and with appropriate abbreviations
-Names are now shown in the Properties area rather than below the map window
-Names can now be inserted into segment properties

To insert a name, unhide the properties area to the left of the map view, then hover the mouse pointer over the segment to be renamed until the locator results appear. Now click the segment to lock the results, use the radio buttons to the left of each result to select the correct name, and click the Copy to Properties button. Finally, click the Edit Address link to enable the editing mode, and you should find the street name field populated with the selected name.

Still Firefox only at the moment...

Code: Select all

// ==UserScript==
// @name                WME to OS link
// @namespace           http://greasemonkey.chizzum.com
// @description         Adds link to WME to open up various mapping sites at the same map location
// @include             https://world.waze.com/editor/*
// @include             https://world.waze.com/map-editor/*
// @include             https://descartesw.waze.com/beta/*
// @require             http://greasemonkey.chizzum.com/osl_10km.js
// @version             0.8.1
// ==/UserScript==

// Contains Ordnance Survey data Crown copyright and database right 2012
// Contents of the osl_10km.js file are derived under the Open Government Licence from the OS Locator dataset


//-----------------------------------------------------------------------------------------------------------------------------------------
// all code between here and the next ------------- marker line is a stripped down version of the original from Paul Dixon
//
// * GeoTools javascript coordinate transformations
// * http://files.dixo.net/geotools.html
// *
// * This file copyright (c)2005 Paul Dixon (paul@elphin.com)
// *
// * This program is free software; you can redistribute it and/or
// * modify it under the terms of the GNU General Public License
// * as published by the Free Software Foundation; either version 2
// * of the License, or (at your option) any later version.
// *
// * This program is distributed in the hope that it will be useful,
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// * GNU General Public License for more details.
// *
// * You should have received a copy of the GNU General Public License
// * along with this program; if not, write to the Free Software
// * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
// *
// * ---------------------------------------------------------------------------
// *
// * Credits
// *
// * The algorithm used by the script for WGS84-OSGB36 conversions is derived
// * from an OSGB spreadsheet (www.gps.gov.uk) with permission. This has been
// * adapted into Perl by Ian Harris, and into PHP by Barry Hunter. Conversion
// * accuracy is in the order of 7m for 90% of Great Britain, and should be
// * be similar to the conversion made by a typical GPSr
// *
// * See accompanying documentation for more information
// * http://files.dixo.net/geotools.html

var northings;
var eastings;
var latitude;
var longitude;

var helmX, helmY, helmZ;
var Pi = 3.14159265358979;

function wgs_to_osgb()
{
	LatLon_to_HelmXYZ();
   var latitude2  = XYZ_to_Lat();
	var longitude2 = Math.atan2(helmY , helmX) * (180 / Pi);
	LatLon_to_OSGrid(latitude2,longitude2);
}

function LatLon_to_HelmXYZ()
{
   var a = 6378137.0;
   var b = 6356752.313;
   var DX = -446.448;
   var DY = 125.157;
   var DZ = -542.060;
   var rotX = -0.1502;
   var rotY = -0.2470;
   var rotZ = -0.8421;
	var sfactor = 20.4894 * 0.000001;

   // perform initial lat-lon to cartesian coordinate translation
   var RadPHI = latitude * (Pi / 180);
   var RadLAM = longitude * (Pi / 180);
   var e2 = (Math.pow(a,2) - Math.pow(b,2)) / Math.pow(a,2);
   var V = a / (Math.sqrt(1 - (e2 * (  Math.pow(Math.sin(RadPHI),2)))));
   var cartX = V * (Math.cos(RadPHI)) * (Math.cos(RadLAM));
   var cartY = V * (Math.cos(RadPHI)) * (Math.sin(RadLAM));
   var cartZ = (V * (1 - e2)) * (Math.sin(RadPHI));

   // Compute Helmert transformed coordinates
	var RadX_Rot = (rotX / 3600) * (Pi / 180);
	var RadY_Rot = (rotY / 3600) * (Pi / 180);
	var RadZ_Rot = (rotZ / 3600) * (Pi / 180);
   helmX = (cartX + (cartX * sfactor) - (cartY * RadZ_Rot) + (cartZ * RadY_Rot) + DX);
	helmY = (cartX * RadZ_Rot) + cartY + (cartY * sfactor) - (cartZ * RadX_Rot) + DY;
	helmZ = (-1 * cartX * RadY_Rot) + (cartY * RadX_Rot) + cartZ + (cartZ * sfactor) + DZ;
}

function XYZ_to_Lat()
{
   var a = 6377563.396;
   var b = 6356256.910;
   var RootXYSqr = Math.sqrt(Math.pow(helmX,2) + Math.pow(helmY,2));
   var e2 = (Math.pow(a,2) - Math.pow(b,2)) / Math.pow(a,2);
   var PHI1 = Math.atan2(helmZ , (RootXYSqr * (1 - e2)) );
   var PHI = Iterate_XYZ_to_Lat(a, e2, PHI1, helmZ, RootXYSqr);
   return PHI * (180 / Pi);
}

function Iterate_XYZ_to_Lat(a, e2, PHI1, Z, RootXYSqr)
{
   var V = a / (Math.sqrt(1 - (e2 * Math.pow(Math.sin(PHI1),2))));
   var PHI2 = Math.atan2((Z + (e2 * V * (Math.sin(PHI1)))) , RootXYSqr);
   while (Math.abs(PHI1 - PHI2) > 0.000000001)
   {
      PHI1 = PHI2;
      V = a / (Math.sqrt(1 - (e2 * Math.pow(Math.sin(PHI1),2))));
      PHI2 = Math.atan2((Z + (e2 * V * (Math.sin(PHI1)))) , RootXYSqr);
   }
   return PHI2;
}

function Marc(bf0, n, PHI0, PHI)
{
   return bf0 * (((1 + n + ((5 / 4) * Math.pow(n,2)) + ((5 / 4) * Math.pow(n,3))) * (PHI - PHI0)) - (((3 * n) + (3 * Math.pow(n,2)) +
          ((21 / 8) * Math.pow(n,3))) * (Math.sin(PHI - PHI0)) * (Math.cos(PHI + PHI0))) + ((((15 / 8) * Math.pow(n,2)) + ((15 / 8) *
          Math.pow(n,3))) * (Math.sin(2 * (PHI - PHI0))) * (Math.cos(2 * (PHI + PHI0)))) - (((35 / 24) * Math.pow(n,3)) *
          (Math.sin(3 * (PHI - PHI0))) * (Math.cos(3 * (PHI + PHI0)))));
}

function LatLon_to_OSGrid(PHI, LAM)
{
   var a = 6377563.396;
   var b = 6356256.910;
   var e0 = 400000;
   var n0 = -100000;
   var f0 = 0.999601272;
   var PHI0 = 49.00000;
   var LAM0 = -2.00000;

   var RadPHI = PHI * (Pi / 180);
   var RadLAM = LAM * (Pi / 180);
   var RadPHI0 = PHI0 * (Pi / 180);
   var RadLAM0 = LAM0 * (Pi / 180);
   var af0 = a * f0;
   var bf0 = b * f0;
   var e2 = (Math.pow(af0,2) - Math.pow(bf0,2)) / Math.pow(af0,2);
   var n = (af0 - bf0) / (af0 + bf0);
   var nu = af0 / (Math.sqrt(1 - (e2 * Math.pow(Math.sin(RadPHI),2) )));
   var rho = (nu * (1 - e2)) / (1 - (e2 * Math.pow(Math.sin(RadPHI),2) ));
   var eta2 = (nu / rho) - 1;
   var p = RadLAM - RadLAM0;
   var M = Marc(bf0, n, RadPHI0, RadPHI);
   var I = M + n0;
   var II = (nu / 2) * (Math.sin(RadPHI)) * (Math.cos(RadPHI));
   var III = ((nu / 24) * (Math.sin(RadPHI)) * (Math.pow(Math.cos(RadPHI),3))) * (5 - (Math.pow(Math.tan(RadPHI),2)) + (9 * eta2));
   var IIIA = ((nu / 720) * (Math.sin(RadPHI)) * (Math.pow(Math.cos(RadPHI),5))) * (61 - (58 * (Math.pow(Math.tan(RadPHI),2))) + (Math.pow(Math.tan(RadPHI),4)));
   var IV = nu * (Math.cos(RadPHI));
   var V = (nu / 6) * ( Math.pow(Math.cos(RadPHI),3)) * ((nu / rho) - (Math.pow(Math.tan(RadPHI),2)));
   var VI = (nu / 120) * (Math.pow(Math.cos(RadPHI),5)) * (5 - (18 * (Math.pow(Math.tan(RadPHI),2))) + (Math.pow(Math.tan(RadPHI),4)) + (14 * eta2) - (58 * (Math.pow(Math.tan(RadPHI),2)) * eta2));
   eastings = Math.round(e0 + (p * IV) + (Math.pow(p,3) * V) + (Math.pow(p,5) * VI));
   northings = Math.round(I + (Math.pow(p,2) * II) + (Math.pow(p,4) * III) + (Math.pow(p,6) * IIIA));
}
//-----------------------------------------------------------------------------------------------------------------------------------------

function wazeifyStreetName(oslName)
{
   var wazeName = '';
   var loop;
   for(loop=0;loop<oslName.length;loop++)
   {
      if((loop == 0)||(oslName[loop-1] == ' ')) wazeName += oslName[loop].toUpperCase();
      else wazeName += oslName[loop].toLowerCase();
   }

   var namePieces = wazeName.split(' ');
   if(namePieces.length > 1)
   {
      var roadType;
      var dirSuffix;
      var thePrefix;
      var namePrefix = '';
      if((namePieces[namePieces.length-1] == 'North')||(namePieces[namePieces.length-1] == 'South')||(namePieces[namePieces.length-1] == 'East')||(namePieces[namePieces.length-1] == 'West'))
      {
         dirSuffix = namePieces[namePieces.length-1][0];
         roadType = namePieces[namePieces.length-2];
         if(namePieces.length > 2)
         {
            if(namePieces[namePieces.length-3] == 'The') thePrefix = true;
            else thePrefix = false;
         }
         for(loop=0;loop<namePieces.length-2;loop++) namePrefix += (namePieces[loop] + ' ');
      }
      else
      {
         dirSuffix = '';
         roadType = namePieces[namePieces.length-1];
         if(namePieces[namePieces.length-2] == 'The') thePrefix = true;
         else thePrefix = false;
         for(loop=0;loop<namePieces.length-1;loop++) namePrefix += (namePieces[loop] + ' ');

      }
      if(thePrefix == false)
      {
         roadType = roadType.replace('Avenue','Ave');
         roadType = roadType.replace('Boulevard','Blvd');
         roadType = roadType.replace('Broadway','Bdwy');
         roadType = roadType.replace('Close','Cl');
         roadType = roadType.replace('Court','Ct');
         roadType = roadType.replace('Crescent','Cr');
         roadType = roadType.replace('Drive','Dr');
         roadType = roadType.replace('Gardens','Gdns');
         roadType = roadType.replace('Garden','Gdn');
         roadType = roadType.replace('Green','Gn');
         roadType = roadType.replace('Grove','Gr');
         roadType = roadType.replace('Lane','Ln');
         roadType = roadType.replace('Mount','Mt');
         roadType = roadType.replace('Place','Pl');
         roadType = roadType.replace('Park','Pk');
         roadType = roadType.replace('Road','Rd');
         roadType = roadType.replace('Square','Sq');
         roadType = roadType.replace('Street','St');
         roadType = roadType.replace('Terrace','Ter');
      }
      wazeName = namePrefix + roadType + ' ' + dirSuffix;
   }
   return wazeName;
}

function oslClick()
{
   var oslElements = document.getElementById('oslDiv');
   for(var loop=0;loop<oslElements.childNodes.length;loop++)
   {
      if(oslElements.childNodes[loop].nodeType == 1)
      {
         attr = oslElements.childNodes[loop].attributes.getNamedItem("type");
         if(attr != null)
         {
            if(attr.value == "radio")
            {
               if(oslElements.childNodes[loop].checked)
               {
                  attr = oslElements.childNodes[loop].attributes.getNamedItem("id").value;
                  oslID = attr.split('_');
                  evalstr = 'var roadData = locatorData_'+oslID[1]+'_'+oslID[2]+'['+oslID[3]+']';
                  eval(evalstr);
                  var locatorElements = roadData.split(":");

                  var oslName = locatorElements[9];
                  if(locatorElements[8].length > 0) oslName += ' ('+locatorElements[8]+')';

                  //var snelms = document.getElementsByName('cityName');
                  //snelms[0].value = oslName;
                  //snelms[0].disabled = false;
                  //snelms = document.getElementsByName('emptyCity');
                  //snelms[0].checked = false;

                  oslName = locatorElements[1];
                  if((locatorElements[0].length > 0)&&(locatorElements[1].length > 0)) oslName += ' - ';
                  oslName += wazeifyStreetName(locatorElements[0]);

                  snelms = document.getElementsByName('streetName');
                  snelms[0].value = oslName;
                  snelms[0].disabled = false;
                  snelms = document.getElementsByName('emptyStreet');
                  snelms[0].checked = false;
               }
            }
         }
      }
   }
}


function toOSGrid(lat, lon, mode)
{
   latitude = lat;
   longitude = lon;
   wgs_to_osgb();

   if(mode == 1)  // OS Locator lookup
   {
      // determine which 10km grid block contains the current WME centrepoint
      var eBlock = (Math.floor(eastings/10000)) * 10000;
      var nBlock = (Math.floor(northings/10000)) * 10000;
      // check to see if there's a corresponding array in the osl_10km data
      var evalstr = 'typeof locatorData_'+eBlock+'_'+nBlock;
      if(eval(evalstr) != "undefined")
      {
         // yes...  make a local copy to avoid having an eval() in each iteration of the loop
         evalstr = 'var blockData = locatorData_'+eBlock+'_'+nBlock;
         eval(evalstr);
         oslDiv.innerHTML = 'OSL matches at '+eastings+','+northings+':<br>';
         var candidates = 0;
         for(var loop = 0;loop < blockData.length; loop++)
         {
            // for each entry in the array, test the centrepoint position to see if it lies within the bounding box for that entry
            // note that we allow a 10m tolerance on all sides of the box to allow for inaccuracies in the latlon->gridref conversion,
            // and to increase the chance of a successful match when the road runs E-W or N-S and thus has a long but narrow bounding box
            var locatorElements = blockData[loop].split(":");
            if((eastings>=parseInt(locatorElements[4])-10)&&(eastings<=parseInt(locatorElements[5])+10)&&(northings>=parseInt(locatorElements[6])-10)&&(northings<=parseInt(locatorElements[7])+10))
            {
               var oslLink = '<input type="radio" name="oslChoice" id="oslID_'+eBlock+'_'+nBlock+'_'+loop+'"></input>';
               if(locatorElements[1].length > 0)
               {
                  oslLink += locatorElements[1];
                  if(locatorElements[0].length > 0)
                  {
                     oslLink += ' - ';
                  }
               }
               oslLink += wazeifyStreetName(locatorElements[0])+'<br>';
               oslDiv.innerHTML += oslLink;
               candidates++;
            }
         }
         if(candidates > 0)
         {
            oslDiv.innerHTML += '<input id="oslSelect" type="button" value="Copy to Properties" />';
            document.getElementById('oslSelect').addEventListener("click", oslClick, true);
         }

      }
   }
   else return '?e='+eastings+'&n='+northings;
}

function processPermalink()
{
   var mousepos = document.getElementById("OpenLayers.Control.MousePosition_26").innerHTML;
   if(mousepos != sessionStorage.mousepos)
   {
      sessionStorage.mousepos = mousepos;
      if(document.getElementById("editPanel").innerHTML.indexOf("editSegmentStreetDetailsForm") == -1)  // segment properties panel isn't open...
      {
         if(document.getElementById("OpenLayers.Layer.Vector.RootContainer_221").innerHTML.indexOf('#03b9da') != -1) // ...and segment is highlighted
         {
            // so update the OS Locator matches
            mouselatlon = mousepos.split(",");
            toOSGrid(mouselatlon[1],mouselatlon[0],1);
         }
      }
   }

   // extract current lat/lon & zoom level from the permalink URL
   var plsrc = document.getElementById("permalink-container").innerHTML;
   var zoompos = plsrc.indexOf("?zoom=");
   var latpos = plsrc.indexOf("&lat=");
   var lonpos = plsrc.indexOf("&lon=");
   var layerpos = plsrc.indexOf("&layers=");

   // does the URL contain all three parameters?
   if((zoompos != -1)&&(latpos != -1)&&(lonpos != -1)&&(layerpos != -1))
   {
      // yes, so extract them...
      var zoom = parseInt(plsrc.substr(zoompos+6,latpos-(zoompos+6)));

      // accommodate both the original permalink ordering of zoom, lat then lon, and the present
      // ordering (as of early July 2012) of zoom, lon then lat...
      if(latpos < lonpos)
      {
         var lat = plsrc.substr(latpos+9,lonpos-(latpos+9));
         var lon = plsrc.substr(lonpos+9,layerpos-(lonpos+9));
      }
      else
      {
         var lat = plsrc.substr(latpos+9,layerpos-(latpos+9));
         var lon = plsrc.substr(lonpos+9,latpos-(lonpos+9));
      }

      // compare the freshly extracted parameters against the persistent copies, and update the
      // links to OSMC & OSOD only if there's a change required - the newly-inserted <a> element
      // can't be clicked on until the insertion process is complete, and if we were to re-insert
      // it every 250ms then it'd spend a lot of its time giving the appearance of being clickable
      // but without actually doing anything...
      if((zoom != sessionStorage.zoom)||(lat != sessionStorage.lat)||(lon != sessionStorage.lon))
      {
         // update the persistent vars with the new position
         sessionStorage.zoom = zoom;
         sessionStorage.lat = lat;
         sessionStorage.lon = lon;

         // translate the zoom level between WME and Musical Chairs - this gives a pretty close match
         var mczoom = zoom + 12;
         if(mczoom > 18) mczoom = 18;
         // generate the Musical Chairs URL
         var osmc_url = 'http://ris.dev.openstreetmap.org/oslmusicalchairs/map?zoom='+mczoom+'&lat='+lat+'&lon='+lon+'&layers=B0TT&view_mode=pseudorandom';

         // translate the zoom level between WME and OpenData - the match here isn't quite so good...
         var odzoom = zoom + 5;
         if(odzoom < 6) odzoom = 6;
         if(odzoom > 10) odzoom = 10;
         // generate the OpenData URL - requires the support of os_opendata_fullheight.user.js
         var osod_url = 'http://www.ordnancesurvey.co.uk/oswebsite/opendata/viewer/'+toOSGrid(lat,lon,0)+'&z='+odzoom;

         // generate the Cartouche URL
         var cartouche_url = 'http://world.waze.com/cartouche_old/?zoom='+zoom+'&lon='+lon+'&lat='+lat;

         // translate the zoom level between WME and live map.  The only correlation is (WME)=[Live] (0 or 1)=[7], (2 or 3)=[8], (4 or more)=[9]
         var livemap_zoom = Math.floor(zoom/2)+7;
         if (livemap_zoom > 9 ) livemap_zoom = 9;
         var livemap_url = 'https://world.waze.com/livemap/?zoom='+livemap_zoom+'&lat='+lat+'&lon='+lon+'&layers=BTTTT';
         // Modify existing livemap link to reference current position in WME
         document.getElementById("livemap").href = livemap_url;
         document.getElementById("livemap").target = '_blank';

         // update the link URLs
         document.getElementById("_linkOSOD").href = osod_url;
         document.getElementById("_linkOSMC").href = osmc_url;
         document.getElementById("_linkCartouche").href = cartouche_url;

         // refresh any of the site tabs/windows we've checked for auto-tracking
         if(document.getElementById('_cbAutoTrackOSOD').checked == 1) window.open(osod_url,'_osopendata');
         if(document.getElementById('_cbAutoTrackOSMC').checked == 1) window.open(osmc_url,'_osmusicalchairs');
         if(document.getElementById('_cbAutoTrackCartouche').checked == 1) window.open(cartouche_url,'_cartouche');
      }
   }
}

// initialise persistent vars
sessionStorage.zoom = 0;
sessionStorage.lat = '';
sessionStorage.lon = '';

// get the colour attribute for the permalink, so that our new links are visually consistent
var pl_colour = document.defaultView.getComputedStyle(document.getElementById("map-footer"),"").getPropertyValue("color");
// create a new child div in the existing map footer div, so we don't have to borrow the bing attribution one any more...
var mlcDiv = document.createElement('div');
mlcDiv.setAttribute('id','MapLinkControls');
// add the anchors and auto-track checkboxes for OS OpenData, Musical Chairs and Cartouche.  Note that the urls are blank at this stage,
// they'll be filled in as soon as we've done our first processPermalink() call
mlcDiv.innerHTML = '<a href="" id="_linkOSOD" target=_osopendata style="color:' + pl_colour +'">OS OpenData</a> <input type="checkbox" id="_cbAutoTrackOSOD"></input> | ';
mlcDiv.innerHTML += '<a href="" id="_linkOSMC" target=_osmusicalchairs style="color:' + pl_colour +'">OS Musical Chairs</a> <input type="checkbox" id="_cbAutoTrackOSMC"></input> | ';
mlcDiv.innerHTML += '<a href="" id="_linkCartouche" target=_cartouche style="color:' + pl_colour +'">Cartouche</a> <input type="checkbox" id="_cbAutoTrackCartouche"></input>';
mlcDiv.innerHTML += '<br>(Checkboxes enable auto-tracking)';
document.getElementById('map-footer').appendChild(mlcDiv);

// add a new div to the edit properties panel, to hold the OS Locator results
var oslDiv = document.createElement('div');
oslDiv.id = "oslDiv";
document.getElementById('editPanel').appendChild(oslDiv);

// set up a check for new map co-ords every 250ms
setInterval(processPermalink,250);
Twister-UK
Waze Local Champs
Waze Local Champs
Posts: 4671
Answers: 2
Has thanked: 736 times
Been thanked: 4687 times
Send a message
Chris (not to be confused with Chris or Chris, or even Tim, Stu, or any of the other champs team...)
AM SE England & Shetland Islands, UK Local Champ, WME Beta Tester & ScriptMangler
WME/Livemap enhancement scripts @ GreasyFork


https://chizzum.com/greasemonkey/images/beta.pnghttps://chizzum.com/greasemonkey/images/s0400.pnghttps://chizzum.com/greasemonkey/images/c5s.png

Post by Twister-UK
Thanks for the feedback! Displaying the bounding boxes is something I've considered, but first I want to sort the results by their distance from the segment centrepoint reference in the OS data - that should make a big difference in helping to choose the correct result in areas where there's one or more long road segments, with correspondingly huge bounding boxes which dominate the local search results, even though the centre point of those segments may not even be visible on the map...

I've also been tinkering with the general useability of the script, and have figured out how to make it auto-click on the "Edit Address" button so that when you click the Copy to Properties button everything is set up ready for you to simply click the Apply button (assuming there are no further changes to be made, of course!).


Also started to look at populating the City field - I thought there was something in the wiki regarding this field, but I couldn't find anything when I went to refresh my memory last night, so do we have a preferred UK formatting standard for this field?

Note that the OS data provides the town/city name, 1990 boundaries area, county and local authority as seperate fields for each road segment, so there's plenty of scope to come up with a suitably formatted combination - and even more scope to get it well and truly wrong...
Twister-UK
Waze Local Champs
Waze Local Champs
Posts: 4671
Answers: 2
Has thanked: 736 times
Been thanked: 4687 times
Send a message
Chris (not to be confused with Chris or Chris, or even Tim, Stu, or any of the other champs team...)
AM SE England & Shetland Islands, UK Local Champ, WME Beta Tester & ScriptMangler
WME/Livemap enhancement scripts @ GreasyFork


https://chizzum.com/greasemonkey/images/beta.pnghttps://chizzum.com/greasemonkey/images/s0400.pnghttps://chizzum.com/greasemonkey/images/c5s.png

Post by Twister-UK
xteejx, remind me never to try reading the wiki when tired - I could have sworn that page was nowhere to be found last night...

Anyhoo, another incremental update brings the following changes:

- results are now sorted by distance from the mouse click gridref to the segment centrepoint gridref
- a city name field has been added to the search results area, allowing this to be set manually once and then auto-populated into every new edit thereafter until you decide to change it
- the results area now has a distinctive background colour, to differentiate it from the standard WME editing controls
- Clicking the "Copy to Properties" button now also causes the "Edit Address" link to be auto-clicked, which is one less click to be performed manually...


Sorting by distance isn't quite as successful as I'd originally thought it would be - it certainly makes a big difference in many areas, but doesn't cope too well when highlighting part of a long road adjacent to a short road. With the benefit of hindsight, this was kinda obvious... I've got some other ideas on how to improve this, but realistically it'll never be 100% accurate given the overlapping nature of the bounding box data. Figuring out a way to visualise the bounding boxes may well have to be the next challenge.

Code: Select all

// ==UserScript==
// @name                WME to OS link
// @namespace           http://greasemonkey.chizzum.com
// @description         Adds link to WME to open up various mapping sites at the same map location
// @include             https://world.waze.com/editor/*
// @include             https://world.waze.com/map-editor/*
// @include             https://descartesw.waze.com/beta/*
// @require             http://greasemonkey.chizzum.com/osl_10km.js
// @version             0.8.2
// ==/UserScript==

// Contains Ordnance Survey data Crown copyright and database right 2012
// Contents of the osl_10km.js file are derived under the Open Government Licence from the OS Locator dataset


//-----------------------------------------------------------------------------------------------------------------------------------------
// all code between here and the next ------------- marker line is a stripped down version of the original from Paul Dixon
//
// * GeoTools javascript coordinate transformations
// * http://files.dixo.net/geotools.html
// *
// * This file copyright (c)2005 Paul Dixon (paul@elphin.com)
// *
// * This program is free software; you can redistribute it and/or
// * modify it under the terms of the GNU General Public License
// * as published by the Free Software Foundation; either version 2
// * of the License, or (at your option) any later version.
// *
// * This program is distributed in the hope that it will be useful,
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// * GNU General Public License for more details.
// *
// * You should have received a copy of the GNU General Public License
// * along with this program; if not, write to the Free Software
// * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
// *
// * ---------------------------------------------------------------------------
// *
// * Credits
// *
// * The algorithm used by the script for WGS84-OSGB36 conversions is derived
// * from an OSGB spreadsheet (www.gps.gov.uk) with permission. This has been
// * adapted into Perl by Ian Harris, and into PHP by Barry Hunter. Conversion
// * accuracy is in the order of 7m for 90% of Great Britain, and should be
// * be similar to the conversion made by a typical GPSr
// *
// * See accompanying documentation for more information
// * http://files.dixo.net/geotools.html

var northings;
var eastings;
var latitude;
var longitude;

var helmX, helmY, helmZ;
var Pi = 3.14159265358979;

function wgs_to_osgb()
{
	LatLon_to_HelmXYZ();
   var latitude2  = XYZ_to_Lat();
	var longitude2 = Math.atan2(helmY , helmX) * (180 / Pi);
	LatLon_to_OSGrid(latitude2,longitude2);
}

function LatLon_to_HelmXYZ()
{
   var a = 6378137.0;
   var b = 6356752.313;
   var DX = -446.448;
   var DY = 125.157;
   var DZ = -542.060;
   var rotX = -0.1502;
   var rotY = -0.2470;
   var rotZ = -0.8421;
	var sfactor = 20.4894 * 0.000001;

   // perform initial lat-lon to cartesian coordinate translation
   var RadPHI = latitude * (Pi / 180);
   var RadLAM = longitude * (Pi / 180);
   var e2 = (Math.pow(a,2) - Math.pow(b,2)) / Math.pow(a,2);
   var V = a / (Math.sqrt(1 - (e2 * (  Math.pow(Math.sin(RadPHI),2)))));
   var cartX = V * (Math.cos(RadPHI)) * (Math.cos(RadLAM));
   var cartY = V * (Math.cos(RadPHI)) * (Math.sin(RadLAM));
   var cartZ = (V * (1 - e2)) * (Math.sin(RadPHI));

   // Compute Helmert transformed coordinates
	var RadX_Rot = (rotX / 3600) * (Pi / 180);
	var RadY_Rot = (rotY / 3600) * (Pi / 180);
	var RadZ_Rot = (rotZ / 3600) * (Pi / 180);
   helmX = (cartX + (cartX * sfactor) - (cartY * RadZ_Rot) + (cartZ * RadY_Rot) + DX);
	helmY = (cartX * RadZ_Rot) + cartY + (cartY * sfactor) - (cartZ * RadX_Rot) + DY;
	helmZ = (-1 * cartX * RadY_Rot) + (cartY * RadX_Rot) + cartZ + (cartZ * sfactor) + DZ;
}

function XYZ_to_Lat()
{
   var a = 6377563.396;
   var b = 6356256.910;
   var RootXYSqr = Math.sqrt(Math.pow(helmX,2) + Math.pow(helmY,2));
   var e2 = (Math.pow(a,2) - Math.pow(b,2)) / Math.pow(a,2);
   var PHI1 = Math.atan2(helmZ , (RootXYSqr * (1 - e2)) );
   var PHI = Iterate_XYZ_to_Lat(a, e2, PHI1, helmZ, RootXYSqr);
   return PHI * (180 / Pi);
}

function Iterate_XYZ_to_Lat(a, e2, PHI1, Z, RootXYSqr)
{
   var V = a / (Math.sqrt(1 - (e2 * Math.pow(Math.sin(PHI1),2))));
   var PHI2 = Math.atan2((Z + (e2 * V * (Math.sin(PHI1)))) , RootXYSqr);
   while (Math.abs(PHI1 - PHI2) > 0.000000001)
   {
      PHI1 = PHI2;
      V = a / (Math.sqrt(1 - (e2 * Math.pow(Math.sin(PHI1),2))));
      PHI2 = Math.atan2((Z + (e2 * V * (Math.sin(PHI1)))) , RootXYSqr);
   }
   return PHI2;
}

function Marc(bf0, n, PHI0, PHI)
{
   return bf0 * (((1 + n + ((5 / 4) * Math.pow(n,2)) + ((5 / 4) * Math.pow(n,3))) * (PHI - PHI0)) - (((3 * n) + (3 * Math.pow(n,2)) +
          ((21 / 8) * Math.pow(n,3))) * (Math.sin(PHI - PHI0)) * (Math.cos(PHI + PHI0))) + ((((15 / 8) * Math.pow(n,2)) + ((15 / 8) *
          Math.pow(n,3))) * (Math.sin(2 * (PHI - PHI0))) * (Math.cos(2 * (PHI + PHI0)))) - (((35 / 24) * Math.pow(n,3)) *
          (Math.sin(3 * (PHI - PHI0))) * (Math.cos(3 * (PHI + PHI0)))));
}

function LatLon_to_OSGrid(PHI, LAM)
{
   var a = 6377563.396;
   var b = 6356256.910;
   var e0 = 400000;
   var n0 = -100000;
   var f0 = 0.999601272;
   var PHI0 = 49.00000;
   var LAM0 = -2.00000;

   var RadPHI = PHI * (Pi / 180);
   var RadLAM = LAM * (Pi / 180);
   var RadPHI0 = PHI0 * (Pi / 180);
   var RadLAM0 = LAM0 * (Pi / 180);
   var af0 = a * f0;
   var bf0 = b * f0;
   var e2 = (Math.pow(af0,2) - Math.pow(bf0,2)) / Math.pow(af0,2);
   var n = (af0 - bf0) / (af0 + bf0);
   var nu = af0 / (Math.sqrt(1 - (e2 * Math.pow(Math.sin(RadPHI),2) )));
   var rho = (nu * (1 - e2)) / (1 - (e2 * Math.pow(Math.sin(RadPHI),2) ));
   var eta2 = (nu / rho) - 1;
   var p = RadLAM - RadLAM0;
   var M = Marc(bf0, n, RadPHI0, RadPHI);
   var I = M + n0;
   var II = (nu / 2) * (Math.sin(RadPHI)) * (Math.cos(RadPHI));
   var III = ((nu / 24) * (Math.sin(RadPHI)) * (Math.pow(Math.cos(RadPHI),3))) * (5 - (Math.pow(Math.tan(RadPHI),2)) + (9 * eta2));
   var IIIA = ((nu / 720) * (Math.sin(RadPHI)) * (Math.pow(Math.cos(RadPHI),5))) * (61 - (58 * (Math.pow(Math.tan(RadPHI),2))) + (Math.pow(Math.tan(RadPHI),4)));
   var IV = nu * (Math.cos(RadPHI));
   var V = (nu / 6) * ( Math.pow(Math.cos(RadPHI),3)) * ((nu / rho) - (Math.pow(Math.tan(RadPHI),2)));
   var VI = (nu / 120) * (Math.pow(Math.cos(RadPHI),5)) * (5 - (18 * (Math.pow(Math.tan(RadPHI),2))) + (Math.pow(Math.tan(RadPHI),4)) + (14 * eta2) - (58 * (Math.pow(Math.tan(RadPHI),2)) * eta2));
   eastings = Math.round(e0 + (p * IV) + (Math.pow(p,3) * V) + (Math.pow(p,5) * VI));
   northings = Math.round(I + (Math.pow(p,2) * II) + (Math.pow(p,4) * III) + (Math.pow(p,6) * IIIA));
}
//-----------------------------------------------------------------------------------------------------------------------------------------

function caseCorrect(wrongcase)
{
   var loop;
   var correctedCase = '';
   for(loop=0;loop<wrongcase.length;loop++)
   {
      if((loop == 0)||(wrongcase[loop-1] == ' ')) correctedCase += wrongcase[loop].toUpperCase();
      else correctedCase += wrongcase[loop].toLowerCase();
   }
   return correctedCase;
}


function wazeifyStreetName(oslName)
{
   var wazeName = '';
   var loop;

   wazeName = caseCorrect(oslName);

   var namePieces = wazeName.split(' ');
   if(namePieces.length > 1)
   {
      var roadType;
      var dirSuffix;
      var thePrefix;
      var namePrefix = '';
      if((namePieces[namePieces.length-1] == 'North')||(namePieces[namePieces.length-1] == 'South')||(namePieces[namePieces.length-1] == 'East')||(namePieces[namePieces.length-1] == 'West'))
      {
         dirSuffix = namePieces[namePieces.length-1][0];
         roadType = namePieces[namePieces.length-2];
         if(namePieces.length > 2)
         {
            if(namePieces[namePieces.length-3] == 'The') thePrefix = true;
            else thePrefix = false;
         }
         for(loop=0;loop<namePieces.length-2;loop++) namePrefix += (namePieces[loop] + ' ');
      }
      else
      {
         dirSuffix = '';
         roadType = namePieces[namePieces.length-1];
         if(namePieces[namePieces.length-2] == 'The') thePrefix = true;
         else thePrefix = false;
         for(loop=0;loop<namePieces.length-1;loop++) namePrefix += (namePieces[loop] + ' ');

      }
      if(thePrefix == false)
      {
         roadType = roadType.replace('Avenue','Ave');
         roadType = roadType.replace('Boulevard','Blvd');
         roadType = roadType.replace('Broadway','Bdwy');
         roadType = roadType.replace('Close','Cl');
         roadType = roadType.replace('Court','Ct');
         roadType = roadType.replace('Crescent','Cr');
         roadType = roadType.replace('Drive','Dr');
         roadType = roadType.replace('Gardens','Gdns');
         roadType = roadType.replace('Garden','Gdn');
         roadType = roadType.replace('Green','Gn');
         roadType = roadType.replace('Grove','Gr');
         roadType = roadType.replace('Lane','Ln');
         roadType = roadType.replace('Mount','Mt');
         roadType = roadType.replace('Place','Pl');
         roadType = roadType.replace('Park','Pk');
         roadType = roadType.replace('Road','Rd');
         roadType = roadType.replace('Square','Sq');
         roadType = roadType.replace('Street','St');
         roadType = roadType.replace('Terrace','Ter');
      }
      wazeName = namePrefix + roadType + ' ' + dirSuffix;
   }
   return wazeName;
}


function cpDistance(cpE, cpN, posE, posN)
{
   return Math.sqrt(((posE - cpE) * (posE - cpE)) + ((posN - cpN) * (posN - cpN)));
}

function gradMinRatio(bbW, bbE, bbS, bbN, posE, posN)
{
   var gradPosToSW = (posN - bbS) / (posE - bbW);
   var gradPosToSE = (posN - bbS) / (posE - bbE);
   var gradNEToSW = (bbN - bbS) / (bbE - bbW);
   var gradNWToSE = (bbN - bbS) / (bbW - bbE);

   var ratioSW = gradPosToSW / gradNEToSW;
   var ratioSE = gradPosToSE / gradNWToSE;
   if(ratioSW < 1) ratioSW = 1 / ratioSW;
   if(ratioSE < 1) ratioSE = 1 / ratioSE;
   if(ratioSW < ratioSE) return ratioSW;
   else return ratioSE;
}

function oslClick()
{
   var cityName = caseCorrect(document.getElementById('myCityName').value);
   sessionStorage.myCity = cityName;
   var oslElements = document.getElementById('oslDiv');
   for(var loop=0;loop<oslElements.childNodes.length;loop++)
   {
      if(oslElements.childNodes[loop].nodeType == 1)
      {
         attr = oslElements.childNodes[loop].attributes.getNamedItem("type");
         if(attr != null)
         {
            if(attr.value == "radio")
            {
               if(oslElements.childNodes[loop].checked)
               {
                  attr = oslElements.childNodes[loop].attributes.getNamedItem("id").value;
                  oslID = attr.split('_');
                  evalstr = 'var roadData = locatorData_'+oslID[1]+'_'+oslID[2]+'['+oslID[3]+']';
                  eval(evalstr);
                  var locatorElements = roadData.split(":");

                  // auto-click the Edit Address link...
                  var editAddress = document.getElementById('editSegmentsApplyChanges');
                  var editButtons = editAddress.getElementsByClassName('edit-button');
                  editButtons[0].click();

                  // fill in the City field
                  //oslName = caseCorrect(locatorElements[9]);
                  //if(locatorElements[8].length > 0) oslName += ' ('+caseCorrect(locatorElements[8])+')';
                  var snelms = document.getElementsByName('cityName');
                  //snelms[0].value = oslName;
                  snelms[0].value = cityName;
                  snelms[0].disabled = false;
                  snelms = document.getElementsByName('emptyCity');
                  snelms[0].checked = false;

                  // and the Street field
                  oslName = locatorElements[1];
                  if((locatorElements[0].length > 0)&&(locatorElements[1].length > 0)) oslName += ' - ';
                  oslName += wazeifyStreetName(locatorElements[0]);

                  snelms = document.getElementsByName('streetName');
                  snelms[0].value = oslName;
                  snelms[0].disabled = false;
                  snelms = document.getElementsByName('emptyStreet');
                  snelms[0].checked = false;
               }
            }
         }
      }
   }
}


function oslMatch(oslLink, oslDistance, oslMinGradRatio)
{
   this.oslLink = oslLink;
   this.oslDistance = oslDistance;
   this.oslMinGradRatio = oslMinGradRatio;
}
function sortCandidates(a,b)
{
   var x = a.oslDistance;
   var y = b.oslDistance;
   return((x<y) ? -1 : ((x>y) ? 1 : 0));
}

function toOSGrid(lat, lon, mode)
{
   latitude = lat;
   longitude = lon;
   wgs_to_osgb();

   if(mode == 1)  // OS Locator lookup
   {
      // determine which 10km grid block contains the current WME centrepoint
      var eBlock = (Math.floor(eastings/10000)) * 10000;
      var nBlock = (Math.floor(northings/10000)) * 10000;
      // check to see if there's a corresponding array in the osl_10km data
      var evalstr = 'typeof locatorData_'+eBlock+'_'+nBlock;
      if(eval(evalstr) != "undefined")
      {
         // yes...  make a local copy to avoid having an eval() in each iteration of the loop
         evalstr = 'var blockData = locatorData_'+eBlock+'_'+nBlock;
         eval(evalstr);
         oslDiv.innerHTML = 'OSL matches at '+eastings+','+northings+':<br>';
         var candidates = new Array();

         for(var loop = 0;loop < blockData.length; loop++)
         {
            // for each entry in the array, test the centrepoint position to see if it lies within the bounding box for that entry
            // note that we allow a 10m tolerance on all sides of the box to allow for inaccuracies in the latlon->gridref conversion,
            // and to increase the chance of a successful match when the road runs E-W or N-S and thus has a long but narrow bounding box
            var locatorElements = blockData[loop].split(":");

            var bbW = parseInt(locatorElements[4]);
            var bbE = parseInt(locatorElements[5]);
            var bbS = parseInt(locatorElements[6]);
            var bbN = parseInt(locatorElements[7]);
            if((eastings>=(bbW-10))&&(eastings<=(bbE+10))&&(northings>=(bbS-10))&&(northings<=(bbN+10)))
            {
               var oslLink = '<input type="radio" name="oslChoice" id="oslID_'+eBlock+'_'+nBlock+'_'+loop+'"></input>';
               if(locatorElements[1].length > 0)
               {
                  oslLink += locatorElements[1];
                  if(locatorElements[0].length > 0)
                  {
                     oslLink += ' - ';
                  }
               }
               oslLink += wazeifyStreetName(locatorElements[0])+'<br>';
               var dist = cpDistance(parseInt(locatorElements[2]),parseInt(locatorElements[3]),eastings,northings);
               var ratio = gradMinRatio(bbW, bbE, bbS, bbN, eastings, northings);
               candidates[candidates.length++] = new oslMatch(oslLink,dist,ratio);
            }
         }
         if(candidates.length > 0)
         {
            if(candidates.length > 1) candidates.sort(sortCandidates);
            for(var loop=0;loop<candidates.length;loop++)
            {
               oslDiv.innerHTML += candidates[loop].oslLink;
               //oslDiv.innerHTML += candidates[loop].oslLink + candidates[loop].oslDistance + ' ' + candidates[loop].oslMinGradRatio + '<br>';
            }
            oslDiv.innerHTML += '<br>City: <input id="myCityName" type="text" value="'+sessionStorage.myCity+'"/><br>';
            oslDiv.innerHTML += '<br><input id="oslSelect" type="button" value="Copy to Properties" />';
            document.getElementById('oslSelect').addEventListener("click", oslClick, true);
         }
      }
   }
   else return '?e='+eastings+'&n='+northings;
}

function processPermalink()
{
   var mousepos = document.getElementById("OpenLayers.Control.MousePosition_26").innerHTML;
   if(mousepos != sessionStorage.mousepos)
   {
      sessionStorage.mousepos = mousepos;
      if(document.getElementById("editPanel").innerHTML.indexOf("editSegmentStreetDetailsForm") == -1)  // segment properties panel isn't open...
      {
         if(document.getElementById("OpenLayers.Layer.Vector.RootContainer_221").innerHTML.indexOf('#03b9da') != -1) // ...and segment is highlighted
         {
            // so update the OS Locator matches
            mouselatlon = mousepos.split(",");
            toOSGrid(mouselatlon[1],mouselatlon[0],1);
         }
      }
   }

   // extract current lat/lon & zoom level from the permalink URL
   var plsrc = document.getElementById("permalink-container").innerHTML;
   var zoompos = plsrc.indexOf("?zoom=");
   var latpos = plsrc.indexOf("&lat=");
   var lonpos = plsrc.indexOf("&lon=");
   var layerpos = plsrc.indexOf("&layers=");

   // does the URL contain all three parameters?
   if((zoompos != -1)&&(latpos != -1)&&(lonpos != -1)&&(layerpos != -1))
   {
      // yes, so extract them...
      var zoom = parseInt(plsrc.substr(zoompos+6,latpos-(zoompos+6)));

      // accommodate both the original permalink ordering of zoom, lat then lon, and the present
      // ordering (as of early July 2012) of zoom, lon then lat...
      if(latpos < lonpos)
      {
         var lat = plsrc.substr(latpos+9,lonpos-(latpos+9));
         var lon = plsrc.substr(lonpos+9,layerpos-(lonpos+9));
      }
      else
      {
         var lat = plsrc.substr(latpos+9,layerpos-(latpos+9));
         var lon = plsrc.substr(lonpos+9,latpos-(lonpos+9));
      }

      // compare the freshly extracted parameters against the persistent copies, and update the
      // links to OSMC & OSOD only if there's a change required - the newly-inserted <a> element
      // can't be clicked on until the insertion process is complete, and if we were to re-insert
      // it every 250ms then it'd spend a lot of its time giving the appearance of being clickable
      // but without actually doing anything...
      if((zoom != sessionStorage.zoom)||(lat != sessionStorage.lat)||(lon != sessionStorage.lon))
      {
         // update the persistent vars with the new position
         sessionStorage.zoom = zoom;
         sessionStorage.lat = lat;
         sessionStorage.lon = lon;

         // translate the zoom level between WME and Musical Chairs - this gives a pretty close match
         var mczoom = zoom + 12;
         if(mczoom > 18) mczoom = 18;
         // generate the Musical Chairs URL
         var osmc_url = 'http://ris.dev.openstreetmap.org/oslmusicalchairs/map?zoom='+mczoom+'&lat='+lat+'&lon='+lon+'&layers=B0TT&view_mode=pseudorandom';

         // translate the zoom level between WME and OpenData - the match here isn't quite so good...
         var odzoom = zoom + 5;
         if(odzoom < 6) odzoom = 6;
         if(odzoom > 10) odzoom = 10;
         // generate the OpenData URL - requires the support of os_opendata_fullheight.user.js
         var osod_url = 'http://www.ordnancesurvey.co.uk/oswebsite/opendata/viewer/'+toOSGrid(lat,lon,0)+'&z='+odzoom;

         // generate the Cartouche URL
         var cartouche_url = 'http://world.waze.com/cartouche_old/?zoom='+zoom+'&lon='+lon+'&lat='+lat;

         // translate the zoom level between WME and live map.  The only correlation is (WME)=[Live] (0 or 1)=[7], (2 or 3)=[8], (4 or more)=[9]
         var livemap_zoom = Math.floor(zoom/2)+7;
         if (livemap_zoom > 9 ) livemap_zoom = 9;
         var livemap_url = 'https://world.waze.com/livemap/?zoom='+livemap_zoom+'&lat='+lat+'&lon='+lon+'&layers=BTTTT';
         // Modify existing livemap link to reference current position in WME
         document.getElementById("livemap").href = livemap_url;
         document.getElementById("livemap").target = '_blank';

         // update the link URLs
         document.getElementById("_linkOSOD").href = osod_url;
         document.getElementById("_linkOSMC").href = osmc_url;
         document.getElementById("_linkCartouche").href = cartouche_url;

         // refresh any of the site tabs/windows we've checked for auto-tracking
         if(document.getElementById('_cbAutoTrackOSOD').checked == 1) window.open(osod_url,'_osopendata');
         if(document.getElementById('_cbAutoTrackOSMC').checked == 1) window.open(osmc_url,'_osmusicalchairs');
         if(document.getElementById('_cbAutoTrackCartouche').checked == 1) window.open(cartouche_url,'_cartouche');
      }
   }
}

// initialise persistent vars
sessionStorage.zoom = 0;
sessionStorage.lat = '';
sessionStorage.lon = '';

// get the colour attribute for the permalink, so that our new links are visually consistent
var pl_colour = document.defaultView.getComputedStyle(document.getElementById("map-footer"),"").getPropertyValue("color");
// create a new child div in the existing map footer div, so we don't have to borrow the bing attribution one any more...
var mlcDiv = document.createElement('div');
mlcDiv.setAttribute('id','MapLinkControls');
// add the anchors and auto-track checkboxes for OS OpenData, Musical Chairs and Cartouche.  Note that the urls are blank at this stage,
// they'll be filled in as soon as we've done our first processPermalink() call
mlcDiv.innerHTML = '<a href="" id="_linkOSOD" target=_osopendata style="color:' + pl_colour +'">OS OpenData</a> <input type="checkbox" id="_cbAutoTrackOSOD"></input> | ';
mlcDiv.innerHTML += '<a href="" id="_linkOSMC" target=_osmusicalchairs style="color:' + pl_colour +'">OS Musical Chairs</a> <input type="checkbox" id="_cbAutoTrackOSMC"></input> | ';
mlcDiv.innerHTML += '<a href="" id="_linkCartouche" target=_cartouche style="color:' + pl_colour +'">Cartouche</a> <input type="checkbox" id="_cbAutoTrackCartouche"></input>';
mlcDiv.innerHTML += '<br>(Checkboxes enable auto-tracking)';
document.getElementById('map-footer').appendChild(mlcDiv);

// add a new div to the edit properties panel, to hold the OS Locator results
var oslDiv = document.createElement('div');
oslDiv.id = "oslDiv";
oslDiv.style.backgroundColor = '#DDFFDD';
document.getElementById('editPanel').appendChild(oslDiv);

// set up a check for new map co-ords every 250ms
setInterval(processPermalink,250);
Twister-UK
Waze Local Champs
Waze Local Champs
Posts: 4671
Answers: 2
Has thanked: 736 times
Been thanked: 4687 times
Send a message
Chris (not to be confused with Chris or Chris, or even Tim, Stu, or any of the other champs team...)
AM SE England & Shetland Islands, UK Local Champ, WME Beta Tester & ScriptMangler
WME/Livemap enhancement scripts @ GreasyFork


https://chizzum.com/greasemonkey/images/beta.pnghttps://chizzum.com/greasemonkey/images/s0400.pnghttps://chizzum.com/greasemonkey/images/c5s.png

Post by Twister-UK
xteejx, I know what you mean regarding the risk of forgetting to change the persistent city field, and if you leave it blank then you can simply fill in the WME city field as normal. However, if you are careful, then using the persistent field does make the naming workflow substantially quicker.
Twister-UK
Waze Local Champs
Waze Local Champs
Posts: 4671
Answers: 2
Has thanked: 736 times
Been thanked: 4687 times
Send a message
Last edited by Twister-UK on Wed Jul 25, 2012 9:35 am, edited 1 time in total.
Chris (not to be confused with Chris or Chris, or even Tim, Stu, or any of the other champs team...)
AM SE England & Shetland Islands, UK Local Champ, WME Beta Tester & ScriptMangler
WME/Livemap enhancement scripts @ GreasyFork


https://chizzum.com/greasemonkey/images/beta.pnghttps://chizzum.com/greasemonkey/images/s0400.pnghttps://chizzum.com/greasemonkey/images/c5s.png

Post by Twister-UK
Ooh, thanks Tim, I'll test that tonight - would be nice to start editing on Chrome again, I'd forgotten just how frustrating the Firefox "wave mouse pointer around until the horizontal segment gets highlighted" issue was...
Twister-UK
Waze Local Champs
Waze Local Champs
Posts: 4671
Answers: 2
Has thanked: 736 times
Been thanked: 4687 times
Send a message
Chris (not to be confused with Chris or Chris, or even Tim, Stu, or any of the other champs team...)
AM SE England & Shetland Islands, UK Local Champ, WME Beta Tester & ScriptMangler
WME/Livemap enhancement scripts @ GreasyFork


https://chizzum.com/greasemonkey/images/beta.pnghttps://chizzum.com/greasemonkey/images/s0400.pnghttps://chizzum.com/greasemonkey/images/c5s.png

Post by Twister-UK
Bah humbug, Chrome is still a no-go zone :cry:

Tim's suggestion allows the OS data to be retrieved in Firefox without using the @require directive, but in its current form it doesn't appear to do anything in Chrome. However, Firefox testing threw up a much bigger issue - whereas @require caches the data locally during the script installation, this workaround downloads the data every time you (re)load the WME page, and at 120MB that's a lot of data to be grabbing every time you start up an editing session, or reload the page to kick WME back into life after it goes loopy again...

Thanks again for the suggestion Tim, but alas it's back to the drawing board as far as Chrome support goes, and back to editing in Firefox.
Twister-UK
Waze Local Champs
Waze Local Champs
Posts: 4671
Answers: 2
Has thanked: 736 times
Been thanked: 4687 times
Send a message
Chris (not to be confused with Chris or Chris, or even Tim, Stu, or any of the other champs team...)
AM SE England & Shetland Islands, UK Local Champ, WME Beta Tester & ScriptMangler
WME/Livemap enhancement scripts @ GreasyFork


https://chizzum.com/greasemonkey/images/beta.pnghttps://chizzum.com/greasemonkey/images/s0400.pnghttps://chizzum.com/greasemonkey/images/c5s.png

Post by Twister-UK
Haven't yet looked at Chrome compatibility again, been a little bit busy with other tweaks. Tonights update is therefore brought to you courtesy of three little words.

Bounding. Box. Visualisation...

The placement of the bounding box highlight is sometimes a bit off, but it's generally good enough to leave the user in no doubt as to which street name refers to the highlighted segment. If anyone notices the placement being significantly off in a certain area, please reply with a permalink and I'll see if I can fine tune the coordinate conversion.

Code: Select all

// ==UserScript==
// @name                WME to OS link
// @namespace           http://greasemonkey.chizzum.com
// @description         Adds link to WME to open up various mapping sites at the same map location
// @include             https://world.waze.com/editor/*
// @include             https://world.waze.com/map-editor/*
// @include             https://descartesw.waze.com/beta/*
// @require             http://greasemonkey.chizzum.com/osl_10km.js
// @version             0.8.3
// ==/UserScript==

// Contains Ordnance Survey data Crown copyright and database right 2012
// Contents of the osl_10km.js file are derived under the Open Government Licence from the OS Locator dataset


//-----------------------------------------------------------------------------------------------------------------------------------------
// all code between here and the next ------------- marker line is a stripped down version of the original from Paul Dixon
//
// * GeoTools javascript coordinate transformations
// * http://files.dixo.net/geotools.html
// *
// * This file copyright (c)2005 Paul Dixon (paul@elphin.com)
// *
// * This program is free software; you can redistribute it and/or
// * modify it under the terms of the GNU General Public License
// * as published by the Free Software Foundation; either version 2
// * of the License, or (at your option) any later version.
// *
// * This program is distributed in the hope that it will be useful,
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// * GNU General Public License for more details.
// *
// * You should have received a copy of the GNU General Public License
// * along with this program; if not, write to the Free Software
// * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
// *
// * ---------------------------------------------------------------------------
// *
// * Credits
// *
// * The algorithm used by the script for WGS84-OSGB36 conversions is derived
// * from an OSGB spreadsheet (www.gps.gov.uk) with permission. This has been
// * adapted into Perl by Ian Harris, and into PHP by Barry Hunter. Conversion
// * accuracy is in the order of 7m for 90% of Great Britain, and should be
// * be similar to the conversion made by a typical GPSr
// *
// * See accompanying documentation for more information
// * http://files.dixo.net/geotools.html

var northings;
var eastings;
var latitude;
var longitude;

var helmX, helmY, helmZ;
var Pi = 3.14159265358979;

function wgs_to_osgb()
{
	LatLon_to_HelmXYZ();
   var latitude2  = XYZ_to_Lat();
	var longitude2 = Math.atan2(helmY , helmX) * (180 / Pi);
	LatLon_to_OSGrid(latitude2,longitude2);
}

function LatLon_to_HelmXYZ()
{
   var a = 6378137.0;
   var b = 6356752.313;
   var DX = -446.448;
   var DY = 125.157;
   var DZ = -542.060;
   var rotX = -0.1502;
   var rotY = -0.2470;
   var rotZ = -0.8421;
	var sfactor = 20.4894 * 0.000001;

   // perform initial lat-lon to cartesian coordinate translation
   var RadPHI = latitude * (Pi / 180);
   var RadLAM = longitude * (Pi / 180);
   var e2 = (Math.pow(a,2) - Math.pow(b,2)) / Math.pow(a,2);
   var V = a / (Math.sqrt(1 - (e2 * (  Math.pow(Math.sin(RadPHI),2)))));
   var cartX = V * (Math.cos(RadPHI)) * (Math.cos(RadLAM));
   var cartY = V * (Math.cos(RadPHI)) * (Math.sin(RadLAM));
   var cartZ = (V * (1 - e2)) * (Math.sin(RadPHI));

   // Compute Helmert transformed coordinates
	var RadX_Rot = (rotX / 3600) * (Pi / 180);
	var RadY_Rot = (rotY / 3600) * (Pi / 180);
	var RadZ_Rot = (rotZ / 3600) * (Pi / 180);
   helmX = (cartX + (cartX * sfactor) - (cartY * RadZ_Rot) + (cartZ * RadY_Rot) + DX);
	helmY = (cartX * RadZ_Rot) + cartY + (cartY * sfactor) - (cartZ * RadX_Rot) + DY;
	helmZ = (-1 * cartX * RadY_Rot) + (cartY * RadX_Rot) + cartZ + (cartZ * sfactor) + DZ;
}

function XYZ_to_Lat()
{
   var a = 6377563.396;
   var b = 6356256.910;
   var RootXYSqr = Math.sqrt(Math.pow(helmX,2) + Math.pow(helmY,2));
   var e2 = (Math.pow(a,2) - Math.pow(b,2)) / Math.pow(a,2);
   var PHI1 = Math.atan2(helmZ , (RootXYSqr * (1 - e2)) );
   var PHI = Iterate_XYZ_to_Lat(a, e2, PHI1, helmZ, RootXYSqr);
   return PHI * (180 / Pi);
}

function Iterate_XYZ_to_Lat(a, e2, PHI1, Z, RootXYSqr)
{
   var V = a / (Math.sqrt(1 - (e2 * Math.pow(Math.sin(PHI1),2))));
   var PHI2 = Math.atan2((Z + (e2 * V * (Math.sin(PHI1)))) , RootXYSqr);
   while (Math.abs(PHI1 - PHI2) > 0.000000001)
   {
      PHI1 = PHI2;
      V = a / (Math.sqrt(1 - (e2 * Math.pow(Math.sin(PHI1),2))));
      PHI2 = Math.atan2((Z + (e2 * V * (Math.sin(PHI1)))) , RootXYSqr);
   }
   return PHI2;
}

function Marc(bf0, n, PHI0, PHI)
{
   return bf0 * (((1 + n + ((5 / 4) * Math.pow(n,2)) + ((5 / 4) * Math.pow(n,3))) * (PHI - PHI0)) - (((3 * n) + (3 * Math.pow(n,2)) +
          ((21 / 8) * Math.pow(n,3))) * (Math.sin(PHI - PHI0)) * (Math.cos(PHI + PHI0))) + ((((15 / 8) * Math.pow(n,2)) + ((15 / 8) *
          Math.pow(n,3))) * (Math.sin(2 * (PHI - PHI0))) * (Math.cos(2 * (PHI + PHI0)))) - (((35 / 24) * Math.pow(n,3)) *
          (Math.sin(3 * (PHI - PHI0))) * (Math.cos(3 * (PHI + PHI0)))));
}

function LatLon_to_OSGrid(PHI, LAM)
{
   var a = 6377563.396;
   var b = 6356256.910;
   var e0 = 400000;
   var n0 = -100000;
   var f0 = 0.999601272;
   var PHI0 = 49.00000;
   var LAM0 = -2.00000;

   var RadPHI = PHI * (Pi / 180);
   var RadLAM = LAM * (Pi / 180);
   var RadPHI0 = PHI0 * (Pi / 180);
   var RadLAM0 = LAM0 * (Pi / 180);
   var af0 = a * f0;
   var bf0 = b * f0;
   var e2 = (Math.pow(af0,2) - Math.pow(bf0,2)) / Math.pow(af0,2);
   var n = (af0 - bf0) / (af0 + bf0);
   var nu = af0 / (Math.sqrt(1 - (e2 * Math.pow(Math.sin(RadPHI),2) )));
   var rho = (nu * (1 - e2)) / (1 - (e2 * Math.pow(Math.sin(RadPHI),2) ));
   var eta2 = (nu / rho) - 1;
   var p = RadLAM - RadLAM0;
   var M = Marc(bf0, n, RadPHI0, RadPHI);
   var I = M + n0;
   var II = (nu / 2) * (Math.sin(RadPHI)) * (Math.cos(RadPHI));
   var III = ((nu / 24) * (Math.sin(RadPHI)) * (Math.pow(Math.cos(RadPHI),3))) * (5 - (Math.pow(Math.tan(RadPHI),2)) + (9 * eta2));
   var IIIA = ((nu / 720) * (Math.sin(RadPHI)) * (Math.pow(Math.cos(RadPHI),5))) * (61 - (58 * (Math.pow(Math.tan(RadPHI),2))) + (Math.pow(Math.tan(RadPHI),4)));
   var IV = nu * (Math.cos(RadPHI));
   var V = (nu / 6) * ( Math.pow(Math.cos(RadPHI),3)) * ((nu / rho) - (Math.pow(Math.tan(RadPHI),2)));
   var VI = (nu / 120) * (Math.pow(Math.cos(RadPHI),5)) * (5 - (18 * (Math.pow(Math.tan(RadPHI),2))) + (Math.pow(Math.tan(RadPHI),4)) + (14 * eta2) - (58 * (Math.pow(Math.tan(RadPHI),2)) * eta2));
   eastings = Math.round(e0 + (p * IV) + (Math.pow(p,3) * V) + (Math.pow(p,5) * VI));
   northings = Math.round(I + (Math.pow(p,2) * II) + (Math.pow(p,4) * III) + (Math.pow(p,6) * IIIA));
}
//-----------------------------------------------------------------------------------------------------------------------------------------

function caseCorrect(wrongcase)
{
   var loop;
   var correctedCase = '';
   for(loop=0;loop<wrongcase.length;loop++)
   {
      if((loop == 0)||(wrongcase[loop-1] == ' ')||(wrongcase[loop-1] == '(')) correctedCase += wrongcase[loop].toUpperCase();
      else correctedCase += wrongcase[loop].toLowerCase();
   }
   return correctedCase;
}


function wazeifyStreetName(oslName)
{
   var wazeName = '';
   var loop;

   wazeName = caseCorrect(oslName);

   var namePieces = wazeName.split(' ');
   if(namePieces.length > 1)
   {
      var roadType;
      var dirSuffix;
      var thePrefix;
      var namePrefix = '';
      if((namePieces[namePieces.length-1] == 'North')||(namePieces[namePieces.length-1] == 'South')||(namePieces[namePieces.length-1] == 'East')||(namePieces[namePieces.length-1] == 'West'))
      {
         dirSuffix = namePieces[namePieces.length-1][0];
         roadType = namePieces[namePieces.length-2];
         if(namePieces.length > 2)
         {
            if(namePieces[namePieces.length-3] == 'The') thePrefix = true;
            else thePrefix = false;
         }
         for(loop=0;loop<namePieces.length-2;loop++) namePrefix += (namePieces[loop] + ' ');
      }
      else
      {
         dirSuffix = '';
         roadType = namePieces[namePieces.length-1];
         if(namePieces[namePieces.length-2] == 'The') thePrefix = true;
         else thePrefix = false;
         for(loop=0;loop<namePieces.length-1;loop++) namePrefix += (namePieces[loop] + ' ');

      }
      if(thePrefix == false)
      {
         roadType = roadType.replace('Avenue','Ave');
         roadType = roadType.replace('Boulevard','Blvd');
         roadType = roadType.replace('Broadway','Bdwy');
         roadType = roadType.replace('Close','Cl');
         roadType = roadType.replace('Court','Ct');
         roadType = roadType.replace('Crescent','Cr');
         roadType = roadType.replace('Drive','Dr');
         roadType = roadType.replace('Gardens','Gdns');
         roadType = roadType.replace('Garden','Gdn');
         roadType = roadType.replace('Green','Gn');
         roadType = roadType.replace('Grove','Gr');
         roadType = roadType.replace('Lane','Ln');
         roadType = roadType.replace('Mount','Mt');
         roadType = roadType.replace('Place','Pl');
         roadType = roadType.replace('Park','Pk');
         roadType = roadType.replace('Road','Rd');
         roadType = roadType.replace('Square','Sq');
         roadType = roadType.replace('Street','St');
         roadType = roadType.replace('Terrace','Ter');
      }
      wazeName = namePrefix + roadType + ' ' + dirSuffix;
   }
   return wazeName;
}


function cpDistance(cpE, cpN, posE, posN)
{
   return Math.sqrt(((posE - cpE) * (posE - cpE)) + ((posN - cpN) * (posN - cpN)));
}

function gradMinRatio(bbW, bbE, bbS, bbN, posE, posN)
{
   var gradPosToSW = (posN - bbS) / (posE - bbW);
   var gradPosToSE = (posN - bbS) / (posE - bbE);
   var gradNEToSW = (bbN - bbS) / (bbE - bbW);
   var gradNWToSE = (bbN - bbS) / (bbW - bbE);

   var ratioSW = gradPosToSW / gradNEToSW;
   var ratioSE = gradPosToSE / gradNWToSE;
   if(ratioSW < 1) ratioSW = 1 / ratioSW;
   if(ratioSE < 1) ratioSE = 1 / ratioSE;
   if(ratioSW < ratioSE) return ratioSW;
   else return ratioSE;
}

var vpLeft = 0;
var vpRight = 0;
var vpBottom = 0;
var vpTop = 0;

function visualiseBoundingBox(boxW, boxE, boxS, boxN)
{
   if(boxW < vpLeft) boxW = vpLeft;
   if(boxE >  vpRight) boxE = vpRight;
   if(boxS < vpBottom) boxS = vpBottom;
   if(boxN > vpTop) boxN = vpTop;

   boxE -= vpLeft;
   boxW -= vpLeft;
   boxS = vpTop - boxS;
   boxN = vpTop - boxN;

   var wmeScale = 22550 / (950 * Math.pow(2,sessionStorage.zoom));
   boxE /= wmeScale;
   boxW /= wmeScale;
   boxS /= wmeScale;
   boxN /= wmeScale;

   boxE = Math.round(boxE);
   boxW = Math.round(boxW);
   boxS = Math.round(boxS);
   boxN = Math.round(boxN);

   var svgSrc = '<svg xmlns="http://www.w3.org/2000/svg" width="'+document.getElementById('WazeMap').offsetWidth+'px" height="'+document.getElementById('WazeMap').offsetHeight+'px" version="1.1">';
   svgSrc += '<rect x="'+boxW+'" y="'+boxN+'" width="'+((boxE-boxW)*1.1)+'" height="'+((boxS-boxN)*1.1)+'" style="fill:yellow;stroke:pink;stroke-width:4;fill-opacity:1;stroke-opacity:1"/>';
   svgSrc += '</svg>';
   bbDiv.innerHTML = svgSrc;
}


function radioClick()
{
   var oslElements = document.getElementById('oslDiv');
   for(var loop=0;loop<oslElements.childNodes.length;loop++)
   {
      if(oslElements.childNodes[loop].nodeType == 1)
      {
         attr = oslElements.childNodes[loop].attributes.getNamedItem("type");
         if(attr != null)
         {
            if(attr.value == "radio")
            {
               if(oslElements.childNodes[loop].checked)
               {
                  attr = oslElements.childNodes[loop].attributes.getNamedItem("id").value;
                  oslID = attr.split('_');
                  evalstr = 'var roadData = locatorData_'+oslID[1]+'_'+oslID[2]+'['+oslID[3]+']';
                  eval(evalstr);
                  var locatorElements = roadData.split(":");

                  visualiseBoundingBox(locatorElements[4],locatorElements[5],locatorElements[6],locatorElements[7])
               }
            }
         }
      }
   }
}


function oslClick()
{
   var cityName = caseCorrect(document.getElementById('myCityName').value);
   sessionStorage.myCity = cityName;
   var oslElements = document.getElementById('oslDiv');
   for(var loop=0;loop<oslElements.childNodes.length;loop++)
   {
      if(oslElements.childNodes[loop].nodeType == 1)
      {
         attr = oslElements.childNodes[loop].attributes.getNamedItem("type");
         if(attr != null)
         {
            if(attr.value == "radio")
            {
               if(oslElements.childNodes[loop].checked)
               {
                  attr = oslElements.childNodes[loop].attributes.getNamedItem("id").value;
                  oslID = attr.split('_');
                  evalstr = 'var roadData = locatorData_'+oslID[1]+'_'+oslID[2]+'['+oslID[3]+']';
                  eval(evalstr);
                  var locatorElements = roadData.split(":");

                  // auto-click the Edit Address link...
                  var editAddress = document.getElementById('editSegmentsApplyChanges');
                  var editButtons = editAddress.getElementsByClassName('edit-button');
                  editButtons[0].click();

                  // fill in the City field
                  //oslName = caseCorrect(locatorElements[9]);
                  //if(locatorElements[8].length > 0) oslName += ' ('+caseCorrect(locatorElements[8])+')';
                  var snelms = document.getElementsByName('cityName');
                  //snelms[0].value = oslName;
                  snelms[0].value = cityName;
                  snelms[0].disabled = false;
                  snelms = document.getElementsByName('emptyCity');
                  snelms[0].checked = false;

                  // and the Street field
                  oslName = locatorElements[1];
                  if((locatorElements[0].length > 0)&&(locatorElements[1].length > 0)) oslName += ' - ';
                  oslName += wazeifyStreetName(locatorElements[0]);

                  snelms = document.getElementsByName('streetName');
                  snelms[0].value = oslName;
                  snelms[0].disabled = false;
                  snelms = document.getElementsByName('emptyStreet');
                  snelms[0].checked = false;

                  bbDiv.innerHTML = '';
               }
            }
         }
      }
   }
}


function oslMatch(oslLink, oslDistance, oslMinGradRatio, oslRadioID)
{
   this.oslLink = oslLink;
   this.oslDistance = oslDistance;
   this.oslMinGradRatio = oslMinGradRatio;
   this.oslRadioID = oslRadioID;
}
function sortCandidates(a,b)
{
   var x = a.oslDistance;
   var y = b.oslDistance;
   return((x<y) ? -1 : ((x>y) ? 1 : 0));
}

function toOSGrid(lat, lon, mode)
{
   latitude = lat;
   longitude = lon;
   wgs_to_osgb();

   if(mode == 1)  // OS Locator lookup
   {
      // determine which 10km grid block contains the current WME centrepoint
      var eBlock = (Math.floor(eastings/10000)) * 10000;
      var nBlock = (Math.floor(northings/10000)) * 10000;
      // check to see if there's a corresponding array in the osl_10km data
      var evalstr = 'typeof locatorData_'+eBlock+'_'+nBlock;
      if(eval(evalstr) != "undefined")
      {
         // yes...  make a local copy to avoid having an eval() in each iteration of the loop
         evalstr = 'var blockData = locatorData_'+eBlock+'_'+nBlock;
         eval(evalstr);
         oslDiv.innerHTML = 'OSL matches at '+eastings+','+northings+':<br>';
         var candidates = new Array();

         for(var loop = 0;loop < blockData.length; loop++)
         {
            // for each entry in the array, test the centrepoint position to see if it lies within the bounding box for that entry
            // note that we allow a 10m tolerance on all sides of the box to allow for inaccuracies in the latlon->gridref conversion,
            // and to increase the chance of a successful match when the road runs E-W or N-S and thus has a long but narrow bounding box
            var locatorElements = blockData[loop].split(":");

            var bbW = parseInt(locatorElements[4]);
            var bbE = parseInt(locatorElements[5]);
            var bbS = parseInt(locatorElements[6]);
            var bbN = parseInt(locatorElements[7]);
            if((eastings>=(bbW-10))&&(eastings<=(bbE+10))&&(northings>=(bbS-10))&&(northings<=(bbN+10)))
            {
               var radioID = 'oslID_'+eBlock+'_'+nBlock+'_'+loop;
               var oslLink = '<input type="radio" name="oslChoice" id="'+radioID+'"></input>';
               if(locatorElements[1].length > 0)
               {
                  oslLink += locatorElements[1];
                  if(locatorElements[0].length > 0)
                  {
                     oslLink += ' - ';
                  }
               }
               oslLink += wazeifyStreetName(locatorElements[0])+'<br>';
               var dist = cpDistance(parseInt(locatorElements[2]),parseInt(locatorElements[3]),eastings,northings);
               var ratio = gradMinRatio(bbW, bbE, bbS, bbN, eastings, northings);
               candidates[candidates.length++] = new oslMatch(oslLink,dist,ratio,radioID);
            }
         }
         if(candidates.length > 0)
         {
            if(candidates.length > 1) candidates.sort(sortCandidates);
            for(var loop=0;loop<candidates.length;loop++)
            {
               oslDiv.innerHTML += candidates[loop].oslLink;
               //oslDiv.innerHTML += candidates[loop].oslLink + candidates[loop].oslDistance + ' ' + candidates[loop].oslMinGradRatio + '<br>';
            }
            oslDiv.innerHTML += '<br>City: <input id="myCityName" type="text" value="'+sessionStorage.myCity+'"/><br>';
            oslDiv.innerHTML += '<br><input id="oslSelect" type="button" value="Copy to Properties" />';
            document.getElementById('oslSelect').addEventListener("click", oslClick, true);
            for(var loop=0;loop<candidates.length;loop++)
            {
               document.getElementById(candidates[loop].oslRadioID).addEventListener("click", radioClick, true);
            }
         }
      }
   }
   else return '?e='+eastings+'&n='+northings;
}

function processPermalink()
{
   var mousepos = document.getElementById("OpenLayers.Control.MousePosition_26").innerHTML;
   if(mousepos != sessionStorage.mousepos)
   {
      sessionStorage.mousepos = mousepos;
      if(document.getElementById("editPanel").innerHTML.indexOf("editSegmentStreetDetailsForm") == -1)  // segment properties panel isn't open...
      {
         if
         (
            (document.getElementById("OpenLayers.Layer.Vector.RootContainer_221").innerHTML.indexOf('#03b9da') != -1) || // ...and segment is highlighted
            (document.getElementById("OpenLayers.Layer.Vector.RootContainer_221").innerHTML.indexOf('#ff3300') != -1)
         )
         {
            // so update the OS Locator matches
            mouselatlon = mousepos.split(",");
            toOSGrid(mouselatlon[1],mouselatlon[0],1);
         }
      }
   }

   // extract current lat/lon & zoom level from the permalink URL
   var plsrc = document.getElementById("permalink-container").innerHTML;
   var zoompos = plsrc.indexOf("?zoom=");
   var latpos = plsrc.indexOf("&lat=");
   var lonpos = plsrc.indexOf("&lon=");
   var layerpos = plsrc.indexOf("&layers=");

   // does the URL contain all three parameters?
   if((zoompos != -1)&&(latpos != -1)&&(lonpos != -1)&&(layerpos != -1))
   {
      // yes, so extract them...
      var zoom = parseInt(plsrc.substr(zoompos+6,latpos-(zoompos+6)));

      // accommodate both the original permalink ordering of zoom, lat then lon, and the present
      // ordering (as of early July 2012) of zoom, lon then lat...
      if(latpos < lonpos)
      {
         var lat = plsrc.substr(latpos+9,lonpos-(latpos+9));
         var lon = plsrc.substr(lonpos+9,layerpos-(lonpos+9));
      }
      else
      {
         var lat = plsrc.substr(latpos+9,layerpos-(latpos+9));
         var lon = plsrc.substr(lonpos+9,latpos-(lonpos+9));
      }

      // compare the freshly extracted parameters against the persistent copies, and update the
      // links to OSMC & OSOD only if there's a change required - the newly-inserted <a> element
      // can't be clicked on until the insertion process is complete, and if we were to re-insert
      // it every 250ms then it'd spend a lot of its time giving the appearance of being clickable
      // but without actually doing anything...
      if((zoom != sessionStorage.zoom)||(lat != sessionStorage.lat)||(lon != sessionStorage.lon))
      {
         // update the persistent vars with the new position
         sessionStorage.zoom = zoom;
         sessionStorage.lat = lat;
         sessionStorage.lon = lon;

         // translate the zoom level between WME and Musical Chairs - this gives a pretty close match
         var mczoom = zoom + 12;
         if(mczoom > 18) mczoom = 18;
         // generate the Musical Chairs URL
         var osmc_url = 'http://ris.dev.openstreetmap.org/oslmusicalchairs/map?zoom='+mczoom+'&lat='+lat+'&lon='+lon+'&layers=B0TT&view_mode=pseudorandom';

         // translate the zoom level between WME and OpenData - the match here isn't quite so good...
         var odzoom = zoom + 5;
         if(odzoom < 6) odzoom = 6;
         if(odzoom > 10) odzoom = 10;
         // generate the OpenData URL - requires the support of os_opendata_fullheight.user.js
         var osod_url = 'http://www.ordnancesurvey.co.uk/oswebsite/opendata/viewer/'+toOSGrid(lat,lon,0)+'&z='+odzoom;

         // generate the Cartouche URL
         var cartouche_url = 'http://world.waze.com/cartouche_old/?zoom='+zoom+'&lon='+lon+'&lat='+lat;

         // translate the zoom level between WME and live map.  The only correlation is (WME)=[Live] (0 or 1)=[7], (2 or 3)=[8], (4 or more)=[9]
         var livemap_zoom = Math.floor(zoom/2)+7;
         if (livemap_zoom > 9 ) livemap_zoom = 9;
         var livemap_url = 'https://world.waze.com/livemap/?zoom='+livemap_zoom+'&lat='+lat+'&lon='+lon+'&layers=BTTTT';
         // Modify existing livemap link to reference current position in WME
         document.getElementById("livemap").href = livemap_url;
         document.getElementById("livemap").target = '_blank';

         // update the link URLs
         document.getElementById("_linkOSOD").href = osod_url;
         document.getElementById("_linkOSMC").href = osmc_url;
         document.getElementById("_linkCartouche").href = cartouche_url;

         // refresh any of the site tabs/windows we've checked for auto-tracking
         if(document.getElementById('_cbAutoTrackOSOD').checked == 1) window.open(osod_url,'_osopendata');
         if(document.getElementById('_cbAutoTrackOSMC').checked == 1) window.open(osmc_url,'_osmusicalchairs');
         if(document.getElementById('_cbAutoTrackCartouche').checked == 1) window.open(cartouche_url,'_cartouche');

         // recalculate the map viewport extents in terms of eastings/northings
         var viewportWidth = document.getElementById('WazeMap').offsetWidth;
         var viewportHeight = document.getElementById('WazeMap').offsetHeight;
         var wmeScale = 22550 / (950 * Math.pow(2,sessionStorage.zoom));
         var vpHalfWidth = Math.round((viewportWidth * wmeScale) / 2);
         var vpHalfHeight = Math.round((viewportHeight * wmeScale) / 2);
         vpLeft = eastings - vpHalfWidth;
         vpRight = eastings + vpHalfWidth;
         vpBottom = northings - vpHalfHeight;
         vpTop = northings + vpHalfHeight;
         bbDiv.innerHTML = '';
      }
   }
}

// initialise persistent vars
sessionStorage.zoom = 0;
sessionStorage.lat = '';
sessionStorage.lon = '';

// get the colour attribute for the permalink, so that our new links are visually consistent
var pl_colour = document.defaultView.getComputedStyle(document.getElementById("map-footer"),"").getPropertyValue("color");
// create a new child div in the existing map footer div, so we don't have to borrow the bing attribution one any more...
var mlcDiv = document.createElement('div');
mlcDiv.setAttribute('id','MapLinkControls');
// add the anchors and auto-track checkboxes for OS OpenData, Musical Chairs and Cartouche.  Note that the urls are blank at this stage,
// they'll be filled in as soon as we've done our first processPermalink() call
mlcDiv.innerHTML = '<a href="" id="_linkOSOD" target=_osopendata style="color:' + pl_colour +'">OS OpenData</a> <input type="checkbox" id="_cbAutoTrackOSOD"></input> | ';
mlcDiv.innerHTML += '<a href="" id="_linkOSMC" target=_osmusicalchairs style="color:' + pl_colour +'">OS Musical Chairs</a> <input type="checkbox" id="_cbAutoTrackOSMC"></input> | ';
mlcDiv.innerHTML += '<a href="" id="_linkCartouche" target=_cartouche style="color:' + pl_colour +'">Cartouche</a> <input type="checkbox" id="_cbAutoTrackCartouche"></input>';
mlcDiv.innerHTML += '<br>(Checkboxes enable auto-tracking)';
document.getElementById('map-footer').appendChild(mlcDiv);

// add a new div to the edit properties panel, to hold the OS Locator results
var oslDiv = document.createElement('div');
oslDiv.id = "oslDiv";
oslDiv.style.backgroundColor = '#DDFFDD';
document.getElementById('editPanel').appendChild(oslDiv);

// add a new div to the map viewport, to hold the bounding box SVG
var bbDiv = document.createElement('div');
bbDiv.id = "bbDiv";
bbDiv.style.position = 'absolute';
bbDiv.style.top = '0';
bbDiv.style.left = '0';
bbDiv.style.width = document.getElementById('WazeMap').offsetWidth;
bbDiv.style.height = document.getElementById('WazeMap').offsetHeight;
bbDiv.style.zIndex = 100;
document.getElementById('WazeMap').appendChild(bbDiv);

// set up a check for new map co-ords every 250ms
setInterval(processPermalink,250);
Twister-UK
Waze Local Champs
Waze Local Champs
Posts: 4671
Answers: 2
Has thanked: 736 times
Been thanked: 4687 times
Send a message
Chris (not to be confused with Chris or Chris, or even Tim, Stu, or any of the other champs team...)
AM SE England & Shetland Islands, UK Local Champ, WME Beta Tester & ScriptMangler
WME/Livemap enhancement scripts @ GreasyFork


https://chizzum.com/greasemonkey/images/beta.pnghttps://chizzum.com/greasemonkey/images/s0400.pnghttps://chizzum.com/greasemonkey/images/c5s.png