Created
May 18, 2013 17:34
-
-
Save kareemgrant/5605219 to your computer and use it in GitHub Desktop.
Preliminary route_builder code (still needs enhancement)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*********************************************************************\ | |
* * | |
* epolys.js by Mike Williams * | |
* * | |
* A Google Maps API Extension * | |
* * | |
* Adds various Methods to GPolygon and GPolyline * | |
* * | |
* .Contains(latlng) returns true is the poly contains the specified * | |
* GLatLng * | |
* * | |
* .Area() returns the approximate area of a poly that is * | |
* not self-intersecting * | |
* * | |
* .Distance() returns the length of the poly path * | |
* * | |
* .Bounds() returns a GLatLngBounds that bounds the poly * | |
* * | |
* .GetPointAtDistance() returns a GLatLng at the specified distance * | |
* along the path. * | |
* The distance is specified in metres * | |
* Reurns null if the path is shorter than that * | |
* * | |
* .GetPointsAtDistance() returns an array of GLatLngs at the * | |
* specified interval along the path. * | |
* The distance is specified in metres * | |
* * | |
* .GetIndexAtDistance() returns the vertex number at the specified * | |
* distance along the path. * | |
* The distance is specified in metres * | |
* Reurns null if the path is shorter than that * | |
* * | |
* .Bearing(v1?,v2?) returns the bearing between two vertices * | |
* if v1 is null, returns bearing from first to last * | |
* if v2 is null, returns bearing from v1 to next * | |
* * | |
* * | |
*********************************************************************** | |
* * | |
* This Javascript is provided by Mike Williams * | |
* Community Church Javascript Team * | |
* http://www.bisphamchurch.org.uk/ * | |
* http://econym.org.uk/gmap/ * | |
* * | |
* This work is licenced under a Creative Commons Licence * | |
* http://creativecommons.org/licenses/by/2.0/uk/ * | |
* * | |
*********************************************************************** | |
* * | |
* Version 1.1 6-Jun-2007 * | |
* Version 1.2 1-Jul-2007 - fix: Bounds was omitting vertex zero * | |
* add: Bearing * | |
* Version 1.3 28-Nov-2008 add: GetPointsAtDistance() * | |
* Version 1.4 12-Jan-2009 fix: GetPointsAtDistance() * | |
* * | |
\*********************************************************************/ | |
// === A method for testing if a point is inside a polygon | |
// === Returns true if poly contains point | |
// === Algorithm shamelessly stolen from http://alienryderflex.com/polygon/ | |
GPolygon.prototype.Contains = function(point) { | |
var j=0; | |
var oddNodes = false; | |
var x = point.lng(); | |
var y = point.lat(); | |
for (var i=0; i < this.getVertexCount(); i++) { | |
j++; | |
if (j == this.getVertexCount()) {j = 0;} | |
if (((this.getVertex(i).lat() < y) && (this.getVertex(j).lat() >= y)) | |
|| ((this.getVertex(j).lat() < y) && (this.getVertex(i).lat() >= y))) { | |
if ( this.getVertex(i).lng() + (y - this.getVertex(i).lat()) | |
/ (this.getVertex(j).lat()-this.getVertex(i).lat()) | |
* (this.getVertex(j).lng() - this.getVertex(i).lng())<x ) { | |
oddNodes = !oddNodes | |
} | |
} | |
} | |
return oddNodes; | |
} | |
// === A method which returns the approximate area of a non-intersecting polygon in square metres === | |
// === It doesn't fully account for spechical geometry, so will be inaccurate for large polygons === | |
// === The polygon must not intersect itself === | |
GPolygon.prototype.Area = function() { | |
var a = 0; | |
var j = 0; | |
var b = this.Bounds(); | |
var x0 = b.getSouthWest().lng(); | |
var y0 = b.getSouthWest().lat(); | |
for (var i=0; i < this.getVertexCount(); i++) { | |
j++; | |
if (j == this.getVertexCount()) {j = 0;} | |
var x1 = this.getVertex(i).distanceFrom(new GLatLng(this.getVertex(i).lat(),x0)); | |
var x2 = this.getVertex(j).distanceFrom(new GLatLng(this.getVertex(j).lat(),x0)); | |
var y1 = this.getVertex(i).distanceFrom(new GLatLng(y0,this.getVertex(i).lng())); | |
var y2 = this.getVertex(j).distanceFrom(new GLatLng(y0,this.getVertex(j).lng())); | |
a += x1*y2 - x2*y1; | |
} | |
return Math.abs(a * 0.5); | |
} | |
// === A method which returns the length of a path in metres === | |
GPolygon.prototype.Distance = function() { | |
var dist = 0; | |
for (var i=1; i < this.getVertexCount(); i++) { | |
dist += this.getVertex(i).distanceFrom(this.getVertex(i-1)); | |
} | |
return dist; | |
} | |
// === A method which returns the bounds as a GLatLngBounds === | |
GPolygon.prototype.Bounds = function() { | |
var bounds = new GLatLngBounds(); | |
for (var i=0; i < this.getVertexCount(); i++) { | |
bounds.extend(this.getVertex(i)); | |
} | |
return bounds; | |
} | |
// === A method which returns a GLatLng of a point a given distance along the path === | |
// === Returns null if the path is shorter than the specified distance === | |
GPolygon.prototype.GetPointAtDistance = function(metres) { | |
// some awkward special cases | |
if (metres == 0) return this.getVertex(0); | |
if (metres < 0) return null; | |
var dist=0; | |
var olddist=0; | |
for (var i=1; (i < this.getVertexCount() && dist < metres); i++) { | |
olddist = dist; | |
dist += this.getVertex(i).distanceFrom(this.getVertex(i-1)); | |
} | |
if (dist < metres) {return null;} | |
var p1= this.getVertex(i-2); | |
var p2= this.getVertex(i-1); | |
var m = (metres-olddist)/(dist-olddist); | |
return new GLatLng( p1.lat() + (p2.lat()-p1.lat())*m, p1.lng() + (p2.lng()-p1.lng())*m); | |
} | |
// === A method which returns an array of GLatLngs of points a given interval along the path === | |
GPolygon.prototype.GetPointsAtDistance = function(metres) { | |
var next = metres; | |
var points = []; | |
// some awkward special cases | |
if (metres <= 0) return points; | |
var dist=0; | |
var olddist=0; | |
for (var i=1; (i < this.getVertexCount()); i++) { | |
olddist = dist; | |
dist += this.getVertex(i).distanceFrom(this.getVertex(i-1)); | |
while (dist > next) { | |
var p1= this.getVertex(i-1); | |
var p2= this.getVertex(i); | |
var m = (next-olddist)/(dist-olddist); | |
points.push(new GLatLng( p1.lat() + (p2.lat()-p1.lat())*m, p1.lng() + (p2.lng()-p1.lng())*m)); | |
next += metres; | |
} | |
} | |
return points; | |
} | |
// === A method which returns the Vertex number at a given distance along the path === | |
// === Returns null if the path is shorter than the specified distance === | |
GPolygon.prototype.GetIndexAtDistance = function(metres) { | |
// some awkward special cases | |
if (metres == 0) return this.getVertex(0); | |
if (metres < 0) return null; | |
var dist=0; | |
var olddist=0; | |
for (var i=1; (i < this.getVertexCount() && dist < metres); i++) { | |
olddist = dist; | |
dist += this.getVertex(i).distanceFrom(this.getVertex(i-1)); | |
} | |
if (dist < metres) {return null;} | |
return i; | |
} | |
// === A function which returns the bearing between two vertices in decgrees from 0 to 360=== | |
// === If v1 is null, it returns the bearing between the first and last vertex === | |
// === If v1 is present but v2 is null, returns the bearing from v1 to the next vertex === | |
// === If either vertex is out of range, returns void === | |
GPolygon.prototype.Bearing = function(v1,v2) { | |
if (v1 == null) { | |
v1 = 0; | |
v2 = this.getVertexCount()-1; | |
} else if (v2 == null) { | |
v2 = v1+1; | |
} | |
if ((v1 < 0) || (v1 >= this.getVertexCount()) || (v2 < 0) || (v2 >= this.getVertexCount())) { | |
return; | |
} | |
var from = this.getVertex(v1); | |
var to = this.getVertex(v2); | |
if (from.equals(to)) { | |
return 0; | |
} | |
var lat1 = from.latRadians(); | |
var lon1 = from.lngRadians(); | |
var lat2 = to.latRadians(); | |
var lon2 = to.lngRadians(); | |
var angle = - Math.atan2( Math.sin( lon1 - lon2 ) * Math.cos( lat2 ), Math.cos( lat1 ) * Math.sin( lat2 ) - Math.sin( lat1 ) * Math.cos( lat2 ) * Math.cos( lon1 - lon2 ) ); | |
if ( angle < 0.0 ) angle += Math.PI * 2.0; | |
angle = angle * 180.0 / Math.PI; | |
return parseFloat(angle.toFixed(1)); | |
} | |
// === Copy all the above functions to GPolyline === | |
GPolyline.prototype.Contains = GPolygon.prototype.Contains; | |
GPolyline.prototype.Area = GPolygon.prototype.Area; | |
GPolyline.prototype.Distance = GPolygon.prototype.Distance; | |
GPolyline.prototype.Bounds = GPolygon.prototype.Bounds; | |
GPolyline.prototype.GetPointAtDistance = GPolygon.prototype.GetPointAtDistance; | |
GPolyline.prototype.GetPointsAtDistance = GPolygon.prototype.GetPointsAtDistance; | |
GPolyline.prototype.GetIndexAtDistance = GPolygon.prototype.GetIndexAtDistance; | |
GPolyline.prototype.Bearing = GPolygon.prototype.Bearing; | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |
<html> | |
<head> | |
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/> | |
<title>Google Maps</title> | |
<script src="http://maps.google.com/maps?file=api&v=2&sensor=false&key=AIzaSyBsmTCDQYlmID4H8rqVe7Gb9Nm_SMpHahA" type="text/javascript"></script> | |
<script src="epoly.js" type="text/javascript"></script> | |
</head> | |
<body onunload="GUnload()"> | |
Click on the map and a path will be drawn that follows the streets.<br /> | |
Drag the markers and the path will be redrawn. | |
<div id="map" style="width: 800px; height: 600px"></div> | |
<div id="link" style="display:none"> | |
<div id="distance"></div> | |
<input type="button" value="Show on maps.google.com" onclick="linkToGoogle()" /> | |
</div> | |
<a href="snap.htm">Back to the tutorial page</a> | |
<noscript><b>JavaScript must be enabled in order for you to use Google Maps.</b> | |
However, it seems JavaScript is either disabled or not supported by your browser. | |
To view Google Maps, enable JavaScript by changing your browser options, and then | |
try again. | |
</noscript> | |
<script type="text/javascript"> | |
//<![CDATA[ | |
if (GBrowserIsCompatible()) { | |
var map = new GMap2(document.getElementById("map")); | |
map.setCenter(new GLatLng(53.7877, -2.9832),13) | |
map.addControl(new GLargeMapControl()); | |
map.addControl(new GMapTypeControl()); | |
// == use different GDirections for adding and dragging, it is just simpler that way == | |
var dirn1 = new GDirections(); | |
var dirn2 = new GDirections(); | |
var dirn3 = new GDirections(); | |
var firstpoint = true; | |
var gmarkers = []; | |
var gpolys = []; | |
var lastindex = 0; | |
GEvent.addListener(map, "click", function(overlay,point) { | |
// == When the user clicks on a the map, get directiobns from that point to itself == | |
if (!overlay) { | |
if (firstpoint) { | |
dirn1.loadFromWaypoints([point.toUrlValue(6),point.toUrlValue(6)],{getPolyline:true}); | |
} else { | |
dirn1.loadFromWaypoints([gmarkers[gmarkers.length-1].getPoint(),point.toUrlValue(6)],{getPolyline:true}); | |
} | |
} | |
}); | |
function calculateDistance() { | |
var dist = 0; | |
for (var i=0; i<gpolys.length; i++) { | |
dist+=gpolys[i].Distance(); | |
} | |
document.getElementById("distance").innerHTML="Path length: "+(dist/1000).toFixed(2)+" km. "+(dist/1609.344).toFixed(2)+" miles."; | |
} | |
// == when the load event completes, plot the point on the street == | |
GEvent.addListener(dirn1,"load", function() { | |
// snap to last vertex in the polyline | |
var n = dirn1.getPolyline().getVertexCount(); | |
var p=dirn1.getPolyline().getVertex(n-1); | |
var marker=new GMarker(p,{draggable:true}); | |
GEvent.addListener(marker, "dragend", function() { | |
lastIndex = marker.MyIndex; | |
var point = marker.getPoint(); | |
if (lastIndex>0) { | |
// recalculate the polyline preceding this point | |
dirn2.loadFromWaypoints([gmarkers[lastIndex-1].getPoint(),point.toUrlValue(6)],{getPolyline:true}); | |
} | |
if (lastIndex<gmarkers.length-1) { | |
// recalculate the polyline following this point | |
dirn3.loadFromWaypoints([point.toUrlValue(6),gmarkers[lastIndex+1].getPoint()],{getPolyline:true}); | |
} | |
}); | |
map.addOverlay(marker); | |
// store the details | |
marker.MyIndex=gmarkers.length; | |
gmarkers.push(marker); | |
if (!firstpoint) { | |
map.addOverlay(dirn1.getPolyline()); | |
gpolys.push(dirn1.getPolyline()); | |
calculateDistance(); | |
} | |
firstpoint = false; | |
if (gmarkers.length>1 && gmarkers.length<26) { | |
document.getElementById("link").style.display=""; | |
} else { | |
document.getElementById("link").style.display="none"; | |
} | |
}); | |
// == move the polyline preceding this point == | |
GEvent.addListener(dirn2,"load", function() { | |
// snap to last vertex in the polyline | |
var n = dirn2.getPolyline().getVertexCount(); | |
var p=dirn2.getPolyline().getVertex(n-1); | |
gmarkers[lastIndex].setPoint(p); | |
// remove the old polyline | |
map.removeOverlay(gpolys[lastIndex-1]); | |
// add the new polyline | |
map.addOverlay(dirn2.getPolyline()); | |
gpolys[lastIndex-1] = (dirn2.getPolyline()); | |
calculateDistance(); | |
}); | |
// == move the polyline following this point == | |
GEvent.addListener(dirn3,"load", function() { | |
// snap to first vertex in the polyline | |
var p=dirn3.getPolyline().getVertex(0); | |
gmarkers[lastIndex].setPoint(p); | |
// remove the old polyline | |
map.removeOverlay(gpolys[lastIndex]); | |
// add the new polyline | |
map.addOverlay(dirn3.getPolyline()); | |
gpolys[lastIndex] = (dirn3.getPolyline()); | |
calculateDistance(); | |
}); | |
GEvent.addListener(dirn1,"error", function() { | |
GLog.write("Failed: "+dirn1.getStatus().code); | |
}); | |
GEvent.addListener(dirn2,"error", function() { | |
GLog.write("Failed: "+dirn2.getStatus().code); | |
}); | |
GEvent.addListener(dirn3,"error", function() { | |
GLog.write("Failed: "+dirn3.getStatus().code); | |
}); | |
function linkToGoogle() { | |
var url="http://maps.google.com?q=from:+Start@" + gmarkers[0].getPoint().toUrlValue(5); | |
for (var i=1; i<gmarkers.length-1; i++) { | |
url+="+to:+"+gmarkers[i].getPoint().toUrlValue(5) | |
} | |
url+="+to:+End@"+gmarkers[gmarkers.length-1].getPoint().toUrlValue(5); | |
window.location = url; | |
} | |
} | |
else { | |
alert("Sorry, the Google Maps API is not compatible with this browser"); | |
} | |
// This Javascript is based on code provided by the | |
// Community Church Javascript Team | |
// http://www.bisphamchurch.org.uk/ | |
// http://econym.org.uk/gmap/ | |
//]]> | |
</script> | |
</body> | |
</html> | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment