Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
345 views
in Technique[技术] by (71.8m points)

php - Great Circle Distance question

I am familiar with the formula to calculate the Great Circle Distance between two points.

i.e.

<?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
?>

What I need though, is the reverse of this. Given a starting point, a distance, and a simple cardinal NSEW direction, to calculate the position of the destination point. It's been a long time since I was in a math class. ;)

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

To answer my own question just so it's here for anyone curious, a PHP class as converted from the C function provided by Chad Birch:

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));
    }

}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...