Contributor: ELLI LECHTMAN

{THIS PROGRAM SHOWS HOW YOU CAN CALCULATE THE 6 TRIG FUNCTIONS. I DID THIS
FOR A COMPUTER PROJECT AND THEREFORE PUT SOME GRAPHICS. THIS INCLUDES
A FADING UNIT FOR 640 X 480 X 16 COLOUR PCX FILES WHICH I CAN ALSO DISPLAY.
I HAVE CREATED A UNIT GAPP2 WHICH CONTAINS A LOT OF NEAT FUNCTIONS AND PROCS.

HAVE MANY OTHER NEAT GENERIC STUFF INCLUDING PLAYING HSC FILES IN BACKGROUND.
THIS IS AL DONE BY MYSELF ELLI LECHTMAN AND KEVIN EPSTEIN WHO IS AN EXPERT
DELPHI PROGRAMMER.

FOR MORE INTERESTING STUFF E - MAIL ME AT  ELLI@ICON.CO.ZA

ENJOY !!!!!}    





{$N+,E+,G+,F+,O+}
{$M 32768,0,655360}

{Compiler directives, are comments with a
          special syntax, and can be used wherever
          comments are allowed.}

PROGRAM Trig;
USES crt,graph,gapp2,screen_d;

{Constant used for the Do_Chan procedure which writes numbers next to the
graphic buttons.}

CONST Chan : ARRAY[1..7] OF Char = ('1','2','3','4','5','6','7');

{Variables used.}

VAR radians,cos_radians1,sIN_radians1,deg:real;
    place,i:INteger;

{Initializes Graphics mode.}

PROCEDURE DO_graph;
VAR gd,gm:INteger;
BEGIN
   gd:=detect;
   INitgraph(gd,gm,''); {Stick your bgi directory in here}
   IF GraphResult <> GrOk THEN
     BEGIN
          Clrscr;
          writeln('SomethINg wrong WITH Graphics');
          Writeln('Check INitlINe');
          Halt(1);
     END;
END;

{Function used to calculate n!.}

FUNCTION FacTOrial(number:INteger):extENDed;
VAR counter:INteger;
    TOtal:extENDed;
BEGIN
   TOtal:=1;
   counter:=0;
   FOR counter:=1 TO number DO TOtal:=TOtal*counter;
   FacTOrial:=TOtal;
END;

{Function used to calculate the the result of a base to the power.}

FUNCTION Exponent(base,power:real):extENDed;
VAR no,i:extENDed;
BEGIN
   no:=base;
   i:=1;
   WHILE i <= power-1 DO
   BEGIN
      no:=no * base;
      i:=i+1;
   END;
   Exponent:=no;
END;

{The Cos function.}

FUNCTION CosINe(rad:real;places:INteger):real;
VAR expo:INteger;
    str1,str2:STRING;
    Accurate:boolean;  {Accuracy to what user wants.}
    ans:real;
    j:INteger;
BEGIN
   expo:=2;
   ans:=1-(exponent(rad,expo)/facTOrial(expo));
   str(ans,str1);
   str1:=copy(str1,0,places+1);
   j:=1;
   Accurate:=false;
   WHILE NOT Accurate DO
   BEGIN
      INc(expo,2);
      IF j MOD 2 = 0 THEN ans:=ans- (exponent(rad,expo)/facTOrial(expo)) ELSE
                              ans:=ans + (exponent(rad,expo)/facTOrial(expo));
      INc(j);
      str(ans,str2);
      str2:=copy(str2,0,places+1);
      accurate:=str1=str2;
      str1:=str2;
      str2:='';
   END;
   cosINe:=ans;
END;

{The Sin Function}

FUNCTION sINe(rad:real;places:INteger):real;
VAR expo,j:INteger;
    str1,str2:STRING;
    Accurate:boolean;
    ans:real;
BEGIN
   expo:=3;
   j:=1;
   ans:=rad-(exponent(rad,expo)/facTOrial(expo));
   str(ans,str1);
   str1:=copy(str1,0,places+1);
   accurate:=false;
   WHILE NOT Accurate DO
   BEGIN
      INc(expo,2);
      IF j MOD 2 = 0 THEN ans:=ans- (exponent(rad,expo)/facTOrial(expo)) ELSE
                              ans:=ans + (exponent(rad,expo)/facTOrial(expo));
      INc(j);
      str(ans,str2);
      str2:=copy(str2,0,places+1);
      accurate:=str1=str2;
      str1:=str2;
      str2:='';
   END;
   sINe:=ans;
END;

{Reduction formulae for the Sin function. Used to deterimine which quadrant
the number is situated. Quadrant 1 is always positive.}

