
	/* routines for converting coordinates to/from various formats */

#include <stdio.h>
#include <math.h>

static char err_msg[100];

	/* put a string containing a formatted HMS measurement into the passed 
	   string argument - this routine exists mostly to handle negative numbers
	   properly. The output string is 12 characters long, plus a NULL at the
	   end. All numbers less than 10 have a '0' (zero) in the ten's place. */

format_hms(hours, minutes, seconds, str)
int hours, minutes;
double seconds;
char *str;
{
	char sign = ' ';

	if ((hours < 0) || (minutes < 0) || (seconds < 0)) {
		if (hours < 0)
			hours = -hours;
		if (minutes < 0)
			minutes = -minutes;
		if (seconds < 0)
			seconds = -seconds;
		sign = '-';
	}
	sprintf(str, "%c%02d:%02d:%05.2lf", sign, hours, minutes, seconds);
}


	/* convert from decimal hours to hours, minutes, seconds. If the sign of
	   the 'hh' argument is negative, make the first non-zero component of the
	   (hours, minutes, seconds) trio negative. */

hhhtohms(hh, hours, minutes, seconds)
double hh, *seconds;
int *hours, *minutes;
{
	double sign = 1.0;

	if (hh < 0) {
		sign = -1;
		hh = 0.0 - hh;
	}
	*hours = floor(hh);
	*minutes = floor((hh - (*hours))*60.0);
	*seconds = ((hh - (*hours)) - (*minutes)/60.0)*3600.0;
	if (*seconds > 59.0)
		*seconds = 59.0;
	*hours *= sign;
	if (*hours == 0) {
		*minutes *= sign;
		if (*minutes == 0)
			*seconds *= sign;
	}
}

	/* convert from hours, minutes, seconds to decimal hours. Watch out for
	   negative values of hours OR minutes OR seconds.  */

hmstohhh(hours, minutes, seconds, hh)
int hours, minutes;
double seconds, *hh;
{
	double sign = 1.0;

	if (hours < 0.0) {
		sign = -1.0;
		hours = 0.0 - hours;
	}
	if (minutes < 0.0) {
		sign = -1.0;
		minutes = 0.0 - minutes;
	}
	if (seconds < 0.0) {
		sign = -1.0;
		seconds = 0.0 - seconds;
	}
	*hh = sign*(hours + minutes/60.0 + seconds/3600.0);
}

	/* convert from decimal hours of RA to degrees; that is, 
	           6.0000   ->   90.00
	          12.0000   ->  180.00
	           1.5000   ->   22.50
	 */

hhhtodeg(hh, deg)
double hh, *deg;
{
	*deg = 15.0*hh;
	if (*deg == 360.0)
		*deg = 0.0;
}

	/* convert from degrees to decimal hours of RA */

degtohhh(deg, hh)
double deg, *hh;
{
	*hh = deg/15.0;
}

	/* convert from HH MM SS.sss of RA to decimal degrees */

ratodeg(hours, minutes, seconds, deg)
int hours, minutes;
double seconds, *deg;
{
	double hhh;
	
	hmstohhh(hours, minutes, seconds, &hhh);
	hhhtodeg(hhh, deg);
}

	/* convert from decimal degrees to HH MM SS.sss of RA */

degtora(deg, hours, minutes, seconds)
double deg, *seconds;
int *hours, *minutes;
{
	double hhh;

	degtohhh(deg, &hhh);
	hhhtohms(hhh, hours, minutes, seconds);
}

	/* read in a string of the form HHMMSS.sss, where the first two digits
	   are the hours, the third and fourth digits the minutes, and the
	   remaining digits the seconds, which may include digits after a
	   decimal point. Convert to decimal degrees, so that 0 hours becomes
	   0 degrees and 24 hours becomes 360 degrees */

