<?php

/*
   ###########################################################################
   SINGLE ARGUMENT INPUT TEMPLATE - WITH 30-DAY COOKIE

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

   This program simply computes degree and hour angle equivalents for a given
   angular argument expressed in decimal or sexagesimal format.

   ###########################################################################
*/

   
ob_start();

   
$cYear date('Y');

// ---------------------------------------------------------------
// Define the program cookie name and set it to expire in 30 days.

   
$CookieName 'Degree-and-Hour-Angle-Equivalents';
   
$ExpiresIn30Days time() + 30*86400;


// ---------------------------------
// Define PHP program and HTML info.

   
$_AUTHOR_           "Jay Tanner";
   
$_PROGRAM_VERSION_  'v2.0 - '$at "&#97;&#116;&#32;&#76;&#111;&#99;&#97;&#108;&#32;&#84;&#105;&#109;&#101;&#32;"$LTC "&#85;&#84;&#67;";
   
$_SCRIPT_FILE_PATH_ Filter_Input(INPUT_SERVER'SCRIPT_FILENAME');
   
$_REVISION_DATE_    $_PROGRAM_VERSION_ .'Revised: 'date("Y-F-d-l $at h:i:s A   ($LTC"FileMTime($_SCRIPT_FILE_PATH_))."&minus;05:00)";
   
$_BROWSER_TAB_TEXT_ "Degree and Hour Angle Equivalents";
   
$_INTERFACE_TITLE_  "<span style='font-size:14pt;'>Degree and Hour Angle Equivalents</span><br><br><span style='font-size:11pt;'>PHP Program by Jay Tanner - $cYear</span>";


// -------------------------------------
// Define main TextArea text and background
// colors and HTML table row span. If an
// error is reported, then these colors
// will change internally to red/white.

   
$TxColor 'black';
   
$BgColor 'white';


