Ada*_*mes 7 google-maps distance google-maps-api-3
我已经开始创建一个网站,用户可以被有效地跟踪(他们知道他们正在被跟踪).用户将走一条特定的路线(更准确地说是英国曼彻斯特),其中有10个检查站.检查点是地图上的静态位置.使用Google Maps API我知道我可以在地图上绘制一个位置,即检查点.我还存储用户到达所述检查点的时间.考虑到检查点之间的距离,我可以使用基本数学计算它们的平均速度.
现在我想做的是根据他们的速度绘制他们的估计位置.我遇到的困难是从沿路线的当前位置绘制一个新的位置x英里/米(任何单位).
如果它是一条直线,这将是简单的.
要使用图像扩展我的示例:

想象一下,用户在上午07:00到达第一位置标记,并且估计他们将在上午09:00到达第二位置标记.现在(例如)的时间是上午08:00,意味着(估计)用户应该在标记之间的大约一半.然后我会计算他们走过的距离(再次,估计)并在地图上绘制距离第一位标记"距离"的位置.
希望我已经清楚地解释了这个场景,让人们理解.
我对Google Maps API比较陌生,所以任何想法都会有所帮助.其他类似的问题已在SO上提出,但从我所看到的情况来看,没有人回答或要求我提供尽可能多的细节.
提前致谢.
更新:花了很多时间试图解决这个问题我失败了.这就是我所知道的:
我过去作为制图师做过很多这样的事情。您的折线由一系列点(纬度/经度坐标)组成。您可以计算每个连续点之间的距离,并在前进过程中将其相加,直到达到所需的距离。
\n\n真正的技巧是计算两个纬度/经度点之间的距离,这些点是球面坐标(即曲面上的点)。由于您处理的距离相当小,因此您可以将纬度/经度坐标转换为本地地图网格系统(平坦的)。两点之间的距离就是直角毕达哥拉斯(平方和所有这些的总和)。Movable Type 网站在此处有很多关于此的优秀(javascript)代码。
\n\n第二种方法是进行球面距离计算 - 不太漂亮,但你可以在这里看到它
\n\n就我个人而言,我会选择将坐标转换为本地网格系统,在英国应该是 OSGB。这是最不扭曲的方法。
\n\n希望这可以帮助
\n\n编辑: \n我假设您可以使用 google api 提取折线坐标。我还没有在 api 版本 3 中这样做,但它应该很简单。此外,折线坐标应该非常接近,您不需要插入中间点 - 只需获取最近的折线坐标(无需进行方位角和距离计算)。
\n\nEdit2 - 带代码
\n\n我尝试过将一些代码放在一起,但可能没有时间在您的时间限制内完成它(我有工作)。你应该能够明白要点。坐标转换代码取自可移动类型网站,基本的谷歌地图内容取自谷歌的示例之一。基本上,它通过鼠标单击绘制一条折线,将每次鼠标单击的纬度/经度放入表字段中,将坐标转换为 OSGB,然后转换为 OS 网格(请参见此处)。第一次单击后,它会计算每个后续点之间的距离。希望这能让你上路。
\n\n<!DOCTYPE html>\n<html>\n <head>\n <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />\n <style type="text/css">\n html { height: 100% }\n body { height: 100%; margin: 0; padding: 0 }\n #map_canvas { height: 100% }\n </style>\n <script type="text/javascript"\n src="http://maps.googleapis.com/maps/api/js?sensor=false">\n </script>\n\n <script src="Map.js" type="text/javascript"></script>\n </head>\n <body onload="initialize()" style="width:100%;height:100%">\n <div style="margin-right:auto;margin-left:auto;margin-top:100px;width:900px;">\n <div id="map_canvas" style="width:600px; height:500px;float:left;"></div>\n <div style="float:right;">\n <table>\n <tr>\n <td align="right">Latitude:</td>\n <td><input id="txtLatitude" maxlength="11" type="text" class="inputField"/></td>\n </tr>\n <tr>\n <td align="right">Longitude:</td>\n <td><input id="txtLongitude" maxlength="11" type="text" class="inputField"/></td>\n </tr>\n\n <tr>\n <td align="right">Eastings:</td>\n <td><input id="txtEast" maxlength="11" type="text" class="inputField"/></td>\n </tr>\n <tr>\n <td align="right">Northings:</td>\n <td><input id="txtNorth" maxlength="11" type="text" class="inputField"/></td>\n </tr>\n\n <tr>\n <td align="right">Distance:</td>\n <td><input id="txtDistance" maxlength="11" type="text" class="inputField"/></td>\n </tr>\n\n <tr>\n <td colspan=2 align="right">\n\n </td>\n </tr>\n</table>\n</div>\n </div>\n\n\n\n </body>\n</html>\nRun Code Online (Sandbox Code Playgroud)\n\n地图.js:
\n\nfunction initialize() {\n\n var myOptions = {\n center: new google.maps.LatLng(53.43057, -2.14727),\n zoom: 18,\n mapTypeId: google.maps.MapTypeId.ROADMAP\n };\n var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);\n var tempIcon = new google.maps.MarkerImage(\n "http://labs.google.com/ridefinder/images/mm_20_green.png",\n new google.maps.Size(12, 20),\n new google.maps.Size(6, 20)\n );\n var newShadow = new google.maps.MarkerImage(\n "http://labs.google.com/ridefinder/images/mm_20_shadow.png",\n new google.maps.Size(22, 20),\n new google.maps.Point(13, 13)\n );\n\n var tempMarker = new google.maps.Marker();\n tempMarker.setOptions({\n icon: tempIcon,\n shadow: newShadow,\n draggable: true\n });\n var latlngs = new google.maps.MVCArray();\n var displayPath = new google.maps.Polyline({\n map: map,\n strokeColor: "#FF0000",\n strokeOpacity: 1.0,\n strokeWeight: 2,\n path: latlngs\n });\n var lastEast;\n var lastNorth;\n function showTempMarker(e) {\n //Pythagorean distance calculates the length of the hypotenuse (the sloping side)\n //of a right angle triangle. Plain (cartesian) coordinates are all right angle triangles.\n //The length of the hypotenuse is always the distance between two coordinates.\n //One side of the triangle is the difference in east coordinate and the other is\n //the difference in north coordinates\n function pythagorasDistance(E, N) {\n if (lastEast) {\n if (lastEast) {\n //difference in east coordinates. We don\'t know what direction we are going so\n //it could be a negative number - so just take the absolute value (ie - get rid of any minus sign)\n var EastDistance = Math.abs(E - lastEast);\n //difference in north coordinates\n var NorthDistance = Math.abs(N - lastNorth);\n //take the power\n var EastPower = Math.pow(EastDistance, 2);\n var NorthPower = Math.pow(NorthDistance, 2);\n //add them together and take the square root\n var pythagorasDistance = Math.sqrt(EastPower + NorthPower );\n //round the answer to get rid of ridiculous decimal places (we\'re not measuring to the neares millimetre)\n var result = Math.floor(pythagorasDistance);\n\n document.getElementById(\'txtDistance\').value = result;\n }\n }\n\n }\n\n function calcCatesian(degLat, degLng) {\n var OSGBLL = LL.convertWGS84toOSGB36(new LatLon(degLat, degLng));\n var EN = LL.LatLongToOSGrid(OSGBLL);\n\n document.getElementById(\'txtEast\').value = EN.east;\n document.getElementById(\'txtNorth\').value = EN.north;\n pythagorasDistance(EN.east, EN.north);\n lastEast = EN.east;\n lastNorth = EN.north;\n\n }\n\n tempMarker.setPosition(e.latLng);\n var lat = e.latLng.lat();\n var lng = e.latLng.lng();\n document.getElementById(\'txtLatitude\').value = lat;\n document.getElementById(\'txtLongitude\').value = lng;\n calcCatesian(lat, lng);\n\n google.maps.event.addListener(tempMarker, "drag", function() {\n document.getElementById(\'txtLatitude\').value = tempMarker.getPosition().lat();\n document.getElementById(\'txtLongitude\').value = tempMarker.getPosition().lng();\n calcCatesian(lat, lng);\n });\n tempMarker.setMap(map);\n\n var newLocation = new google.maps.LatLng(lat, lng);\n latlngs.push(newLocation);\n displayPath.setPath(latlngs);\n\n }\n\n google.maps.event.addListener(map, "click", showTempMarker);\n}\n\n// ---- the following are duplicated from LatLong.html ---- //\n\n/*\n * construct a LatLon object: arguments in numeric degrees & metres\n *\n * note all LatLong methods expect & return numeric degrees (for lat/long & for bearings)\n */\nfunction LatLon(lat, lon, height) {\n if (arguments.length < 3)\n height = 0;\n this.lat = lat;\n this.lon = lon;\n this.height = height;\n}\n\nfunction setPrototypes() {\n\n /*\n * represent point {lat, lon} in standard representation\n */\n LatLon.prototype.toString = function() {\n return this.lat.toLat() + \', \' + this.lon.toLon();\n }\n // extend String object with method for parsing degrees or lat/long values to numeric degrees\n //\n // this is very flexible on formats, allowing signed decimal degrees, or deg-min-sec suffixed by\n // compass direction (NSEW). A variety of separators are accepted (eg 3\xc2\xba 37\' 09"W) or fixed-width\n // format without separators (eg 0033709W). Seconds and minutes may be omitted. (Minimal validation\n // is done).\n\n String.prototype.parseDeg = function() {\n if (!isNaN(this))\n return Number(this); // signed decimal degrees without NSEW\n\n var degLL = this.replace(/^-/, \'\').replace(/[NSEW]/i, \'\'); // strip off any sign or compass dir\'n\n var dms = degLL.split(/[^0-9.]+/); // split out separate d/m/s\n for (var i in dms)\n if (dms[i] == \'\')\n dms.splice(i, 1);\n // remove empty elements (see note below)\n switch (dms.length) { // convert to decimal degrees...\n case 3:\n // interpret 3-part result as d/m/s\n var deg = dms[0] / 1 + dms[1] / 60 + dms[2] / 3600;\n break;\n case 2:\n // interpret 2-part result as d/m\n var deg = dms[0] / 1 + dms[1] / 60;\n break;\n case 1:\n // decimal or non-separated dddmmss\n if (/[NS]/i.test(this))\n degLL = \'0\' + degLL; // - normalise N/S to 3-digit degrees\n var deg = dms[0].slice(0, 3) / 1 + dms[0].slice(3, 5) / 60 + dms[0].slice(5) / 3600;\n break;\n default:\n return NaN;\n }\n if (/^-/.test(this) || /[WS]/i.test(this))\n deg = -deg; // take \'-\', west and south as -ve\n return deg;\n }\n // note: whitespace at start/end will split() into empty elements (except in IE)\n\n // extend Number object with methods for converting degrees/radians\n\n Number.prototype.toRad = function() { // convert degrees to radians\n return this * Math.PI / 180;\n }\n Number.prototype.toDeg = function() { // convert radians to degrees (signed)\n return this * 180 / Math.PI;\n }\n // extend Number object with methods for presenting bearings & lat/longs\n\n Number.prototype.toDMS = function(dp) { // convert numeric degrees to deg/min/sec\n if (arguments.length < 1)\n dp = 0; // if no decimal places argument, round to int seconds\n var d = Math.abs(this); // (unsigned result ready for appending compass dir\'n)\n var deg = Math.floor(d);\n var min = Math.floor((d - deg) * 60);\n var sec = ((d - deg - min / 60) * 3600).toFixed(dp);\n // fix any nonsensical rounding-up\n if (sec == 60) {\n sec = (0).toFixed(dp);\n min++;\n }\n if (min == 60) {\n min = 0;\n deg++;\n }\n if (deg == 360)\n deg = 0;\n // add leading zeros if required\n if (deg < 100)\n deg = \'0\' + deg;\n if (deg < 10)\n deg = \'0\' + deg;\n if (min < 10)\n min = \'0\' + min;\n if (sec < 10)\n sec = \'0\' + sec;\n return deg + \'\\u00B0\' + min + \'\\u2032\' + sec + \'\\u2033\';\n }\n Number.prototype.toLat = function(dp) { // convert numeric degrees to deg/min/sec latitude\n return this.toDMS(dp).slice(1) + (this < 0 ? \'S\' : \'N\'); // knock off initial \'0\' for lat!\n }\n Number.prototype.toLon = function(dp) { // convert numeric degrees to deg/min/sec longitude\n return this.toDMS(dp) + (this > 0 ? \'E\' : \'W\');\n }\n /*\n * extend Number object with methods for converting degrees/radians\n */\n Number.prototype.toRad = function() { // convert degrees to radians\n return this * Math.PI / 180;\n }\n Number.prototype.toDeg = function() { // convert radians to degrees (signed)\n return this * 180 / Math.PI;\n }\n /*\n * pad a number with sufficient leading zeros to make it w chars wide\n */\n Number.prototype.padLZ = function(w) {\n var n = this.toString();\n for (var i = 0; i < w - n.length; i++)\n n = \'0\' + n;\n return n;\n }\n};\n\nsetPrototypes();\n\nLL = function() {\n\n // ellipse parameters\n var e = {\n WGS84: {\n a: 6378137,\n b: 6356752.3142,\n f: 1 / 298.257223563\n },\n Airy1830: {\n a: 6377563.396,\n b: 6356256.910,\n f: 1 / 299.3249646\n }\n };\n\n // helmert transform parameters\n var h = {\n WGS84toOSGB36: {\n tx: -446.448,\n ty: 125.157,\n tz: -542.060, // m\n rx: -0.1502,\n ry: -0.2470,\n rz: -0.8421, // sec\n s: 20.4894\n }, // ppm\n OSGB36toWGS84: {\n tx: 446.448,\n ty: -125.157,\n tz: 542.060,\n rx: 0.1502,\n ry: 0.2470,\n rz: 0.8421,\n s: -20.4894\n }\n };\n\n return {\n\n convertOSGB36toWGS84: function(p1) {\n var p2 = this.convert(p1, e.Airy1830, h.OSGB36toWGS84, e.WGS84);\n return p2;\n },\n convertWGS84toOSGB36: function(p1) {\n var p2 = this.convert(p1, e.WGS84, h.WGS84toOSGB36, e.Airy1830);\n return p2;\n },\n convert: function(p1, e1, t, e2) {\n // -- convert polar to cartesian coordinates (using ellipse 1)\n\n p1.lat = p1.lat.toRad();\n p1.lon = p1.lon.toRad();\n\n var a = e1.a, b = e1.b;\n\n var sinPhi = Math.sin(p1.lat), cosPhi = Math.cos(p1.lat);\n var sinLambda = Math.sin(p1.lon), cosLambda = Math.cos(p1.lon);\n var H = p1.height;\n\n var eSq = (a * a - b * b) / (a * a);\n var nu = a / Math.sqrt(1 - eSq * sinPhi * sinPhi);\n\n var x1 = (nu + H) * cosPhi * cosLambda;\n var y1 = (nu + H) * cosPhi * sinLambda;\n var z1 = ((1 - eSq) * nu + H) * sinPhi;\n\n // -- apply helmert transform using appropriate params\n\n var tx = t.tx, ty = t.ty, tz = t.tz;\n var rx = t.rx / 3600 * Math.PI / 180; // normalise seconds to radians\n var ry = t.ry / 3600 * Math.PI / 180;\n var rz = t.rz / 3600 * Math.PI / 180;\n var s1 = t.s / 1e6 + 1; // normalise ppm to (s+1)\n\n // apply transform\n var x2 = tx + x1 * s1 - y1 * rz + z1 * ry;\n var y2 = ty + x1 * rz + y1 * s1 - z1 * rx;\n var z2 = tz - x1 * ry + y1 * rx + z1 * s1;\n\n // -- convert cartesian to polar coordinates (using ellipse 2)\n\n a = e2.a, b = e2.b;\n var precision = 4 / a; // results accurate to around 4 metres\n\n eSq = (a * a - b * b) / (a * a);\n var p = Math.sqrt(x2 * x2 + y2 * y2);\n var phi = Math.atan2(z2, p * (1 - eSq)), phiP = 2 * Math.PI;\n while (Math.abs(phi - phiP) > precision) {\n nu = a / Math.sqrt(1 - eSq * Math.sin(phi) * Math.sin(phi));\n phiP = phi;\n phi = Math.atan2(z2 + eSq * nu * Math.sin(phi), p);\n }\n var lambda = Math.atan2(y2, x2);\n H = p / Math.cos(phi) - nu;\n\n return new LatLon(phi.toDeg(), lambda.toDeg(), H);\n },\n /*\n * convert numeric grid reference (in metres) to standard-form grid ref\n */\n gridrefNumToLet: function(e, n, digits) {\n // get the 100km-grid indices\n var e100k = Math.floor(e / 100000), n100k = Math.floor(n / 100000);\n\n if (e100k < 0 || e100k > 6 || n100k < 0 || n100k > 12)\n return \'\';\n\n // translate those into numeric equivalents of the grid letters\n var l1 = (19 - n100k) - (19 - n100k) % 5 + Math.floor((e100k + 10) / 5);\n var l2 = (19 - n100k) * 5 % 25 + e100k % 5;\n\n // compensate for skipped \'I\' and build grid letter-pairs\n if (l1 > 7)\n l1++;\n if (l2 > 7)\n l2++;\n var letPair = String.fromCharCode(l1 + \'A\'.charCodeAt(0), l2 + \'A\'.charCodeAt(0));\n\n // strip 100km-grid indices from easting & northing, and reduce precision\n e = Math.floor((e % 100000) / Math.pow(10, 5 - digits / 2));\n n = Math.floor((n % 100000) / Math.pow(10, 5 - digits / 2));\n\n var gridRef = letPair + e.padLZ(digits / 2) + n.padLZ(digits / 2);\n\n return gridRef;\n },\n LatLongToOSGrid: function(p) {\n var lat = p.lat.toRad(), lon = p.lon.toRad();\n\n var a = 6377563.396, b = 6356256.910; // Airy 1830 major & minor semi-axes\n var F0 = 0.9996012717; // NatGrid scale factor on central meridian\n var lat0 = (49).toRad(), lon0 = (-2).toRad(); // NatGrid true origin\n var N0 = -100000, E0 = 400000; // northing & easting of true origin, metres\n var e2 = 1 - (b * b) / (a * a); // eccentricity squared\n var n = (a - b) / (a + b), n2 = n * n, n3 = n * n * n;\n\n var cosLat = Math.cos(lat), sinLat = Math.sin(lat);\n var nu = a * F0 / Math.sqrt(1 - e2 * sinLat * sinLat); // transverse radius of curvature\n var rho = a * F0 * (1 - e2) / Math.pow(1 - e2 * sinLat * sinLat, 1.5); // meridional radius of curvature\n var eta2 = nu / rho - 1;\n\n var Ma = (1 + n + (5 / 4) * n2 + (5 / 4) * n3) * (lat - lat0);\n var Mb = (3 * n + 3 * n * n + (21 / 8) * n3) * Math.sin(lat - lat0) * Math.cos(lat + lat0);\n var Mc = ((15 / 8) * n2 + (15 / 8) * n3) * Math.sin(2 * (lat - lat0)) * Math.cos(2 * (lat + lat0));\n var Md = (35 / 24) * n3 * Math.sin(3 * (lat - lat0)) * Math.cos(3 * (lat + lat0));\n var M = b * F0 * (Ma - Mb + Mc - Md); // meridional arc\n\n var cos3lat = cosLat * cosLat * cosLat;\n var cos5lat = cos3lat * cosLat * cosLat;\n var tan2lat = Math.tan(lat) * Math.tan(lat);\n var tan4lat = tan2lat * tan2lat;\n\n var I = M + N0;\n var II = (nu / 2) * sinLat * cosLat;\n var III = (nu / 24) * sinLat * cos3lat * (5 - tan2lat + 9 * eta2);\n var IIIA = (nu / 720) * sinLat * cos5lat * (61 - 58 * tan2lat + tan4lat);\n var IV = nu * cosLat;\n var V = (nu / 6) * cos3lat * (nu / rho - tan2lat);\n var VI = (nu / 120) * cos5lat * (5 - 18 * tan2lat + tan4lat + 14 * eta2 - 58 * tan2lat * eta2);\n\n var dLon = lon - lon0;\n var dLon2 = dLon * dLon, dLon3 = dLon2 * dLon, dLon4 = dLon3 * dLon, dLon5 = dLon4 * dLon, dLon6 = dLon5 * dLon;\n\n var N = I + II * dLon2 + III * dLon4 + IIIA * dLon6;\n var E = E0 + IV * dLon + V * dLon3 + VI * dLon5;\n\n E = Math.floor(E * 100) / 100;\n N = Math.floor(N * 100) / 100;\n\n //return this.gridrefNumToLet(E, N, 8);\n return { east: E, north: N }\n ;\n }\n }\n\n} ();\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
5437 次 |
| 最近记录: |