如何根据沿线距离在谷歌地图折线上添加标记?

发布于 2024-08-30 04:22:49 字数 220 浏览 3 评论 0原文

我正在尝试创建一个谷歌地图,用户可以在其中绘制他步行/跑步/骑自行车的路线,并查看他跑了多长时间。带有 getLength() 方法的 GPolyline 类在这方面非常有帮助(至少对于 Google Maps API V2),但我想根据距离添加标记,例如例如 1 公里、5 公里、10 公里等的标记,但似乎没有明显的方法可以根据折线上的距离来查找折线上的点。有什么建议吗?

I am trying to create a Google Map where the user can plot the route he walked/ran/bicycled and see how long he ran. The GPolyline class with it’s getLength() method is very helpful in this regard (at least for Google Maps API V2), but I wanted to add markers based on distance, for example a marker for 1 km, 5 km, 10 km, etc., but it seems that there is no obvious way to find a point on a polyline based on how far along the line it is. Any suggestions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

彡翼 2024-09-06 04:22:49

回答了类似的问题几个月前,关于如何在 SQL Server 2008 的服务器端解决这个问题,我使用 Google 地图 API v2

在本示例中,我们使用一条简单的 4 点折线,总长度约为 8,800 米。下面的代码片段将定义这条折线并将其渲染在地图上:

var map = new GMap2(document.getElementById('map_canvas'));

var points = [
   new GLatLng(47.656, -122.360),
   new GLatLng(47.656, -122.343),
   new GLatLng(47.690, -122.310),
   new GLatLng(47.690, -122.270)
];

var polyline = new GPolyline(points, '#f00', 6);

map.setCenter(new GLatLng(47.676, -122.343), 12);
map.addOverlay(polyline);

现在,在我们采用实际算法之前,我们需要一个函数,在给定起点、终点以及沿该点行驶的距离时返回目的地点幸运的是,Chris Veness 在 计算距离,有一些方便的 JavaScript 实现,纬度/经度点之间的方位角和更多信息

特别是,我从上述来源改编了以下两种方法来与 Google 的 GLatLng 类一起使用:

这些用于通过方法 moveTowards() 扩展 Google 的 GLatLng 类,当给定另一个点和距离时,该方法以米为单位,当从原始点向作为参数传递的点行进的距离时,它将沿着该线返回另一个 GLatLng 。

GLatLng.prototype.moveTowards = function(point, distance) {   
   var lat1 = this.lat().toRad();
   var lon1 = this.lng().toRad();
   var lat2 = point.lat().toRad();
   var lon2 = point.lng().toRad();         
   var dLon = (point.lng() - this.lng()).toRad();

   // Find the bearing from this point to the next.
   var brng = Math.atan2(Math.sin(dLon) * Math.cos(lat2),
                         Math.cos(lat1) * Math.sin(lat2) -
                         Math.sin(lat1) * Math.cos(lat2) * 
                         Math.cos(dLon));

   var angDist = distance / 6371000;  // Earth's radius.

   // Calculate the destination point, given the source and bearing.
   lat2 = Math.asin(Math.sin(lat1) * Math.cos(angDist) + 
                    Math.cos(lat1) * Math.sin(angDist) * 
                    Math.cos(brng));

   lon2 = lon1 + Math.atan2(Math.sin(brng) * Math.sin(angDist) *
                            Math.cos(lat1), 
                            Math.cos(angDist) - Math.sin(lat1) *
                            Math.sin(lat2));

   if (isNaN(lat2) || isNaN(lon2)) return null;

   return new GLatLng(lat2.toDeg(), lon2.toDeg());
}

有了这个方法,我们现在可以按如下方式解决问题:

  1. 迭代路径的每个点。
  2. 求迭代中当前点到下一个点之间的距离。
  3. 如果点 2 的距离大于我们需要在路径上行驶的距离:

    ...那么目标点就在这个点和下一个点之间。只需将 moveTowards() 方法应用于当前点,并传递下一个点和要行进的距离。返回结果并中断迭代。

    其他:

    ...目标点距离迭代中的下一个点更远。我们需要从沿着路径行驶的总距离中减去这一点和下一点之间的距离。继续使用修改后的距离进行迭代。

