本文介绍了在PHP中实现Vincenty公式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我一直在尝试通过以下方式实现 Vincenty的公式:
I've been attempting to implement Vincenty's formulae with the following:
/* Implemented using Vincenty's formulae from http://en.wikipedia.org/wiki/Vincenty%27s_formulae,
* answers "Direct Problem".
* $latlng is a ('lat'=>x1, 'lng'=>y1) array
* $distance is in miles
* $angle is in degrees
*/
function addDistance($latlng, $distance, $bearing) {
//variables
$bearing = deg2rad($bearing);
$iterations = 20; //avoid too-early termination while avoiding the non-convergant case
//knowns
$f = EARTH_SPHEROID_FLATTENING; //1/298.257223563
$a = EARTH_RADIUS_EQUATOR_MILES; //3963.185 mi
$phi1 = deg2rad($latlng['lat']);
$l1 = deg2rad($latlng['lng']);
$b = (1 - $f) * $a;
//first block
$tanU1 = (1-$f)*tan($phi1);
$U1 = atan($tanU1);
$sigma1 = atan($tanU1 / cos($bearing));
$sinalpha = cos($U1)*sin($bearing);
$cos2alpha = (1 - $sinalpha) * (1 + $sinalpha);
$usquared = $cos2alpha * (($a*$a - $b*$b) / 2);
$A = 1 + ($usquared)/16384 * (4096+$usquared*(-768+$usquared*(320 - 175*$usquared)));
$B = ($usquared / 1024)*(256*$usquared*(-128 + $usquared * (74 - 47*$usquared)));
//the loop - determining our value
$sigma = $distance / ($b * $A);
for($i = 0; $i < $iterations; ++$i) {
$twosigmam = 2*$sigma1 + $sigma;
$delta_sigma = $B * sin($sigma) * (cos($twosigmam)+(1/4)*$B*(cos(-1 + 2*cos(cos($twosigmam))) - (1/6)*$B*cos($twosigmam)*(-3+4*sin(sin($sigma)))*(-3+4*cos(cos($twosigmam)))));
$sigma = $distance / ($b * $A) + $delta_sigma;
}
//second block
$phi2 = atan((sin($U1)*cos($sigma)+cos($U1)*sin($sigma)*cos($bearing)) / ((1-$f) * sqrt(sin($sinalpha) + pow(sin($U1)*sin($sigma) - cos($U1)*cos($sigma)*cos($bearing), 2))));
$lambda = atan((sin($sigma) * sin($bearing)) / (cos($U1)*cos($sigma) - sin($U1)*sin($sigma)*cos($bearing)));
$C = ($f / 16)* $cos2alpha * (4+$f*(4-3*$cos2alpha));
$L = $lambda - (1 - $C) * $f * $sinalpha * ($sigma + $C*sin($sigma)*(cos($twosigmam)+$C*cos($sigma)*(-1+2*cos(cos($twosigmam)))));
$alpha2 = atan($sinalpha / (-sin($U1)*sin($sigma) + cos($U1)*cos($sigma)*cos($bearing)));
//and return our results
return array('lat' => rad2deg($phi2), 'lng' => rad2deg($lambda));
}
var_dump(addDistance(array('lat' => 93.129, 'lng' => -43.221), 20, 135);
问题是结果不合理-我得到的最大经度和纬度方差保持距离为20.不是以球面上的椭圆距离为单位吗?我是在误解什么,还是我的实现存在缺陷?
The issue is that the results are not reasonable - I'm getting variances of up to 20 latitude and longitude keeping the distance at 20. Is it not in units of elliptical distance on the sphere? Am I misunderstanding something, or is my implementation flawed?
推荐答案
- 您的
u
表达式的分母中有2
,应有b
; - 您的
A
和B
表达式对于是否需要对初始分数因子进行括号以正确地将a / b * c
表示为(a/b) * c
不一致-没有括号会发生什么是我不知道的php语法问题答案,但您应该更清楚; - 您应该迭代直到sigma没有明显变化为止",这可能会或可能不会发生在您固定的迭代次数中;
- 您的DELTA_sigma公式中有错误:
- 在Wikipedia页面上,方括号
[
中的第一项是cos sigma (-1
等,而您有cos (-1
等,这是非常不同的; - 在相同的公式中以及以后,请注意,
cos
x 表示(cos x)(cos x)
,不是cos cos x
!
- Your
u
expression has2
in the denominator where it should haveb
; - Your
A
andB
expressions are inconsistent about whether the initial fraction factor needs to be parenthesised to correctly expressa / b * c
as(a/b) * c
- what happens without parentheses is a php syntax issue which I don't know the answer to, but you should favour clarity; - You should be iterating "until there is no significant change in sigma", which may or may not happen in your fixed number of iterations;
- There are errors in your DELTA_sigma formula:
- on the wikipedia page, the first term inside the square bracket
[
iscos sigma (-1
etc, whereas you havecos (-1
etc, which is very different; - in the same formula and also later, note that
cos
x means(cos x)(cos x)
, notcos cos x
!
我认为就这些.
这篇关于在PHP中实现Vincenty公式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!
- on the wikipedia page, the first term inside the square bracket
- 在Wikipedia页面上,方括号