ear-fung.us I’m a programmer. I’m also pro-grammar.

11Jan/083

PHP, Math, and Navagation

In my spare time I've been starting the write my own web based geocaching software in PHP so I can do some semi-automated statistical analysis on geocaches I've found.

I was looking for some pre-built functions do to some things like calculate distance between two lon/lat pairs as well as bearing and midpoints. Why re-invent the wheel if someone has already done it, right?

I found the mathematical calculation for how to calculate some if the things I was looking for at pilotsweb.com

Distance:
Distance
Where:
D = Distance (in Nautical Miles)
L1 = Original Latitude
L2 = Destination Latitude
Gammas = Origin Longitude
Gammas = Destination Longitude Latitude

Direction:
Bearing
Where:
C = Initial Bearing (in degrees)
D = Distance
L1 = Original Latitude
L2 = Destination Latitude

But that doesn't really help too much for writing code... I know I could figure it out, but when Joel De Gan has already figured it out and published his code, why not use that?

Here's some code from his site that I've changed a bit, re-formatted to my coding preferences, and added a bit of functionality too:

/*
Distance between two points
*/
function distance($lat1, $lon1, $lat2, $lon2, $units = 'miles')
{
	$lat1 = rad($lat1); $lon1 = rad($lon1);
	$lat2 = rad($lat2); $lon2 = rad($lon2);
	switch ($units)
	{
		case "miles":
		case "m":
		case "M":
			$r = 3963.1;
			break;
		case "nmiles":
		case "n":
		case "N":
			$r = 3443.9; break;
		case "kilo":
		case "k":
		case "K":
			$r = 6378;
			break;
	}

	return acos(sin($lat1)*sin($lat2) + cos($lat1)*cos($lat2)*cos($lon2-$lon1)) * $r;
}

/*
Bearing from point 1 to point 2
*/
function bearing($lat1,$lon1, $lat2, $lon2)
{
	$y = sin($lon2-$lon1) * cos($lat2);
	$x = cos($lat1)*sin($lat2) - sin($lat1)*cos($lat2)*cos($lon2-$lon1);

	return atan2($y, $x);
}

/*
Midpoint for two locations
*/
function midpoint($lat1, $lon1, $lat2, $lon2)
{
	$lat1 = rad($lat1); $lon1 = rad($lon1);
	$lat2 = rad($lat2); $lon2 = rad($lon2);
	$dLon = $lon2 - $lon1;
	$Bx = (cos($lat2) * cos($dLon));
	$By = (cos($lat2) * sin($dLon));
	$lat3 = atan2( sin($lat1) + sin($lat2), sqrt( (cos($lat1)+$Bx) * (cos($lat1)+$Bx) + ($By * $By)) );
	$lon3 = $lon1 + atan2($By, cos($lat1) + $Bx);

	if (!$lat3 || !$lon3) return false;

	return array($lat3 * 180 / M_PI, $lon3 * 180 / M_PI);
}

/*
Support functions
*/
function rad($v)
{
	return ($v * M_PI / 180);
}

/*
Degree, Minute, Seconds to decimal degrees
*/
function dms2deg($D, $M, $S, $dir)
{
	if(strpos(‘ WsSs’, $dir)>0)
		return(-1 * ($D + ($M + $S/60)/60));
	else
		return($D + ($M + $S/60)/60);
}

function dms($rad)
{
	$d = abs($rad * 180 / M_PI);
	$d += 1/7200; // add 1/2 second for rounding
	$deg = floor($d);
	$min = floor(($d-$deg)*60);
	$sec = floor(($d-$deg-$min/60)*3600);
	// add leading zeros if required
	if ($deg< 100) $deg = '0' + $deg;
	if ($deg< 10)  $deg = '0' + $deg;
	if ($min< 10)  $min = '0' + $min;
	if ($sec< 10)  $sec = '0' + $sec;
	return $deg + '\u00B0' + $min + '\u2032' + $sec + '\u2033';
}

Thanks for the help, Joel!

Comments (3) Trackbacks (0)
  1. Does that take into account the curvature of the earth’s surface? And why is it using nautical miles?

  2. glad it helps..
    I sort of wish I had been able to finish up the original app for handling this data and testing the theory I was presenting.
    However, I left that company where I was doing all this real-world location work and have kind of dropped most of it.
    Glad it helped someone though!


Leave a comment


No trackbacks yet.