您可能已经注意到,我们可以轻松地递归实现上述内容,而不是迭代。那么让我们这样做:

function moveAlongPath(points, distance, index) {
   index = index || 0;  // Set index to 0 by default.

   if (index < points.length) {
      // There is still at least one point further from this point.

      // Construct a GPolyline to use its getLength() method.
      var polyline = new GPolyline([points[index], points[index + 1]]);

      // Get the distance from this point to the next point in the polyline.
      var distanceToNextPoint = polyline.getLength();

      if (distance <= distanceToNextPoint) {
         // distanceToNextPoint is within this point and the next. 
         // Return the destination point with moveTowards().
         return points[index].moveTowards(points[index + 1], distance);
      }
      else {
         // The destination is further from the next point. Subtract
         // distanceToNextPoint from distance and continue recursively.
         return moveAlongPath(points,
                              distance - distanceToNextPoint,
                              index + 1);
      }
   }
   else {
      // There are no further points. The distance exceeds the length  
      // of the full path. Return null.
      return null;
   }  
}

使用上面的方法,如果我们定义一个 GLatLng 点数组,并使用该点数组和一个距离调用 moveAlongPath() 函数2,500 米,它将在距离第一个点 2.5 公里的路径上返回 GLatLng

var points = [
   new GLatLng(47.656, -122.360),
   new GLatLng(47.656, -122.343),
   new GLatLng(47.690, -122.310),
   new GLatLng(47.690, -122.270)
];

var destinationPointOnPath = moveAlongPath(points, 2500);

// destinationPointOnPath will be a GLatLng on the path 
// at 2.5km from the start.

因此,我们需要做的就是为路径上需要的每个检查点调用 moveAlongPath() 。如果您需要 1 公里、5 公里和 10 公里处的三个标记,您可以简单地执行以下操作:

map.addOverlay(new GMarker(moveAlongPath(points, 1000)));
map.addOverlay(new GMarker(moveAlongPath(points, 5000)));
map.addOverlay(new GMarker(moveAlongPath(points, 10000)));

但是请注意,如果我们请求距离总数更远的检查点,moveAlongPath() 可能会返回 null路径的长度,因此在将返回值传递给 new GMarker() 之前检查它是明智的做法。

我们可以将其整合在一起以进行全面实施。在此示例中,我们沿着前面定义的 8.8 公里路径每 1,000 米放置一个标记:

<!DOCTYPE html>
<html> 
<head> 
   <meta http-equiv="content-type" content="text/html; charset=UTF-8"/> 
   <title>Google Maps - Moving point along a path</title> 
   <script src="http://maps.google.com/maps?file=api&v=2&sensor=false"
           type="text/javascript"></script> 
</head> 
<body onunload="GUnload()"> 
   <div id="map_canvas" style="width: 500px; height: 300px;"></div>

   <script type="text/javascript"> 

   Number.prototype.toRad = function() {
      return this * Math.PI / 180;
   }

   Number.prototype.toDeg = function() {
      return this * 180 / Math.PI;
   }

   GLatLng.prototype.moveTowards = function(point, distance) {   
      var lat1 = this.lat().toRad();
      var lon1 = this.lng().toRad();
      var lat2 = point.lat().toRad();
      var lon2 = point.lng().toRad();         
      var dLon = (point.lng() - this.lng()).toRad();

      // Find the bearing from this point to the next.
      var brng = Math.atan2(Math.sin(dLon) * Math.cos(lat2),
                            Math.cos(lat1) * Math.sin(lat2) -
                            Math.sin(lat1) * Math.cos(lat2) * 
                            Math.cos(dLon));

      var angDist = distance / 6371000;  // Earth's radius.

      // Calculate the destination point, given the source and bearing.
      lat2 = Math.asin(Math.sin(lat1) * Math.cos(angDist) + 
                       Math.cos(lat1) * Math.sin(angDist) * 
                       Math.cos(brng));

      lon2 = lon1 + Math.atan2(Math.sin(brng) * Math.sin(angDist) *
                               Math.cos(lat1), 
                               Math.cos(angDist) - Math.sin(lat1) *
                               Math.sin(lat2));

      if (isNaN(lat2) || isNaN(lon2)) return null;

      return new GLatLng(lat2.toDeg(), lon2.toDeg());
   }

   function moveAlongPath(points, distance, index) {        
      index = index || 0;  // Set index to 0 by default.

      if (index < points.length) {
         // There is still at least one point further from this point.

         // Construct a GPolyline to use the getLength() method.
         var polyline = new GPolyline([points[index], points[index + 1]]);

         // Get the distance from this point to the next point in the polyline.
         var distanceToNextPoint = polyline.getLength();

         if (distance <= distanceToNextPoint) {
            // distanceToNextPoint is within this point and the next. 
            // Return the destination point with moveTowards().
            return points[index].moveTowards(points[index + 1], distance);
         }
         else {
            // The destination is further from the next point. Subtract
            // distanceToNextPoint from distance and continue recursively.
            return moveAlongPath(points,
                                 distance - distanceToNextPoint,
                                 index + 1);
         }
      }
      else {
         // There are no further points. The distance exceeds the length  
         // of the full path. Return null.
         return null;
      }  
   }

   var map = new GMap2(document.getElementById('map_canvas'));

   var points = [
      new GLatLng(47.656, -122.360),
      new GLatLng(47.656, -122.343),
      new GLatLng(47.690, -122.310),
      new GLatLng(47.690, -122.270)
   ];

   var polyline = new GPolyline(points, '#f00', 6);

   var nextMarkerAt = 0;     // Counter for the marker checkpoints.
   var nextPoint = null;     // The point where to place the next marker.

   map.setCenter(new GLatLng(47.676, -122.343), 12);

   // Draw the path on the map.
   map.addOverlay(polyline);

   // Draw the checkpoint markers every 1000 meters.
   while (true) {
      // Call moveAlongPath which will return the GLatLng with the next
      // marker on the path.
      nextPoint = moveAlongPath(points, nextMarkerAt);

      if (nextPoint) {
         // Draw the marker on the map.
         map.addOverlay(new GMarker(nextPoint));

         // Add +1000 meters for the next checkpoint.
         nextMarkerAt += 1000;    
      }
      else {
         // moveAlongPath returned null, so there are no more check points.
         break;
      }            
   }
   </script>
</body> 
</html>

上例的屏幕截图,显示每 1,000 米一个标记:

Google 地图 - 沿路径移动点

Having answered a similar problem a couple of months ago on how to tackle this on the server-side in SQL Server 2008, I am porting the same algorithm to JavaScript using the Google Maps API v2.

For the sake of this example, let's use a simple 4-point polyline, with a total length of circa 8,800 meters. The snippet below will define this polyline and will render it on the map:

var map = new GMap2(document.getElementById('map_canvas'));

var points = [
   new GLatLng(47.656, -122.360),
   new GLatLng(47.656, -122.343),
   new GLatLng(47.690, -122.310),
   new GLatLng(47.690, -122.270)
];

var polyline = new GPolyline(points, '#f00', 6);

map.setCenter(new GLatLng(47.676, -122.343), 12);
map.addOverlay(polyline);

Now before we approach the actual algorithm, we will need a function that returns the destination point when given a start point, an end point, and the distance to travel along that line, Luckily, there are a few handy JavaScript implementations by Chris Veness at Calculate distance, bearing and more between Latitude/Longitude points.

In particular I have adapted the following two methods from the above source to work with Google's GLatLng class:

These were used to extend Google's GLatLng class with a method moveTowards(), which when given another point and a distance in meters, it will return another GLatLng along that line when the distance is travelled from the original point towards the point passed as a parameter.

