本文介绍了如何根据沿线距离在Google地图多段线上添加标记?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个Google地图,用户可以在其中绘制他走/跑/骑自行车的路线并查看他跑了多久。 > GPolyline 类与它的 getLength()方法在这方面非常有帮助(至少对于Google Maps API V2来说) ,但我想根据距离添加标记,例如1公里,5公里,10公里等标记,但似乎没有明显的方法在多段线上找到点,它是。任何建议?

解决方案

有转换为JavaScript 。



为了举例,我们使用一个简单的4点折线,总长度大约为8,800米。下面的代码片段将定义这条折线并将它呈现在地图上:

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

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

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

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

现在在我们接近实际算法之前,我们需要一个函数,当给定起点,终点,以及沿着该线路行进的距离,幸运的是,Chris Veness在


这些用于扩展Google的 GLatLng 类,方法 moveTowards(),当以米为单位给出另一个点和距离时,它将返回另一个 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();

//找到从这一点到下一个的方位。
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 =距离/ 6371000; //地球的半径。

//计算目标点,给出源和方位。
lat2 = Math.asin(Math.sin(lat1)* Math.cos(angDist)+
Math.cos(lat1)* Math.sin(angDist)*
Math.cos方位角));

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))返回null;

返回新的GLatLng(lat2.toDeg(),lon2.toDeg());
}

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


  1. 遍历路径的每个点。
  2. 查找迭代中当前点与下一个点。

  3. 如果点2中的距离大于我们需要在路径上行进的距离:

    ...然后目标点在这个点和下一个点之间。只需将 moveTowards()方法应用到当前点,传递下一个点和距离即可。返回结果并中止迭代。



    其他:

    ...目标点位于从迭代中的下一个点开始的路径。我们需要从总距离中减去此点与下一个点之间的距离,以沿着路径行进。


您可能已经注意到我们可以轻松地实现上述递归,而是的迭代。所以让我们来做:

  function moveAlongPath(points,distance,index){
index = index || 0; //默认情况下将索引设置为0。

if(index< points.length){
//此处至少还有一点。

//构造一个GPolyline来使用它的getLength()方法。
var polyline = new GPolyline([points [index],points [index + 1]]);

//获取从这一点到多段线中下一个点的距离。
var distanceToNextPoint = polyline.getLength();

if(距离 // distanceToNextPoint在这一点和下一个点内。
//用moveTowards()返回目标点。
return points [index] .moveTowards(points [index + 1],distance);
}
else {
//目的地距离下一点更远。从距离减去
// distanceToNextPoint并递归地继续。
return moveAlongPath(points,
distance - distanceToNextPoint,
index + 1);
}
}
其他{
//没有其他要点。距离超过完整路径的长度
//。返回null。
返回null;






$ b

使用上述方法,如果我们定义一个数组 GLatLng 分,并且我们使用这组点来调用我们的 moveAlongPath()函数,距离为2500米,它会在距离第一点2.5公里的地方返回一个 GLatLng

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

var destinationPointOnPath = moveAlongPath(points,2500);

// destinationPointOnPath将成为路径
//在距离开始2.5km处的GLatLng。

因此,我们需要做的是调用 moveAlongPath()我们需要在路径上的每个检查点。如果你在1公里,5公里和10公里处需要三个标记,你可以简单地做:

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

请注意, moveAlongPath()可能会返回 null 如果我们请求一个距离路径总长度更远的检查点,所以在将它传递给之前检查返回值是明智的。新的GMarker()



我们可以将它们放在一起以便全面实施。在这个例子中,我们沿着之前定义的8.8km路径每隔1000米放置一个标记:

 <!DOCTYPE html> 
< html>
< head>
< meta http-equiv =content-typecontent =text / html; charset = UTF-8/>
< title> Google地图 - 沿着路径的移动点< / title>
< script src =http://maps.google.com/maps?file=api&v=2&sensor=false
type =text / javascript>< /脚本>
< / head>
< body onunload =GUnload()>
< div id =map_canvasstyle =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();

//找到从这一点到下一个的方位。
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 =距离/ 6371000; //地球的半径。

//计算目标点,给出源和方位。
lat2 = Math.asin(Math.sin(lat1)* Math.cos(angDist)+
Math.cos(lat1)* Math.sin(angDist)*
Math.cos方位角));

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))返回null;

返回新的GLatLng(lat2.toDeg(),lon2.toDeg());
}

函数moveAlongPath(points,distance,index){
index = index || 0; //默认情况下将索引设置为0。

if(index< points.length){
//此处至少还有一点。

//构造一个GPolyline来使用getLength()方法。
var polyline = new GPolyline([points [index],points [index + 1]]);

//获取从这一点到多段线中下一个点的距离。
var distanceToNextPoint = polyline.getLength();

if(距离 // distanceToNextPoint在这一点和下一个点内。
//用moveTowards()返回目标点。
return points [index] .moveTowards(points [index + 1],distance);
}
else {
//目的地距离下一点更远。从距离减去
// distanceToNextPoint并递归地继续。
return moveAlongPath(points,
distance - distanceToNextPoint,
index + 1);
}
}
其他{
//没有其他要点。距离超过完整路径的长度
//。返回null。
返回null;



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

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

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

var nextMarkerAt = 0; //标记检查点的计数器。
var nextPoint = null; //放置下一个标记的位置。

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

//在地图上绘制路径。
map.addOverlay(polyline);

//每1000米绘制检查点标记。
while(true){
//调用moveAlongPath,它将返回GLatLng与路径上的下一个
//标记。
nextPoint = moveAlongPath(points,nextMarkerAt);

if(nextPoint){
//在地图上绘制标记。
map.addOverlay(new GMarker(nextPoint));

//为下一个检查点增加+1000米。
nextMarkerAt + = 1000;
}
else {
// moveAlongPath返回null,所以没有更多的检查点。
休息;
}
}
< / script>
< / body>
< / html>

以上示例的屏幕截图显示了每1000米有一个标记:


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?

解决方案

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地图多段线上添加标记?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-06 06:02