[comp.sys.handhelds] 48SX/S: Astronomy routines and Alamanc

fin@norge.unet.umn.edu (Craig A. Finseth) (04/15/91)

This is a repost of the routines first posted a year or so ago.  This
repost fixes a typo.  It also fixes some problems with flag -51 and
cleans up the interface a bit (smaller, too, by 600 bytes).

If you like this, be sure to grab the browser that will be posted
next...

Craig A. Finseth			fin@unet.umn.edu [CAF13]
University Networking Services		+1 612 624 3375 desk
University of Minnesota			+1 612 625 0006 problems
130 Lind Hall, 207 Church St SE		+1 612 626 1002 FAX
Minneapolis MN 55455-0134, U.S.A.

======================================================================

Written by: Lauren Nelson, Craig Finseth
When: 23 June 1990, revised 13 April 1991
What: Astronomy routines

	NOTE:  This program requires the separately supplied BROWSER
	routine.

ALMANAC	ALMANAC program.  See below
G->JD	Converts a date in y.md format to a Julian day number.
JD->G	Converts a Julian day number to a date in y.md format.
JD	Returns the current time as a Julian day number.
LSIDT	Continuously displays the local sidereal time.
SETUP	Initialize or modify ASPAR.

ADATE	Format a HP-48 date into a string as per the HP-41.
ASOK	Checks whether ASPAR is present and calls SETUP if not.
ASPAR	AStronomy PARameters. See below.
ATIME	Format a HP-48 time in h.ms format into a string as per HP-41.
deltaDAYS  Returns the number of days between two dates in y.md format.
ELEV	Returns the elevation entry from ASPAR.  Ensures that ASPAR is present.

GTDIF	Returns the Greenwich time difference entry from ASPAR. 
	Ensures that ASPAR is present.
->h$	Format a HP-48 angle in h.ms format into a string.
JD->LSIDT  Converts a Julian day number with fractions to the local sidereal time.
JDOW	Converts a Julian day number to the string form of its day of the week.
LAT	Returns the latitude entry from ASPAR in decimal degrees. Ensures
	that ASPAR is present.
LONG	Returns the longitude entry from ASPAR in decimal degrees. Ensures
	that ASPAR is present.

OBJECTS	Directory of astronomical object information.  These items
	must be set manually.  They are:

	SolarSystem	Contains names and special RA/decl flags for
			selected solar system objects.
	BrightStars	Contains names and RA/decl data for selected
			bright stars.
	Messier		Contains names and RA/decl data for selected
			Messier objects.

P->R	Polar to Rectangular coordinate conversion.
R->P	Rectangular to Polar coordinate conversion.
YMD->	Converts a date in y.md format to HP-48SX format.
->YMD	Converts a date in HP-48SX format to y.md format.
YMD$	Converts a date in y.md format to string form.


General notes:

Julian day numbers: Many of these routines use Julian day numbers. 
These routines assume that the Julian to Gregorian calendar switch was
made in October 1582.  They also assume that there is no year 0.

YY.MMDD Format: Many of these routines use this format for dates.  This
format allows for direct representation of negative years.  They also allow
for representing time as a fractional day of the month.

------------------------------------------------------------
ASPAR:  AStronomy PARameters

This data object is contains the basic astronomical observation
parameters.  It is a list with four entries:

	Greenwich Mean Time Difference: The difference between your
	local time and GMT in h.ms form.  Positive for time zones west
	of Greenwich.

	Longitude: Your longitude in d.ms format.

	Latitude: Your latitude in d.ms format.

	Elevation: Your height above mean sea level (MSL) in meters.

These values can be accessed directly, or through interface procedures
(GTDIF, LONG, LAT, ELEV).  All uses of ASPAR should be prefaced with a
call to ASOK to ensure that ASPAR exists.  If you use these interface
procedures, this call is handled for you.

------------------------------------------------------------
Detailed Interfaces:

ALMANAC	Directory.

G->JD	Stack Input:	date in YY.MMDD format
	Stack Output:	corresponding Julian day number
	Calls:		JD->G

JD->G	Stack Input:	Julian day number
	Stack Output:	corresponding date in YY.MMDD format

JD	Stack Input:	none
	Stack Output:	current time as a Julian day number fraction to
			4 decimal places
	Calls:		G->JD, GTDIF, ->YMD

LSIDT	Stack Input:	none
	Stack Output:	none
	Calls:		ATIME, GTDIF, LONG

	Continual display of the local time and the local sidereal time. 
	Exits when any key is pressed.

SETUP	Stack Input:	none
	Stack Output:	none
	Global Input:	ASPAR
	Global Output:	ASPAR
	Calls:		BROWSE

ADATE	Stack Input:	date in HP-48 format
	Stack Output:	date formatted into a string as per HP-41

ASOK	Stack Input:	none
	Stack Output:	none
	Global Input:	ASPAR
	Calls:		SETUP

	Checks whether ASPAR is present and performs some minimal
verfification of its integrity.   If ASPAR is not present or not
intact, it calls SETUP.

ASPAR	AStronomy PARameters.  See above.

ATIME	Stack Input:	time in HH.MMSS format
	Stack Output:	time formatted into a string as per HP-41

deltaDAYS  Stack Input:	date1 in YY.MMDD format
			date2 in YY.MMDD format
	Stack Output:	number of days between the dates
	Calls:		G->JD

ELEV	Stack Input:	none
	Stack Output:	height value from ASPAR
	Global Input:	ASPAR
	Calls:		ASOK

GTDIF	Stack Input:	none
	Stack Output:	Greenwich mean time difference value from
			ASPAR in decimal hours
	Global Input:	ASPAR
	Calls:		ASOK

->h$	Stack Input:	angle in h.ms format
	Stack Output:	angle formatted into a string

JD->LSIDT  Stack Input:	Julian day number and fraction
	Stack Output:	local sidereal time for that instant
	Calls:		GTDIF, JD->G, LONG, YMD->

JDOW	Stack Input:	Julian day number
	Stack Output:	day of week for that date in string format

LAT	Stack Input:	none
	Stack Output:	latitude value from ASPAR in decimal degrees
	Global Input:	ASPAR
	Calls:		ASOK

LONG	Stack Input:	none
	Stack Output:	longitude value from ASPAR in decimal degrees
	Global Input:	ASPAR
	Calls:		ASOK

OBJECTS	Directory.

P->R	Stack Input:	radius
			angle
	Stack Output:	x coordinate w/tag
			y coordinate w/tag

	Polar to rectangular coordinate conversions.  You would have
	thought that HP would include this.

R->P	Stack Input:	x coordinate
			y coordinate
	Stack Output:	radius w/tag
			angle w/tag

	Rectangular to polar coordinate conversions.  You would have
	thought that HP would include this.

YMD->	Stack Input:	date in YY.MMDD format
	Stack Output:	corresponding date in the current format
	Calls:		->YMD

->YMD	Stack Input:	date in the current HP-48 format
	Stack Output:	corresponding date in YY.MMDD format

YMD$	Stack Input:	date in YY.MMDD
	Stack Output:	date formatted into a string
	Calls:		ATIME

============================================================
ALMANAC Directory

NOW	Set the date/time to the now.
THING	Select an object and display its alt/az.
SUN	Display the Sun's alt/az.
MOON	Display the Moon's alt/az.
RISE	Calculate the rise and set times for the object whose
	alt/az was last calculated.
WHEN	Prompts for the observation date and time.

ASOBJECT  Variable: Current object.  Set by THING.
C->AA	Transform RA/decl coordinates to alt/az.
DECL	Variable: Declination.  Set by FIG.
E->C	Transform ecliptical coordinatess to RA/decl coordinates.
FIGC	Figure alt/az for the specified object.
FIGT	Figure the Century Time.