GLatLng.prototype.moveTowards = function(point, distance) {   
   var lat1 = this.lat().toRad();
   var lon1 = this.lng().toRad();
   var lat2 = point.lat().toRad();
   var lon2 = point.lng().toRad();         
   var dLon = (point.lng() - this.lng()).toRad();

   // Find the bearing from this point to the next.
   var brng = Math.atan2(Math.sin(dLon) * Math.cos(lat2),
                         Math.cos(lat1) * Math.sin(lat2) -
                         Math.sin(lat1) * Math.cos(lat2) * 
                         Math.cos(dLon));

   var angDist = distance / 6371000;  // Earth's radius.

   // Calculate the destination point, given the source and bearing.
   lat2 = Math.asin(Math.sin(lat1) * Math.cos(angDist) + 
                    Math.cos(lat1) * Math.sin(angDist) * 
                    Math.cos(brng));

   lon2 = lon1 + Math.atan2(Math.sin(brng) * Math.sin(angDist) *
                            Math.cos(lat1), 
                            Math.cos(angDist) - Math.sin(lat1) *
                            Math.sin(lat2));

   if (isNaN(lat2) || isNaN(lon2)) return null;

   return new GLatLng(lat2.toDeg(), lon2.toDeg());
}

Having this method, we can now tackle the problem as follows:

  1. Iterate through each point of the path.
  2. Find the distance between the current point in the iteration to the next point.
  3. If the distance in point 2 is greater the distance we need to travel on the path:

    ...then the destination point is between this point and the next. Simply apply the moveTowards() method to the current point, passing the next point and the distance to travel. Return the result and break the iteration.

    Else:

    ...the destination point is further in the path from the next point in the iteration. We need to subtract the distance between this point and the next point from the total distance to travel along the path. Continue through the iteration with the modified distance.

You may have noticed that we can easily implement the above recursively, instead of iteratively. So let's do it:

function moveAlongPath(points, distance, index) {
   index = index || 0;  // Set index to 0 by default.

   if (index < points.length) {
      // There is still at least one point further from this point.

      // Construct a GPolyline to use its getLength() method.
      var polyline = new GPolyline([points[index], points[index + 1]]);

      // Get the distance from this point to the next point in the polyline.
      var distanceToNextPoint = polyline.getLength();

      if (distance <= distanceToNextPoint) {
         // distanceToNextPoint is within this point and the next. 
         // Return the destination point with moveTowards().
         return points[index].moveTowards(points[index + 1], distance);
      }
      else {
         // The destination is further from the next point. Subtract
         // distanceToNextPoint from distance and continue recursively.
         return moveAlongPath(points,
                              distance - distanceToNextPoint,
                              index + 1);
      }
   }
   else {
      // There are no further points. The distance exceeds the length  
      // of the full path. Return null.
      return null;
   }  
}

With the above method, if we define an array of GLatLng points, and we invoke our moveAlongPath() function with this array of points and with a distance of 2,500 meters, it will return a GLatLng on that path at 2.5km from the first point.

var points = [
   new GLatLng(47.656, -122.360),
   new GLatLng(47.656, -122.343),
   new GLatLng(47.690, -122.310),
   new GLatLng(47.690, -122.270)
];

var destinationPointOnPath = moveAlongPath(points, 2500);

// destinationPointOnPath will be a GLatLng on the path 
// at 2.5km from the start.

Therefore all we need to do is to call moveAlongPath() for each check point we need on the path. If you need three markers at 1km, 5km and 10km, you can simply do:

map.addOverlay(new GMarker(moveAlongPath(points, 1000)));
map.addOverlay(new GMarker(moveAlongPath(points, 5000)));
map.addOverlay(new GMarker(moveAlongPath(points, 10000)));

Note however that moveAlongPath() may return null if we request a check point further from the total length of the path, so it will be wiser to check for the return value before passing it to new GMarker().

We can put this together for the full implementation. In this example we are dropping a marker every 1,000 meters along the 8.8km path defined earlier:

<!DOCTYPE html>
<html> 
<head> 
   <meta http-equiv="content-type" content="text/html; charset=UTF-8"/> 
   <title>Google Maps - Moving point along a path</title> 
   <script src="http://maps.google.com/maps?file=api&v=2&sensor=false"
           type="text/javascript"></script> 