// ---------------------------------------------
// Do this only if [SUBMIT] button was clicked.

   
$w Filter_Input(INPUT_POST'SubmitButton');

   if (!IsSet(
$w))
  {

// ----------------------------------------------------------------------
// If this program is being called externally, rather than being executed
// by clicking the [SUBMIT] button, and an active cookie also exists,
// then restore the previously saved interface settings from it. If
// the user leaves and comes back later, all the interface settings
// will be remembered and restored if the cookie was not deleted.

   
$w Filter_Input(INPUT_COOKIE$CookieName);

   if (IsSet(
$w))
      {
       
$CookieDataString Filter_Input(INPUT_COOKIE$CookieName);
       list(
$AngleArg) = Preg_Split("[\|]"$CookieDataString);
      }

   else

// -----------------------------------------------------------
// If there is no previous cookie with the interface settings,
// then set the initial default interface startup values and
// store them in a new cookie.

 
{
  
$AngleArg '1';


// -------------------------------------------
// Store current interface settings in cookie.

   
$CookieDataString "$AngleArg";
   
SetCookie ($CookieName$CookieDataString$ExpiresIn30Days);
  } 
// End of  else {...}

  
// End of  if (!isset(_POST['SubmitButton']))


// ------------------------------------------
// Read values of all interface arguments and
// set any empty arguments to default values.

   
$w Filter_Input(INPUT_POST'SubmitButton');

   if (isset(
$w))
{
   
$AngleArg trim(Filter_Input(INPUT_POST'AngleArg'));

// ------------------
// Set default value.

   
if ($AngleArg == '') {$AngleArg '1';}

// -------------------------------------
// Store interface argument in a cookie.

   
$CookieDataString "$AngleArg";
   
SetCookie ($CookieName$CookieDataString$ExpiresIn30Days);
}


// -----------------------------------------------
// Optionally check (AngleArg) value for validity.
// If error, set error flag and message values.

   
$ErrFlag FALSE;
   
$ErrMssg '';




// *******************************************************************
// *******************************************************************
// START MAIN FUNCTION CALL CODE HERE.

   
$out Angular_Equivalents ($AngleArg);


// -----------------------------
// Set initial uniform width for
// tables alignment in pixels.

   
$TableWidth '520';


// ******************************************
// ******************************************
// If error was reported (TRUE), then display
// the error message on a red background.

   
if ($out === FALSE)
  {
   
$TxColor 'white';
   
$BgColor '#CC0000';
   
$ErrMssg =
"
A non-numerical argument value was encountered.
'
$AngleArg'

All angular elements: degrees, hours, minutes and
seconds of arc or time,  must be purely numerical
values.

1 Element  = Decimal Degrees or Hours
2 Elements = Degrees or Hours and Minutes
3 Elements = Degrees or Hours, Minutes and Seconds

Anything following a third argument is ignored.
"
;

   
$ErrMssg trim($ErrMssg);

   
$TextArea1Text =
"=== ERROR ===

$ErrMssg";
  }

else


  {
// *********************************************************
// BEGIN MAIN COMPUTATIONS HERE IF NO ERRORS DETECTED ABOVE.
// *********************************************************




// ----------------------------------
// Computation or function call code.





// *******************************************
// DROP THROUGH HERE AFTER COMPUTATIONS ABOVE
// TO PRINT OUT THE RESULTS OF THE OPERATIONS.
// *******************************************

   
$TextArea1Text =
"  GENERAL ANGULAR EQUIVALENTS


$out
"
;
  }


// ****************************
// Define TextArea2 text block.

   
$TextArea2Text =
"                            GENERAL INFORMATION

This program simply computes degree and hour angle equivalents for a
given angular argument expressed in decimal or sexagesimal format.


The angular input argument can be entered as a string of one to three
numerical elements.

For example, a single input '1.25' would be interpreted as 1.25 degrees
or hours of arc or time.

The dual input '5 35' would be interpreted as 5 or degrees or hours and
35 minutes of arc or time.

The triple input '17 02 03.456' would be interpreted as 17 degrees or
hours and 3 minutes and 3.456 seconds of arc or time.

Anything following the third element is ignored.

The program also displays the angle in radians and its basic circular
trigonometric functions, the sine, cosine and tangent.
"
;



// **************************************************************************
// Determine number of text columns and rows to use in the output text areas.
// These values vary randomly according to the text block width and length.
// The idea is to eliminate the need for scroll-bars within the text areas
// or worry as much about the variable dimensions of a text display area.

// --------------------
// Text Area 1 columns.

   
$Text1Cols Max(Array_Map('StrLen'PReg_Split("[\n]"trim($TextArea1Text))));
   if (
$Text1Cols 80) {$Text1Cols 32;}  // Default
   
$Text1Rows Substr_Count($TextArea1Text"\n");

   if (
$out === FALSE) {$Text1Cols '52';  $Text1Rows '16';}

// --------------------
// Text Area 2 columns.

   
$Text2Cols Max(Array_Map('StrLen'PReg_Split("[\n]"trim($TextArea2Text))));
   if (
$Text2Cols 80) {$Text2Cols 73;} // Default
   
$Text2Rows Substr_Count($TextArea2Text"\n");



// ******************************************
// ******************************************
// GENERATE CLIENT WEB PAGE TO DISPLAY OUTPUT

   
print <<< _HTML

<!DOCTYPE HTML>
<HTML>

<head>
<title>
$_BROWSER_TAB_TEXT_</title>

<meta name='viewport' content='width=device-width, initial-scale=0.8'>

<meta http-equiv='content-type' content='text/html; charset=UTF-8'>
<meta http-equiv='pragma'  content='no-cache'>
<meta http-equiv='expires' content='-1'>
<meta name='description' content='xxxxxxxxxxxxxxx'>
<meta name='keywords' content='PHPScienceLabs.com'>
<meta name='author' content='Jay Tanner - https://www.PHPScienceLabs.com'>
<meta name='robots' content='index,follow'>
<meta name='googlebot' content='index,follow'>

<style>

 BODY {color:white; background:black; font-family:Verdana; font-size:12pt; line-height:125%;}

 TABLE
{font-size:13pt; border: 1px solid black;}


 TD
{
 color:black; background:white; line-height:150%; font-size:10pt;
 padding:6px; text-align:center;
}


 UL
{font-family:Verdana; font-size:12pt; line-height:150%; text-align:justify;}


 PRE
{
 background:white; color:black; font-family:monospace; font-size:12.5pt;
 font-weight:bold; text-align:left; line-height:125%; padding:6px;
 border:2px solid black; border-radius:8px;
 page-break-before:page;
}


 DIV
{
 background:white; color:black; font-family:Verdana; font-size:11pt;
 font-weight:normal; line-height:125%; padding:6px;
}


 TEXTAREA
{
 background:white; color:black; font-family:monospace; font-size:13pt;
 font-weight:bold; padding:4pt; white-space:pre; border-radius:8px;
 line-height:125%;
}


 INPUT[type='text']::-ms-clear {width:0; height:0;}

 INPUT[type='text']
{
 font-family:monospace; color:black; background:white; font-size:13pt;
 font-weight:bold; text-align:center; box-shadow:2px 2px 3px #666666;
 border:2px solid black; border-radius:4px;
}
 INPUT[type='text']:focus
{
 font-family:monospace; background:white; box-shadow:2px 2px 3px #666666;
 font-size:13pt; border:2px solid blue; text-align:center; font-weight:bold;
 border-radius:4px;
}



 INPUT[type='submit']
{
 background:black; color:cyan; font-family:Verdana; font-size:10pt;
 font-weight:bold; border-radius:4px; border:4px solid #777777;
 padding:3pt;
}
 INPUT[type='submit']:hover
{
 background:black; color:white; font-family:Verdana; font-size:10pt;
 font-weight:bold; border-radius:4px; border:4px solid red;
 padding:3pt;
}





// Link states MUST be set in the following order:
// :link, :visited, :hover, :active

 A:link
{
 font-size:10pt; background:transparent; color:#8080FF; border-radius:4px;
 font-family:Verdana; font-weight:bold; text-decoration:none;
 line-height:175%; padding:3px; border:1px solid transparent;
}
 A:visited
{
 font-size:10pt; background:transparent; color:DarkCyan; border-radius:4px;
}
 A:hover
{
 font-size:10pt; background:yellow; color:black; border:1px solid black;
 box-shadow:1px 1px 3px #222222; border-radius:4px;
}
 A:active
{
 font-size:10pt; background:yellow; color:black; border-radius:4px;
}


 HR {background:red; height:4px; border:0px;}


[title-text]:hover:after
{
 opacity:1.0;
 transition:all 1.0s ease 1.0s;
 text-align:left;
 visibility:visible;
}

[title-text]:after
{
 opacity:1.0;
 content:attr(title-text);
 text-align:left;
 left:50%;
 background-color:yellow;
 color:black;
 font-size:10pt;
 position:absolute;
 padding:1px 5px 2px 5px;
 white-space:pre;
 border:1px solid red;
 z-index:1;
 visibility:hidden;
}

[title-text] {position: relative;}


::selection{background-color:yellow !important; color:black !important;}
::-moz-selection{background-color:yellow !important; color:black !important;}
</style>

</head>

<body>

<!-- Define container form --->
<form name="form1" method="post" action="">

<!-- Define main page title/header. --->
<table width="
$TableWidth" align="center" border="0" cellspacing="1" cellpadding="3">


<tr><td colspan="99" style="color:white; background-color:#000066; border:2px solid white; border-radius:8px 8px 0px 0px;">
$_INTERFACE_TITLE_</td></tr>
</table>


<!-- Define input (AngleArg) text box  --->
<table width="
$TableWidth" align="center" border="0" cellspacing="1" cellpadding="3">
<tr><td style="line-height:175%;" title=' Enter Angle Assuming:\n\n Decimal Degrees  or  D M S String\nor\nDecimal Hours  or  H M S String '><b>Angular Argument String</b><br><input name="AngleArg"  type="text" value="
$AngleArg"  size="33" maxlength="32">
</td></tr>
</table>


<!-- Define [SUBMIT] button --->
<table width="
$TableWidth" align="center" border="0" cellspacing="1" cellpadding="3">
<tr><td colspan="99" style="background-color:black;"><input type="submit" name="SubmitButton" value=" S U B M I T "></td></tr>

<!-- Yellow source code view link. --->
<tr>
<td colspan='1' style='background:transparent; color:black; font-size:10pt;
                       text-align:center;'>
<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>

</table>


<!-- Define TextArea1 --->
<table width="
$TableWidth" align="center" border="0" cellspacing="1" cellpadding="3">
<tr>
<td colspan="99" style="text-align:center; color:GreenYellow; background-color:black;">Double-Click Within Text Area to Select ALL Text<br>
<textarea ID="TextArea1" name="TextArea1" style="color:
$TxColor; background:$BgColor; padding:6px; border:2px solid white;" cols="$Text1Cols" rows="$Text1Rows" ReadOnly OnDblClick="this.select();" OnMouseUp="return true;">
$TextArea1Text
</textarea>
</td>
</tr>
</table>


<!-- Define TextArea2 --->
<table width="
$TableWidth" align="center" border="0" cellspacing="1" cellpadding="3">
<tr>
<td colspan="99" style="text-align:center; color:GreenYellow; background:black;">Double-Click Within Text Area to Select ALL Text<br>
<textarea ID="TextArea2" name="TextArea2" style="color:black; background:white; padding:6px;" cols="
$Text2Cols" rows="$Text2Rows" ReadOnly OnDblClick="this.select();" OnMouseUp="return true;">
$TextArea2Text
</textarea>
</tr>
</table>


<!-- Define page footer --->
<table width="
$TableWidth" align="center" border="0" cellspacing="1" cellpadding="3">
<tr>
<td colspan="99" style="color:GreenYellow; background:black;">PHP Program by 
$_AUTHOR_<br><span style="color:silver; background:black;">$_REVISION_DATE_</span></td>
</tr>
</table>

</form>
<!-- End of container form --->


<!-- Extra bottom scroll space --->
<br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br>

</body>
</HTML>



_HTML;




/*
   ###########################################################################
   This function converts a DMS time string into equivalent decimal degrees.

   INPUT: 1, 2 or 3-element DMS (Degrees Minutes Seconds) separated by spaces
          as angular string as 'deg min sec' values.

   Example: Given DMS string = '9 12 50.306'
            Returns: 9.2139738888888889

   NO DEPENDENCIES

   ERRORS:
   No error checking is done.
   ###########################################################################
*/

   
function DMS_to_Degrees ($DMSstr$Decimals=16)
{
   
$dms StrToLower(trim($DMSstr));

   
$Q 40;
   
$q trim($Decimals);

/* ----------------------------------------------------
   Normalize the spacing and then split and extract the
   individual angular 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"$Q) : "0";
   
$mm = ($wdmscount >= 2)? bcAdd($wdms[1],"0"$Q) : "0";
   
$ss = ($wdmscount >= 3)? bcAdd($wdms[2],"0"$Q) : "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",$Q),bcMul($mm,"60",$Q),$Q),$ss,$Q);

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

   
if (bcComp($w2'0'$Q) == 0) {$NumSign '';}

// -------------------------------------------------------
// Return result to (q) decimals, recalling original sign.

   
$z Str_Repeat('0'$q);
   
$w $NumSign bcAdd(bcDiv($w2,"3600",$Q), "0.".$z."5"$q);
// $w = RTrim(RTrim($w, '0'), '.');

   
return $w;

// End of  DMS_to_Degrees (...)




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

   INPUT:
   AngDeg = Degrees as numerical string, like '123.3456789065741'

   Optional symbols may be attached to the angle elements.  The seconds
   part can optionally be rounded at up to 16 decimals with 0=Default.
   +009° 10' 11.1234567890123456"
   -017° 22' 13.184"

   posSign = '+' = Force positive sign in positive output values, such
             as +085 23 18.713  instead of  085 23 18.713
             '' = Empty string = Default = No positive sign attached.
             This has no effect on negative values.

   ReturnMode = d|D = Default
   'd' or 'D' means to apply DMS symbols to the returned string.
   123° 04' 56.7891"
  -000° 00' 01.234"

   ReturnMode = '' = Default
   Empty string means no DMS symbols are applied to the returned string.
   123 04 05.6789
  -015 01 09

   OUTPUT:
   Returns a space-delimited string like:
   12° 34' 56.789"

   ERRORS:
   This function does NOT check for errors.

   NO DEPENDENCIES
   ===========================================================================
*/

   
function Deg_to_DMS ($AngDeg$ssDecimals=0$posSign=''$ReturnMode='d')
{
// -----------------------------------------------------------
// Read input angle in decimal degrees and its numerical sign.
// Work with absolute value.  Sign will be restored on exit.

   
$a trim($AngDeg);   $sign = ($a 0)? '-' '';
   
$a Str_Replace('+'''Str_Replace('-'''$a));

// ---------------------------------
// Account for numerical sign output.

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

// ----------------------------------------------------
// Set number of decimals to use in seconds part not to
// exceed 16 decimals.  Default = 0 decimals.

   
$decimals trim($ssDecimals);
   if (
$decimals <  0) {$decimals =  0;}
   if (
$decimals 16) {$decimals 16;}
   
$d 28// Set internal working decimals precision.

// --------------------------------------------
// Compute degrees, minutes and seconds of arc.

   
$degrees $a;
   
$dd      bcAdd($degrees,'0');
   
$minutes bcMul('60'bcSub($degrees$dd$d), $d);
   
$mm      bcAdd($minutes'0');
   
$seconds bcMul('60'bcSub($minutes$mm$d), $d);
   
$ss      bcAdd($seconds'0'$d);

// ----------------------------------
// Patch for that blasted 60s glitch.

   
if ($ss == 60) {$ss 0$mm++;}
   if (
$mm == 60) {$mm 0$dd++;}

// ----------------------------
// Format the angular elements.

   
$dd SPrintF("% 3d",  $dd);
   
$mm SPrintF("%02d",  $mm);
   
$ss bcAdd($ss'0.'.Str_Repeat('0'$ssDecimals).'5'$ssDecimals);
   if (
$ss 10) {$ss "0$ss";}

// ------------------------------------------
// Attach optional DMS symbols, if indicated.
// Default = d|D  = Attach DMS symbols.
// Empty string   = No DMS symbols attached.

   
$_deg_ $_mm_ $_ss_ '';

   if (
$ReturnMode === TRUE or substr(StrToLower($ReturnMode),0,1) == 'd')
      {
       
$_deg_ "&deg;";     $_mm_ "'";     $_ss_ '"';
      }

// Do some output formatting.
   
$w "$sign$dd$_deg_ $mm$_mm_ $ss$_ss_";
   
$w Str_Replace('-  ''  -'$w);
   
$w Str_Replace('- ',  ' -',  $w);
   
$w Str_Replace('+  ''  +'$w);
   
$w Str_Replace('+ ',  ' +',  $w);

// -----
// Done.
   
return $w;

// End of  Deg_to_DMS(...)




/*
   ===========================================================================
   This function converts a DMS time string into equivalent decimal degrees.

   INPUT: 1, 2 or 3-element DMS (Degrees minutes Seconds)
          angular string as 'deg min sec' values.

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

   NO DEPENDENCIES
   ===========================================================================
*/

   
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('°',     " "$dms);
   
$dms Str_Replace("'",     " "$dms);
   
$dms Str_Replace('"',     " "$dms);

   
$dms Str_Replace("&deg;"" "$dms);
   
$dms Str_Replace("&#39;"" "$dms);
   
$dms Str_Replace("&#34;"" "$dms);

   
$dms Str_Replace('hrs',   " "$dms);
   
$dms Str_Replace('hr',    " "$dms);
   
$dms Str_Replace('h',     " "$dms);

   
$dms Str_Replace('deg',   " "$dms);
   
$dms Str_Replace('min',   " "$dms);
   
$dms Str_Replace('sec',   " "$dms);

   
$dms Str_Replace('d',     " "$dms);
   
$dms Str_Replace('m',     " "$dms);
   
$dms Str_Replace('s',     " "$dms);


// ----------------------------------------------------
// Normalize the spacing and then split and extract the
// individual angular 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 (...)









/*
   ###########################################################################
   This function converts a HMS time string into equivalent decimal hours.

   INPUT: 1, 2 or 3-element HMS (Hours Minutes Seconds) separated by spaces
          in angular string as 'hrs min sec' values.

   Example: Given HMS string = '18 15 30.361'
            Returns:  18.2584336111111111

   NO DEPENDENCIES

   ERRORS:
   No error checking is done.
   ###########################################################################
*/

   
function HMS_to_Hours ($HMSstr$Decimals=16)
{
   
$hms StrToLower(trim($HMSstr));

   
$Q 40// Internal working decimals.
   
$q trim($Decimals);

/* ----------------------------------------------------
   Normalize the spacing and then split and extract the
   individual time string elements (hh, mm,ss).
*/
   
$hms PReg_Replace("/\s+/"" "trim($hms));
   
$whms PReg_Split("[ ]"$hms);
   
$whmsCount count($whms);
   
$hh = ($whmsCount >= 1)? bcAdd($whms[0],'0'$Q) : '0';
   
$mm = ($whmsCount >= 2)? bcAdd($whms[1],'0'$Q) : '0';
   
$ss = ($whmsCount >= 3)? bcAdd($whms[2],'0'$Q) : '0';

/* -------------------------------------------------
   Remember and then remove any numerical (+/-) sign
   for reattachment to the returned output.
*/
   
$NumSign = (substr($HMSstr,0,1) == '-')? '-' '';
   
$hh Str_Replace('+'''Str_Replace('-'''$hh));

/* -------------------------------------------------------------
   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($HMSstr,0,1) == '+') {$NumSign '+';}

/* ----------------------------------------------
   Compute decimal hours value equivalent
   to the given HHMS argument elements.
*/
   
$w2 bcAdd(bcAdd(bcMul($hh,"3600",$Q),bcMul($mm,"60",$Q),$Q),$ss,$Q);

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

   
if (bcComp($w2'0'$Q) == 0) {$NumSign '';}

// -------------------------------------------------------
// Return result to (q) decimals, recalling original sign.

   
$zeros Str_Repeat('0'$q);
   
$w $NumSign bcAdd(bcDiv($w2,"3600",$Q), '0.'.$zeros.'5'$q);
// $w = RTrim(RTrim($w, '0'), '.');

   
return $w;

// End of  HMS_to_Hours (...)





/*
   ===========================================================================
   This function returns the equivalent H:M:S time string with
   several formatting options.

  hours         = Â± Decimal hours value
  ssDecimals    = Number of decimals in seconds part

  posSign = Symbol to use for positive values ('' or '+')
      ''  = Empty = Return numbers only, no symbols.
      '+' = Attach '+' sign to positive values.
            Has no effect on negative values.

  SymbolsMode   = If or not to attach time symbols (h m s) or (:)
                  'h' = '01h 02m 03s' (Default)
                  ':' = '01:02:03'
                  ''  = '01 02 03'
   ERRORS
   No special  error checking is done by this function.

   NO DEPENDENCIES
*/

   
function Hours_to_HMS ($hours$ssDec=0$posSignSymb=''$SymbMode='h')
{
// Initialize symbol carriers.
   
$_h_ $_m_ $_s_ '';
   if (
trim($posSignSymb) == '')  {$posSignSymb FALSE;}

// Remember original numerical sign and work with absolute value.
   
$sign = ($hours 0)? '-' '';    $hours abs($hours);

// Remember numerical sign to be restored on exit, if any.
   
if (($posSignSymb === TRUE or $posSignSymb == '+') and $sign == '')
       {
$sign '+';}

// Compute time elements from absolute hours argument.
   
$hh floor($hours);
   
$minutes 60*($hours $hh);    $mm floor($minutes);
   
$seconds 60*($minutes $mm);  $ss SPrintF("%1.3f",  $seconds);

// Format the time elements.
   
$hh SPrintF("%02d",  $hh);
   
$mm SPrintF("%02d",  $mm);
   
$ss SPrintF("%1.$ssDec"f"$ss);

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

   
$hh SPrintF("%02d",  $hh);
   
$mm SPrintF("%02d",  $mm);

   
$ss SPrintF("%1.$ssDec"f"$ss);
   if (
$ss 10) {$ss "0$ss";}

// Attach optional (h, m, s, :) symbols as indicated.
// Default = 'h'
   
if ($SymbMode == or $SymbMode == '')
      {
$_h_  =  $_m_  =  $_s_  ' ';}

   if (
$SymbMode == or $SymbMode == ':')
      {
$_h_  =  ':';  $_m_  =  ':';  $_s_  '';}

   if (
$SymbMode == or StrToLower($SymbMode) == 'h')
      {
$_h_  =  'h ';  $_m_  =  'm ';  $_s_  =  's';}

   
$w "$sign$hh$_h_$mm$_m_$ss$_s_";

// Done.
   
return $w;

// End of  Hours_to_HMS(...)

// ===========================================================================




























   
function Angular_Equivalents ($AngleString)
{
   
$a trim($AngleString);

// Check if ALL data elements are numeric and return
// FALSE if a non-numeric value is encountered.
   
$a PReg_Replace("/\s+/"" "trim($a));
   
$wArray PReg_Split("[ ]"$a);
   
$wCount count($wArray);
   for (
$i=0;   $i $wCount;   $i++)
       if (!
Is_Numeric(trim($wArray[$i]))) {return FALSE;}


   
$out1 "------------------------------\nDegree Angle Context\n\n";
   
$aDMS $a;
   
$aDeg DMS_to_Deg ($aDMS);
   
$aRad Deg2Rad($aDeg);
   
$aSin sin($aRad);
   
$aCos cos($aRad);
   
$aTan tan($aRad);
   
$aDMS trim(Deg_to_DMS($aDeg3'''d'));
   
$aHrs bcDiv($aDeg'15'14);
   
$aHMS Hours_to_HMS($aHrs3'''h');

// Filters for ±Infinity
   
if ($aDeg == -180 or $aDeg ==  90){$aTan '+Infinity';}
   if (
$aDeg ==  180 or $aDeg == -90){$aTan '-Infinity';}

   
$out1 .= "= $aDMS\n";
   
$out1 .= "= $aDeg &deg;\n\n";
   
$out1 .= "= $aHrs h\n";
   
$out1 .= "= $aHMS\n\n";
   
$out1 .= "= $aRad rad\n\n";
   
$out1 .= "sin = $aSin\n";
   
$out1 .= "cos = $aCos\n";
   
$out1 .= "tan = $aTan\n";



   
$out2 "\n------------------------------";
   
$aHMS $a;
   
$aHrs HMS_to_Hours ($a);
   
$aHMS Hours_to_HMS($aHrs3'''h');
   
$aDeg bcMul($aHrs'15'14);
   
$aRad Deg2Rad($aDeg);
   
$aSin sin($aRad);
   
$aCos cos($aRad);
   
$aTan tan($aRad);
   
$aDMS trim(Deg_to_DMS ($aDeg3'''d'));

// Filters for ±Infinity
   
if ($aDeg == -180 or $aDeg ==  90){$aTan '+Infinity'$aCos '0';}
   if (
$aDeg ==  180 or $aDeg == -90){$aTan '-Infinity'$aCos '0';}

   
$out2 .= "\nHour Angle Context\n\n= $aHMS\n";
   
$out2 .= "= $aHrs h\n\n";
   
$out2 .= "= $aDeg &deg;\n";
   
$out2 .= "= $aDMS\n\n";
   
$out2 .= "= $aRad rad\n\n";
   
$out2 .= "sin = $aSin\n";
   
$out2 .= "cos = $aCos\n";
   
$out2 .= "tan = $aTan\n";

   return 
trim("$out1$out2");

}









// END OF PROGRAM

?>