【问题标题】:Draw line in direction given distance - google Maps在给定距离的方向上画线 - 谷歌地图
【发布时间】:2012-04-19 07:59:45
【问题描述】:

我正在尝试使用谷歌地图 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);
}

谁能帮帮我。我真的很想让这个工作。

【问题讨论】:

  • 我需要更多关于你到底想要做什么的信息。我可以在谷歌地图部分提供帮助,我不太了解的数学。我建议您将 37.470625 和 -122.266823 替换为变量。那些是你的目的地吗?我对您的代码进行了一些更改,以从地图中心绘制一条线到此计算的 lat2、lon2。 jsfiddle.net/X25dZ
  • 基本上我希望用户能够在远处输入。然后我想在这个距离的谷歌地图上画一条线,但只在我的默认起点以东。所以基本上我将在美国划出一条线,因为我希望我的起点在旧金山。具有挑战性的是我没有明确的终点。我只有默认的起点和线的距离。所以例如最后我的地图看起来像这样:jsfiddle.net/X25dZ/1

标签: javascript google-maps-api-3


【解决方案1】:

数学都在这里解释: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° 线在地图上是笔直且水平的,您需要 Rhumb 线:http://www.movable-type.co.uk/scripts/latlong.html#rhumblines。这要复杂得多,但该页面再次允许根据距离和方位计算端点,并解释了必要的数学和 Javascript。


同一页面建议向 Number 添加方法以将度数转换为弧度并再次转换:

/** 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

【讨论】:

    【解决方案2】:

    我在 Google Maps 脚手架 http://jsfiddle.net/khwLd/ 中添加了,但我的数学计算失败了 :( 你可以看到线条转向南方。谷歌搜索 “找到给定方位和距离的终端坐标”给了我一个 python 函数,我对其进行了转换和检查,但仍然没有给出预期的结果。

    Calculating coordinates given a bearing and a distance

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

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

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

    【讨论】:

      【解决方案3】:

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

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

      我刚刚将rhumbDestinationPointhttps://raw.githubusercontent.com/chrisveness/geodesy/master/latlon-spherical.js粘贴到下面的sn-p(改编自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>

      【讨论】:

        猜你喜欢
        • 2020-12-12
        • 1970-01-01
        • 2016-09-04
        • 2014-08-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-23
        相关资源
        最近更新 更多