FUNCTION SINCheck(VAR num:real):real;
BEGIN
   IF (num<=180) AND (num>90) THEN num:=180-num ELSE {Quadrant 2}
   IF (num >180) AND (num<=270) THEN num:=-(num-180) ELSE {Quadrant 3}
   IF (num>270) AND (num<=360) THEN num:=-(360 -num); {Quadrant 4}
   SINcheck:=num;
END;

{Reduction formulae for the Cos Function. Same as Sin Function.}

FUNCTION CosCheck(VAR num:real):real;
BEGIN
   IF (num<=180) AND (num>90) THEN num:=-num ELSE {Quadrant 1}
   IF (num >180) AND (num<=270) THEN num:=-(180 - num)ELSE {Quadrant 2}
   IF (num > 270) AND (num <=360) THEN num:=360 - num; {Quadrant 3}
   CosCheck:=num;
END;

{Reduction formulae for Tan. As well as to check the different quadrants
of the individual Cos and Sin values.}

FUNCTION Tan_check(VAR num,sIN_radians,cos_radians:real):real;
BEGIN
   IF (num > 90) AND (num <=180) THEN num:=-(180-num); {Quadrant 2}
   IF (num >180) AND (num <=270) THEN num:=num-180; {Quadrant 3}
   IF (cos_radians >-1) AND (cos_radians < 1) AND
   (sIN_radians >=0) AND (sIN_radians<1) THEN
   Tan_check:=sINe(sIN_radians,place)/cosINe(cos_radians,place) ELSE
   IF (sIN_radians <0) OR (sIN_radians >1) AND (cos_radians<-1) OR (cos_radians>1)
   THEN BEGIN
           SINcheck(deg);
           sIN_radians:=(num*pi)/180;
           Coscheck(deg);
           cos_radians:=(num*pi)/180;
           Tan_check:=sINe(sIN_radians,place)/cosINe(cos_radians,place);
        END;
END;

{Function to convert a Real number to String. Works better than str and
is more easier in Assembler.}

FUNCTION RTOS( nNum: REAL; nLength, nDec: INTEGER ): STRING;
VAR
   s: ^STRING;
BEGIN
     ASM
          mov     sp, bp
          push    ss
          push    WORD PTR @RESULT
     END;
     STR( nNum:nLength:nDec, s^ );
END;

{Lets the user enter the degrees.}

PROCEDURE Write_degs(VAR degrees:real;VAR st:STRING);
VAR s:STRING;
    x,y,x1,y1,err:INteger;
BEGIN
   SETtextstyle(6,0,1);
   x:=30;
   x1:=30+120;
   y:=40;
   y1:=40 +120;
   SETcolOR(black);
   SETfillstyle(solidfill,blue);
   bar(x+550,y+225,x1-100,y1-20);
   frame(x+550,y+225,x1-100,y1-20,White,darkgray);
   Outtextxy(x+10,y+100,'   Please enter degrees : ');
   s:='';
   WHILE s = '' DO readlnxy(x+208,y+114,10,s,blue,white);
   st:=s;
   val(st,degrees,err);
END;

{Lets the user enter accuracy of decimal places.}

PROCEDURE Write_place(VAR deci:INteger);
VAR s:STRING;
    x,y,x1,y1,err:INteger;
BEGIN
     SETtextstyle(6,0,1);
     x:=30;
     x1:=30+120;
     y:=40;
     y1:=40 +120;
     SETcolOR(black);
     Outtextxy(x+23,y+135,' Please enter accuracy of decimal places : ');
     s:='';
     WHILE s = '' DO readlnxy(x+355,y+148,10,s,blue,white);
     val(s,deci,err);
END;

{Displays all the results of Sin Function.}

PROCEDURE DO_sINe;
VAR st,st2:STRING;
    x,y:INteger;
BEGIN
   x:=30;
   y:=40;
   st:='';
   SETtextstyle(6,0,1);
   write_degs(deg,st);
   write_place(place);
   radians:=(deg*pi)/180;
   SETcolOR(black);
   SETtextstyle(6,0,1);
   IF (radians >=0) AND (radians<1) THEN
   BEGIN
   Outtextxy(x+28,y+175,'The Sine of ');
   st:=st + 'ø';
   Outtextxy(x+120,y+175,st);
   Outtextxy(x+240,y+175,'is');
   SETcolOR(red);
   Outtextxy(x+220+50,y+175,rTOs(sINe(radians,place),5,place));
   END;
   IF (radians <0) OR (radians >1) THEN
   BEGIN
      SINcheck(deg);
      radians:=(deg*pi)/180;
      Outtextxy(x+28,y+175,'The Sine of ');
      st:=st + 'ø';
      Outtextxy(x+120,y+175,st);
      Outtextxy(x+240,y+175,'is');
      SETcolOR(red);
      Outtextxy(x+220+50,y+175,rTOs(sINe(radians,place),5,place));
   END;
   readln;
