我熟悉计算两点之间大圆距离的公式。
即
<?php
$theta = $lon1 - $lon2;
$dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
$dist = acos($dist);
$dist = rad2deg($dist);
//convert degrees to distance depending on units desired
?>
我需要的是与此相反的。给定起点,距离和简单的基数NSEW方向,以计算目标点的位置。自从我上数学课以来已经很久了。 ;)
答案 0 :(得分:8)
回答我自己的问题就是这样,对于任何好奇的人来说,这是一个由Chad Birch提供的C函数转换而来的PHP类:
class GreatCircle
{
/*
* Find a point a certain distance and vector away from an initial point
* converted from c function found at: http://sam.ucsd.edu/sio210/propseawater/ppsw_c/gcdist.c
*
* @param int distance in meters
* @param double direction in degrees i.e. 0 = North, 90 = East, etc.
* @param double lon starting longitude
* @param double lat starting latitude
* @return array ('lon' => $lon, 'lat' => $lat)
*/
public static function getPositionByDistance($distance, $direction, $lon, $lat)
{
$metersPerDegree = 111120.00071117;
$degreesPerMeter = 1.0 / $metersPerDegree;
$radiansPerDegree = pi() / 180.0;
$degreesPerRadian = 180.0 / pi();
if ($distance > $metersPerDegree*180)
{
$direction -= 180.0;
if ($direction < 0.0)
{
$direction += 360.0;
}
$distance = $metersPerDegree * 360.0 - $distance;
}
if ($direction > 180.0)
{
$direction -= 360.0;
}
$c = $direction * $radiansPerDegree;
$d = $distance * $degreesPerMeter * $radiansPerDegree;
$L1 = $lat * $radiansPerDegree;
$lon *= $radiansPerDegree;
$coL1 = (90.0 - $lat) * $radiansPerDegree;
$coL2 = self::ahav(self::hav($c) / (self::sec($L1) * self::csc($d)) + self::hav($d - $coL1));
$L2 = (pi() / 2) - $coL2;
$l = $L2 - $L1;
$dLo = (cos($L1) * cos($L2));
if ($dLo != 0.0)
{
$dLo = self::ahav((self::hav($d) - self::hav($l)) / $dLo);
}
if ($c < 0.0)
{
$dLo = -$dLo;
}
$lon += $dLo;
if ($lon < -pi())
{
$lon += 2 * pi();
}
elseif ($lon > pi())
{
$lon -= 2 * pi();
}
$xlat = $L2 * $degreesPerRadian;
$xlon = $lon * $degreesPerRadian;
return array('lon' => $xlon, 'lat' => $xlat);
}
/*
* copy the sign
*/
private static function copysign($x, $y)
{
return ((($y) < 0.0) ? - abs($x) : abs($x));
}
/*
* not greater than 1
*/
private static function ngt1($x)
{
return (abs($x) > 1.0 ? self::copysign(1.0 , $x) : ($x));
}
/*
* haversine
*/
private static function hav($x)
{
return ((1.0 - cos($x)) * 0.5);
}
/*
* arc haversine
*/
private static function ahav($x)
{
return acos(self::ngt1(1.0 - ($x * 2.0)));
}
/*
* secant
*/
private static function sec($x)
{
return (1.0 / cos($x));
}
/*
* cosecant
*/
private static function csc($x)
{
return (1.0 / sin($x));
}
}
答案 1 :(得分:5)
这是我发现的一个C实现,转换为PHP应该相当简单:
#define KmPerDegree 111.12000071117
#define DegreesPerKm (1.0/KmPerDegree)
#define PI M_PI
#define TwoPI (M_PI+M_PI)
#define HalfPI M_PI_2
#define RadiansPerDegree (PI/180.0)
#define DegreesPerRadian (180.0/PI)
#define copysign(x,y) (((y)<0.0)?-fabs(x):fabs(x))
#define NGT1(x) (fabs(x)>1.0?copysign(1.0,x):(x))
#define ArcCos(x) (fabs(x)>1?quiet_nan():acos(x))
#define hav(x) ((1.0-cos(x))*0.5) /* haversine */
#define ahav(x) (ArcCos(NGT1(1.0-((x)*2.0)))) /* arc haversine */
#define sec(x) (1.0/cos(x)) /* secant */
#define csc(x) (1.0/sin(x)) /* cosecant */
/*
** GreatCirclePos() --
**
** Compute ending position from course and great-circle distance.
**
** Given a starting latitude (decimal), the initial great-circle
** course and a distance along the course track, compute the ending
** position (decimal latitude and longitude).
** This is the inverse function to GreatCircleDist).
*/
void
GreatCirclePos(dist, course, slt, slg, xlt, xlg)
double dist; /* -> great-circle distance (km) */
double course; /* -> initial great-circle course (degrees) */
double slt; /* -> starting decimal latitude (-S) */
double slg; /* -> starting decimal longitude(-W) */
double *xlt; /* <- ending decimal latitude (-S) */
double *xlg; /* <- ending decimal longitude(-W) */
{
double c, d, dLo, L1, L2, coL1, coL2, l;
if (dist > KmPerDegree*180.0) {
course -= 180.0;
if (course < 0.0) course += 360.0;
dist = KmPerDegree*360.0-dist;
}
if (course > 180.0) course -= 360.0;
c = course*RadiansPerDegree;
d = dist*DegreesPerKm*RadiansPerDegree;
L1 = slt*RadiansPerDegree;
slg *= RadiansPerDegree;
coL1 = (90.0-slt)*RadiansPerDegree;
coL2 = ahav(hav(c)/(sec(L1)*csc(d))+hav(d-coL1));
L2 = HalfPI-coL2;
l = L2-L1;
if ((dLo=(cos(L1)*cos(L2))) != 0.0)
dLo = ahav((hav(d)-hav(l))/dLo);
if (c < 0.0) dLo = -dLo;
slg += dLo;
if (slg < -PI)
slg += TwoPI;
else if (slg > PI)
slg -= TwoPI;
*xlt = L2*DegreesPerRadian;
*xlg = slg*DegreesPerRadian;
} /* GreatCirclePos() */
来源:http://sam.ucsd.edu/sio210/propseawater/ppsw_c/gcdist.c
答案 2 :(得分:2)
我想,要退出Haversine公式,然后生成你自己的公司会更难。
首先,通过在表面上行“直线”从地球核心产生的角度(你认为它是直的,但它是弯曲的)。
弧度角度=弧长/半径。 角度= ArcLen / 6371 km
纬度应该很容易,只是角度的“垂直”(北/南)分量。
Lat1 + Cos(方位)*角度
经度除法因纬度而异。所以这变得更难。你会用:
Sin(方位)*角度(东方定义为负)以找到经度方向的角度,但转换回该纬度的实际经度将更加困难。
答案 3 :(得分:0)
请参阅本网站目的地点给定距离并从起点承担部分:http://www.movable-type.co.uk/scripts/latlong.html