几个月前,当
回答了一个类似的问题
关于如何在SQL Server 2008中的服务器端解决此问题时,我正在使用
Google Maps API v2.>
为了这个例子,让我们使用一个简单的4点多段线,总长度大约为8800米。下面的代码段将定义此多段线并在地图上呈现它:
var map=new gmap2(document.getElementByID('map_canvas'));
VAR点=
新格拉特灵(47.656,-122.360)
新格拉特灵(47.656,-122.343)
新格拉特灵(47.690,-122.310)
新格拉特朗(47.690,-122.270)
;
var polyline=新的gpolyline(点,f00',6);
map.setcenter(新格拉特隆(47.676,-122.343),12);
map.addoverlay(折线);
< /代码>
现在,在我们接近实际算法之前,我们需要一个函数,当给定一个起点、终点和沿着这条线行进的距离时,返回目标点,幸运的是,Chris Estence在计算纬度/经度点之间的距离、方位等。
特别是,我已经从上面的源代码中调整了以下两种方法来使用Google的glatlngclass:。
这些是用来扩展Google的glatlngclass with a methodmovedirective(),当给定另一个点和以米为单位的距离时,它将返回另一个glatlng沿着该行,当距离是从原始点向作为参数传递的点移动时。
glatlng.prototype.moveTowards=函数(点,距离){
var lat1=this.lat().torad();
var lon1=this.lng().torad();
var lat2=点.lat().torad();
var lon2=点.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)-
数学.sin(lat1)*数学.cos(lat2)*
数学cos(dlon));
var angdist=距离/6371000;//地球半径。
//给定源和方位,计算目标点。
lat2=math.asin(math.sin(lat1)*math.cos(angdist)+
math.cos(lat1)*math.sin(angdist)*
数学cos(brng));
lon2=lon1+math.atan2(math.sin(brng)*math.sin(angdist)*
数学,COS(LAT1),
math.cos(angdist)-math.sin(lat1)*
数学.sin(lat2));
if(isnan(lat2)isnan(lon2))返回空值;
返回新的glatlng(lat2.todeg(),lon2.todeg());
}
< /代码>
有了这个方法,我们现在可以解决如下问题:
- 循环访问路径的每个点。
-
- 找到迭代中当前点与下一点之间的距离。
-
如果点2中的距离大于路径上需要行驶的距离:
…然后目标点在该点和下一个点之间。只需将moveTowards()方法应用于当前点,传递下一个点和要移动的距离。返回结果并中断迭代。
:< /P>
…目标点位于迭代中下一个点的路径中。我们需要从沿着路径行驶的总距离中减去这一点和下一点之间的距离。使用修改后的距离继续迭代。
您可能已经注意到,我们可以很容易地递归实现上面的内容,而不是迭代。那么,让我们来做:
函数moveAlongPath(点,距离,索引){
index=index 0;//默认设置index为0。
如果(index<points.length){
//离这一点还有至少一个点。
//构造gpolyline以使用其getLength()方法。
var polyline=新gpolyline([点[索引],点[索引+1]);
//获取从该点到多段线中下一点的距离。
var distanceToNextPoint=polyline.getLength();
如果(距离<=DistanceToNextPoint){
//距离ToNextPoint在该点和下一个点之间。
//使用moveTowards()返回目标点。
返回点[index].movetoward(点[index+1],距离);
}
否则{
//目的地离下一点更远。减去
//DistanceTonextPoint与距离,然后递归继续。
返回移动路径(点,
距离-距离ToNextPoint,
指数+ 1);
}
}
否则{
//没有其他点。距离超过长度
//完整路径。返回空值。
返回空;
}
}
< /代码>
使用上述方法,如果我们定义一个glatlngpoints数组,并调用我们的movealongpath()function with this array of points and with a distance of 2500 meters,it will return aglatlng
on that path at 2.5km from the first point.
var points=[
新格拉特灵(47.656,-122.360)
新格拉特灵(47.656,-122.343)
新格拉特灵(47.690,-122.310)
新格拉特朗(47.690,-122.270)
;
var destinationpointonpath=movealongpath(点,2500);
//destinationpointonpath将是路径上的glatling
//起点2.5公里处。
< /代码>
因此,我们需要做的就是为路径上需要的每个检查点调用moveAlongPath().如果在1公里、5公里和10公里处需要三个标记,您只需:
map.addoverlay(new gmarker(movealongpath(points,1000)));
map.addoverlay(新gmarker(movealongpath(points,5000));
map.addoverlay(新gmarker(movealongpath(points,10000));
< /代码>
但是请注意,如果我们从路径的总长度进一步请求一个检查点,那么在将其传递给new gmarker()之前,它将更明智地检查返回值。
我们可以把这些放在一起,以便全面实施。在本例中,我们将沿着前面定义的8.8km路径每隔1000米放置一个标记:
<!文档类型HTML>
& HTML& GT;
&头;
<meta http equiv=“content type”content=“text/html;charset=utf-8”/>gt;
<title>谷歌地图-沿路径移动点</title>
<script src=“http://maps.google.com/maps?”文件=api&v=2&sensor=false”
type=“text/javascript”></script>
和/头& GT;
<body onUnload=“gunload()”>
<div id=“map_canvas”style=“width:500px;height:300px;”></div>
<script type=“text/javascript”>
number.prototype.torad=函数()。{
返回此*math.pi/180;
}
number.prototype.todeg=函数()。{
返回这个*180/math.pi;
}
glatlng.prototype.movetowards=函数(点、距离){
var lat1=this.lat().torad();
var lon1=this.lng().torad();
var lat2=点.lat().torad();
var lon2=点.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)-
数学.sin(lat1)*数学.cos(lat2)*
数学cos(dlon));
var angdist=距离/6371000;//地球半径。
//给定源和方位,计算目标点。
lat2=math.asin(math.sin(lat1)*math.cos(angdist)+
math.cos(lat1)*math.sin(angdist)*
数学cos(brng));
lon2=lon1+math.atan2(math.sin(brng)*math.sin(angdist)*
数学,COS(LAT1),
math.cos(angdist)-math.sin(lat1)*
数学.sin(lat2));
if(isnan(lat2)isnan(lon2))返回空值;
返回新的glatlng(lat2.todeg(),lon2.todeg());
}
函数movealOngPath(点、距离、索引){
index=index 0;//默认设置index为0。
如果(index<points.length){
//离这一点还有至少一个点。
//构造一个gpolyline以使用getLength()方法。
var polyline=新gpolyline([点[索引],点[索引+1]);
//获取从该点到多段线中下一点的距离。
var distanceToNextPoint=polyline.getLength();
如果(距离<=DistanceToNextPoint){
//距离ToNextPoint在该点和下一个点之间。
//使用moveTowards()返回目标点。
返回点[index].movetoward(点[index+1],距离);
}
否则{
//目的地离下一点更远。减去
//DistanceTonextPoint与距离,然后递归继续。
返回移动路径(点,
距离-距离ToNextPoint,
指数+ 1);
}
}
否则{
//没有其他点。距离超过长度
//完整路径。返回空值。
返回空;
}
}
var map=new gmap2(document.getElementByID('map_canvas'));
VAR点=
新格拉特灵(47.656,-122.360)
新格拉特灵(47.656,-122.343)
新格拉特灵(47.690,-122.310)
新格拉特朗(47.690,-122.270)
;
var polyline=新的gpolyline(点,f00',6);
var nextmarkerat=0;//标记检查点的计数器。
var next point=null;//放置下一个标记的位置。
map.setcenter(新格拉特隆(47.676,-122.343),12);
//在地图上绘制路径。
map.addoverlay(折线);
//每1000米绘制一次检查点标记。
当(真){
//调用movealongpath,它将返回带有下一个
//路径上的标记。
nextpoint=移动路径(点,nextmarkerat);
如果(下一个点){
//在地图上绘制标记。
map.addoverlay(新的gmarker(nextpoint));
//为下一个检查点添加+1000米。
下一个市场:+=1000;
}
否则{
//movealOngPath返回了空值,因此没有更多的检查点。
断裂;
}
}
& /脚本& GT;
和/身体;
& lt//html & gt;
< /代码>
以上示例的屏幕截图,每1000米显示一个标记:
几个月前,关于如何在SQL Server 2008的服务器端解决这个问题,我使用Google Maps API v2.
为了这个例子,让我们使用一个简单的4点多段线,总长度大约为8800米。下面的代码段将定义此多段线并在地图上呈现它:
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 Estence在Calculate distance, bearing and more between Latitude/Longitude points.
特别是,我已经从上面的源代码中调整了以下两种方法来使用Google的GLatLng
班级:
这些是用来扩展谷歌的格拉特兰
用方法初始化moveTowards()
当给另一个点和以米为单位的距离时,它将返回另一个点。格拉特兰
当距离从原始点向作为参数传递的点移动时,沿该线移动。
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());
}
有了这个方法,我们现在可以解决如下问题:
- 遍历路径的每个点。
- 找到迭代中当前点与下一点之间的距离。
如果点2中的距离大于我们在路径上行驶所需的距离:
…那么目的地就在这一点和下一点之间。只需应用MOVETWORD()
方法到当前点,通过下一个点和要行驶的距离。返回结果并中断迭代。
其他:
…目标点在迭代的下一个点的路径中更远。我们需要从沿着路径行驶的总距离中减去这一点和下一点之间的距离。使用修改后的距离继续迭代。
您可能已经注意到,我们可以很容易地递归实现上面的内容,而不是迭代。让我们这样做:
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;
}
}
使用上面的方法,如果我们定义一个格拉特兰
点,我们调用moveAlongPath()
使用此点数组和2500米的距离,它将返回格拉特兰
在距离第一个点2.5公里的那条小路上。
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.
所以我们只需要打电话MOVELAN PATH()
对于路径上需要的每个检查点。如果您在1公里、5公里和10公里处需要三个标记,您只需执行以下操作:
map.addOverlay(new GMarker(moveAlongPath(points, 1000)));
map.addOverlay(new GMarker(moveAlongPath(points, 5000)));
map.addOverlay(new GMarker(moveAlongPath(points, 10000)));
但是请注意MOVELAN PATH()
可能返回null
如果我们请求的检查点距离路径的总长度更远,那么在将返回值传递给new GMarker()
.
我们可以把这些放在一起,以便全面实施。在本例中,我们将沿着前面定义的8.8km路径每隔1000米放置一个标记:
<!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>
以上示例的屏幕截图,每1000米显示一个标记: