<?php

/*
  --------------------------------------------------------------------------
  Geodetic Distance Calculator

  This program computes the geodetic surface distance between two points on
  Earth given their respective latitudes and longitudes.

  It is based on the Andoyer Algorithm and theoretically accurate to the
  nearest 0.1 km.

  Author:
  Jay Tanner - 2025

  Current Web Site
  www.NeoProgrammics.com

  AUTHOR   : Jay Tanner - 2025
  LANGUAGE : PHP v8.2.12
  LICENSE  : Public Domain
  --------------------------------------------------------------------------
*/

   
ob_start();

// -----------------------------------
// Get current year from system clock.
   
$cYear date('Y');

/* ------------------------------------------
   Define program version and revision dates.
*/
   
$ProgramVersion "v1.13";
   
$RevisionDate   "2020-May-19-Tue";

   
$ReKm  6378.137;
   
$ReMi  3963.191;
   
$ReNmi sprintf("%1.3f"$ReKm 1.852);

   
$flattening  "1/298.257";
   list(
$u$w) = preg_split("[\/]"$flattening);
   
$f $u/$w;

// COMPUTE POLAR RADIUS OF THE EARTH FROM THE
// FLATTENING AND THE EQUATORIAL RADIUS.
   
$RpKm  6378.137 * ($f);
   
$RpMi  sprintf("%1.3f"$RpKm 1.609344);
   
$RpNmi sprintf("%1.3f"$RpKm 1.852);
   
$RpKm  sprintf("%1.3f"$RpKm);
   
$f     sprintf("%1.9f"$f);

   
$OutputText '';

// Define status message to be displayed in TEXTAREA while working.
   
$StatusText1 "OutputTextArea.innerHTML='COMPUTING ...';";

/* -----------------------------------------------
   Set the path to the program to be executed when
   any submit button is clicked.  In this case, it
   is this program itself. It modifies itself each
   time it is called.
*/
   
$RUN_PROGRAM $_SERVER['SCRIPT_NAME'];

// READ GEOGRAPHIC COORDINATES OF THE TWO POINTS.
   
$LatLon1 = @$_POST['LatLon1'];
   
$LatLon2 = @$_POST['LatLon2'];

   
$Loc1 = @$_POST['Loc1'];
   
$Loc2 = @$_POST['Loc2'];

   if(
trim($Loc1) == '')  {$Loc1 "Point A";}
   if(
trim($Loc2) == '')  {$Loc2 "Point B";}

   if(
trim($LatLon1) == '' and trim($LatLon2) == '')
{
/*
   SELECT DEFAULT RANDOM LOCATION COORDINATES.
*/
   
$Loc1    "Point A";
   
$LatLon1 90*Rand_Decimal(16TRUE) . ', ' 180*Rand_Decimal(16TRUE);
   
$Loc2    "Point B";
   
$LatLon2 90*Rand_Decimal(16TRUE) . ', ' 180*Rand_Decimal(16TRUE);

// OVERRIDE DEFAULTS ABOVE
   
$Loc1    "Washington, DC, USA";
   
$LatLon1 '+38.9213889;  -77.0655556';
   
$Loc2    "Paris, France";
   
$LatLon2 '+48.8363889;   +2.3372222';



/*
   $Loc1    = "Rubha na Lice, Mull of Kintyre, Mean High Water Springs, Scotland";
   $LatLon1 = "+55.299691653,  -5.799218022";
   $Loc2    = "Torr Head, Antrim, Ireland";
   $LatLon2 = "+55.198861053,  -6.062220511";
*/

/*
   $Loc1    = "Paris, France";
   $LatLon1 = "+48.8363889,   +2.3372222";
   $Loc2    = "Washington, DC, USA";
   $LatLon2 = "+38.9213889,  -77.0655556";
*/
}
   
$w1 Process_Lat_Lon_String($LatLon1);
   
$w2 Process_Lat_Lon_String($LatLon2);

// PARSE INDIVIDUAL COORDINATES VALUES.
   
list($lat1$lon1) = preg_split("[ ]"$w1);
   list(
$lat2$lon2) = preg_split("[ ]"$w2);

// FORMAT FOR DISPLAY.
   