MNalphadelta  Figure the RA and decl for the Moon.
OTJD	Variable: The Julian date/time that the observation is for.
	Set with STOT
RA	Variable: Right ascension.  Set by FIG.
SETOT	Set the observation time.
SNalphadelta  Figure the RA and decl for the Sun.


Note: The formulae used in this program have been approximated for
late 20th century use.  More exact formulae may be created by
consulting the references.  These objects are affected by these
approximations:

	E->C
	FIGT
	MNalphadelta
	SNalphadelta
	OBJECTS:BrightStars
	OBJECTS:Messier	


Basic operation:

1) Run SETUP to initialize ASPAR.

2) Press NOW or enter a date using WHEN.

3) Press THING and select an object, or press SUN or MOON.

4) If desired, press RISE to see the rise and set times.

You may add additional objects by adding to the existing objects in
the OBJECTS directory, or by creating new object lists (they will
automatically be picked up by THING).  If you wish to add objects
whose RA/decl vary, you need to define and use special flag RAs (93,
94, ...), add them to FIG, and create procedures to calculate the
RA/decl.

In future versions, we will replace the RA and decl constants and flag
information with a procedure that returns these values.

------------------------------------------------------------
Data Types:

what			name used	range			type
			in program

object			N		selected list		string

observer latitude			-90 (S) to +90 (N)	D.MS
observer longitude			-180 (E) to +180 (W)	D.MS

right ascension		RA, alpha	0 to 23.5959		H.MS
declination		DECL, delta	0 to 359.5959		D.MS

altitude				-90 (nadir) to +90 (zenith)	D.MS
azimuth					0 (N) to +359.59.59 	D.MS
					 (E=90, S=180, W=270)
ecliptical (celestial)
	longitude	lambda		0 to +359.59.59	 	decimal degrees
ecliptical (celestial)
	latitude	beta		-90 to +90		decimal degrees



Object List:

The object lists in the OBJECTS directory are lists of lists.  Each
sublist has an object name, its right ascention, and its declination
as:

	{ { N1 RA1 decl1 } { N2 RA2 decl2 } ... }

An object with a declination of +91 is assumed to be the Sun.  An
object with a declination of +92 is assumed to be the Moon.


------------------------------------------------------------
Detailed Interfaces:

NOW	Stack Input:	none
	Stack Output:	none
	Calls:		SETOT, ->YMD

THING	Stack Input:	none
	Stack Output:	object
			object's altitude
			object's azimuth
	Global Input:	OBJECTS directory
	Global Output:	ASOBJECT
	Calls:		BROWSE (separately supplied), FIGC

SUN	Stack Input:	none
	Stack Output:	none
	Screen:		"Sun"
			Sun's altitude
			Sun's azimuth
	Global Output:	ASOBJECT
	Calls:		FIGC

MOON	Stack Input:	none
	Stack Output:	none
	Screen:		"Moon"
			Moon's altitude
			Moon's azimuth
	Global Output:	ASOBJECT
	Calls:		FIGC

RISE	Stack Input:	none
	Stack Output:	none
	Screen:		oject name
			object's rising time
			object's rising azimuth
			object's setting time
			object's setting azimuth
	Global Input:	ASOBJECT, DECL, OTJD, RA
	Global Output:	OTJD
	Calls:		ATIME, G->JD, GTDIF, JD->G, LAT, LONG, YMD->,
			->YMD

	Figure an object's rise and set times.  It uses the last
object whose altitude and azimuth were computed (i.e., the last
invocation of THING, SUN, or MOON).

WHEN	Stack Input:	none
	Stack Output:	none
	Calls:		SETOT

	Prompts for observation date and time.

ASOBJECT  Variable.

