在给定距离的方向上画线 - 谷歌地图



我正在尝试使用谷歌地图API V3从默认起点绘制一条线,并进入给定距离的给定方向。例如,假设我的默认起点是旧金山,用户输入一个距离,我希望能够根据该输入距离绘制一条向东穿过美国的直线。我遇到了这个叫做轴承的东西,但我不确定如何正确使用它。这是我正在使用的代码:

function initializeMap(){
var mapOptions = {
center: new google.maps.LatLng(36.033036, -93.8655744),
zoom: 4,
mapTypeId: google.maps.MapTypeId.ROADMAP
};   
var map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions);
var R = 6378137;
var dis = parseInt(document.form['input']['val'].value);
var bearing = 80; 
var lat2 = Math.asin(   Math.sin(37.470625)*Math.cos(dis/R)+Math.cos(37.470625)*Math.sin(dis/R)*Math.cos(bearing) );
var lon2 = -122.266823 + Math.atan2(Math.sin(bearing)*Math.sin(dis/R)*Math.cos(37.470625),Math.cos(dis/R)-Math.sin(37.470625)*Math.sin(-122.266823));

var impactP = new google.maps.Polyline({
  path: new google.maps.LatLng(lat2,lon2), 
              strokeColor: "#FF0000",
  strokeOpacity: 1.0,
          strokeWeight: 2
        });
impactP.setMap(map);
}

有人可以帮我吗?我真的很想让它工作。

数学都在这里解释: http://www.movable-type.co.uk/scripts/latlong.html#destPoint

var lat2 = Math.asin( Math.sin(lat1)*Math.cos(d/R) + 
              Math.cos(lat1)*Math.sin(d/R)*Math.cos(brng) );
var lon2 = lon1 + Math.atan2(Math.sin(brng)*Math.sin(d/R)*Math.cos(lat1), 
                     Math.cos(d/R)-Math.sin(lat1)*Math.sin(lat2));

请注意,lat1,lon1(起点)和lat2,lon2(终点)以弧度为单位,而不是度数。 d是行进的距离,R地球的半径。这些可以采用任何单位,只要它们都是相同的单位。

如果您以弧度工作,看起来您在问题中的代码可以工作。

如果您从北半球的 90° 方位开始,您最终将稍微向南移动(您的最终方位将超过 90°)。球面几何是一件美妙的事情!

如果你想要一条恒定方位线,那么90°线在地图上是直线和水平的,你需要恒向线:http://www.movable-type.co.uk/scripts/latlong.html#rhumblines。这要复杂得多,但同样,该页面允许从距离和方位角计算端点,并解释必要的数学和Javascript。


同一页面建议在数字中添加方法,以从度数转换为弧度,然后再转换回来:

/** Converts numeric degrees to radians */
if (typeof(Number.prototype.toRad) === "undefined") {
  Number.prototype.toRad = function() {
    return this * Math.PI / 180;
  }
}
/** Converts radians to numeric (signed) degrees */
if (typeof(Number.prototype.toDeg) === "undefined") {
  Number.prototype.toDeg = function() {
    return this * 180 / Math.PI;
  }
}

因此(78).toRad() 1.3613568.

我把谷歌地图脚手架放进了 http://jsfiddle.net/khwLd/但我的数学不:(你可以看到线条转向南方。谷歌搜索"查找给定方位和距离的终端坐标"给了我一个 python 函数,我转换并检查了它,但仍然没有给出预期的结果。

计算给定方位角和距离的坐标

您需要做的是在开始时修复所有数学,以便:

getDestination(origin_lat, origin_lng, bearing, distance)返回google.maps.LatLng(destination_lat, destination_lng)

抱歉,我无法生成完整的工作解决方案:(

您可以使用

Chris Veness https://github.com/chrisveness/geodesy 的库中rhumbDestinationPoint的方法,另请参阅此处 http://www.movable-type.co.uk/scripts/latlong.html

rhumbDestinationPoint应用于LatLon对象,并将以米为单位的距离作为第一个参数,以六十进制度为单位作为第二个参数,即 0是北,90是东,180是南,270是西。

我刚刚将 https://raw.githubusercontent.com/chrisveness/geodesy/master/latlon-spherical.js rhumbDestinationPoint粘贴到下面的片段中(改编自OP http://jsfiddle.net/X25dZ/1/)

function initializeMap() {
  mapCenter = new google.maps.LatLng(36.033036, -93.8655744);
  defaultStart = new google.maps.LatLng(37.470625, -122.266823);
  var mapOptions = {
    center: mapCenter,
    zoom: 2,
    mapTypeId: google.maps.MapTypeId.ROADMAP
  };
  var map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions);
  var distance_in_meter = 600000;
  var bearing = 90;
  var start = new LatLon(defaultStart.lat(), defaultStart.lng());
  var destination = start.rhumbDestinationPoint(distance_in_meter, bearing);
  var impactP = new google.maps.Polyline({
    map: map,
    path: [defaultStart,
      new google.maps.LatLng(destination.lat, destination.lon)
    ],
    strokeColor: "#FF0000",
    strokeOpacity: 1.0,
    strokeWeight: 2
  });
}
google.maps.event.addDomListener(window, 'load', initializeMap);
html {
  height: 100%
}
body {
  height: 100%;
  margin: 0;
  padding: 0
}
#map-canvas {
  height: 100%
}
#menu {
  position: absolute;
  top: 0px;
  left: 0px;
  padding: 0px;
  font-family: Arial, sans-serif;
}
<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?sensor=false"></script>
<script type="text/javascript">
// Taken from https://raw.githubusercontent.com/chrisveness/geodesy/master/latlon-spherical.js	
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
/* Latitude/longitude spherical geodesy tools                         (c) Chris Veness 2002-2016  */
/*                                                                                   MIT Licence  */
/* www.movable-type.co.uk/scripts/latlong.html                                                    */
/* www.movable-type.co.uk/scripts/geodesy/docs/module-latlon-spherical.html                       */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
'use strict';
if (typeof module!='undefined' && module.exports) var Dms = require('./dms'); // ≡ import Dms from 'dms.js'
/**
 * Library of geodesy functions for operations on a spherical earth model.
 *
 * @module   latlon-spherical
 * @requires dms
 */
