222 lines
6.7 KiB
HTML
222 lines
6.7 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
|
|
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
|
|
<title>Geodesic lines, circles, envelopes in Google Maps</title>
|
|
<meta name="description"
|
|
content="Geodesic lines, circles, envelopes in Google Maps" />
|
|
<meta name="author" content="Charles F. F. Karney">
|
|
<meta name="keywords"
|
|
content="geodesics,
|
|
geodesic distance,
|
|
geographic distance,
|
|
shortest path,
|
|
direct geodesic problem,
|
|
inverse geodesic problem,
|
|
distance and azimuth,
|
|
distance and heading,
|
|
range and bearing,
|
|
geographic circle,
|
|
geodesic envelope,
|
|
geodesic astroid,
|
|
latitude and longitude,
|
|
Google Maps,
|
|
WGS84 ellipsoid,
|
|
GeographicLib" />
|
|
<link href="http://code.google.com/apis/maps/documentation/javascript/examples/default.css"
|
|
rel="stylesheet" type="text/css" />
|
|
<script type="text/javascript"
|
|
src="http://geographiclib.sf.net/scripts/geographiclib.js">
|
|
</script>
|
|
<script type="text/javascript"
|
|
src="http://maps.googleapis.com/maps/api/js?sensor=false">
|
|
</script>
|
|
<script type="text/javascript">
|
|
var geod = GeographicLib.Geodesic.WGS84;
|
|
var dms = GeographicLib.DMS;
|
|
var geodesic, circle, envelope;
|
|
|
|
function initialize() {
|
|
var mapOptions = {
|
|
zoom: 8,
|
|
center: new google.maps.LatLng(41.3, -5.5),
|
|
mapTypeId: google.maps.MapTypeId.ROADMAP
|
|
};
|
|
map = new google.maps.Map(document.getElementById('map_canvas'), mapOptions);
|
|
|
|
var geodesicOptions = {
|
|
strokeColor: '#0000FF',
|
|
strokeOpacity: 1,
|
|
strokeWeight: 3,
|
|
geodesic: true
|
|
}
|
|
geodesic = new google.maps.Polyline(geodesicOptions);
|
|
geodesic.setMap(map);
|
|
|
|
var circleOptions = {
|
|
strokeColor: '#00FF00',
|
|
strokeOpacity: 1,
|
|
strokeWeight: 3,
|
|
geodesic: true
|
|
}
|
|
circle = new google.maps.Polyline(circleOptions);
|
|
circle.setMap(map);
|
|
|
|
var envelopeOptions = {
|
|
strokeColor: '#FF0000',
|
|
strokeOpacity: 1,
|
|
strokeWeight: 3,
|
|
geodesic: true
|
|
}
|
|
envelope = new Array(4);
|
|
for (var i = 0; i < 4; ++i) {
|
|
envelope[i] = new google.maps.Polyline(envelopeOptions);
|
|
envelope[i].setMap(map);
|
|
}
|
|
}
|
|
|
|
function formatpoint(lat, lon, azi, dmsformat, prec) {
|
|
prec += 5;
|
|
if (dmsformat) {
|
|
var trail = prec < 2 ? dms.DEGREE :
|
|
(prec < 4 ? dms.MINUTE : dms.SECOND);
|
|
prec = prec < 2 ? prec : (prec < 4 ? prec - 2 : prec - 4);
|
|
return (dms.Encode(lat, trail, prec, dms.LATITUDE) + " " +
|
|
dms.Encode(lon, trail, prec, dms.LONGITUDE) + " " +
|
|
dms.Encode(azi, trail, prec, dms.AZIMUTH));
|
|
} else {
|
|
return (lat.toFixed(prec) + " " +
|
|
lon.toFixed(prec) + " " +
|
|
azi .toFixed(prec));
|
|
}
|
|
}
|
|
|
|
function GeodesicInverse(input) {
|
|
var result = {};
|
|
try {
|
|
// Input is a blank-delimited line: lat1 lon1 lat2 lon2
|
|
var t = new String(input);
|
|
t = t.replace(/^\s+/,"").replace(/\s+$/,"").split(/[\s,]+/,6);
|
|
if (t.length != 4)
|
|
throw new Error("Need 4 input items");
|
|
var p1 = GeographicLib.DMS.DecodeLatLon(t[0], t[1]);
|
|
var p2 = GeographicLib.DMS.DecodeLatLon(t[2], t[3]);
|
|
var v = geod.Inverse(p1.lat, p1.lon, p2.lat, p2.lon);
|
|
result.status = "OK";
|
|
result.p1 = formatpoint(v.lat1, v.lon1, v.azi1, true, 0);
|
|
result.p2 = formatpoint(v.lat2, v.lon2, v.azi2, true, 0);
|
|
result.s12 = v.s12.toFixed(0);
|
|
draw(v);
|
|
}
|
|
catch (e) {
|
|
result.status = "ERROR: " + e.message;
|
|
result.p1 = "";
|
|
result.p2 = "";
|
|
result.s12 = "";
|
|
}
|
|
return result;
|
|
}
|
|
function GeodesicDirect(input) {
|
|
var result = {};
|
|
try {
|
|
// Input is a blank-delimited line: lat1 lon1 azi1 s12
|
|
var t = new String(input);
|
|
t = t.replace(/^\s+/,"").replace(/\s+$/,"").split(/[\s,]+/,6);
|
|
if (t.length != 4)
|
|
throw new Error("Need 4 input items");
|
|
var p1 = GeographicLib.DMS.DecodeLatLon(t[0], t[1]);
|
|
var azi1 = GeographicLib.DMS.DecodeAzimuth(t[2]);
|
|
var s12 = parseFloat(t[3]);
|
|
var v = geod.Direct(p1.lat, p1.lon, azi1, s12);
|
|
result.status = "OK";
|
|
result.p1 = formatpoint(v.lat1, v.lon1, v.azi1, true, 0);
|
|
result.p2 = formatpoint(v.lat2, v.lon2, v.azi2, true, 0);
|
|
result.s12 = v.s12.toFixed(0);
|
|
draw(v);
|
|
}
|
|
catch (e) {
|
|
result.status = "ERROR: " + e.message;
|
|
result.p1 = "";
|
|
result.p2 = "";
|
|
result.s12 = "";
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function draw(v) {
|
|
var points = geod.DirectPath(v.lat1, v.lon1, v.azi1, v.s12,
|
|
100000, 100);
|
|
clearPaths();
|
|
var i, k, path;
|
|
|
|
path = geodesic.getPath();
|
|
for (k = 0; k < points.length; ++k)
|
|
path.push(new google.maps.LatLng(points[k].lat, points[k].lon));
|
|
points = geod.Circle(v.lat1, v.lon1, v.azi1, v.s12, 72);
|
|
path = circle.getPath();
|
|
for (k = 0; k < points.length; ++k)
|
|
path.push(new google.maps.LatLng(points[k].lat, points[k].lon));
|
|
for (i = 0; i < 4; ++i) {
|
|
points = geod.Envelope(v.lat1, v.lon1, 72, i+1);
|
|
path = envelope[i].getPath();
|
|
for (k = 0; k < points.length; ++k)
|
|
path.push(new google.maps.LatLng(points[k].lat, points[k].lon));
|
|
}
|
|
map.panTo(new google.maps.LatLng(v.lat2, v.lon2));
|
|
}
|
|
|
|
function clearPaths() {
|
|
cPath = geodesic.getPath();
|
|
while (cPath.getLength()) cPath.pop();
|
|
cPath = circle.getPath();
|
|
while (cPath.getLength()) cPath.pop();
|
|
for (var i = 0; i < 4; ++i) {
|
|
cPath = envelope[i].getPath();
|
|
while (cPath.getLength()) cPath.pop();
|
|
}
|
|
}
|
|
</script>
|
|
</head>
|
|
<body onload="initialize()">
|
|
<div id="map_canvas"
|
|
style="position:relative; border: 1px solid black; width:99.5%;
|
|
height:72%;">
|
|
</div>
|
|
<div>
|
|
<p>
|
|
Direct:
|
|
<input id="inputb" size=60 value="41°19'S 174°49'E 135° 60000e3" />
|
|
<input type="button" value="compute"
|
|
onclick="var t = GeodesicDirect(document.getElementById('inputb').value);
|
|
document.getElementById('status').value = t.status;
|
|
document.getElementById('p1').value = t.p1;
|
|
document.getElementById('p2').value = t.p2;
|
|
document.getElementById('s12').value = t.s12;" />
|
|
</p>
|
|
<p>
|
|
Inverse:
|
|
<input id="inputa" size=60 value="41°19'S 174°49'E 40°58'N 5°30'W" />
|
|
<input type="button" value="compute"
|
|
onclick="var t = GeodesicInverse(document.getElementById('inputa').value);
|
|
document.getElementById('status').value = t.status;
|
|
document.getElementById('p1').value = t.p1;
|
|
document.getElementById('p2').value = t.p2;
|
|
document.getElementById('s12').value = t.s12;" />
|
|
</p>
|
|
<p>
|
|
lat1 lon1 azi1: <input type="text" "readonly" id="p1" size=60>
|
|
</p>
|
|
<p>
|
|
lat2 lon2 azi2: <input type="text" "readonly" id="p2" size=60>
|
|
</p>
|
|
<p>
|
|
s12: <input type="text" "readonly" id="s12" size=20>
|
|
status: <input "readonly" id="status" size=30>
|
|
|
|
<a href="geod-google-instructions.html"><b>INSTRUCTIONS HERE</b></a>
|
|
</p>
|
|
</div>
|
|
</body>
|
|
</html>
|