C->AA	Stack Input:	RA
			decl
	Stack Output:	az w/tag
			alt w/tag
	Global Input:	OTJD
	Calls:		JD->LSIDT, LAT

	Applies correction for atmospheric refraction for altitudes
starting at -.55 degrees.

DECL	Variable.

E->C	Stack Input:	ecliptical longitude
			ecliptical latitude
	Stack Output:	RA
			decl
	Calls:		R->P

FIGC	Stack Input:	list containing object, RA, decl
	Stack Output:	object
			azimuth w/tag
			altitude w/tag
	Global Input:	ASOBJECT
	Global Output:	DECL, RA
	Calls:		C->AA, MNalphadelta, SNalphadelta

	Figure the altitude and azimuth for the specified object.
	Also record the object's right ascension and declination.

FIGT	Stack Input:	none
	Stack Output:	Century Time
	Global Input:	OTJD

MNalphadelta  Stack Input:	none
	Stack Output:	Moon's RA
			Moon's declination
	Calls:		E->C, FIGT

OTJD	Variable.

RA	Variable.

SETOT	Stack Input:	date in YY.MMDD format
	Stack Output:	none
	Global Output:	OTJD
	Calls:		G->JD, GTDIF

SUNalphadelta	Stack Input:	none
	Stack Output:	Sun's RA
			Sun's declination
	Calls:		FIGT, R->P

------------------------------------------------------------
References:

Hirshfeld, Alan and Sinnott, Roger W., "Sky Catalogue 2000.0," 2
volumes, Cambridge University Press, Cambridge, UK, 1982.

Meeus, Jean, "Astronomical Formulae for Calculators, Second Edition,"
Willmann-Bell, Inc., Richmond, VA, 1982.

"The Concise Planetary Ephemeris for 1950 to 2000 A.D.," The Hieratic
Publishing Co., Medford, MA, 1977.


Checksum: #a5h
Size: 9243.5
------------------------------------------------------------
%%HP: T(3)A(D)F(.);
DIR
  ALMANAC
    DIR
      NOW
        \<< TIME DATE
WHEN
        \>>
      THING
        \<< PATH
OBJECTS {
"    Select a Class"
1 0
          \<<
          \>> } VARS
BROWSE SWAP DROP
OBJ\-> DROP SWAP DROP
          IF 0 ==
          THEN
UPDIR DROP
          ELSE {
"  Select an Object"
1 0
            \<< 1 GET
            \>> }
SWAP BROWSE SWAP
DROP OBJ\-> DROP SWAP
DROP
            IF 0 ==
            THEN
UPDIR DROP
            ELSE
UPDIR SWAP EVAL
'ASOBJECT' STO FIGC
            END
          END
        \>>
      SUN
        \<< { "Sun"
91 0 } 'ASOBJECT'
STO FIGC 4 RND
"Alt: " SWAP + SWAP
4 RND "Az: " SWAP +
        \>>
      MOON
        \<< { "Moon"
92 0 } 'ASOBJECT'
STO FIGC 4 RND
"Alt: " SWAP + SWAP
4 RND "Az: " SWAP +
        \>>
      RISE
        \<< OTJD DUP
GTDIF 24 / - \-> P O
          \<< RCLF
DEG 0 3
            FOR I
-.009
              IF
ASOBJECT 1 GET DUP
"Sun" SAME SWAP
"Moon" SAME OR
              THEN
.0045 -
              END
LAT SIN DECL HMS\->
SIN * - LAT COS
DECL HMS\-> COS * /
ACOS 15 / RA HMS\->
SWAP DUP2 - 3 ROLLD
+ 1.002738 6.66452
LONG 15 / - SWAP
GTDIF * + O JD\->G
YMD\-> 1.012 DDAYS
15.218442 / - DUP
ROT SWAP - 24 MOD
1.002738 / 3 ROLLD
- 24 MOD 1.002738 /
O JD\->G YMD\-> \->YMD
              IF I
2 <
              THEN
ROT DROP SWAP
              ELSE