$latDMS1 Deg_to_DMS($lat13'+''d');
   
$lonDMS1 Deg_to_DMS($lon13'+''d');
   
$latDMS2 Deg_to_DMS($lat23'+''d');
   
$lonDMS2 Deg_to_DMS($lon23'+''d');
   
$LatLon1 "$lat1,  $lon1";
   
$LatLon2 "$lat2,  $lon2";


   
$DoneFlag FALSE;

if (
$lat1 == $lat2 and $lon1 == $lon2)
   {
   
$OutputText =
"
      GEODETIC DISTANCE BETWEEN TWO LOCATIONS ON THE EARTH SPHEROID
           Based on the Andoyer Algorithm  (to nearest &plusmn;0.1 km)

FIRST LOCATION: 
$Loc1

Latitude  = 
$lat1 &deg; \t= $latDMS1
Longitude = 
$lon1 &deg; \t= $lonDMS1

----------------------------------------------------------------------
SECOND LOCATION: 
$Loc2

Latitude  = 
$lat2 &deg; \t= $latDMS2
Longitude = 
$lon2 &deg; \t= $lonDMS2

----------------------------------------------------------------------
THE GEODETIC DISTANCE BETWEEN THE LOCATIONS:
kilometers, statute miles and nautical miles

0.0 km  =  0.0 mi  =  0.0 nmi

Both points are at the same coordinates. There is no distance between
them.
"
;

$DoneFlag TRUE;
}



if (
$DoneFlag === FALSE)
{
// FORMAT FOR DISPLAY.
   
$latDMS1 Deg_to_DMS($lat13'+''d');
   
$lonDMS1 Deg_to_DMS($lon13'+''d');
   
$latDMS2 Deg_to_DMS($lat23'+''d');
   
$lonDMS2 Deg_to_DMS($lon23'+''d');

   
$DistKm  Geodetic_Dist ($lat1,$lon1,  $lat2,$lon2); // km output
   
$DistMi  $DistKm 1.609344;
   
$DistNMi number_format($DistKm/1.8521);
   
$DistKm  number_format($DistKm1);
   
$DistMi  number_format($DistMi1);


   
$lat1 RTrim(RTrim($lat1'0'), '.');
   
$lat2 RTrim(RTrim($lat2'0'), '.');
   
$lon1 RTrim(RTrim($lon1'0'), '.');
   
$lon2 RTrim(RTrim($lon2'0'), '.');


   
$LatLon1 "$lat1 ;  $lon1";
   
$LatLon2 "$lat2 ;  $lon2";

// COMPUTE THEORETICAL MAXIMUM MARGIN OF ERROR
// BASED ON THE DISTANCE BETWEEN THE POINTS.
   
$MoEkm  = (floatval($DistKm) / 20037.508) * 0.05;
   
$MoEmi  $MoEkm 1.609344;
   
$MoEnmi $MoEkm 1.852;

// FORMAT FOR DISPLAY.
   
$MoEkm  sprintf("%1.3f"$MoEkm);
   
$MoEmi  sprintf("%1.3f"$MoEmi);
   
$MoEnmi sprintf("%1.3f"$MoEnmi);

   
$NS1 = ($lat1 0)? '(S) ':'(N) ';  if ($lat1 == 0) {$NS1 '(&#149;) ';}
   
$NS2 = ($lat2 0)? '(S) ':'(N) ';  if ($lat2 == 0) {$NS2 '(&#149;) ';}
   
$EW1 = ($lon1 0)? '(W) ':'(E) ';  if ($lon1 == 0) {$EW1 '(&#149;) ';}
   
$EW2 = ($lon2 0)? '(W) ':'(E) ';  if ($lon2 == 0) {$EW2 '(&#149;) ';}



   
$OutputText =
"
      GEODETIC DISTANCE BETWEEN TWO LOCATIONS ON THE EARTH SPHEROID
           Based on the Andoyer Algorithm  (to nearest &plusmn;0.1 km)

1st LOCATION = 
$Loc1

Latitude  = 
$NS1$lat1&deg;      \t= $latDMS1
Longitude = 
$EW1$lon1&deg;      \t= $lonDMS1

----------------------------------------------------------------------
2nd LOCATION = 
$Loc2

Latitude  = 
$NS2$lat2&deg;      \t= $latDMS2
Longitude = 
$EW2$lon2&deg;      \t= $lonDMS2

----------------------------------------------------------------------
THE GEODETIC DISTANCE BETWEEN THE LOCATIONS:
kilometers, statute miles and nautical miles

$DistKm km  =  $DistMi mi  =  $DistNMi nmi
"
;

$DoneFlag TRUE;
}