read_ra_to_degrees(string, degrees)
char *string;
double *degrees;
{
	char buf[10];
	int hours, minutes;
	double seconds;

#ifdef SPACES
	squish_coords(string);
#endif

	buf[0] = string[0];
	buf[1] = string[1];
	buf[2] = '\0';
	if (sscanf(buf, "%2d", &hours) != 1) {
		sprintf(err_msg, "read_ra_to_degrees: bad hours in string %s", string);
		error(0, err_msg);
	}
	buf[0] = string[2];
	buf[1] = string[3];
	if (sscanf(buf, "%2d", &minutes) != 1) {
		sprintf(err_msg, "read_ra_to_degrees: bad minutes in string %s", string);
		error(0, err_msg);
	}
	if (sscanf(string + 4, "%lf", &seconds) != 1) {
		sprintf(err_msg, "read_ra_to_degrees: bad seconds in string %s", string);
		error(0, err_msg);
	}
	ratodeg(hours, minutes, seconds, degrees);
}

	/* read in a string of the form +DDMMSS.sss, where the first digit may be
	   a sign character (either '+' or '-'), the next two digits
	   are the degrees, the next two digits the minutes, and the
	   remaining digits the seconds, which may include digits after a
	   decimal point. Convert to decimal degrees. */

read_dec_to_degrees(string, degrees)
char *string;
double *degrees;
{
	char buf[10];
	int deg, minutes, sign, off;
	double seconds;

#ifdef SPACES
	squish_coords(string);
#endif

	if ((string[0] != '+') && (string[0] != '-')) {
		off = 0;
		sign = 1;
	}
	else {
		off = 1;
		if (string[0] == '+')
			sign = 1;
		else 
			sign = -1;
	}

	buf[0] = string[0 + off];
	buf[1] = string[1 + off];
	buf[2] = '\0';
	if (sscanf(buf, "%2d", &deg) != 1) {
		sprintf(err_msg, "read_dec_to_degrees: bad degrees in string %s", string);
		error(0, err_msg);
	}
	buf[0] = string[2 + off];
	buf[1] = string[3 + off];
	if (sscanf(buf, "%2d", &minutes) != 1) {
		sprintf(err_msg, "read_dec_to_degrees: bad minutes in string %s", string);
		error(0, err_msg);
	}
	if (sscanf(string + 4 + off, "%lf", &seconds) != 1) {
		sprintf(err_msg, "read_dec_to_degrees: bad seconds in string %s", string);
		error(0, err_msg);
	}
	hmstohhh(deg, minutes, seconds, degrees);
	*degrees *= sign;
}

	/* convert an astronomical coordinate string from the form
	               1        45       34.3
                 hours   minutes   seconds
	   to a more compact form, with no blanks and each of the first
	   two numbers in two-digit format, leading zeros if necessary, 
	   like this:
                     014534.3
	   this is extra hard because the 'printf()' functions on the Sun
	   are broken, so we have to take care of negative numbers ourselves.
	   Also, we must beware of missing a negative sign if it precedes a
	   zero.
	*/
	
squish_coords(str)
char *str;
{
	int h, m, sign;
	double s;

	sign = 1;
	h = 0;
	m = 0;
	s = 0.0;

	/* check the string for any '-' signs at all, so that a '-0' will not
	   be missed */
	if (strchr(str, '-') != NULL)
		sign = -1;

	sscanf(str, "%d %d %lf", &h, &m, &s);
	if (h < 0) {
		sign = -1;
		h = -h;
	}
	if (m < 0) {
		sign = -1;
		m = -m;
	}
	if (s < 0) {
		sign = -1;
		s = -s;
	}
	if (sign == -1)
		sprintf(str, "-%02d%02d%04.1lf", h, m, s);
	else
		sprintf(str, "%02d%02d%04.1lf", h, m, s);
}

	/* converts from an RA expressed as a string of the form
	             'HH:MM:SS.sss' 
	   to decimal degrees. returns 0 if all OK, or -1 if an error. */

int
val_ra2deg(val, ra)
char *val;
double *ra;
{
	int hour, minute;
	double second;
	char buf[100];

	if (pf_valtostr(val, buf) < 0) 
		return(-1);
	if (sscanf(buf, "%d:%d:%lf", &hour, &minute, &second) != 3)
		return(-1);

	ratodeg(hour, minute, second, ra);
	return(0);
}


	/* converts from a Dec expressed as a string of the form
	             '+/-DD:MM:SS.sss' 
	   to decimal degrees. returns 0 if all OK, or -1 if an error. */

val_dec2deg(val, dec)
char *val;
double *dec;
{
	int deg, minute;
	double second;
	char buf[100];

	if (pf_valtostr(val, buf) < 0) 
		return(-1);
	if (sscanf(buf, "%d:%d:%lf", &deg, &minute, &second) != 3)
		return(-1);

	hmstohhh(deg, minute, second, dec);
	return(0);
}