SWAP DROP SWAP
              END
              IF I
2 MOD 1 ==
              THEN
DUP \->HMS 4 RND
ATIME
IF I 1 ==
THEN "RISE"
ELSE "SET"
END \->TAG I 1 + DISP
              END
240000 / + G\->JD
GTDIF 24 / + 'OTJD'
STO FIGC ROT
              IF I
0 ==
              THEN
CLLCD 1 DISP
              ELSE
DROP
              END
DROP
              IF I
2 MOD 1 ==
              THEN
2 RND "Az" \->TAG I 2
+ DISP
              ELSE
DROP
              END
            NEXT 7
FREEZE STOF P
'OTJD' STO
          \>>
        \>>
      WHEN
        \<< \->YMD
SETOT
        \>>
      ASOBJECT {
"Sun" 91 0 }
      C\->AA
        \<< HMS\-> SWAP
HMS\-> 15 * SWAP \-> \Ga
\Gd
          \<< OTJD
JD\->LSIDT HMS\-> 15 *
\Ga - \-> H
            \<< RCLF
DEG H SIN H COS LAT
SIN * \Gd TAN LAT COS
* - SWAP R\->C ARG
180 + 360 MOD LAT
SIN \Gd SIN * LAT COS
\Gd COS * H COS * +
ASIN DUP
              IF
-.55 >
              THEN
DUP 3.4 + 1.6 SWAP
/ .017130621 - +
              END
\->HMS "Alt" \->TAG
SWAP \->HMS "Az" \->TAG
SWAP ROT STOF
            \>>
          \>>
        \>>
      DECL
9.09308006447
      E\->C
        \<<
23.4392911 \-> \Gl \Gb \Ge
          \<< RCLF
DEG \Gl SIN \Ge COS * \Gb
TAN \Ge SIN * - \Gl COS
SWAP R\->P SWAP DROP
15 / \->HMS \Gb SIN \Ge
COS * \Gb COS \Ge SIN *
\Gl SIN * + ASIN \->HMS
ROT STOF
          \>>
        \>>
      FIGC
        \<< ASOBJECT
OBJ\-> DROP DUP2 DROP
          IF 91 ==
          THEN
DROP2 SN\Ga\Gd
          END
          IF DUP2
DROP 92 ==
          THEN
DROP2 MN\Ga\Gd
          END DUP2
'DECL' STO 'RA' STO
C\->AA
        \>>
      FIGT
        \<< OTJD
2415020 - 36525 /
        \>>
      MN\Ga\Gd
        \<< FIGT \-> T
          \<<
270.434164
481267.8831 T * +
360 MOD 358.475833
35999.0498 T * +
296.104608
477198.8491 T * +
350.737486
445267.1142 T * +
11.250889
483202.0251 T * + \->
LP M MP D F
            \<< RCLF
DEG LP 6.28875 MP
SIN * + 1.274018 D
2 * MP - SIN * +
.658309 D 2 * SIN *
+ 5.128189 F SIN *
.280606 MP F + SIN
* + .277693 MP F -
SIN * + E\->C ROT
STOF
            \>>
          \>>
        \>>
      OTJD
2448360.23786
      RA
1.27187705312
      SETOT
        \<< G\->JD SWAP
HMS\-> GTDIF + 24 / +
'OTJD' STO
        \>>
      SN\Ga\Gd
        \<< RCLF DEG
FIGT \-> T
          \<<
279.69668
36000.76892 T * +
.0003025 T SQ * +
358.47583
35999.04975 T * +
.00015 T SQ * -
.0000033 T 3 ^ * -
\-> L M
            \<<
1.91946 .004789 T *
- .000014 T SQ * -
M SIN * .020094
.0001 T * - M 2 *
SIN * + .000293 M 3
* SIN * + 23.452294
.0130125 T * -
.00000164 T SQ * -
.000000503 T 3 ^ *
+ 259.18 1934.142 T
* - DUP COS .00256
* ROT + \-> C \GW \Ge
              \<< L C