// DETERMINE HOW MANY ROWS TO USE FOR THE OUTPUT TEXTAREA.
   
$TextRows substr_count($OutputText"\n");



print <<< _HTML
<!DOCTYPE HTML>

<html lang='en'>
<head>

<title>Geodetic Distance Between Any Two Points On Earth Spheroid</title>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<meta http-equiv='content-type' content='text/html; charset=UTF-8'>
<meta name='description' content='This program computes the geodetic distance between any two points on the Earth spheroid based on the Andoyer algorithm.'>
<meta name='keywords' content='Andoyer algorithm,Andoyer,geodesic distance,geodesic,Earth geodesic,distance between points on Earth'>
<meta name='author' content='Jay Tanner - PHPScienceLabs.com'>
<meta http-equiv='pragma'  content='no-cache'>
<meta http-equiv='expires' content='-1'>
<meta name='robots'    content='index,follow'>
<meta name='googlebot' content='index,follow'>
<link rel="canonical" href="https://www.phpsciencelabs.com/earth-geodetic-distance-calculator/">

<style type='text/css'>
BODY  {color:silver; background-color:black;  font-family:Verdana; font-size:16px}
TABLE {font-size:12px; border: 1px solid black;}
TD    {color:black; background-color:white;  line-height:155%; font-size:11px; padding:6px; text-align:center;}
DIV   {color:black; background-color:white;  font-family:Verdana; text-align:justify; padding:4px; font-size:16px;}
PRE   {color:black; background-color:white;  font-family:monospace; font-size:15px; font-weight:bold; text-align:left; padding:4px; border-radius:8px;}

CODE  {font-family:Consolas,monospace; font-size:15px; font-weight:normal;}

