home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / GRAPHICS / MISC / WORLD10.ZIP / WORLDMAP.TXT < prev   
Encoding:
Text File  |  1987-12-06  |  30.5 KB  |  988 lines

  1.  
  2.  
  3. ==============================
  4.  
  5.           READ.ME
  6.  
  7. ==============================
  8.  
  9.  
  10. To use Cartog.pas with an EGA or Hercules board, you will need to use
  11. the following constants.
  12.  
  13.  
  14. EGA Constants:                Hercules Constants:
  15.  
  16. CONST XCENTER = 320;          CONST XCENTER = 360;
  17.       YCENTER = 174;                YCENTER = 174;
  18.       ASPECT  = 1.37;               ASPECT  = 1.5;
  19.       R       = 70;                 R       = 70;
  20.  
  21. Also you will need a software driver for these boards.  For example, if
  22. you want to use Turbo Graphics Toolbox, you will need to make the
  23. following changes: The following three lines go at the top of the
  24. program, right after the line "Program Cartog;"
  25.  
  26. {$I Typedef.sys}
  27. {$I graphix.sys}
  28. {$I Kernel.sys}
  29.  
  30. replace "HiRes;  HiResColor(15);" with the following four lines:
  31.  
  32. Initgraphic;
  33. defineWorld(1,0,348,719,0);
  34. selectWorld(1);
  35. selectWindow(1);
  36.  
  37. Finally replace  TEXTMODE(BW80); with  Leavegraphic;                  
  38.  
  39.  
  40. ---------
  41. Setup for the plotter:
  42.  
  43. Our plots were made with a Hewlett-Packard 7475. A separate
  44. version of CARTOG was made to output to the plotter. The
  45. constants that we used were:
  46.  
  47. CONST XCENTER = 6.2; { Page center for B size plot }
  48.       YCENTER = 5.1;
  49.       ASPECT  = 1;  { Scale factors are the same in both axes    } 
  50.       R       = 1;  { Unit radius, scale in the plotting routine }
  51.  
  52. We also added a plotter initialization procedure:
  53.  
  54. PROCEDURE Initialize;
  55. { PLT is a text file containing the plotter commands. 
  56.   At the termination of this program, the file is copied to the
  57.   plotter 
  58. }
  59. BEGIN
  60.    WRITE(' ':13, 'Enter map size (A/B): '); READLN(SIZE);
  61.    SIZE:=UPCASE(SIZE);
  62.  
  63.    ASSIGN(PLT, 'WORLD.PLT');  REWRITE(PLT);
  64.  
  65.    WRITELN(PLT, 'IN;');  { Command to initialize plotter }
  66.  
  67.              { Set paper size and scaling points, so
  68.                plotter effectively works in inches
  69.                for B size plots and a little less for
  70.                A size plots }
  71.    IF SIZE = 'A' THEN
  72.     WRITELN(PLT,'PS4; IP 100,100,868,868;')
  73.    ELSE
  74.     WRITELN(PLT, 'PS0; IP 100,100,1124,1124;');
  75.    WRITELN(PLT, 'SC 0,1,0,1;');
  76.             { Set pen speed (slow) and select pen 3 } 
  77.    WRITELN(PLT, 'VS 4; SP 3;');
  78.  
  79. END;                    { Initialize. }
  80.  
  81. Finally, we substituted the following for PROCEDURE PlotPt:
  82.  
  83. PROCEDURE PlotPt(VAR LastPtVis: BOOLEAN);
  84. {  Draws a line from the last point to the current (XP,YP) if it
  85.    is visible. }
  86. BEGIN
  87.     IF LastPtVis THEN           { Pen down, go to XP, YP }
  88.      WRITELN(PLT, 'PD', XP:7:3, ',', YP:7:3,';')
  89.     ELSE                        { Pen up,   go to XP, YP }
  90.      WRITELN(PLT, 'PU' , XP:7:3, ',', YP:7:3,';');
  91.  
  92.     LastX:=; LastY:=YP;
  93.         LastPtVis:=TRUE;
  94. END; { PlotPt. }
  95.  
  96.  
  97.  
  98.  
  99. ==============================
  100.  
  101.           CARTOG.PAS
  102.  
  103. ==============================
  104.  
  105.  
  106. _______________________________________________________________________
  107.  
  108. CARTOG.PAS Accompanies "Mapping the World in Pascal" by Robert Miller and 
  109. Francis Reddy, BYTE, December 1987, page 329
  110. _______________________________________________________________________
  111.  
  112. PROGRAM Cartog;
  113. { This program plots geographic data from the file
  114.   WORLD.DAT and coordinate grids on the Mercator,
  115.   Equidistant Cylindrical, Sinusoidal, Hammer, and
  116.   Orthographic map projections.
  117. }
  118. CONST Sqrt2        = 1.4142135623731;
  119.       PI           = 3.1415926535898;
  120.       HalfPI       = 1.5707963267949;
  121.       TwoPI        = 6.2831853071796;
  122.       Radian       = 1.7453292519943E-2;
  123.       RadianDiv100 = 1.7453292519943E-4; { PI/180/100, needed to convert }
  124.                                          { data in WORLD.DAT to radians  }
  125.  
  126. CONST XCENTER    : INTEGER = 320;        { CGA Graphics constants.       }
  127.       YCENTER    : INTEGER =  99;        { Screen center X and Y         }
  128.       ASPECT     : REAL    = 2.4;        { 640x200 aspect ratio          }
  129.       R          : REAL    =  40;        { Default map radius            }
  130.       NotVisible : INTEGER = -32767;     { Flag for point visibility     }
  131.  
  132. TYPE  LLREC      = RECORD
  133.       CODE       : ARRAY[0..1] OF CHAR;
  134.       LONGI, LATI: INTEGER; END;
  135.  
  136. VAR   LL         : LLREC;
  137.       LLF        : FILE OF LLREC;
  138.  
  139. VAR   LastX, LastY, XP, YP    : INTEGER; { Save variables for plotting }
  140.       COLOR_GLB               : INTEGER;
  141.  
  142. VAR   I, J, K, MapType, M, X1,Y1,
  143.       X2, Y2, SX, SY, CENTER  : INTEGER;
  144.  
  145. VAR   L, L1, LONGR, LSTEP,
  146.       B, LATR, BSTEP, X, Y,
  147.       PHI1, Lambda0           : REAL;
  148.  
  149. VAR   XX, YY, SA, SB          : REAL;
  150.  
  151. VAR   LastPtVis, GRID         : BOOLEAN;
  152. VAR   CH                      : CHAR;
  153.  
  154. FUNCTION ArcCos(X: REAL): REAL;
  155. BEGIN
  156.     IF  ABS(X) < 1  THEN ArcCos:= ARCTAN(SQRT(1-SQR(X))/X)
  157.     ELSE  IF X = 1  THEN ArcCos:=  0
  158.     ELSE  IF X =-1  THEN ArcCos:= PI;
  159. END;   { ArcCos. }
  160.  
  161. FUNCTION ArcSin(X: REAL): REAL;
  162. BEGIN
  163.     IF ABS(X) < 1  THEN ArcSin:= ARCTAN(X/SQRT(1-SQR(X)))
  164.     ELSE IF X = 1  THEN ArcSin:= HalfPI
  165.     ELSE IF X =-1  THEN ArcSin:=-HalfPI;
  166. END;    { ArcSin. }
  167.  
  168. FUNCTION ArcTanH(X : Real):  Real;
  169. VAR A,T :  REAL;
  170. BEGIN
  171.     T:=ABS(X);
  172.     IF T < 1 THEN
  173.     BEGIN
  174.        A := 0.5 * LN((1 + T)/(1 - T));
  175.        IF X < 0 THEN ArcTanH := -A ELSE ArcTanH :=A;
  176.     END;
  177. END;  { ArcTanH. }
  178.  
  179. FUNCTION Meridian(Lambda, Lambda0: REAL):REAL;
  180. { Returns difference between current longitude and map center. }
  181. VAR DelLam : REAL;
  182. BEGIN
  183.     DelLam := Lambda - Lambda0;
  184.     IF DelLam < -PI THEN DelLam := DelLam + TwoPI
  185.     ELSE
  186.     IF DelLam >  PI THEN DelLam := DelLam - TwoPI;
  187.     Meridian:=DelLam;
  188. END;   { Meridian. }
  189.  
  190. PROCEDURE Mercator(Lambda, Lambda0, Phi, R : REAL; VAR X, Y : REAL);
  191. { For R = 1: -Pi <= X <= Pi, -Pi/2 <= Y <= Pi/2.  }
  192. CONST MaxLat : REAL = 1.397;   {~80 degrees. }
  193.      { REAL = 1.483;    ~85 degrees. }
  194. BEGIN
  195.     IF ABS(Phi) < MaxLat THEN
  196.     BEGIN
  197.        Lambda := Meridian(Lambda, Lambda0);
  198.        X := R * Lambda;
  199.        Y := R * ArcTanH(SIN(Phi));
  200.     END
  201.     ELSE X := NotVisible;
  202. END;   { Mercator. }
  203.  
  204. PROCEDURE EquiCyl(Lambda, Lambda0, Phi, Phi1, R : REAL; VAR X, Y : REAL);
  205. { For R = 1: -Pi <= X <= Pi, -Pi/2 <= Y <= Pi/2. }
  206. BEGIN
  207.     Lambda := Meridian(Lambda, Lambda0);
  208.     X := R * Lambda * COS(Phi1);
  209.     Y := R * Phi;
  210. END;   { EquiCyl. }
  211.  
  212. PROCEDURE Sinusoidal(Lambda, Lambda0, Phi, R : REAL; VAR X, Y : REAL);
  213. { For R = 1:  -Pi <= X <= Pi  and  -Pi/2 <= Y <= Pi/2. }
  214. BEGIN
  215.      Lambda := Meridian(Lambda, Lambda0);
  216.      X := R * Cos(Phi) * Lambda ;
  217.      Y := R * Phi;
  218. END;  { Sinusoidal. }
  219.  
  220. PROCEDURE Hammer(Lambda, Lambda0, Phi, R : REAL; VAR X, Y : REAL);
  221. { For R = 1: -2√2 <= X <=2√2  and  - √2 <= Y <= √2. }
  222. VAR K, CosPhi, HalfLambda        : REAL;
  223. BEGIN
  224.     HalfLambda := 0.5*Meridian(Lambda, Lambda0);
  225.     CosPhi:=COS(Phi);
  226.     K := R * SQRT2 / SQRT(1 +CosPhi * COS(HalfLambda));
  227.     X := 2 * K * CosPhi * (SIN(HalfLambda));
  228.     Y := K * SIN(Phi);
  229. END;  { Hammer. }
  230.  
  231. PROCEDURE Orthographic(Lambda, Lambda0, Phi, Phi1, R: REAL; VAR X, Y : REAL);
  232. { For R = 1: -2 <= X,Y <= 2. }
  233. VAR CosC, CosL, SinPhi1, CosPhi1, SinPhi, CosPhi, R2 :  Real;
  234. BEGIN
  235.     Lambda :=Meridian(Lambda, Lambda0);  R2:=R+R;
  236.     CosPhi1:=COS(Phi1);   SinPhi1:=SIN(Phi1);
  237.     CosPhi :=COS(Phi);    SinPhi:= SIN(Phi);
  238.     CosL   :=COS(Lambda)*CosPhi;
  239.     CosC   :=SinPhi1 * SinPhi + CosPhi1 * COSL;
  240.     IF CosC >= 0 THEN
  241.     BEGIN
  242.        X :=R2 * CosPhi * SIN(Lambda);
  243.        Y :=R2 * (CosPhi1 * SinPhi - SinPhi1 * COSL);
  244.     END ELSE X:=NotVisible;
  245. END;  { Orthographic. }
  246.  
  247. PROCEDURE Beep;
  248. { Sounds a tone when map is complete. }
  249. BEGIN
  250.     Sound(880);  Delay(250);  NoSound;
  251. END;
  252.  
  253. PROCEDURE PlotPt(VAR LastPtVis: BOOLEAN);
  254. { Draws a line from the last point to the current (XP,YP) if it is visible. }
  255. VAR IX,IY: INTEGER;
  256. LABEL XIT;
  257. BEGIN
  258.     IX:=ROUND(XP); IY:=ROUND(YP);
  259.     IF LastPtVis THEN DRAW(LastX,LastY,IX,IY,1);
  260.     LastX:=IX; LastY:=IY;
  261.     LastPtVis:=TRUE;
  262.   XIT:
  263. END; { PlotPt. }
  264.  
  265. PROCEDURE CoordinateGrid(OUTLINE: BOOLEAN; MapType: INTEGER);
  266. CONST LatitudeSpacing  = 30;
  267.       LongitudeSpacing = 30;
  268.  
  269. VAR Longitude, Latitude, LatLimit,
  270.     MaxLat, LongIncr, LatIncr      : INTEGER;
  271. VAR LL, PP, A, R2, RA, XN, YN,
  272.     SINDT, COSDT                   : REAL;
  273. BEGIN
  274.     CASE MapType OF
  275.        1: BEGIN   MaxLat:=80;  LongIncr:=360;  LatIncr:=160;    END;
  276.        2: BEGIN   MaxLat:=90;  LongIncr:=360;  LatIncr:=180;    END;
  277.        3: BEGIN   MaxLat:=90;  LongIncr:=360;  LatIncr:=5;      END;
  278.     4..5: BEGIN   Maxlat:=90;  LongIncr:=5;    LatIncr:=5;      END;
  279.     END;  { CASE...}
  280.  
  281.     LL:=0;  PP:=Phi1;
  282.     IF OUTLINE THEN
  283.     BEGIN
  284.         IF MapType = 5 THEN PP:=0;
  285.         LatLimit:=MaxLat;              { Draw only extreme latitudes }
  286.                                        { to make map outline         }
  287.     END
  288.     ELSE LatLimit:= MaxLat DIV LatitudeSpacing*LatitudeSpacing;
  289.  
  290.     Latitude:=LatLimit;
  291.  
  292.     WHILE Latitude >= -LatLimit DO      { Draw parallels }
  293.     BEGIN
  294.        LATR:=Latitude*Radian;
  295.        LastPtVis:=FALSE;
  296.  
  297.        Longitude:=-180;
  298.        WHILE Longitude <= 180 DO
  299.        BEGIN
  300.           LONGR:=Longitude*Radian;
  301.  
  302.           CASE MapType OF
  303.           1: BEGIN MERCATOR(LONGR, LL, LATR, R, X, Y);      END;
  304.           2: BEGIN EQUICYL(LONGR, LL, LATR, PP, R, X, Y);   END;
  305.           3: BEGIN SINUSOIDAL(LONGR, LL, LATR, R, X, Y);    END;
  306.           4: BEGIN HAMMER(LONGR, LL, LATR, R, X, Y);        END;
  307.           5: BEGIN ORTHOGRAPHIC (LONGR, LL, LATR, PP, R, X, Y); END;
  308.           END;  { CASE...}
  309.  
  310.           IF X > -300 THEN
  311.           BEGIN
  312.              XP:=ROUND(X*ASPECT)+XCENTER;
  313.              YP:=YCENTER-ROUND(Y);
  314.              PlotPt(LastPtVis);
  315.           END ELSE LastPtVis:=FALSE;
  316.  
  317.           Longitude:=Longitude+LongIncr;
  318.        END;
  319.  
  320.        IF OUTLINE THEN
  321.             Latitude:=Latitude-2*MaxLat
  322.        ELSE
  323.             Latitude:=Latitude-LatitudeSpacing;
  324.        END;
  325.  
  326.        IF OUTLINE THEN LL:=0 ELSE LL:=Lambda0;
  327.  
  328.        Longitude:=-180;                   { Draw meridians }
  329.  
  330.        IF MapType >= 4 THEN MaxLat:=90;
  331.        WHILE Longitude <= 180 DO
  332.        BEGIN
  333.           LONGR:=Longitude*Radian;
  334.           LastPtVis:=FALSE;
  335.           Latitude:=MaxLat;
  336.           WHILE Latitude >= -MaxLat DO
  337.           BEGIN
  338.              LATR:=Latitude*Radian;
  339.  
  340.              CASE MapType OF
  341.              1: BEGIN MERCATOR(LONGR, LL, LATR, R, X, Y);      END;
  342.              2: BEGIN EQUICYL(LONGR, LL, LATR, PP, R, X, Y);   END;
  343.              3: BEGIN SINUSOIDAL(LONGR, LL, LATR, R, X, Y);    END;
  344.              4: BEGIN HAMMER(LONGR, LL, LATR, R, X, Y);        END;
  345.              5: BEGIN ORTHOGRAPHIC( LONGR, LL, LATR, PP, R, X, Y); END;
  346.              END;  { CASE...}
  347.  
  348.           IF X > -300 THEN
  349.           BEGIN
  350.              XP:=ROUND(X*ASPECT)+XCENTER;
  351.              YP:=YCENTER-ROUND(Y);
  352.              PlotPt(LastPtVis);
  353.           END ELSE LastPtVis:=FALSE;
  354.  
  355.           Latitude:=Latitude-LatIncr;
  356.      END;
  357.  
  358.      IF OUTLINE THEN
  359.           Longitude:=Longitude+360
  360.      ELSE
  361.           Longitude:=Longitude+LongitudeSpacing;
  362.  END;
  363.  
  364.  IF OUTLINE AND (MapType=5) THEN
  365.  BEGIN
  366.     A:=0;                           { Draw circular outline }
  367.     LastPtVis:=False;
  368.     R2:=R + R;
  369.     RA:= R2 * Aspect;
  370.     SINDT:= 0.05996400648;
  371.     COSDT:= 0.99820053993;
  372.     X:=1;   Y:=0;
  373.     XP:= ROUND(XCENTER + RA);
  374.     YP:= ROUND(YCENTER);
  375.     PlotPt(LastPtVis);
  376.     WHILE A <= TwoPI DO
  377.     BEGIN                           { Compute points on the circle }
  378.        XN:= X * COSDT - Y * SINDT;
  379.        YN:= X * SINDT + Y * COSDT;
  380.        X:= XN;  Y:= YN;
  381.        XP:= XCENTER + ROUND(X*RA);
  382.        YP:= YCENTER + ROUND(Y*R2);
  383.        PlotPt(LastPtVis);
  384.        A:= A+0.06;
  385.     END; { While. }
  386.   END;
  387. END;  { CoordinateGrid. }
  388.  
  389. PROCEDURE DrawMap(MapType: INTEGER);
  390. VAR Latitude, Longitude : REAL;
  391. VAR LastX : INTEGER;
  392. LABEL XIT;
  393. BEGIN
  394.     LastPtVis:=FALSE; LastX:=0;
  395.  
  396.     ASSIGN(LLF, 'WORLD.DAT');  RESET(LLF);
  397.     WHILE NOT EOF(LLF) DO
  398.     BEGIN
  399.        READ(LLF, LL);
  400.        IF KeyPressed THEN GOTO XIT;
  401.        LONGR:=LL.LONGI * RadianDiv100;
  402.        LATR :=LL.LATI  * RadianDiv100;
  403.  
  404.        IF LL.CODE = 'LS' THEN LastPtVis:=FALSE;
  405.        IF (LL.CODE = 'S ') OR (LL.CODE = 'LS') THEN
  406.        BEGIN
  407.           CASE MapType OF
  408.           1: BEGIN MERCATOR(LONGR, Lambda0, LATR, R, X, Y);      END;
  409.           2: BEGIN EQUICYL(LONGR, Lambda0, LATR, Phi1, R, X, Y); END;
  410.           3: BEGIN SINUSOIDAL(LONGR, Lambda0, LATR, R, X, Y);    END;
  411.           4: BEGIN HAMMER(LONGR, Lambda0, LATR, R, X, Y);        END;
  412.           5: BEGIN ORTHOGRAPHIC(LONGR, Lambda0, LATR, Phi1, R, X, Y);  END;
  413.           END;  { CASE...}
  414.  
  415.           IF X > -300 THEN
  416.           BEGIN
  417.              XP:=ROUND(X*ASPECT)+XCENTER;
  418.              IF ABS(LastX-XP) > 100 THEN LastPtVis:=FALSE;
  419.              YP:= YCENTER-ROUND(Y);
  420.              PlotPt(LastPtVis);  LastX:=XP;
  421.           END ELSE LastPtVis:=FALSE;
  422.        END;
  423.     END;
  424.  XIT:
  425. END;  { DrawMap. }
  426.  
  427. (* ---------------------  MAIN  PROGRAM  ------------------ *)
  428.  
  429. VAR RESP : CHAR;
  430. LABEL XIT;
  431. BEGIN
  432.     MapType:=1;
  433.     WHILE MapType > 0 DO      (*       MENU       *)
  434.     BEGIN
  435.         ClrScr;
  436.  
  437.         GOTOXY(24,1);  WRITE('C A R T O G');
  438.         LowVideo;
  439.         GOTOXY(1,24);
  440.         WRITE('':4,'Copyright 1987 by Robert Miller and Francis Reddy');
  441.         GOTOXY(1,3);
  442.         WRITELN(' ':4,'To PLOT:  Choose a projection.  Enter the Central ');
  443.         WRITELN(' ':4,'Meridian of the map (180 to -180 degrees, longitudes');
  444.         WRITELN(' ':4,'west of Greenwich negative). If applicable, enter');
  445.         WRITELN(' ':4,'the Standard Parallel (90 to -90 degrees, southern');
  446.         WRITELN(' ':4,'latitudes negative). The file WORLD.DAT must also be');
  447.         WRITELN(' ':4,'on the logged drive. A tone means the map is done.');
  448.         WRITELN;
  449.         WRITELN(' ':4,'Any key ABORTS plot.  Hit return to restore MENU.');
  450.         NormVideo;
  451.         WRITELN;
  452.         WRITELN;
  453.         WRITE(' ':6,'1. Mercator');
  454.         WRITELN(' ':21,'4. Hammer');
  455.         WRITE(' ':6,'2. Equidistant Cylindrical');
  456.         WRITELN(' ':6,'5. Orthographic');
  457.         WRITELN(' ':6,'3. Sinusoidal');
  458.         WRITELN;
  459.         WRITE(' ':8,'Projection number (1-5) or 0 to quit:   ');
  460.         READLN(MapType);
  461.         If MapType = 0 THEN GOTO XIT;
  462.  
  463.         WRITELN;
  464.         WRITE(' ':8,'Central Longitude of Map (default = 0): ');
  465.         Lambda0:=0;
  466.         READLN(Lambda0);  Lambda0:=Lambda0*Radian;
  467.  
  468.         IF (MapType = 2) OR (MapType = 5) THEN
  469.         BEGIN
  470.             WRITE(' ':8,'Central Latitude  of Map (default = 0): ');
  471.             Phi1:=0;  READLN(Phi1);
  472.             IF Phi1 = 90 THEN Phi1 := HalfPI
  473.             ELSE
  474.             Phi1:=Phi1*Radian;
  475.         END;
  476.  
  477.         IF MapType >= 4 THEN R:=83 ELSE R:=70;
  478.         WRITE(' ':8,'Plot grid, continents or both (G/C/B)?  ');
  479.         READLN(RESP);  RESP:=UPCASE(RESP);
  480.         GRID:=(RESP ='G') OR (RESP = 'B');
  481.  
  482.         HiRes;  HiResColor(15);            { Set CGA Graphics Mode }
  483.  
  484.         IF GRID THEN CoordinateGrid(FALSE,  MapType);
  485.         CoordinateGrid(TRUE, MapType);
  486.  
  487.         IF (RESP = 'B') OR (RESP = 'C') THEN DrawMap(MapType);
  488.       Beep;
  489.     XIT:
  490.  
  491.     IF MapType > 0 THEN
  492.        While NOT KeyPressed DO ;           { Wait for key strike }
  493.  
  494.     TEXTMODE(BW80);                        { Return to Text Mode }
  495.     ClrScr;
  496.     END;  { WHILE MapType > 0...}
  497. END.
  498.  
  499.  
  500.  
  501. ==============================
  502.  
  503.           CPLOT.PAS
  504.  
  505. ==============================
  506.  
  507.  
  508.  
  509. _______________________________________________________________________
  510.  
  511. CPLOT.PAS Accompanies "Mapping the World in Pascal" by Robert Miller and Francis Reddy, BYTE, December 1987, page 329
  512. _______________________________________________________________________
  513.  
  514. PROGRAM MapProjections;
  515. {  Map projection program for Hewlett-Packard 7475 plotter. }
  516. {$V-}
  517. CONST Sqrt2   = 1.4142135623710;
  518.       PI      = 3.141592653589793238;
  519.       HalfPI  = 1.570796326794897;
  520.       ThreePI2= 4.71238898038469;
  521.       TwoPI   = 6.283185307179587;
  522.       Degree  = 57.29577951308232088;
  523.       Radian  = 0.01745329251994329577;
  524.  
  525. CONST XCENTER : REAL    = 6.2;      { CGA Graphics constants. }
  526.       YCENTER : REAL    = 5.1;
  527.       ASPECT  : REAL    =   1;
  528.       R       : REAL    =   1;
  529.  
  530. TYPE  S80       = STRING[80];
  531. TYPE  LLREC     = RECORD
  532.       CODE        : ARRAY[0..1] OF CHAR;
  533.       LONGI, LATI : INTEGER; END;
  534.  
  535. VAR   LL         : LLREC;
  536.       LLF        : FILE OF LLREC;
  537.       PLT        : TEXT[$1000];
  538. VAR   FNAME      : STRING[64];
  539.  
  540. VAR   LastX, LastY, XP, YP  : REAL;  { Save variables for plotting. }
  541.       COLOR_GLB, IPEN       : INTEGER;
  542.       SIZE                  : CHAR;
  543.  
  544. VAR   I, J, K, MapType, M, X1,Y1, X2, Y2,
  545.       SX, SY, CENTER        : INTEGER;
  546.  
  547. VAR   L, L1, LONGR, LSTEP,
  548.       B, LATR, BSTEP, X, Y,
  549.       PHI1, Lambda0         : REAL;
  550.  
  551. VAR XX, YY, SA, SB          : REAL;
  552.  
  553. VAR   LastPtVis, GRID       : BOOLEAN;
  554. VAR   CH                    : CHAR;
  555.  
  556. PROCEDURE Initialize;
  557. BEGIN
  558.     WRITE(' ':13, 'Enter map size (A/B): '); READLN(SIZE);
  559.     SIZE:=UPCASE(SIZE);;
  560.  
  561.     ASSIGN(PLT, 'WORLD.PLT');  REWRITE(PLT);
  562.     WRITELN(PLT, 'IN;');
  563.     IF SIZE = 'A' THEN WRITELN(PLT,'PS4; IP 100,100,868,868;')
  564.     ELSE  WRITELN(PLT, 'PS0; IP 100,100,1124,1124;');
  565.     WRITELN(PLT, 'SC 0,1,0,1;');
  566.     WRITELN(PLT, 'VS 4; SP 3;');
  567. END;  { Initialize. }
  568.  
  569. PROCEDURE LabelMap(MapType : INTEGER);
  570. VAR TITLE  : STRING[80];
  571. VAR XT, YT : REAL;
  572. BEGIN
  573.      CASE MapType OF
  574.      1: BEGIN TITLE:='Mercator';                  END;
  575.      2: BEGIN TITLE:='Equidistant Cylindrical';   END;
  576.      3: BEGIN TITLE:='Miller';                    END;
  577.      4: BEGIN TITLE:='Sinusoidal';                END;
  578.      5: BEGIN TITLE:='Hammer';                    END;
  579.      6: BEGIN TITLE:='Orthographic' ;             END;
  580.      7: BEGIN TITLE:='Stereographic';             END;
  581.      END;
  582.  
  583.      TITLE:=TITLE + ' Map Projection';
  584.      IF SIZE = 'A' THEN XT:=12.38
  585.      ELSE XT:= 14;
  586.      YT:= YCENTER-4.5;
  587.      WRITELN(PLT, 'DI 0,1; SR 18,18; PU',XT:7:2, ',', YT:7:2);
  588.      WRITELN(PLT, 'LB' + TITLE + CHR(3)+';');
  589.  
  590.      XT:=XT +0.24;
  591.      WRITELN(PLT, 'PU ',XT:7:2, ',', YT:7:2, '; SR 14,14;');
  592.      WRITELN(PLT, 'LBCentral Meridian ',ROUND(Lambda0*Degree):4,
  593.                   ' degrees'+CHR(3)+';');
  594.  
  595.      IF (MapType = 2) OR (MapType = 6) OR (MapType = 7) THEN
  596.      BEGIN
  597.          XT:=XT +0.24;
  598.          WRITELN(PLT, 'PU ',XT:7:2, ',', YT:7:2, ';');
  599.          WRITELN(PLT, 'LBCentral Latitude ',ROUND(Phi1*Degree):4,
  600.                       ' degrees'+CHR(3)+';');
  601.      END;
  602.  
  603.      XT:=XT +0.24;
  604.      WRITELN(PLT, 'SR 10,10; PU', XT:7:2 ,',', YT:7:2,';');
  605.      WRITELN(PLT, 'LBRobert D. Miller, 1986.' +CHR(3)+';');
  606. END;  { LabelMap. }
  607.  
  608. FUNCTION ArcCos(X: REAL): REAL;
  609. BEGIN
  610.     IF  ABS(X) < 1  THEN ArcCos:= ARCTAN(SQRT(1-SQR(X))/X)
  611.     ELSE  IF X = 1  THEN ArcCos:=  0
  612.     ELSE  IF X =-1  THEN ArcCos:= PI;
  613. END;   { ArcCos. }
  614.  
  615. FUNCTION ArcSin(X: REAL): REAL;
  616. BEGIN
  617.     IF ABS(X) < 1  THEN ArcSin:= ARCTAN(X/SQRT(1-SQR(X)))
  618.     ELSE IF X = 1  THEN ArcSin:= HalfPI
  619.     ELSE IF X =-1  THEN ArcSin:=-HalfPI;
  620. END;    { ArcSin. }
  621.  
  622. FUNCTION ArcTanH(TERM : Real):  Real;   (* Inverse hyperbolic tangent *)
  623. VAR A,T :  real;
  624. BEGIN
  625.     T:=ABS(TERM);
  626.     IF T < 1 THEN
  627.     BEGIN
  628.         A := 0.5 * LN((1 +T)/(1 -T));
  629.         IF TERM < 0 THEN ArcTanH := -A ELSE ArcTanH :=A;
  630.     END;
  631. END;  { ArcTanH. }
  632.  
  633. (*
  634.         Map Projection Library
  635.         by Robert Miller and Francis Reddy, 20 October 1986.
  636.         The following routines are based on equations found
  637.         in the U.S. Geological Survey's Bulletin 1532,
  638.         "Map Projections Used by the U.S. Geological Survey"
  639.         by John P. Snyder and "Introduction to Map Projections"
  640.         by Porter McDonnell, Jr.
  641. *)
  642. FUNCTION Meridian(Lambda, Lambda0: REAL):REAL;
  643. { Returns difference between current longitude and map center. }
  644. VAR DelLam : REAL;
  645. BEGIN
  646.     DelLam := Lambda - Lambda0;
  647.     IF DelLam < -PI THEN DelLam := DelLam + TwoPi
  648.     ELSE
  649.     IF DelLam >  PI THEN DelLam := DelLam - TwoPi;
  650.     Meridian:=DelLam;
  651. END;   { Meridian. }
  652.  
  653. PROCEDURE Mercator(Lambda, Lambda0, Phi, R : REAL; VAR X, Y : REAL);
  654. {  For R = 1: -Pi <= X <= Pi, -Pi/2 <= Y <= Pi/2.  }
  655. CONST MaxLat : REAL = 1.397;   {~80 degrees. }
  656.              { REAL = 1.483;    ~85 degrees. }
  657. BEGIN
  658.     IF ABS(Phi) < MaxLat THEN
  659.     BEGIN
  660.         Lambda := Meridian(Lambda, Lambda0);
  661.         X := R * Lambda;
  662.         Y := R * ArcTanH(SIN(Phi));
  663.     END
  664.     ELSE X := -32767;
  665. END;   { Mercator. }
  666.  
  667. PROCEDURE EquiCyl(Lambda, Lambda0, Phi, Phi1, R : REAL; VAR X, Y : REAL);
  668. {  For R = 1: -Pi <= X <= Pi, -Pi/2 <= Y <= Pi/2. }
  669. BEGIN
  670.     Lambda := Meridian(Lambda, Lambda0);
  671.     X := R * Lambda * COS(Phi1);
  672.     Y := R * Phi;
  673. END;   { EquiCyl. }
  674.  
  675. PROCEDURE Miller(Lambda, Lambda0, Phi, R : REAL; VAR X, Y : REAL);
  676. { For R = 1: -Pi <= X <= Pi, -Pi/2 <= Y <= Pi/2. }
  677. BEGIN
  678.      Lambda := Meridian(Lambda, Lambda0);
  679.      X := R * Lambda;
  680.      Y := R * ArcTanH(SIN(0.8 * Phi)) * 1.25;
  681. END;   { Miller. }
  682.  
  683. PROCEDURE Sinusoidal(Lambda, Lambda0, Phi, R : REAL; VAR X, Y : REAL);
  684. { For R = 1:  -Pi <= X <= Pi  and  -Pi/2 <= Y <= Pi/2. }
  685. BEGIN
  686.      Lambda := Meridian(Lambda, Lambda0);
  687.      X := R * Cos(Phi) * Lambda ;
  688.      Y := R * Phi;
  689. END;  { Sinusoidal. }
  690.  
  691. PROCEDURE Hammer(Lambda, Lambda0, Phi, R : REAL; VAR X, Y : REAL);
  692. {  For R = 1: -2√2 <= X <=2√2  and  -√2 <= Y <= √2. }
  693. VAR K, CosPhi, HalfLambda        : REAL;
  694. BEGIN
  695.     HalfLambda := 0.5*Meridian(Lambda, Lambda0);
  696.     CosPhi:=COS(Phi);
  697.     K := R * SQRT2 / SQRT(1 +CosPhi * COS(HalfLambda));
  698.     X := 2 * K * CosPhi * (SIN(HalfLambda));
  699.     Y := K * SIN(Phi);
  700. END;  { Hammer. }
  701.  
  702. PROCEDURE Orthographic(Lambda, Lambda0, Phi, Phi1, R: REAL; VAR X, Y : REAL);
  703. {  For unit radius R of generating globe, R = 1,  -2 <= X,Y <= 2. }
  704. VAR CosC, CosL, SinPhi1, CosPhi1, SinPhi, CosPhi, R2 :  Real;
  705. BEGIN
  706.     Lambda :=Meridian(Lambda, Lambda0);  R2:=R+R;
  707.     CosPhi1:=COS(Phi1);   SinPhi1:=SIN(Phi1);
  708.     CosPhi :=COS(Phi);    SinPhi:= SIN(Phi);
  709.     CosL   :=COS(Lambda)*CosPhi;
  710.     CosC   :=SinPhi1 * SinPhi + CosPhi1 * COSL;
  711.     IF CosC >= 0 THEN
  712.     BEGIN
  713.         X :=R2 * CosPhi * SIN(Lambda);
  714.         Y :=R2 * (CosPhi1 * SinPhi - SinPhi1 * COSL);
  715.     END ELSE X:=-32767;
  716. END;  { Orthographic. }
  717.  
  718. PROCEDURE Stereographic(Lambda, Lambda0, Phi, Phi1, R : REAL; VAR X, Y :REAL);
  719. {  For R = 1, -2 <= X,Y <= 2. }
  720. VAR K, CosC, CosL, CosPhi, SinPhi, SinPhi1, CosPhi1  : Real;
  721. BEGIN
  722.     Lambda :=Meridian(Lambda, Lambda0);
  723.     IF (Lambda <> Lambda0 + TwoPi) OR (Lambda <> Lambda0-TwoPi) THEN
  724.     BEGIN
  725.         SinPhi:= SIN(Phi);    CosPhi:= COS(Phi);
  726.         SinPhi1:=SIN(Phi1);   CosPhi1:=COS(Phi1);
  727.         CosL:=COS(Lambda) * CosPhi;
  728.         CosC :=SinPhi1 * SinPhi + CosPhi1 * COSL;
  729.         IF CosC >= 0 THEN
  730.         BEGIN
  731.             K := R * 2 / (1 + CosC);
  732.             X := K * CosPhi * SIN(Lambda);
  733.             Y := K * (CosPhi1 * SinPhi - SinPhi1 * COSL) ;
  734.         END
  735.         ELSE X:=-32767;
  736.     END;
  737. END;  { Stereographic. }
  738.  
  739. PROCEDURE PlotPt(VAR LastPtVis: BOOLEAN);
  740. {   Draws a line from the last point to the current (XP,YP) if it is visible. }
  741. LABEL XIT;
  742. BEGIN
  743.     IF LastPtVis THEN  WRITELN(PLT, 'PD',XP:7:3, ',', YP:7:3,';')
  744.     ELSE WRITELN(PLT, 'PU',XP:7:3, ',', YP:7:3,';');
  745.     LastX:=XP; LastY:=YP; LastPtVis:=TRUE;
  746.   XIT:
  747. END; { PlotPt. }
  748.  
  749. PROCEDURE CoordinateGrid(OUTLINE: BOOLEAN; MapType: INTEGER);
  750. VAR Longitude, Latitude, MaxLat, LongIncr, LatIncr : INTEGER;
  751. VAR LL, PP, A, RA, R2   : REAL;
  752. VAR X, Y, XN, YN, SINDT, COSDT  : REAL;
  753. BEGIN
  754.     CASE MapType OF
  755.        1: BEGIN   MaxLat:=75;  LongIncr:=360;  LatIncr:=160;    END;
  756.        2: BEGIN   MaxLat:=90;  LongIncr:=360;  LatIncr:=180;    END;
  757.        3: BEGIN   MaxLat:=90;  LongIncr:=360;  LatIncr:=5;      END;
  758.     4..5: BEGIN   MaxLat:=75;  LongIncr:=5;    LatIncr:=5;      END;
  759.     END;  { CASE...}
  760.  
  761.     LL:=0;  PP:=Phi1;
  762.     IF OUTLINE THEN
  763.     BEGIN IF MapType >  1 THEN MaxLat:=90
  764.           ELSE MaxLat:=80;
  765.           IF MapType >= 5 THEN PP:=0;
  766.     END;
  767.  
  768.     Latitude:=MaxLat;
  769.  
  770.     WHILE Latitude >= -MaxLat DO       { Draw parallels }
  771.     BEGIN
  772.         LATR:=Latitude*Radian;
  773.         LastPtVis:=FALSE;
  774.  
  775.         Longitude:=-180;
  776.         WHILE Longitude <= 180 DO
  777.         BEGIN
  778.             LONGR:=Longitude*Radian;
  779.  
  780.             CASE MapType OF
  781.             1: BEGIN MERCATOR(LONGR, LL, LATR, R, X, Y);      END;
  782.             2: BEGIN EQUICYL(LONGR, LL, LATR, PP, R, X, Y);   END;
  783.             3: BEGIN MILLER(LONGR, LL, LATR, R, X, Y);        END;
  784.             4: BEGIN SINUSOIDAL(LONGR, LL, LATR, R, X, Y);    END;
  785.             5: BEGIN HAMMER(LONGR, LL, LATR, R, X, Y);        END;
  786.             6: BEGIN ORTHOGRAPHIC( LONGR, LL, LATR, PP, R, X, Y); END;
  787.             7: BEGIN STEREOGRAPHIC(LONGR, LL, LATR, PP, R, X, Y); END;
  788.             END;  { CASE...}
  789.  
  790.             IF X > -300 THEN
  791.             BEGIN
  792.                 XP:=X+XCENTER;
  793.                 YP:=Y+YCENTER;
  794.                 PlotPt(LastPtVis);
  795.             END ELSE LastPtVis:=FALSE;
  796.  
  797.             Longitude:=Longitude+LongIncr;
  798.         END;
  799.  
  800.         IF OUTLINE THEN Latitude:=Latitude-2*MaxLat
  801.         ELSE Latitude:=Latitude-15;    { Latitude:=Latitude-10; }
  802.     END;
  803.  
  804.     IF OUTLINE THEN LL:=0 ELSE LL:=Lambda0;
  805.  
  806.     Longitude:=-180;                   { Draw meridians }
  807.     IF OUTLINE AND (MapType > 5) THEN Longitude:=-90;
  808.  
  809.     IF MapType >= 4 THEN MaxLat:=90;
  810.     WHILE Longitude <= 180 DO
  811.     BEGIN
  812.         LONGR:=Longitude*Radian;
  813.         LastPtVis:=FALSE;
  814.         Latitude:=MaxLat;
  815.         WHILE Latitude >= -MaxLat DO
  816.         BEGIN
  817.             LATR:=Latitude*Radian;
  818.  
  819.             CASE MapType OF
  820.             1: BEGIN MERCATOR(LONGR, LL, LATR, R, X, Y);      END;
  821.             2: BEGIN EQUICYL(LONGR, LL, LATR, PP, R, X, Y);   END;
  822.             3: BEGIN MILLER(LONGR, LL, LATR, R, X, Y);        END;
  823.             4: BEGIN SINUSOIDAL(LONGR, LL, LATR, R, X, Y);    END;
  824.             5: BEGIN HAMMER(LONGR, LL, LATR, R, X, Y);        END;
  825.             6: BEGIN ORTHOGRAPHIC( LONGR, LL, LATR, PP, R, X, Y); END;
  826.             7: BEGIN STEREOGRAPHIC(LONGR, LL, LATR, PP, R, X, Y); END;
  827.             END;  { CASE...}
  828.  
  829.             IF X > -300 THEN
  830.             BEGIN
  831.                 XP:=X+XCENTER;
  832.                 YP:=Y+YCENTER;
  833.                 PlotPt(LastPtVis);
  834.             END ELSE LastPtVis:=FALSE;
  835.  
  836.             Latitude:=Latitude-LatIncr;
  837.         END;
  838.  
  839.         IF OUTLINE THEN
  840.             IF MapType <= 5 THEN Longitude:=Longitude+360
  841.             ELSE
  842.             Longitude:=Longitude+180
  843.         ELSE Longitude:=Longitude+15;
  844.     END;
  845.  
  846.     IF NOT OUTLINE AND (MapType = 6) THEN { Draw circular outline. }
  847.     BEGIN
  848.         A:=0;     LastPtVis:=FALSE;
  849.         R2:=R+R;  RA:=R2*Aspect;
  850.         SINDT:=0.05996400648;
  851.         COSDT:=0.99820053993;
  852.  
  853.         X:=1;  Y:=0;
  854.         XP:=ROUND(XCENTER+RA);  YP:=ROUND(YCENTER);
  855.         PlotPt(LastPtVis);
  856.  
  857.         WHILE A <= 6.28318 DO
  858.         BEGIN
  859.             XN:= X*COSDT - Y*SINDT;
  860.             YN:= X*SINDT + Y*COSDT;
  861.             X:=XN;  Y:=YN;
  862.             XP:=XCENTER + ROUND(X*RA);  YP:=YCENTER + ROUND(Y*R2);
  863.             PlotPt(LastPtVis);
  864.             A:=A+0.06;
  865.         END;
  866.     END;
  867. END;  { CoordinateGrid. }
  868.  
  869. PROCEDURE DrawMap(MapType: INTEGER);
  870. VAR Latitude, Longitude : REAL;
  871. VAR LastX : REAL;
  872. BEGIN
  873.     LastPtVis:=FALSE;  LastX:=0;  LastY:=0;
  874.  
  875.     IF Fname = '' THEN
  876.     ASSIGN(LLF, 'EARTH.LAT')
  877.     ELSE ASSIGN(LLF, Fname);
  878.  
  879.     RESET(LLF);
  880.  
  881.     WHILE NOT EOF(LLF) DO
  882.     BEGIN
  883.         READ(LLF, LL);
  884.         LONGR:=LL.LONGI* 1.745329251994329577E-4;
  885.         LATR :=LL.LATI * 1.745329251994329577E-4;
  886.  
  887.         IF LL.CODE = 'LS' THEN LastPtVis:=FALSE;
  888.         IF (LL.CODE = 'S ') OR (LL.CODE = 'LS') THEN
  889.         BEGIN
  890.             CASE MapType OF
  891.             1: BEGIN MERCATOR(LONGR, Lambda0, LATR, R, X, Y);      END;
  892.             2: BEGIN EQUICYL(LONGR, Lambda0, LATR, Phi1, R, X, Y); END;
  893.             3: BEGIN MILLER(LONGR, Lambda0, LATR, R, X, Y);        END;
  894.             4: BEGIN SINUSOIDAL(LONGR, Lambda0, LATR, R, X, Y);    END;
  895.             5: BEGIN HAMMER(LONGR, Lambda0, LATR, R, X, Y);        END;
  896.             6: BEGIN ORTHOGRAPHIC(LONGR, Lambda0, LATR, Phi1, R, X, Y);  END;
  897.             7: BEGIN STEREOGRAPHIC(LONGR, Lambda0, LATR, Phi1, R, X, Y); END;
  898.             END;  { CASE...}
  899.  
  900.              IF X > -300 THEN
  901.              BEGIN
  902.                  XP:=X+XCENTER;
  903.                  IF ABS(LastX-XP) > 0.4 THEN LastPtVis:=FALSE;
  904.                  YP:=Y+YCENTER;
  905.                  PlotPt(LastPtVis);  LastX:=XP;
  906.               END ELSE LastPtVis:=FALSE;
  907.         END;
  908.     END;
  909. END;  { DrawMap. }
  910.  
  911. (* ---------------------  MAIN  PROGRAM  ------------------ *)
  912. VAR RESP : CHAR;
  913. LABEL XIT;
  914. BEGIN
  915.     LastPtVis:=FALSE;  LastX:=0;  LastY:=0;  IPEN:=-1;
  916.     MapType:=1;
  917.     Fname:='';
  918.     Fname:='WORLD4.DAT';
  919.  
  920. (*                             MENU                                  *)
  921.     WHILE MapType > 0 DO
  922.     BEGIN
  923.         ClrScr;
  924.  
  925.         GOTOXY(30,1);  WRITE('GLOBE MAP PROJECTIONS');
  926.         GOTOXY(32,3);  WRITELN('SELECT PARAMETERS');
  927.  
  928.         WRITELN;
  929.         WRITELN(' ':10,'1. Mercator');
  930.         WRITELN(' ':10,'2. Equidistant Cylindrical');
  931.         WRITELN(' ':10,'3. Miller Cylindrical');
  932.         WRITELN(' ':10,'4. Sinusoidal');
  933.         WRITELN(' ':10,'5. Hammer-Aitoff');
  934.         WRITELN(' ':10,'6. Orthographic');
  935.         WRITELN(' ':10,'7. Stereographic');
  936.  
  937.         WRITELN;
  938.         WRITE(' ':13,'Projection number (1-7) or 0 to quit: ');
  939.         READLN(MapType);
  940.         If MapType = 0 THEN GOTO XIT;
  941.  
  942.         CASE MapType OF
  943.         1: BEGIN R:=1.82;   END;
  944.         2: BEGIN R:=1.82;   END;
  945.         3: BEGIN R:=1.82;   END;
  946.         4: BEGIN R:=1.82;   END;
  947.         5: BEGIN R:=2.04;   END;
  948.         6: BEGIN R:=2.18;   END;
  949.         7: BEGIN R:=2.18;   END;
  950.         END;
  951.  
  952.         WRITELN;
  953.         WRITE(' ':13,'Central Longitude of Map (degrees, default = 0): ');
  954.         Lambda0:=0;
  955.         READLN(Lambda0);  Lambda0:=Lambda0*Radian;
  956.  
  957.         IF (MapType = 2) OR (MapType = 6) OR (MapType = 7) THEN
  958.         BEGIN
  959.             WRITE(' ':13,'Central Latitude  of Map (degrees, -90 - 90): ');
  960.             Phi1:=0;  READLN(Phi1);  Phi1:=Phi1*Radian;
  961.         END;
  962.  
  963.         WRITE(' ':13, 'Plot grid, continents or both (G/C/B)? ');
  964.         READLN(RESP); RESP:=UPCASE(RESP);
  965.         GRID:=(RESP ='G') OR (RESP = 'B');
  966.  
  967.         Initialize;
  968.  
  969.         IF GRID THEN
  970.         BEGIN
  971.             WRITELN(PLT,'SP 2;');
  972.             CoordinateGrid(FALSE,  MapType);
  973.         END;
  974.  
  975.         WRITELN(PLT,'SP 3;');
  976.         CoordinateGrid(TRUE, MapType);
  977.  
  978.         WRITELN(PLT, 'SP 1');
  979.         IF (RESP = 'B') OR (RESP = 'C') THEN DrawMap(MapType);
  980.  
  981.      {  LabelMap(MapType);  }
  982.  
  983.      WRITELN(PLT, 'PU 0,0; SP 0;');
  984.      CLOSE(PLT);
  985.   XIT:
  986.     END;  { WHILE MapType > 0...}
  987. END.
  988.