+ .00569 .00479 \GW
SIN * - - \-> SLA
\<< \Ge COS SLA SIN *
SLA COS SWAP R\->P
SWAP DROP 15 / \->HMS
\Ge SIN SLA SIN *
ASIN \->HMS
\>>
              \>>
            \>>
          \>> ROT
STOF
        \>>
    END
  G\->JD
    \<< DUP DUP IP
SWAP ABS FP 100 *
DUP IP SWAP FP 100
* 4 ROLL 0 0 0 0 \->
Y M D J M1 Y1 C B
      \<<
        IF M 2 \<=
        THEN Y 1 -
'Y1' STO M 12 +
'M1' STO
        ELSE Y 'Y1'
STO M 'M1' STO
        END
        IF J
1582.1015 \>=
        THEN 2 Y1
100 / IP - Y1 400 /
IP + 'B' STO
        END
        IF Y 0 \<=
        THEN .75
'C' STO 1 'Y1' STO+
        END 365.25
Y1 * C - IP 30.6001
M1 1 + * IP + D +
1720994.5 + B + DUP
J SWAP JD\->G
        IF \=/
        THEN DROP J
# D01h DOERR
        END
      \>>
    \>>
  JD\->G
    \<< DUP
      IF 0 <
      THEN
"Negative Julian Day"
DOERR
      END .5 + DUP
IP DUP ROT FP SWAP
1867216.25 -
36524.25 / IP 3
PICK
      IF 2299161 <
      THEN DROP
SWAP
      ELSE DUP 4 /
IP - 1 + ROT +
      END 1524 +
DUP 122.1 - 365.25
/ IP DUP 365.25 *
IP DUP 4 PICK SWAP
- 30.6001 / IP SWAP
4 ROLL SWAP - SWAP
DUP 30.6001 * IP
ROT SWAP - 4 ROLL +
SWAP DUP
      IF 13.5 <
      THEN 1 -
      ELSE 13 -
      END DUP
      IF 2.5 >
      THEN ROT 4716
-
      ELSE ROT 4715
-
      END DUP
      IF 0 \<=
      THEN 1 -
      END SWAP ROT
100 / + 100 / SWAP
DUP SIGN SWAP ABS
ROT + *
    \>>
  JD
    \<< GTDIF TIME
HMS+ 4 RND HMS\-> 24
/ DUP FP 10000 /
SWAP IP DATE SWAP
DATE+ \->YMD SWAP +
G\->JD
    \>>
  LSIDT
    \<< 6.66452 LONG
15 / - GTDIF
1.002738 * + .0002
+ RCLF 3 FIX CLLCD
"Local Siderial Time."
5 DISP
"Local Time." 1
DISP SWAP \-> a
      \<<
        DO a DATE
1.012 DDAYS
15.21842 / - \-> Y
          \<<
            WHILE
              IF 0
KEY ==
              THEN
TIME .00005 HMS+
DUP HMS\-> DUP 4 TRNC
              ELSE
0 0
              END 0
\=/
            REPEAT
SWAP 4 TRNC ATIME 2
DISP 1.002738 * Y +
24 MOD \->HMS 4 TRNC
RCLF SWAP -41 SF
ATIME 6 DISP STOF
            END
          \>>
        UNTIL 0 ==
        END
      \>> DROP STOF
    \>>
  SETUP
    \<< { :GMT: 0
:EST: 5 :EDT: 4
:CST: 6 :CDT: 5
:MST: 7 :MDT: 6
:PST: 8 :PDT: 7
:AST: 9 :ADT: 8 } \->
TZ
      \<< { } ASPAR
DUP TYPE
        IF 5 \=/ SWAP
SIZE 4 \=/ OR
        THEN :GMT:
0
        ELSE ASPAR