/**
 * Creates a LatLon point on the earth's surface at the specified latitude / longitude.
 *
 * @constructor
 * @param {number} lat - Latitude in degrees.
 * @param {number} lon - Longitude in degrees.
 *
 * @example
 *     var p1 = new LatLon(52.205, 0.119);
 */
function LatLon(lat, lon) {
// allow instantiation without 'new'
if (!(this instanceof LatLon)) return new LatLon(lat, lon);
this.lat = Number(lat);
this.lon = Number(lon);
}
/**
 * Returns the destination point having travelled along a rhumb line from ‘this’ point the given
 * distance on the  given bearing.
 *
 * @param   {number} distance - Distance travelled, in same units as earth radius (default: metres).
 * @param   {number} bearing - Bearing in degrees from north.
 * @param   {number} [radius=6371e3] - (Mean) radius of earth (defaults to radius in metres).
 * @returns {LatLon} Destination point.
 *
 * @example
 *     var p1 = new LatLon(51.127, 1.338);
 *     var p2 = p1.rhumbDestinationPoint(40300, 116.7); // 50.9642°N, 001.8530°E
 */
LatLon.prototype.rhumbDestinationPoint = function(distance, bearing, radius) {
radius = (radius === undefined) ? 6371e3 : Number(radius);
var δ = Number(distance) / radius; // angular distance in radians
var φ1 = this.lat.toRadians(), λ1 = this.lon.toRadians();
var θ = Number(bearing).toRadians();
var Δφ = δ * Math.cos(θ);
var φ2 = φ1 + Δφ;
// check for some daft bugger going past the pole, normalise latitude if so
if (Math.abs(φ2) > Math.PI/2) φ2 = φ2>0 ? Math.PI-φ2 : -Math.PI-φ2;
var Δψ = Math.log(Math.tan(φ2/2+Math.PI/4)/Math.tan(φ1/2+Math.PI/4));
var q = Math.abs(Δψ) > 10e-12 ? Δφ / Δψ : Math.cos(φ1); // E-W course becomes ill-conditioned with 0/0
var Δλ = δ*Math.sin(θ)/q;
var λ2 = λ1 + Δλ;
return new LatLon(φ2.toDegrees(), (λ2.toDegrees()+540) % 360 - 180); // normalise to −180..+180°
};
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
/**
 * Checks if another point is equal to ‘this’ point.
 *
 * @param   {LatLon} point - Point to be compared against this point.
 * @returns {bool}   True if points are identical.
 *
 * @example
 *   var p1 = new LatLon(52.205, 0.119);
 *   var p2 = new LatLon(52.205, 0.119);
 *   var equal = p1.equals(p2); // true
 */
LatLon.prototype.equals = function(point) {
if (!(point instanceof LatLon)) throw new TypeError('point is not LatLon object');
if (this.lat != point.lat) return false;
if (this.lon != point.lon) return false;
return true;
};
/**
 * Returns a string representation of ‘this’ point, formatted as degrees, degrees+minutes, or
 * degrees+minutes+seconds.
 *
 * @param   {string} [format=dms] - Format point as 'd', 'dm', 'dms'.
 * @param   {number} [dp=0|2|4] - Number of decimal places to use - default 0 for dms, 2 for dm, 4 for d.
 * @returns {string} Comma-separated latitude/longitude.
 */
LatLon.prototype.toString = function(format, dp) {
return Dms.toLat(this.lat, format, dp) + ', ' + Dms.toLon(this.lon, format, dp);
};
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
/** Extend Number object with method to convert numeric degrees to radians */
if (Number.prototype.toRadians === undefined) {
Number.prototype.toRadians = function() { return this * Math.PI / 180; };
}
/** Extend Number object with method to convert radians to numeric (signed) degrees */
if (Number.prototype.toDegrees === undefined) {
Number.prototype.toDegrees = function() { return this * 180 / Math.PI; };
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
if (typeof module != 'undefined' && module.exports) module.exports = LatLon; // ≡ export default LatLon    </script>
<div id="map-canvas"></div>

最新更新