TEXTAREA {color:black; background-color:white; font-family:monospace; font-size:155%; font-weight:bold; padding:8px; box-shadow:4px 4px 3px #888888; border-radius:8px; border:1px solid black; padding:4px; white-space:pre;}

INPUT[type="text"]::-ms-clear {width:0; height:0;}
INPUT[type="text"] {background-color:white; box-shadow:2px 2px 3px #666666; font-family:monospace; font-size:150%; font-weight:bold; text-align:center; border:2px solid black; border-radius:4px;}
INPUT[type="text"]:focus {background-color:white; box-shadow:2px 2px 3px #666666; font-family:monospace; font-size:150%; border:2px solid blue; text-align:center; font-weight:bold; border-radius:4px;}

INPUT[type="submit"]{font-weight:bold; border:1px solid black; border-radius:4px;}
INPUT[type="submit"]:hover {box-shadow:2px 2px 5px #222222; font-weight:bold; background:cyan; border:1px solid black; border-radius:4px;}

INPUT[type="checkbox"]:checked {box-shadow:2px 2px 3px #222222;}

HR {background-color:black; height:2px; border:0px;}

A:link,  A:visited {background-color:transparent; color:blue; font-family:Verdana; font-size:90%; font-weight:bold; text-decoration:none; line-height:150%; padding:2px;}
A:hover, A:active  {background-color:transparent; color:red;  font-family:Verdana; font-size:90%; font-weight:bold; text-decoration:none; line-height:150%; padding:2px;}

::selection      {background-color:yellow; color:black;}  /* Only affects IE9+ and Safari     */
::-moz-selection {background-color:yellow; color:black;}  /* Only affects FireFox and Mozilla */
</style>

</head>

<body>

<form name="form1" method="post" action="
$RUN_PROGRAM">
<table align='center' width="800" border="0" cellspacing='1'>

<tr><td colspan="2" style='color:white; background-color:#000066; border:2px solid white; font-size:150%; font-weight:normal; border-radius:8px 8px 0px 0px'>Geodetic Distance Between Any Two Points On the Earth Spheroid<br><span style='font-size:80%;'>Based on the Andoyer Algorithm (theoretical accuracy about &plusmn;50 meters)</span><br><span style='font-size:70%;'>PHP Program by Jay Tanner</span></td></tr>

<tr><td style='color:black; background-color:yellow;'><b>1<sup>st</sup>&nbsp; LOCATION</b></td> <td style='color:black; background-color:GreenYellow;'><b>2<sup>nd</sup>&nbsp; LOCATION</b></td></tr>

<tr><td style='color:black; background-color:LightYellow; line-height:175%;'>Optional First Place Name / Label<br><input type="text" name="Loc1" value="
$Loc1" size='45' maxlength='68' title="$Loc1"><br><br>Enter <b>1</b><sup>st</sup> &nbsp; <b>Latitude ; Longitude</b> &nbsp; as  Deg.ddd &nbsp; or as  D M S<input type="text" name="LatLon1" value="$LatLon1" size='35' maxlength='34'></td><td style='color:black; background-color:#CCFFD8; line-height:175%;'>Optional Second Place Name / Label<br><input type="text" name="Loc2" value="$Loc2" size='45' maxlength='68' title="$Loc2"><br><br>Enter <b>2</b><sup>nd</sup>&nbsp; <b>Latitude ; Longitude</b>  as  Deg.ddd &nbsp;or as  D M S<input type="text" name="LatLon2" value="$LatLon2" size='35' maxlength='34'></td></tr>

<tr><td colspan="2">Coordinates Convention: &nbsp; <b>Latitude</b> Neg/Pos = South/North &nbsp;&nbsp;&nbsp;&nbsp;and&nbsp;&nbsp;&nbsp;&nbsp; <b>Longitude</b> Neg/Pos = West/East</td></tr>

<tr><td colspan="2"><input type="submit" value="C O M P U T E" onclick="StatusText1"></td></tr>

<!-- Yellow source code view link. --->
<tr>
<td colspan='2' style='background:transparent; color:black; font-size:10pt;
                       text-align:center; line-height:200%;'>
<a href='View-Source-Code.php' target='_blank'
   style='font-family:Verdana; color:black; background:yellow;
         text-decoration:none; border:1px solid black; padding:4px;
         border-radius:4px;'>
         &nbsp;<span style='font-weight:normal;'>View/Copy PHP Source Code</span>&nbsp;</a>
</td>
</tr>



<tr><td colspan="2" style='background-color:#DDDDDD;'><textarea ID="OutputTextArea" rows="
$TextRows" cols='72' readonly='readonly' style='white-space:pre; padding:8px;'>$OutputText</textarea></td></tr>

<tr><td colspan="2">Jay Tanner - 
$cYear</td></tr>

<tr><td colspan="2" style='background-color:#DDDDDD;'>

<table align='center' style='background-color:#DDDDDD; border:1px solid #DDDDDD;'>

<tr><td style='background-color:#DDDDDD;'>

<pre style='width:700px; color:black; background-color:white; padding:8px; border:1px solid black; box-shadow:4px 4px 3px #888888;'>
GENERAL INFORMATION

The program&#39;s initial default startup values are for Washington, DC, USA
and Paris, France.

This program computes  the geodetic distance between two locations on the
Earth geoid. The maximum theoretical error is on the order of &plusmn;50 meters,
but the computed distance is rounded to the nearest &plusmn;0.1 (km|mi|nmi).

---------------------------------------------------------------------------
LATITUDE/LONGITUDE CONVENTIONS

The standard longitude convention is Neg/Pos = West/East.

Everyone essentially knows that when we refer to latitudes, positive means
north and negative means south of the equator.  Longitudes are a different
matter and more than one longitude convention can be used.

Although the program was designed with the standard coordinates system in
mind, where negative longitudes are west and positive longitudes are to
the east of Greenwich, if you prefer the opposite convention where east
is negative, then you can use that convention instead. Due to the basic
symmetry of the geoid, either convention will work equally well, so it
doesn&#39;t really matter which one you use as long as you&#39;re consistent
and apply the same longitude convention to both locations.

---------------------------------------------------------------------------
GEOGRAPHIC COORDINATE FORMATS

Coordinates may be obtained from  https://www.gps-coordinates.net
and copied/pasted directly to this program interface in the same
Lat,Lon format as "+46.789, -76.543" and separated by a comma.

The coordinates may be entered as decimal degrees or as degrees,
minutes and seconds, separated by spaces.  In either case, the
coordinates are separated by a comma and are not restricted to
purely integer values.

EXAMPLES OF VALID COORDINATE VALUES
+123.456789   = D     = 1 element  = Degrees only
+12 34.56     = D M   = 2 elements = Degrees and Minutes
-00 00 12.345 = D M S = 3 elements = Degrees, Minutes and Seconds

For Paris, France, the coordinates could be entered as:
+48.8363889,  +2.3372222
or as
+48 50 11.000,  +02 20 14.000
or as
48 50 11,  2 20 14

NOTE:
Different sources may differ on the precise geographic coordinates of some
major world locations.  Some places are too large to apply a single set of
fixed coordinates. But certain fixed points can serve as benchmarks.

---------------------------------------------------------------------------
UNITS AND BASIC DATA:

UNITS:
1 Statute mile      1.609344 km
1 Nautical mile     1.852 km

EARTH DATA:
Equatorial Radius   
$ReKm km  =  $ReMi mi  =  $ReNmi nmi
Polar Radius        
$RpKm km  =  $RpMi mi  =  $RpNmi nmi

Polar Flattening    
$flattening    = $f
</pre>

</td></tr></table>
</td></tr>

<tr><td colspan='4' style='color:silver; background-color:black;'>Jay Tanner - 
$cYear</td></tr>


</table>
</form>

<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>

</body>
</html>


_HTML;






/*
// Paris
   $lat1 = +48.8363889;
   $lon1 = +2.3372222;

// Washington, D.C.
   $lat2 = +38.9213889;
   $lon2 = -77.0655556;
*/


   
function Process_Lat_Lon_String($LatLonString)
{
   
$LatLonStr Strip_Wspace($LatLonString);

   if (
$LatLonStr == '') {$LatLonStr "0.0, 0.0";}

// CONVERT ANY SEMICOLON INTO A COMMA.
   
$LatLonStr str_replace(';'','$LatLonStr);

// if no comma, then attach ', 0.0' . There must be a
// latitude and longitude value separated by a comma
// or semicolon only.
   
if (strpos($LatLonStr',') === FALSE) {$LatLonStr "$LatLonStr, 0.0";}

// Split the 'Lat , Lon' coordinates at the comma.
   
list($LatStr$LonStr) = preg_split("[,]"$LatLonStr);

   
$LatStr trim($LatStr);
   
$LonStr trim($LonStr);

// make sure coordinates are in degrees.
   
$LatStr DMS_to_Deg($LatStr);
   
$LonStr DMS_to_Deg($LonStr);

// RETURN SPACE-DELIMITED SIGNED LAT/LON VALUES
// IN DEGREES ROUNDED TO 9 DECIMALS.
   
$LatStr sprintf("%+2.9f"$LatStr);
   
$LonStr sprintf("%+3.9f"$LonStr);

   return 
"$LatStr $LonStr";
}

// ---------------------------------------------------------------
// This function computes the geodetic distance between two points
// on the spheroid from their longitude and latitude coordinates
// in degrees.
//
// The distance can be returned in kilometers (default) or miles.
//
// Longitudes assume standard convention (Neg/Pos = West/East),
// but the inverse convention will work equally as well.
//
// Based on the Andoyer Algorithm.

   
function Geodetic_Dist ($lat1,$lon1,  $lat2,$lon2,  $KmMi='km')
{
   
$Km_or_Mi = (strtolower(substr(trim($KmMi),0,1)) == 'k')? 1:1.609344;

// DEFINE EARTH EQUATORIAL RADIUS
// AND FLATTENING FACTOR.
   
$R 6378.137;
   
$flattening 298.257;

   
$f  deg2rad(($lat1 $lat2) / 2);
   
$g  deg2rad(($lat1 $lat2) / 2);
   
$h  deg2rad(($lon1 $lon2) / 2);

   
$sf sin($f);  $cf cos($f);
   
$sg sin($g);  $cg cos($g);
   
$sh sin($h);  $ch cos($h);

   
$w1 = ($sg $ch)*($sg $ch);
   
$w2 = ($cf $sh)*($cf $sh);
   
$s  $w1 $w2;

   
$w1 = ($cg $ch)*($cg $ch);
   
$w2 = ($sf $sh)*($sf $sh);
   
$c  $w1 $w2;
   
$o  atan(sqrt($s/$c));
   
$r  sqrt($s*$c) / $o;
   
$d  $R $o;

   
$h1 = (3*$r-1) / (2*$c);
   
$h2 = (3*$r+1) / (2*$s);

   
$w1 = ($sf $cg) * ($sf $cg) * $h1 $flattening 1;
   
$w2 = ($cf $sg) * ($cf $sg) * $h2 $flattening;

   return 
$d * ($w1 $w2) * $Km_or_Mi;
}






/*
   Convert DMS string to decimal degrees.

   Example: Given DMS string = "9 12 50.306"
            Returned = 9.2139738888888889

*/

   
function DMS_to_Deg ($DMSstr)
{

// ----------------------------------------------------------
// Read angle/time string argument and force to lower case in
// the event any (deg d h m s : ° ' ") symbols are used.

   
$dms strtolower(trim($DMSstr));

// ------------------------------------------------------
// Convert any (deg d m s ° ' ") symbols into spaces.

   
$dms str_replace('deg'' '$dms);
   
$dms str_replace('d',   ' '$dms);
   
$dms str_replace('m',   ' '$dms);
   
$dms str_replace('s',   ' '$dms);
   
$dms str_replace('°',   ' '$dms);
   
$dms str_replace("'",   ' '$dms);
   
$dms str_replace('"',   ' '$dms);
   
$dms str_replace("&deg;",   ' '$dms);
// ----------------------------------------------------
// Normalize the spacing and then split and extract the
// individual angle/time string elements (dh or hh, mm,ss).

   
$dms preg_replace("/\s+/"" "trim($dms));
   
$wdms preg_split("[ ]"$dms);
   
$wdmsCount count($wdms);
   
$dd = ($wdmsCount >= 1)? bcadd($wdms[0],"0"20) : "0";
   
$mm = ($wdmsCount >= 2)? bcadd($wdms[1],"0"20) : "0";
   
$ss = ($wdmsCount >= 3)? bcadd($wdms[2],"0"20) : "0";

// ------------------------------------------------
// Remember and then remove any numerical (±) sign.

   
$NumSign = (substr($DMSstr,0,1) == '-')? '-' '';
   
$dd str_replace('-'''$dd);
   
$dd str_replace('+'''$dd);

// -------------------------------------------------------------
// If original angle argument began with a + sign, then preserve
// it so that all returned positive results will have a + sign.
// Otherwise, positive results will NOT have a + sign.

   
if (substr($DMSstr,0,1) == '+') {$NumSign '+';}

// ----------------------------------------------
// Compute decimal degrees/hours value equivalent
// to the given dhms argument elements.

   
$w2 bcadd(bcadd(bcmul($dd,"3600",20),bcmul($mm,"60",20),20),$ss,20);

// -----------------------------------------------------------
// If result equates to zero, then suppress any numerical sign.

   
if (bccomp($w2"0"20) == 0) {$NumSign '';}

// ---------------------------------------------------------
// Round off result to 16 decimals, recalling original sign.

   
return $NumSign bcadd(bcdiv($w2,"3600",20), "0.00000000000000005",16);

// End of  DMS_to_Deg (...)



/*
   ========================================================================
   Convert decimal degrees to degrees, minutes, seconds of arc.
   The angular elements are returned in a space-delimited string.

   Optional symbols are attached to the angle elements. The seconds can
   optionally be rounded to up to 3 decimals with 0=Default.

   Symbols mode = TRUE|FALSE or d|D
   TRUE|d|D means to apply DMS symbols to returned string.
   FALSE means no DMS symbols are applied to returned string.

   ========================================================================
*/

   
function Deg_to_DMS ($AngDeg$ssDecimals=0$PosSignSymbol=''$SymbolsMode='d')
{

// Init
   
$_d_ $_m_ $_s_ '';

// ------------------------------------------------------
// Compute signed angular elements from decimal argument.
// This value is taken as decimal degrees.
   
$sign = ($AngDeg 0)? '-' '';

   if ((
$PosSignSymbol === TRUE or $PosSignSymbol == '+') and $sign == '') {$sign '+';}

   
$degrees abs($AngDeg);
   
$dd      floor($degrees);
   
$minutes 60*($degrees $dd);
   
$mm      floor($minutes);
   
$seconds 60*($minutes $mm);
   
$ss      sprintf("%1.3f"$seconds);

// ----------------------------------
// Check for that blasted 60s glitch.
   
if ($ss == 60) {$ss 0$mm++;}
   if (
$mm == 60) {$mm 0$dd++;}

// ----------------------------
// Format the angular elements.
   
$dd sprintf("%02d",  $dd);
   
$mm sprintf("%02d",  $mm);
   
$ss sprintf("%1.$ssDecimals"f"$ss);

   if (
$ss 10) {$ss "0$ss";}

// Attach optional DMS symbols.
// Default = TRUE (deprecated). Can also use newer 'd' as DMS symbols flag.
   
if ($SymbolsMode === TRUE or substr(strtolower($SymbolsMode),0,1) == 'd')
      {
       
$_d_ "&deg;";
       
$_m_ "'";
       
$_s_ '"';
      }

// Done.
   
return "$sign$dd$_d_ $mm$_m_ $ss$_s_";

// End of  Deg_to_DMS (...)




   
function Strip_WSpace ($TextString)
{
   return 
preg_replace("/\s+/"" "trim($TextString));
}


/*
   ========================================================================
   Generates a string of any number of random digits in any given base
   from 2 to 36.

   All letters (A to Z) used as digits will be returned in uppercase.

   ERRORS:
   On error, FALSE is returned for invalid argument(s).
   ========================================================================
*/

   
function Rand_Digits_Base_B ($NumDigits=1$BaseB=10$LZeroSuppressed=FALSE)
{

// Read arguments.
   
$N intval($NumDigits);
   
$B intval($BaseB);

// Check for invalid argument(s).
   
if ($B or $B 36 or $N 1) {return FALSE;}

// Define digits spectrum for the given base.
   
$DigitsSpectrum substr("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ",0,$B);

// Construct an N-digit random sequence in base B, one digit at
// a time, using a random 50/50 digit alternation method. There
// will be at least one random base B digit returned.
   
$RandomDigits "";

   for (
$i=0;   $i $N;   $i++)
  {
   if (
mt_rand() % == 0)
  {
$RandomDigits .= substr($DigitsSpectrummt_rand(0,$B-1),1);}
   else
  {
$RandomDigits substr($DigitsSpectrummt_rand(0,$B-1),1) . $RandomDigits;}
  }

// If LZeroSuppressed flag === TRUE, then leftmost digit of returned
// random digits string must NOT be zero.  If it is, then another
// random non-zero digit will be attached to the left of it and
// the rightmost digit dropped.  The result will be a normal
// integer value with the required number of digits, but
// never starting with 0 (zero) as the first digit.
   
if ($LZeroSuppressed === TRUE)
  {
   
$RandomDigits substr($DigitsSpectrummt_rand(1,$B-1),1) . $RandomDigits;
  }
   return 
substr("$RandomDigits"0$N);

// End of  Rand_Digits_Base_B(...)




   
function Rand_Decimal($NumDigits=1$RandSignFlag=FALSE)
  {
   
$RandSign '';
   
$NumDigits floor($NumDigits);
   
$RandSignFlag = ($RandSignFlag === TRUE)? TRUE:FALSE;

   if (
$RandSignFlag === TRUE)
      {
       
$RandSign = (mt_rand() % == 0)? '-':'+';
      }

   return 
$RandSign.'0.'.Rand_Digits_Base_B($NumDigits);

  } 
// End of  Rand_Decimal()




?>