1 GET
        END {
"SELECT A TIME ZONE"
} TZ ROT POS + 0 +
        \<<
        \>> + TZ
BROWSE 1 GET SWAP
DROP
      \>> +
"ENTER Your longitude"
10 CHR +
"as deg . min sec"
+ { } ":Long.:"
      IFERR ASPAR 2
GET DTAG
      THEN ""
      END + + -8 +
V + INPUT OBJ\-> +
"ENTER Your latitude."
10 CHR +
"as deg . min sec"
+ { } ":Lat.:"
      IFERR ASPAR 3
GET DTAG
      THEN ""
      END + + -7 +
V + INPUT OBJ\-> +
"ENTER Your altitude"
10 CHR +
"in meters." + { }
":ELEV.:"
      IFERR ASPAR 4
GET DTAG OBJ\-> DROP
      THEN ""
      END + + -7 +
V + INPUT OBJ\-> '1_m
' \->UNIT "ELEV."
\->TAG + 'ASPAR' STO
    \>>
  ADATE
    \<< DUP 1 TSTR 1
10 SUB SWAP 100 *
FP 10000 * +
    \>>
  ASOK
    \<< ASPAR DUP
TYPE
      IF 5 \=/ SWAP
SIZE 4 \=/ OR
      THEN SETUP
      END
    \>>
  ASPAR { :CDT: 5
:Long.: 93.104213
:Lat.: 44.57546
:ELEV.: '278.9_m' }
  ATIME
    \<< HMS\-> \->HMS
      IF -41 FC?
      THEN 24 MOD
      END DUP SIGN
SWAP ABS DUP IP
SWAP DUP DUP 4 TRNC
- 10000 * SWAP FP
1.1 SWAP
      IF -41 FC?
      THEN 4 PICK +
      END TSTR -41
      IF FS?
      THEN 17 22
SUB SWAP DUP
        IF 0 ==
        THEN DROP
        ELSE \->STR
          IF DUP
"E" POS 0 ==
          THEN DUP
DUP "." POS SWAP
SIZE SUB +
          ELSE DROP
          END
        END
      ELSE DUP 14
21 SUB " " + SWAP
22 22 SUB + "M" +
SWAP DROP
      END SWAP
      IF -41 FS?
      THEN \->STR DUP
1 SWAP "." POS 1 -
DUP
        IF 1 <
        THEN DROP
OVER SIZE
        END SUB
SWAP +
      ELSE DROP
      END SWAP
      IF 0 <
      THEN "-" SWAP
+
      END
    \>>
  \GdDAYS
    \<< G\->JD SWAP
G\->JD -
    \>>
  ELEV
    \<< ASOK ASPAR 4
GET
    \>>
  GTDIF
    \<< ASOK ASPAR 1
GET HMS\->
    \>>
  \->h$
    \<< RCLF STD SWAP
HMS\-> \->HMS DUP FP
\->STR SIZE DUP 4
      IF \<=
      THEN DROP 4
FIX
      ELSE 1 - FIX
      END \->STR DUP
"." POS SWAP OVER
"h" REPL DUP 3 PICK
2 + OVER SIZE SUB 1
"m" REPL ROT 3 +
DUP 4 ROLLD SWAP
REPL "s" + SWAP 2 +
OVER OVER OVER SIZE
DUP2
      IF \>=
      THEN 4 DROPN
      ELSE SUB 1
"." REPL SWAP 1 +
SWAP REPL
      END SWAP STOF
    \>>
  JD\->LSIDT
    \<< GTDIF 24 / -
\-> J
      \<< 1.002738
6.66452 LONG 15 / -
OVER GTDIF * + J
JD\->G YMD\-> 1.012
DDAYS 15.218442 / -
SWAP J JD\->G 10000 *
FP 24 * * + 24 MOD
\->HMS
      \>>
    \>>
  JDOW
    \<< 0 RND 1 + 7
