我偶然发现这个奇妙的页面 http://www.movable-type.co.uk/scripts/latlong.html通过可移动类型的地理空间计算公式。更好的是,大多数公式都是已经用 JavaScript 编写 http://www.movable-type.co.uk/scripts/latlong.html#latlon-src这对于我的 Phonegap 应用程序来说非常酷。然而,引起我注意的公式是this one http://www.movable-type.co.uk/scripts/latlong.html#crossTrack用于计算两点之间的跨轨道距离。就我的应用程序和实际使用而言,这意味着即使 GPS 更新频率不够高而错过了目标位置的半径,我也可以根据最近位置和位置之间的路径来计算用户是否访问过目标。它的前身。
EDIT24/04/15:我修复了一个错误constrainedCrossTrackDistance
函数,因此任何使用它的人都应该将其实现更新为本答案中的实现。
JS 库不包含这个公式,所以我扩展了 Movable Type 库来实现它:
/**
* Calculates distance of a point from a great-circle path (also called cross-track distance or cross-track error)
*
* Formula: dxt = asin(sin(d13/R)*sin(b13-b12)) * R
* where
* d13 is distance from start point to third point
* b13 is (initial) bearing from start point to third point
* b12 is (initial) bearing from start point to end point
* R is the earth's radius
*
* @param {LatLon} startPoint - Point denoting the start of the great-circle path
* @param {LatLon} endPoint - Point denoting the end of the great-circle path
* @param {Number} [precision=4] - no of significant digits to use for calculations and returned value
* @return {Number} - distance in km from third point to great-circle path
*/
LatLon.prototype.crossTrackDistance = function(startPoint, endPoint, precision){
var R = this._radius;
var d13 = startPoint.distanceTo(this, 10);
var b13 = startPoint.bearingTo(this).toRad();
var b12 = startPoint.bearingTo(endPoint).toRad();
var d = Math.asin(Math.sin(d13/R)*Math.sin(b13-b12)) * R;
return d.toPrecisionFixed(precision);
}
然而,现实世界的测试再次表明这并不能完全完成工作。问题在于该函数给出了误报,因为它没有考虑由两个端点和半径形成的边界框。这导致我添加了一个进一步的函数来将交叉轨道距离限制在该边界框内:
/**
* Calculates distance of a point from a great-circle path if the point is within the bounding box defined by the path.
* Otherwise, it returns the distance from the point to the closest end of the great-circle path.
*
* @param {LatLon} startPoint - Point denoting the start of the great-circle path
* @param {LatLon} endPoint - Point denoting the end of the great-circle path
* @param {Number} [precision=4] - no of significant digits to use for calculations and returned value
* @return {Number} - distance in km from third point to great-circle path
*/
LatLon.prototype.constrainedCrossTrackDistance = function(startPoint, endPoint, precision){
var bAB = startPoint.bearingTo(endPoint);
var bAB_plus_90 = Geo.adjustBearing(bAB, 90);
var bAB_minus_90 = Geo.adjustBearing(bAB, -90);
var bAC = startPoint.bearingTo(this);
var bBC = endPoint.bearingTo(this);
var dAC = startPoint.distanceTo(this, 10);
var dBC = endPoint.distanceTo(this, 10);
if(Geo.differenceInBearings(bAC, bBC) > 90 && ((bBC > bAB_plus_90 && bAC < bAB_plus_90) || (bAC > bAB_minus_90 && bBC < bAB_minus_90))){
return Math.abs(this.crossTrackDistance(startPoint, endPoint, precision));
}else if((bBC < bAB_plus_90 && bAC < bAB_plus_90) || (bBC > bAB_minus_90 && bAC > bAB_minus_90)){
return Math.abs(dBC);
}else if((bBC > bAB_plus_90 && bAC > bAB_plus_90) || (bBC < bAB_minus_90 && bAC < bAB_minus_90)){
return Math.abs(dAC);
}else{
return (Math.abs(dBC) < Math.abs(dAC) ? Math.abs(dBC) : Math.abs(dAC));
}
}
然后可以用它来确定目标位置是否在现实场景中被访问过:
// Calculate if target location visited
if(
currentPos.distanceTo(targetPos)*1000 < tolerance ||
(prevPos && Math.abs(targetPos.constrainedCrossTrackDistance(prevPos, currentPos)*1000) < tolerance)
){
visited = true;
}else{
visited = false;
}
这是一个小提琴 http://jsfiddle.net/dpa99c/frL2u/说明用例
我花了很长时间和大量的测试才想出这个,所以我希望它对其他人有帮助:-)