</head> 
<body onunload="GUnload()"> 
   <div id="map_canvas" style="width: 500px; height: 300px;"></div>

   <script type="text/javascript"> 

   Number.prototype.toRad = function() {
      return this * Math.PI / 180;
   }

   Number.prototype.toDeg = function() {
      return this * 180 / Math.PI;
   }

   GLatLng.prototype.moveTowards = function(point, distance) {   
      var lat1 = this.lat().toRad();
      var lon1 = this.lng().toRad();
      var lat2 = point.lat().toRad();
      var lon2 = point.lng().toRad();         
      var dLon = (point.lng() - this.lng()).toRad();

      // Find the bearing from this point to the next.
      var brng = Math.atan2(Math.sin(dLon) * Math.cos(lat2),
                            Math.cos(lat1) * Math.sin(lat2) -
                            Math.sin(lat1) * Math.cos(lat2) * 
                            Math.cos(dLon));

      var angDist = distance / 6371000;  // Earth's radius.

      // Calculate the destination point, given the source and bearing.
      lat2 = Math.asin(Math.sin(lat1) * Math.cos(angDist) + 
                       Math.cos(lat1) * Math.sin(angDist) * 
                       Math.cos(brng));

      lon2 = lon1 + Math.atan2(Math.sin(brng) * Math.sin(angDist) *
                               Math.cos(lat1), 
                               Math.cos(angDist) - Math.sin(lat1) *
                               Math.sin(lat2));

      if (isNaN(lat2) || isNaN(lon2)) return null;

      return new GLatLng(lat2.toDeg(), lon2.toDeg());
   }

   function moveAlongPath(points, distance, index) {        
      index = index || 0;  // Set index to 0 by default.

      if (index < points.length) {
         // There is still at least one point further from this point.

         // Construct a GPolyline to use the getLength() method.
         var polyline = new GPolyline([points[index], points[index + 1]]);

         // Get the distance from this point to the next point in the polyline.
         var distanceToNextPoint = polyline.getLength();

         if (distance <= distanceToNextPoint) {
            // distanceToNextPoint is within this point and the next. 
            // Return the destination point with moveTowards().
            return points[index].moveTowards(points[index + 1], distance);
         }
         else {
            // The destination is further from the next point. Subtract
            // distanceToNextPoint from distance and continue recursively.
            return moveAlongPath(points,
                                 distance - distanceToNextPoint,
                                 index + 1);
         }
      }
      else {
         // There are no further points. The distance exceeds the length  
         // of the full path. Return null.
         return null;
      }  
   }

   var map = new GMap2(document.getElementById('map_canvas'));

   var points = [
      new GLatLng(47.656, -122.360),
      new GLatLng(47.656, -122.343),
      new GLatLng(47.690, -122.310),
      new GLatLng(47.690, -122.270)
   ];

   var polyline = new GPolyline(points, '#f00', 6);

   var nextMarkerAt = 0;     // Counter for the marker checkpoints.
   var nextPoint = null;     // The point where to place the next marker.

   map.setCenter(new GLatLng(47.676, -122.343), 12);

   // Draw the path on the map.
   map.addOverlay(polyline);

   // Draw the checkpoint markers every 1000 meters.
   while (true) {
      // Call moveAlongPath which will return the GLatLng with the next
      // marker on the path.
      nextPoint = moveAlongPath(points, nextMarkerAt);

      if (nextPoint) {
         // Draw the marker on the map.
         map.addOverlay(new GMarker(nextPoint));

         // Add +1000 meters for the next checkpoint.
         nextMarkerAt += 1000;    
      }
      else {
         // moveAlongPath returned null, so there are no more check points.
         break;
      }            
   }
   </script>
</body> 
</html>

Screenshot of the above example, showing a marker every 1,000 meters:

Google Maps - Move Point Along a Path

南汐寒笙箫 2024-09-06 04:22:49

这些是所需函数的原型:

google.maps.Polygon.prototype.Distance = function() {
   var dist = 0;
   for (var i=1; i < this.getPath().getLength(); i++) {
      dist += this.getPath().getAt(i).distanceFrom(this.getPath().getAt(i-1));
   }
   return dist;
}

google.maps.LatLng.prototype.distanceFrom = function(newLatLng) {
    //var R = 6371; // km (change this constant to get miles)
    var R = 6378100; // meters
    var lat1 = this.lat();
    var lon1 = this.lng();
    var lat2 = newLatLng.lat();
    var lon2 = newLatLng.lng();
    var dLat = (lat2-lat1) * Math.PI / 180;
    var dLon = (lon2-lon1) * Math.PI / 180;
    var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
      Math.cos(lat1 * Math.PI / 180 ) * Math.cos(lat2 * Math.PI / 180 ) *
      Math.sin(dLon/2) * Math.sin(dLon/2);
    var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
    var d = R * c;
    return d;
}

These are the prototypes for the required functions:

google.maps.Polygon.prototype.Distance = function() {
   var dist = 0;
   for (var i=1; i < this.getPath().getLength(); i++) {
      dist += this.getPath().getAt(i).distanceFrom(this.getPath().getAt(i-1));
   }
   return dist;
}

google.maps.LatLng.prototype.distanceFrom = function(newLatLng) {
    //var R = 6371; // km (change this constant to get miles)
    var R = 6378100; // meters
    var lat1 = this.lat();
    var lon1 = this.lng();
    var lat2 = newLatLng.lat();
    var lon2 = newLatLng.lng();
    var dLat = (lat2-lat1) * Math.PI / 180;
    var dLon = (lon2-lon1) * Math.PI / 180;
    var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
      Math.cos(lat1 * Math.PI / 180 ) * Math.cos(lat2 * Math.PI / 180 ) *
      Math.sin(dLon/2) * Math.sin(dLon/2);
    var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
    var d = R * c;
    return d;
}

source

泪是无色的血 2024-09-06 04:22:49

最好的方法可能是计算这些点的位置。

作为基本算法,您可以迭代折线中的所有点,并计算累积距离 - 如果下一段使您超出距离,您可以在达到距离的点进行插值 - 然后只需添加一个兴趣点到你的地图上。

Possibly the best approach would be to calculate where these points are.

As a basic algorithm you could iterate over all the points in the Polyline, and calculate the cumulative distance - if the next segment puts you over your distance, you can interpolate the point where the distance has been reached - then simply add a point of interest to your map for that.

情场扛把子 2024-09-06 04:22:49

我已经使用 Martin Zeitler 方法来处理 Google Map V3,并且工作正常。

 function init() {
       var mapOptions = {
            zoom: 15,
            center: new google.maps.LatLng(-6.208437004433984, 106.84543132781982),
            suppressInfoWindows: true,
                     };

        // Get all html elements for map
        var mapElement = document.getElementById('map1');

        // Create the Google Map using elements
        map = new google.maps.Map(mapElement, mapOptions);

        var nextMarkerAt = 0;     // Counter for the marker checkpoints.
        var nextPoint = null;     // The point where to place the next marker.


        while (true) {

            var routePoints = [ new google.maps.LatLng(47.656, -122.360),
                                new google.maps.LatLng(47.656, -122.343),
                                new google.maps.LatLng(47.690, -122.310),
                                new google.maps.LatLng(47.690, -122.270)];

                nextPoint = moveAlongPath(routePoints, nextMarkerAt);

            if (nextPoint) {
              //Adding marker from localhost
                MarkerIcon = "http://192.168.1.1/star.png";
                var marker = new google.maps.Marker
                    ({position: nextPoint,
                        map: map,
                        icon: MarkerIcon
                    });
                // Add +1000 meters for the next checkpoint.
                nextMarkerAt +=1000;

            }
            else {
                // moveAlongPath returned null, so there are no more check points.
                break;
            }
        }
 }


   Number.prototype.toRad = function () {
        return this * Math.PI / 180;
    }

    Number.prototype.toDeg = function () {
        return this * 180 / Math.PI;
    }

    function moveAlongPath(point, distance, index) {
        index = index || 0;  // Set index to 0 by default.

        var routePoints = [];

        for (var i = 0; i < point.length; i++) {
            routePoints.push(point[i]);
        }

        if (index < routePoints.length) {
            // There is still at least one point further from this point.

            // Construct a GPolyline to use the getLength() method.
            var polyline = new google.maps.Polyline({
                path: [routePoints[index], routePoints[index + 1]],
                strokeColor: '#FF0000',
                strokeOpacity: 0.8,
                strokeWeight: 2,
                fillColor: '#FF0000',
                fillOpacity: 0.35
            });

            // Get the distance from this point to the next point in the polyline.
            var distanceToNextPoint = polyline.Distance();

            if (distance <= distanceToNextPoint) {
                // distanceToNextPoint is within this point and the next.
                // Return the destination point with moveTowards().
                return moveTowards(routePoints, distance,index);
            }
            else {
                // The destination is further from the next point. Subtract
                // distanceToNextPoint from distance and continue recursively.
                return moveAlongPath(routePoints,
                    distance - distanceToNextPoint,
                    index + 1);
            }
        }
        else {
            // There are no further points. The distance exceeds the length
            // of the full path. Return null.
            return null;
        }
    }

    function moveTowards(point, distance,index) {

        var lat1 = point[index].lat.toRad();
        var lon1 = point[index].lng.toRad();
        var lat2 = point[index+1].lat.toRad();
        var lon2 = point[index+1].lng.toRad();
        var dLon = (point[index + 1].lng - point[index].lng).toRad();

        // Find the bearing from this point to the next.
        var brng = Math.atan2(Math.sin(dLon) * Math.cos(lat2),
            Math.cos(lat1) * Math.sin(lat2) -
            Math.sin(lat1) * Math.cos(lat2) *
            Math.cos(dLon));

        var angDist = distance / 6371000;  // Earth's radius.

        // Calculate the destination point, given the source and bearing.
        lat2 = Math.asin(Math.sin(lat1) * Math.cos(angDist) +
            Math.cos(lat1) * Math.sin(angDist) *
            Math.cos(brng));

        lon2 = lon1 + Math.atan2(Math.sin(brng) * Math.sin(angDist) *
            Math.cos(lat1),
            Math.cos(angDist) - Math.sin(lat1) *
            Math.sin(lat2));

        if (isNaN(lat2) || isNaN(lon2)) return null;



        return new google.maps.LatLng(lat2.toDeg(), lon2.toDeg());
    }

    google.maps.Polyline.prototype.Distance = function () {
        var dist = 0;
        for (var i = 1; i < this.getPath().getLength(); i++) {
            dist += this.getPath().getAt(i).distanceFrom(this.getPath().getAt(i - 1));
        }
        return dist;
    }

    google.maps.LatLng.prototype.distanceFrom = function (newLatLng) {
        //var R = 6371; // km (change this constant to get miles)
        var R = 6378100; // meters
        var lat1 = this.lat();
        var lon1 = this.lng();
        var lat2 = newLatLng.lat();
        var lon2 = newLatLng.lng();
        var dLat = (lat2 - lat1) * Math.PI / 180;
        var dLon = (lon2 - lon1) * Math.PI / 180;
        var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
            Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
            Math.sin(dLon / 2) * Math.sin(dLon / 2);
        var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        var d = R * c;
        return d;
    }

