Measuring the Distance to the Sun: Pascal Source Code

The following source code has been written and tested with the Turbo Pascal compiler. But it should be possible to compile it by other compilers with only very few changes.

In order to make quite comfortable input possible the source code is somewhat longer than necessary. The following items are to be noticed:

The Source Code


program ParallaxOfTheSun;



uses Crt;



const deg = Pi/180.0;



type real = extended;                    (* highest precision is necessary! *)



var name: String;                            (* name of the observed object *)

    day, month, year: integer;                  (* date of the observations *)

    UT1, UT2,                                    (* observation times in UT *)

    long1, lat1, h1, long2, lat2, h2: real;(* observer's geogr. coordinates *)

    alpha1, delta1, d1, alpha2, delta2, d2,       (* geocentric coordinates *)

    alpha11, delta11, alpha21, delta21,          (* topocentric coordinates *)

    dist, parallaxe, dmin: real;

    geozC, key: Char;

    geoz: boolean;

    dayStr, monthStr, yearStr: String;     (* strings for comfortable input *)

    UT1Str, UT2Str: String;

    alpha1Str, delta1Str, alpha11Str, delta11Str, d1Str: String;

    alpha2Str, delta2Str, alpha21Str, delta21Str, d2Str: String;

    lat1Str, long1Str, h1Str, lat2Str, long2Str, h2Str: String;



function hmin2hdec(hmin: real): real;

               (* ... convertes hours with minutes into hours with decimals *)



   begin

   hmin2hdec:=Trunc(hmin)+(hmin-Trunc(hmin))/0.6

   end;



function String2Angle(s: String): real;

(* ... converts a string into an angle in rad. The must have one of the

following forms:

   - degree with decimals XXX.YYYY, for instance 35.134,

   - hours with minutes and seconds XXhYYmZZ.ZZZ, for instance 3h56m5.03,

   - degrees with arcmin and arcsec XXdYYmZZ.ZZZ, for instance 25d35m28.33,

   - degrees with arcmin and arcsec XXgYYmZZ.ZZZ, for instance 25g35m28.33.*)



   var pd, ph, code, sgn: integer;

       r, r1: real;

       s1: String;



   begin

   while (s[1]=' ') do Delete(s, 1, 1);

   while Pos(',', s)>0 do s[Pos(',', s)]:='.';

   if s[1]='-'

      then

         begin

         sgn:=-1; Delete(s, 1, 1);

         end

      else sgn:=1;

   pd:=Pos('d', s); ph:=Pos('h', s);

   if (pd=0) and (ph=0)

      then

         begin

         Val(s, r, code);

         if Code>0 then begin Write(#7); Halt end;

         end

      else

         if pd>0

            then

               begin

               s1:=Copy(s, 1, pd-1); Delete(s, 1, pd);

               Val(s1, r, code);

               pd:=Pos('m', s);

               if pd=0 then pd:=Pos(#39, s);

               s1:=Copy(s, 1, pd-1); Delete(s, 1, pd);

               Val(s1, r1, code);

               r:=r+r1/60.0;

               Val(s, r1, code);

               r:=r+r1/3600.0;

               end

            else

               begin

               s1:=Copy(s, 1, ph-1); Delete(s, 1, ph);

               Val(s1, r, code);

               ph:=Pos('m', s);

               s1:=Copy(s, 1, ph-1); Delete(s, 1, ph);

               Val(s1, r1, code);

               r:=r+r1/60.0;

               Val(s, r1, code);

               r:=(r+r1/3600.0)*15.0;

               end;

   String2Angle:=sgn*r*deg

   end;



procedure readAngle(s: String; var sw: String; var w: real);

(* quite comfortable input routine for angles: The prechoosen value is

displayed. Pressing "return" only will keep the old value unchanged. *)



   var sh: String;

       Code: integer;



   begin

   Write(s+'('+sw+') '); ReadLn(sh);

   if sh<>'' then sw:=sh;

   w:=String2Angle(sw)

   end;



procedure readReal(s: String; var sr: String; var r: real);

       (* quite comfortable input routine for reals, similar to "readAngle" *)



   var sh: String;

       Code: integer;



   begin

   Write(s+'('+sr+') '); ReadLn(sh);

   if sh<>'' then sr:=sh;

   Val(sr, r, Code);

   end;



procedure readInteger(s: String; var si: String; var i: integer);

    (* quite comfortable input routine for integers, similar to "readAngle" *)



   var sh: String;

       Code: integer;



   begin

   Write(s+'('+si+') '); ReadLn(sh);

   if sh<>'' then si:=sh;

   Val(si, i, Code);

   end;



procedure polar2cart(alpha, delta, r: real; var x, y, z: real);

               (* ... converts polar coordinates in rectangular coordinates *)

   var rcst: real;



   begin

   rcst:=r*cos(delta);

   x:=rcst*cos(alpha);

   y:=rcst*sin(alpha);

   z:=r*sin(delta);

   end;



function julDate(day, month, year: integer; UT: real): real;

(* ... calculates the Julian date according to normal date and time

                                                              (in h.dec UT) *)



   var t, k, b, y, m: real; a: integer;



   begin

   t:=day+UT/24.0;

   k:=10000.0*year+100.0*month+t;

   b:=-63.5;

   y:=year+4712.0;

   m:=month+1.0;

   if m<=3.0 then

      begin

      y:=y-1.0; m:=m+12.0

      end;

   if k>=15821015.0 then

      begin

      a:=Trunc((y+88.0)/100.0);

      b:=b+38.0-a+Trunc(a/4.0)

      end;

   t:=Trunc(365.25*y)+Trunc(30.6001*m)+t+b;

   julDate:=t

   end;



function sideralTime(day, month, year: integer; UT, longitude: real): real;

(* ... calculates the sideral time for a moment and a site with

                   geographical "longtude" (in rad; east of Greenwich: >0!) *)



   const ST2UT = 1.0027379093;



   var s, j: real;



   begin

   j:=julDate(day, month, year, 0.0);

   s:=6.656306+0.0657098242*(j-2445700.5)+longitude*12.0/Pi;

   s:=s+ST2UT*UT;

   while s>24.0 do s:=s-24.0;

   while s< 0.0 do s:=s+24.0;

   sideralTime:=s/12.0*Pi;

   end;



procedure ObserversCoord(day, month, year: integer;

                         ut, longitude, latitude, height: real;

                         var alpha, delta, rho: real);

(* ... calculates the equitorial coordinates of an observer for one moment,

takes into account that the earth is no perfect sphere. Latitude>0 means:

east of Greenwich! ( see J. Meeus, Astronomical Algorithms, for instance) *)



   const exEarth = 0.08181922;          (* excentricity of the earth's body *)



   var denum, sinl, cosl, rhosin, rhocos: real;



   begin

   sinl:=sin(latitude); cosl:=cos(latitude);

   denum:=sqrt(1.0-sqr(exEarth*sinl));

   rhocos:=cosl/denum+height/6378140.0*sinl;

   rhosin:=(1.0-exEarth*exEarth)*sinl/denum+height/6378140.0*cosl;

   rho:=sqrt(sqr(rhosin)+sqr(rhocos));

   delta:=arctan(rhosin/rhocos);

   alpha:=sideraltime(day, month, year, ut, longitude);

   end;



procedure initialisation;

(* presetting of the input variables, allowing a test run by pressing

                                                              "return" only *)

   begin

   lat1Str:= '52.25417'; long1Str:='8.3244'; h1Str:='200.0';

   lat2Str:= '52.25417'; long2Str:='8.3244'; h2Str:='200.0';

   UT1Str:='19.1695'; UT2Str:='20.1002';

   dayStr:='14'; monthStr:='10'; yearStr:='1996';

   alpha1Str:='2h42m47.518'; delta1Str:='33d9m6.54';

   alpha11Str:='2h42m47.729'; delta11Str:='33d9m1.332'; d1Str:='1.028148';

   alpha2Str:='2h42m45.377'; delta2Str:='33d9m11.67';

   alpha21Str:='2h42m45.54'; delta21Str:='33d9m6.732'; d2Str:='1.028072';

   end;



procedure input;



   begin

   ClrScr;

   WriteLn('This program calculates the sun'+#39+'s parallax from');

   WriteLn

   ('- two simult. topocentric positions and the corresp. geocentric distance,');

   WriteLn

   ('- two sequ. topocentric positions and the corresp. geocentric proper motion,');

   WriteLn

   ('- one topocentric position and corresponding geocentric coordinates.');

   WriteLn;

   Write(' Asteroid'+#39+'s name : '); ReadLn(name);

   Write(' Has '+name+' been observed twice (y/n) ? '); ReadLn(geozC);

   geoz:=geozC in ['n','N'];

   WriteLn;

   WriteLn(' Date:');

   readInteger('   Day: ', dayStr, day);

   readInteger(' Month: ', monthStr, month);

   readInteger('  Year: ', yearStr, year);

   WriteLn('geographic coordinates of observer 1:');

   readAngle(' latitude = ', lat1Str, lat1);

   readAngle(' longitude (east of Greenwich: >0) =  ', long1Str, long1);

   readReal(' height [meters over sea level] = ', h1Str, h1);

   WriteLn;

   readReal(' observation time 1 (h.min UT) = ', UT1Str, UT1);

   UT1:=hmin2hdec(UT1);

   if not geoz then

      begin

      readReal(' observation time 2 (h.min MEZ) = ', UT2Str, UT2);

      UT2:=hmin2hdec(UT2);

      end;

   WriteLn;

   WriteLn(' topocentric coordinates:');

   readAngle(' longitude = ', alpha11Str, alpha11);

   readAngle('  latitude = ', delta11Str, delta11);

   WriteLn(' geocentric coordinates:');

   if UT1<>UT2 then

      begin

      readAngle(' longitude = ', alpha1Str, alpha1);

      readAngle('  latitude = ', delta1Str, delta1);

      end;

   readReal(' distance [AU] = ', d1Str, d1);

   if not geoz then

      begin

      WriteLn;

      WriteLn(' geographic coordinates of observer 2:');

      readAngle(' latitude = ', lat2Str, lat2);

      readAngle(' longitude (east of Greenwich: >0) = ', long2Str, long2);

      readReal(' height [meters over sea level] = ', h2Str, h2);

      WriteLn;

      WriteLn(' topocentric coordinates:');

      readAngle(' longitude = ', alpha21Str, alpha21);

      readAngle('  latitude = ', delta21Str, delta21);

      WriteLn(' geocentric coordinates:');

      if UT1<>UT2 then

         begin

         readAngle(' longitude = ', alpha2Str, alpha2);

         readAngle('  latitude = ', delta2Str, delta2);

         end;

      readReal(' distance [AU] = ', d2Str, d2);

      end;

   end;



function arccos(x: real): real;



   begin

   if x>0.0

      then arccos:=arctan(sqrt(1.0/sqr(x)-1.0))

      else if x<0.0

              then arccos:=-arctan(sqrt(1.0/sqr(x)-1.0))+Pi

              else arccos:=Pi/2.0 end;



function distance(alpha1, delta1, alpha2, delta2: real): real;

(*... calculates the angular distance of two points of the celestial sphere *)



   begin

   distance:=arccos(sin(delta1)*sin(delta2)+

                    cos(delta1)*cos(delta2)*cos(alpha1-alpha2))

   end;



procedure calculation(var dist, parallaxe, dmin: real);

                                               (* the heart of this program *)

   var ao1, do1, ro1, ao2, do2, ro2: real;

       xo1, yo1, zo1, xo2, yo2, zo2: real;

       xe1, ye1, ze1, xe2, ye2, ze2: real;

       lpm, lmm, lambda, mu, r, AU: real;



   begin

   ObserversCoord(day, month, year, UT1, long1, lat1, h1, ao1, do1, ro1);

   polar2cart(ao1, do1, ro1, xo1, yo1, zo1);

   polar2cart(alpha11, delta11, 1.0, xe1, ye1, ze1);

   if not geoz

      then

         begin

         ObserversCoord(day, month, year, UT2, long2, lat2, h2, ao2, do2,ro2);

         polar2cart(ao2, do2, ro2, xo2, yo2, zo2);

         if UT1<>UT2 then

            begin                    (* reduction of topoc. position no. 2: *)

            alpha21:=alpha21-(alpha2-alpha1);

            delta21:=delta21-(delta2-delta1);

            end;

         polar2cart(alpha21, delta21, 1.0, xe2, ye2, ze2);

         end

      else

         begin

         polar2cart(alpha1, delta1, 1.0, xe2, ye2, ze2);

         xo2:=0.0; yo2:=0.0; zo2:=0.0;

         end;

                                                              (* lambda+mu: *)

   lpm:=((xo2-xo1)*(xe1-xe2)+(yo2-yo1)*(ye1-ye2)+(zo2-zo1)*(ze1-ze2))/

        (1.0-(xe1*xe2+ye1*ye2+ze1*ze2));

                                                              (* lambda-mu: *)

   lmm:=((xo2-xo1)*(xe1+xe2)+(yo2-yo1)*(ye1+ye2)+(zo2-zo1)*(ze1+ze2))/

        (1.0+(xe1*xe2+ye1*ye2+ze1*ze2));

   lambda:=0.5*(lpm+lmm);

       mu:=0.5*(lpm-lmm);

                                 (* shortest distance of the lines of view: *)

   dmin:=sqrt(sqr(xo1+lambda*xe1-xo2-mu*xe2)+

              sqr(yo1+lambda*ye1-yo2-mu*ye2)+

              sqr(zo1+lambda*ze1-zo2-mu*ze2));

                  (* geocentric distance as multiple of the earth's radius: *)

   r:=sqrt(sqr(xo1+lambda*xe1)+sqr(yo1+lambda*ye1)+sqr(zo1+lambda*ze1));

                (* the Astronomical Unit as multiple of the earth's radius: *)

   if lambda<0.0 then dmin:=-dmin;

   if geoz

      then AU:=r/d1

      else AU:=r/(0.5*(d1+d2));

   parallaxe:=1.0/AU;

   dist:=distance(alpha11, delta11, alpha21, delta21);

   end;



procedure output(var key: Char);

                                     (* ... displays input data and results *)

   begin

   ClrScr;

   Write('Two topocentric observations of ', name);

   WriteLn(', ', month, '/', day, '/', year);

   WriteLn('=============================================================');

   WriteLn('Observation 1:');

   WriteLn('--------------');

   WriteLn('UT: ', UT1Str);

   Write(' geographic position:');

   Write(' latitude = ', lat1Str, ',');

   Write(' longitude = ', long1Str, ',');

   WriteLn(' height = ', h1Str);

   Write('topocentric position:');

   Write(' alpha = ', alpha11Str, ',');

   WriteLn(' delta = ', delta11Str);

   Write(' geocentric position:');

   Write(' alpha = ', alpha1Str, ',');

   WriteLn(' delta = ', delta1Str);

   WriteLn('                          r = ', d1Str, ' AU');

   if not geoz then

      begin

      WriteLn;

      WriteLn('Observation 2:');

      WriteLn('--------------');

      WriteLn('UT: ', Ut2Str);

      Write(' geographic position:');

      Write(' latitude = ', lat2Str, ',');

      WriteLn(' longitude = ', long2Str, ',');

      WriteLn(' height = ', h1Str);

      Write('topocentric position:');

      Write  (' alpha = ', alpha21Str, ',');

      WriteLn(' delta = ', delta21Str);

      Write(' geocentric position:');

      Write  (' alpha = ', alpha2Str, ',');

      WriteLn(' delta = ', delta2Str);

      WriteLn('                          r = ', d2Str, ' AU');

      end;

   WriteLn;

   WriteLn('angle of parallax: ', dist/deg*3600.0:6:3, '"');

   WriteLn('calculated parallax of the sun: ', parallaxe/deg*3600.0:6:3, '"');

   WriteLn('=======================================');

   WriteLn('minimal distance of the lines of view:', dmin:6:3, ' rE');

   WriteLn; WriteLn;

   Write('                           once more (y/n) ? '); ReadLn(key);

   end;



begin                                                      (* main program: *)

initialisation;

repeat

   input;

   calculation(dist, parallaxe, dmin);

   output(key);

until key='n';

end.