MOD
"SUNMONTUEWEDTHUFRISAT"
SWAP DUP 3 * 1 +
SWAP 1 + 3 * SUB
    \>>
  LAT
    \<< ASOK ASPAR 3
GET HMS\->
    \>>
  LONG
    \<< ASOK ASPAR 2
GET HMS\->
    \>>
  OBJECTS
    DIR
      SolarSystem {
{ "Sun" 91 0 } {
"Moon" 92 0 } }
      BrightStars {
{ "\Ga Tau:Aldebaran"
4.3555 16.3033 } {
"\Gb Per:Algol" 3.081
40.5721 } {
"\Ga Aql:Altair"
19.5046 8.5206 } {
"\Ga Sco:Antares"
16.2924 -26.2555 }
{ "\Ga Boo:Arcturus"
14.1539 19.1057 } {
"\Gg Ori:Bellatrix"
5.2507 6.2059 } {
"\Ga Ori:Betelguese"
5.551 7.2426 } {
"\Ga Car:Canopus"
6.2357 -45.5651 } {
"\Ga Aur:Capella"
5.1641 45.5953 } {
"\Ga Cyg:Deneb"
20.4125 45.1649 } {
"\Gb Tau:Elnath"
5.2617 28.3627 } {
"\Ga PsA:Fomalhaut"
22.5738 -29.372 } {
"\Gs Cet:Mira" 2.1921
60.291 } {
"\Ga UMi:Polaris"
2.315 89.1551 } {
"\Gb Gem:Pollux"
7.4518 28.0134 } {
"\Ga CMi:Procyon"
7.3918 5.133 } {
"\Ga Leo:Regulus"
10.0822 11.5802 } {
"\Gb Ori:Rigel"
5.1432 -8.1206 } {
"\Ga Sgr:Rukbat"
19.2353 -40.3658 }
{ "\Ga CMa:Sirius"
6.4508 -16.4258 } {
"\Ga Vir:Spica"
13.2511 -11.0941 }
{ "\Ga Lyr:Vega"
18.3656 38.4701 } {
"\Ga Cen" 14.3935
-60.5013 } {
"\Gt Cet" 1.4404
-15.5615 } }
      Messier { {
"M1:Crab Nebula"
5.34 22.01 } {
"M31:Andromeda" .43
41.16 } {
"M42:Orion Nebula"
5.35 -5.27 } {
"M45:Pleiades" 3.47
24.07 } }
    END
  P\->R
    \<< DUP2 COS *
"x" \->TAG 3 ROLLD
SIN * "y" \->TAG
    \>>
  R\->P
    \<< R\->C DUP ABS
"r" \->TAG SWAP ARG
"\<)" \->TAG
    \>>
  YMD\->
    \<< 4 TRNC
      IF -42 FC?
      THEN \->YMD
\->YMD 100 /
      ELSE DUP IP
SWAP FP 100 * DUP
IP SWAP FP 100 *
SWAP ROT 10000 / +
100 / +
      END
    \>>
  \->YMD
    \<< DUP IP SWAP
FP 100 * DUP IP
SWAP FP 10000 *
      IF -42 FC?
      THEN ROT ROT
      ELSE SWAP ROT
      END 100 / +
100 / +
    \>>
  YMD$
    \<< DUP SIGN SWAP
ABS DUP IP SWAP DUP
DUP 4 TRNC - 10000
* SWAP FP 1.1 SWAP
TSTR -41
      IF FS?
      THEN 17 22
      ELSE 16 21
      END SUB SWAP
RCLF SWAP STD DUP
      IF 0 ==
      THEN DROP
      ELSE ROT "  "
+ SWAP 24 * \->HMS 4
RND ATIME + SWAP
      END STOF +
SWAP
      IF 0 <
      THEN "-" SWAP
+
      END 1 2
      START DUP ":"
POS "/" REPL
      NEXT
    \>>
END