END;

{Same as Do_Sine but for Cos Function.}

PROCEDURE DO_Cos;
VAR st,st2:STRING;
    x,y:INteger;
BEGIN
   x:=30;
   y:=40;
   st:='';
   write_degs(deg,st);
   write_place(place);
   radians:=(deg*pi)/180;
   SETcolOR(black);
   SETtextstyle(6,0,1);
   IF (radians >-1) AND (radians < 1) THEN
   BEGIN
      Outtextxy(x+28,y+175,'The Cosine of ');
      st:=st + 'ø';
      Outtextxy(x+140,y+175,st);
      Outtextxy(x+240,y+175,'is');
      SETcolOR(red);
      Outtextxy(x+220+50,y+175,rTOs(cosINe(radians,place),5,place));
   END;
   IF (radians<-1) OR (radians>1) THEN
   BEGIN
      Coscheck(deg);
      radians:=(deg*pi)/180;
      Outtextxy(x+28,y+175,'The Cosine of ');
      st:=st + 'ø';
      Outtextxy(x+140,y+175,st);
      Outtextxy(x+240,y+175,'is');
      SETcolOR(red);
      Outtextxy(x+220+50,y+175,rTOs(cosINe(radians,place),5,place));
   END;
   readln;
END;

{Same as above}

PROCEDURE DO_Tan;
VAR x,y:INteger;
    st:STRING;
BEGIN
   x:=30;
   y:=40;
   st:='';
   write_degs(deg,st);
   SETtextstyle(6,0,1);
   {Due to assimptote situation.}
   IF (deg = 90) OR (deg = 270) OR (deg =450) OR (deg= 630) THEN
   Outtextxy(x+25,y+135,'Sorry, the result of this function is undefined !!!') ELSE
   BEGIN
      write_place(place);
      radians:=(deg*pi)/180;
      SETtextstyle(6,0,1);
      SETcolOR(black);
      cos_radians1:=(deg*pi)/180;
      sIN_radians1:=(deg*pi)/180;
      Outtextxy(x+28,y+175,'The Tan of ');
      st:=st + 'ø';
      Outtextxy(x+120,y+175,st);
      Outtextxy(x+240,y+175,'is');
      SETcolOR(red);
      Outtextxy(x+220+50,y+175,rTOs(tan_check(deg,sIN_radians1,cos_radians1),5,place));
   END;
   readln;
END;

{Inverse of Sin function. Cannot invert 0 so if answer is 0 then keep it.}

PROCEDURE DO_Cosec;
VAR st,st2:STRING;
    x,y:INteger;
BEGIN
   radians:=0;
   x:=30;
   y:=40;
   st:='';
   SETtextstyle(6,0,1);
   write_degs(deg,st);
   write_place(place);
   radians:=(deg*pi)/180;
   SETcolOR(black);
   SETtextstyle(6,0,1);
   IF (radians >=0) AND (radians<1) THEN
   BEGIN
     Outtextxy(x+28,y+175,'The Cosec of ');
     st:=st + 'ø';
     Outtextxy(x+136,y+175,st);
     Outtextxy(x+240+length(st)+20,y+175,'is');
     IF ((trunc(deg) MOD 360 = 0)) OR ((trunc(deg) MOD 360 = 180)) THEN
     BEGIN
       SETcolOR(red);
       Outtextxy(x+220+100,y+175,rTOs(sINe(radians,place),5,place));
     END;
     IF ((trunc(deg) MOD 360 <> 0)) OR ((trunc(deg) MOD 360 <> 180 )) THEN
     BEGIN
        SETcolOR(red);
        Outtextxy(x+220+100,y+175,rTOs(1/(sINe(radians,place)),5,place));
     END;
   END;
     IF (radians <0) OR (radians >1) THEN
     BEGIN
        SINcheck(deg);
        radians:=(deg*pi)/180;
        Outtextxy(x+28,y+175,'The Cosec of ');
        st:=st + 'ø';
        Outtextxy(x+136,y+175,st);
        Outtextxy(x+240+length(st)+20,y+175,'is');
        IF (trunc(deg) MOD 360 = 0) OR (trunc(deg) MOD 360 = 180) THEN
        BEGIN
          SETcolOR(red);
          Outtextxy(x+220+50,y+175,rTOs(sINe(radians,place),5,place));
        END;
        IF (trunc(deg) MOD 360 <> 0) OR (trunc(deg) MOD 360 = 180 ) THEN
        BEGIN
          SETcolOR(red);
          Outtextxy(x+220+50,y+175,rTOs(1/(sINe(radians,place)),5,place));
        END;
     END;
   readln;