I have used Martin Zeitler method to work with Google Map V3 and its working fine.

 function init() {
       var mapOptions = {
            zoom: 15,
            center: new google.maps.LatLng(-6.208437004433984, 106.84543132781982),
            suppressInfoWindows: true,
                     };

        // Get all html elements for map
        var mapElement = document.getElementById('map1');

        // Create the Google Map using elements
        map = new google.maps.Map(mapElement, mapOptions);

        var nextMarkerAt = 0;     // Counter for the marker checkpoints.
        var nextPoint = null;     // The point where to place the next marker.


        while (true) {

            var routePoints = [ new google.maps.LatLng(47.656, -122.360),
                                new google.maps.LatLng(47.656, -122.343),
                                new google.maps.LatLng(47.690, -122.310),
                                new google.maps.LatLng(47.690, -122.270)];

                nextPoint = moveAlongPath(routePoints, nextMarkerAt);

            if (nextPoint) {
              //Adding marker from localhost
                MarkerIcon = "http://192.168.1.1/star.png";
                var marker = new google.maps.Marker
                    ({position: nextPoint,
                        map: map,
                        icon: MarkerIcon
                    });
                // Add +1000 meters for the next checkpoint.
                nextMarkerAt +=1000;

            }
            else {
                // moveAlongPath returned null, so there are no more check points.
                break;
            }
        }
 }


   Number.prototype.toRad = function () {
        return this * Math.PI / 180;
    }

    Number.prototype.toDeg = function () {
        return this * 180 / Math.PI;
    }

    function moveAlongPath(point, distance, index) {
        index = index || 0;  // Set index to 0 by default.

        var routePoints = [];

        for (var i = 0; i < point.length; i++) {
            routePoints.push(point[i]);
        }

        if (index < routePoints.length) {
            // There is still at least one point further from this point.

            // Construct a GPolyline to use the getLength() method.
            var polyline = new google.maps.Polyline({
                path: [routePoints[index], routePoints[index + 1]],
                strokeColor: '#FF0000',
                strokeOpacity: 0.8,
                strokeWeight: 2,
                fillColor: '#FF0000',
                fillOpacity: 0.35
            });

            // Get the distance from this point to the next point in the polyline.
            var distanceToNextPoint = polyline.Distance();

            if (distance <= distanceToNextPoint) {
                // distanceToNextPoint is within this point and the next.
                // Return the destination point with moveTowards().
                return moveTowards(routePoints, distance,index);
            }
            else {
                // The destination is further from the next point. Subtract
                // distanceToNextPoint from distance and continue recursively.
                return moveAlongPath(routePoints,
                    distance - distanceToNextPoint,
                    index + 1);
            }
        }
        else {
            // There are no further points. The distance exceeds the length
            // of the full path. Return null.
            return null;
        }
    }

    function moveTowards(point, distance,index) {

        var lat1 = point[index].lat.toRad();
        var lon1 = point[index].lng.toRad();
        var lat2 = point[index+1].lat.toRad();
        var lon2 = point[index+1].lng.toRad();
        var dLon = (point[index + 1].lng - point[index].lng).toRad();

        // Find the bearing from this point to the next.
        var brng = Math.atan2(Math.sin(dLon) * Math.cos(lat2),
            Math.cos(lat1) * Math.sin(lat2) -
            Math.sin(lat1) * Math.cos(lat2) *
            Math.cos(dLon));

        var angDist = distance / 6371000;  // Earth's radius.

        // Calculate the destination point, given the source and bearing.
        lat2 = Math.asin(Math.sin(lat1) * Math.cos(angDist) +
            Math.cos(lat1) * Math.sin(angDist) *
            Math.cos(brng));

        lon2 = lon1 + Math.atan2(Math.sin(brng) * Math.sin(angDist) *
            Math.cos(lat1),
            Math.cos(angDist) - Math.sin(lat1) *
            Math.sin(lat2));

        if (isNaN(lat2) || isNaN(lon2)) return null;



        return new google.maps.LatLng(lat2.toDeg(), lon2.toDeg());
    }

    google.maps.Polyline.prototype.Distance = function () {
        var dist = 0;
        for (var i = 1; i < this.getPath().getLength(); i++) {
            dist += this.getPath().getAt(i).distanceFrom(this.getPath().getAt(i - 1));
        }
        return dist;
    }

    google.maps.LatLng.prototype.distanceFrom = function (newLatLng) {
        //var R = 6371; // km (change this constant to get miles)
        var R = 6378100; // meters
        var lat1 = this.lat();
        var lon1 = this.lng();
        var lat2 = newLatLng.lat();
        var lon2 = newLatLng.lng();
        var dLat = (lat2 - lat1) * Math.PI / 180;
        var dLon = (lon2 - lon1) * Math.PI / 180;
        var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
            Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
            Math.sin(dLon / 2) * Math.sin(dLon / 2);
        var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        var d = R * c;
        return d;
    }
秋日私语 2024-09-06 04:22:49

我想将 Daniel Vassalo 的答案移植到 iOS,但它无法正常工作,并且一些标记被放错位置,直到我更改

var dLon = (point.lng() - this.lng()).toRad();

var dLon = point.lng().toRad() - this.lng().toRad();

因此,如果有人无法弄清楚为什么标记放错了位置,请尝试一下,也许会有所帮助。

I wanted to port Daniel Vassalo's answer to iOS, but it wasn't worked properly and some markers were misplaced until I changed

var dLon = (point.lng() - this.lng()).toRad();

to

var dLon = point.lng().toRad() - this.lng().toRad();

So if anyone having a trouble to figure out why are the markers are misplaced, try this and maybe it will help.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文