END;

{Inverse of Cos Function.}

PROCEDURE DO_Sec;
VAR st,st2:STRING;
    x,y:INteger;
BEGIN
   radians:=0;
   x:=30;
   y:=40;
   st:='';
   SETtextstyle(6,0,1);
   write_degs(deg,st);
   write_place(place);
   radians:=(deg*pi)/180;
   SETcolOR(black);
   SETtextstyle(6,0,1);
   IF (radians >=0) AND (radians<1) THEN
   BEGIN
     Outtextxy(x+28,y+175,'The Sec of ');
     st:=st + 'ø';
     Outtextxy(x+116,y+175,st);
     Outtextxy(x+240,y+175,'is');
     IF ((trunc(deg) MOD 90 = 0)) OR ((trunc(deg) MOD 90 = 45)) THEN
     BEGIN
       SETcolOR(red);
       Outtextxy(x+220+50,y+175,rTOs(cosINe(radians,place),5,place));
     END;
     IF ((trunc(deg) MOD 90 <> 0)) OR ((trunc(deg) MOD 360 <> 45 )) THEN
     BEGIN
        SETcolOR(red);
        Outtextxy(x+220+50,y+175,rTOs(1/(cosINe(radians,place)),5,place));
     END;
   END;
     IF (radians <0) OR (radians >1) THEN
     BEGIN
        SINcheck(deg);
        radians:=(deg*pi)/180;
        Outtextxy(x+28,y+175,'The Sec of ');
        st:=st + 'ø';
        Outtextxy(x+116,y+175,st);
        Outtextxy(x+240,y+175,'is');
        IF (trunc(deg) MOD 90 = 0) OR (trunc(deg) MOD 90 = 45) THEN
        BEGIN
          SETcolOR(red);
           Outtextxy(x+220+50,y+175,rTOs(cosINe(radians,place),5,place));
        END;
        IF (trunc(deg) MOD 90 <> 0) OR (trunc(deg) MOD 90 = 45 ) THEN
        BEGIN
          SETcolOR(red);
          Outtextxy(x+220+50,y+175,rTOs(1/(cosINe(radians,place)),5,place));
        END;
     END;
   readln;
END;

{Inverse of Cot Function.}

PROCEDURE DO_Cot;
VAR x,y:INteger;
    st:STRING;
BEGIN
   x:=30;
   y:=40;
   st:='';
   write_degs(deg,st);
   SETtextstyle(6,0,1);
   IF (deg = 90) OR (deg = 270) OR (deg =450) OR (deg= 630) THEN
   Outtextxy(x+25,y+135,'Sorry, the result of this function is undefINed !!!') ELSE
   BEGIN
      write_place(place);
      radians:=(deg*pi)/180;
      SETtextstyle(6,0,1);
      SETcolOR(black);
      cos_radians1:=(deg*pi)/180;
      sIN_radians1:=(deg*pi)/180;
      Outtextxy(x+28,y+175,'The Cot of ');
      st:=st + 'ø';
      Outtextxy(x+120,y+175,st);
      Outtextxy(x+240,y+175,'is');
      IF (trunc(deg) MOD 180 = 0) THEN
      BEGIN
        SETcolOR(red);
        Outtextxy(x+220+50,y+175,rTOs(tan_check(deg,sIN_radians1,cos_radians1),5,place));
      END;
      IF (trunc(deg) MOD 180 <>0) THEN
      BEGIN
         SETcolOR(red);
        Outtextxy(x+220+50,y+175,rTOs(1/(tan_check(deg,sIN_radians1,cos_radians1)),5,place));
      END;
   END;
   readln;
END;

{Used to draw numbers next to a button to let user use program with keyboard
only.}

PROCEDURE DOChan(x,y : INteger;s : STRING);
BEGIN
     SETfillstyle(solidfill,black);
     Bar(x-2,y-2,x+25,y+25);
     Bar(x-2,y-2,x+25,y+25);
     Frame(x-2,y-2,x+25,y+25,White,darkgray);
     SETcolOR(White);
     SETtextstyle(6,0,2);
     Outtextxy(x+6,y-4,s);
END;

{Main menu. Loads a PCX file 640 X 480 X 16 dimensions. Then displays buttons.}

PROCEDURE Menu;
VAR i:INteger;
BEGIN
     Fadeout;
     readscr('background.pcx');
     DOButTOn(230,100,'Sin Function ');
     DOButTOn(230,100,'Sin Function ');
     DOButTOn(230,150,'Cos Function ');
     DObutTOn(230,200,'Tan Function');
     DOButTOn(230,250,'Cosec Function');
     DOButTOn(230,300,'Sec Function ');
     DOButTOn(230,350,'Cot Function ');
     DObutTOn(230,400,'Quit');
     ShowmousecursOR;
     FOR i := 1 TO 7 DO DOChan(180,50 + (i*50),Chan[i]);
     FadeIN;
END;

Procedure SetUpScreen;
Begin
     ClrScr;
     textcolor(blue);
     writeln;
     Writeln('                      Program written by Elli Lechtman         ');
     writeln;
     textcolor(lightred);
     Writeln('                                  STD 10 ');
     writeln('                          Sandringham High School');
     writeln('                                   1997');
     writeln;
     textcolor(lightblue);
     writeln('                                 Home Page');
     writeln('                    http://www.icon.co.za/~elli/welcome.htm');
     GotoXY (1,5);
     TextColor (yellow);
     GotoXY(21, 19);
     Writeln('This Program is Copyrighted by Elli Lechtman');
     GotoXY(13,21);
     Writeln('This Program is Public Domain as long as not sold for profit.');
End;

{This is where the user controls the Functions that he wants.}

PROCEDURE Menu_Screen;
VAR
   ch : Char;
   rep : INteger;
   quit:boolean;

   PROCEDURE Proc1;
   BEGIN
        Banimate(230,100,'Sin Function ');
        hidemousecursOR;
        DO_Sine;
        menu;
        showmousecursOR;
   END;

   PROCEDURE Proc2;
   BEGIN
        BAnimate(230,150,'Cos Function ');
        hidemousecursOR;
        DO_cos;
        menu;
        showmousecursOR;
   END;

   PROCEDURE Proc3;
   BEGIN
        Banimate(230,200,'Tan Function');
        hidemousecursOR;
        DO_tan;
        menu;
        showmousecursOR;
   END;

   PROCEDURE Proc4;
   BEGIN
        Banimate(230,250,'Cosec Function');
        hidemousecursOR;
        DO_cosec;
        menu;
        showmousecursOR;
   END;

   PROCEDURE proc5;
   BEGIN
       Banimate(230,300,'Sec Function ');
       hidemousecursOR;
       DO_sec;
       menu;
       showmousecursOR;
   END;

   PROCEDURE proc6;
   BEGIN
        Banimate(230,350,'Cot Function ');
        hidemousecursOR;
        DO_cot;
        menu;
        showmousecursOR;
   END;

   PROCEDURE MaINProc;
   BEGIN
     Quit := False;
     FOR i := 1 TO 6 DO DOChan(180,50 + (i*50),Chan[i]);
     REPEAT
           Ch := ' ';
           REPEAT
                 ShowmousecursOR;
                 IF Keypressed THEN Ch := readkey;
           UNTIL (GetbutTOnpressed = 1) OR (Ch <> ' ');
           IF (CButTOn(230,100,'Sin Function ') AND
           (getbutTOnpressed = 1))  OR (Ch = '1') THEN Proc1;
           IF (CbutTOn(230,150,'Cos Function ') AND
           (getbutTOnpressed = 1)) OR (Ch = '2') THEN Proc2;
           IF (CbutTOn(230,200,'Tan Function') AND
           (getbutTOnpressed = 1)) OR (Ch = '3') THEN Proc3;
           IF (CButTOn(230,250,'Cosec Function') AND
           (getbutTOnpressed = 1)) OR (Ch = '4') THEN Proc4;
           IF (CButTOn(230,300,'Sec Function') AND
           (getbutTOnpressed = 1)) OR (Ch = '5') THEN Proc5;
           IF (CButTOn(230,350,'Cot Function') AND
           (getbutTOnpressed = 1)) OR (Ch = '6') THEN Proc6;
           IF (CbutTOn(230,400,'Quit') AND (getbutTOnpressed = 1))
           OR (upCASE(Ch) = '7') THEN
           BEGIN
              quit:=true;
              Banimate(230,400,'Quit');
              fadeout;
              hidemousecursor;
              closegraph;
              fadein;
           END;
     UNTIL Quit;
END;
BEGIN
   maINproc;
END;

BEGIN
   radians:=0; {Initializes variables}
   deg:=0;
   place:=0;
   DO_graph;
   readscr('trig.pcx'); {Loads introductory PCX file}
   delay(3000);
   menu;
   menu_screen;
   restorecrtmode;
   SetUpScreen;
   readln;
END.