 /********************************************************************/
 /****                                                            ****/
 /****                                                            ****/
 /****    Program          : C-Plot.c                             ****/
 /****                                                            ****/
 /****    Version          :    03.71                             ****/
 /****                                                            ****/
 /****    Erstversion      : 14.08.1988                           ****/
 /****                                                            ****/
 /****    Letzte Änderung  : 09.08.1990                           ****/
 /****                                                            ****/
 /****    Compiliert mit   : siehe MAKEFILE                       ****/
 /****                                                            ****/
 /****    Gelinkt mit      : siehe MAKEFILE                       ****/
 /****                                                            ****/
 /********************************************************************/
 /****                                                            ****/
 /****                                                            ****/
 /****               Copyright by Rüdiger Dreier                  ****/
 /****                                                            ****/
 /****                                                            ****/
 /********************************************************************/
 
 /* Einbinden der Include-Files */
 
 #ifdef DEBUG
 #include <exec/types.h>
 #include <proto/tool.h>
 #include "Plotter.h"
 #endif
 #include <string.h>
 #include <devices/printer.h>
 #include <intuition/intuitionbase.h>
 #include <graphics/regions.h>
 #include <proto/mathieeedoubbas.h>
 #include <proto/mathieeedoubtrans.h>
 #include <proto/layers.h>
 #include <math.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <exec/memory.h>
 #include <exec/tasks.h>
 #include <libraries/dosextens.h>
 #include <dos.h>
 
 
 /* Variablendeklaration */
 BOOL KoordinatenKreuz_gezeichnet; /* Gibt an, ob Koordinatenkreuz neu gezeichnet werden muß   */
 int GE=1;                         /* Für die Genauigkeit der Zeichnung                        */
 int Groesse;
 
 APTR                  Konstantenstart; /* Zeiger auf die Konstanten  */
 struct Block          *StartBlock;     /* Zeiger auf ersten Block    */
 struct LayersBase     *LayersBase;
 struct ViewPort       *viep;           /* Zeiger auf ViewPort        */
 struct IntuitionBase  *IntuitionBase;  /* Zeiger auf IntuitionBase   */
 struct ToolBase       *ToolBase;
 struct Library        *MathIeeeDoubTransBase;
 struct Window         *Window;         /* Zeiger auf Fenster         */
 struct RastPort       *RastPort;       /* Zeiger auf RastPort        */
 struct Screen         *Screen;         /* Zeiger auf Screen          */
 struct GfxBase        *GfxBase;        /* Zeiger auf Grafik-Library  */
 struct View           *View;
 struct BitMap         bitmap;
 struct Layer          *layer;
 struct Layer_Info     *layerinfo;
 struct info           msgInfo;
 
 /* Strings */
 UBYTE undo1[20];                              /* Für Gadget, Intervall und Konstanten */
 UBYTE undoFormel[MAXCHARS];                   /* Für Gadget, Formeleingabe            */
 UBYTE xmpstring[20], xmnstring[20];           /* Strings für Intervall                */
 UBYTE ympstring[20], ymnstring[20];           /* Strings für Intervall                */
 UBYTE KonAString[20],KonBString[20];          /* Strings für Konstanten               */
 UBYTE KonCString[20],KonDString[20];          /* Strings für Konstanten               */
 UBYTE Formeln[11][MAXCHARS];                  /* Strings für Formeln                  */
 UBYTE Abgeleitet[2][MAXCHARS];                /* Strings für 1. und 2. Ableitung      */
 char  SubMenuTitle[10][16];                   /* Die Strings für die 10 SubItems      */
 
 SHORT XOffset,YOffset;
 
 /* Variablen, in denen wichtige Werte gespeichert werden                              */
 LONG   xx=609,yy=PLOT_Y;                         /* Punkte in x/y-Richtung               */
 double xmp,xmn,ymp,ymn;                       /* Intervallgrenzen                     */
 double x0,y0;                                 /* Position der Achsen                  */
 double xm,ym;                                 /* Maßstab für x/y-Achse                */
 
 /* Daten für Screen und Window */
 
 struct NewScreen Schirm=
  {
   0,0,640,YSCREEN,2,2,1,HIRES,CUSTOMSCREEN,NULL,"Plotter",NULL,NULL
  };
 
 struct NewWindow Fenster=
  {
   0,10,640,YSCREEN-10,FARBE0,FARBE1,MENUPICK|MOUSEBUTTONS|RAWKEY,
   BORDERLESS|ACTIVATE|REPORTMOUSE|SUPER_BITMAP,
   NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
   CUSTOMSCREEN
  };
 
 /* Hauptprogramm */
 
 VOID _main()
  {
   /* Einige Formeln vorschlagen */
   strcpy(Formeln[0],"sin(x)");
   strcpy(Formeln[1],"cos(x)");
   strcpy(Formeln[2],"tan(x)");
   strcpy(Formeln[3],"x^2");
   strcpy(Formeln[4],"x^3");
   strcpy(Formeln[5],"5*x");
   strcpy(Formeln[6],"x");
   strcpy(Formeln[7],"sqr(x)");
   strcpy(Formeln[8],"ln(x)");
   strcpy(Formeln[9],"log(x)");
   
   /* Intervall vorschlagen */
   strcpy(xmpstring,"pi");
   strcpy(xmnstring,"-pi");
   ympstring[0]='1';         /* global, NULL ist schon gesetzt */
   ymnstring[0]='-';
   ymnstring[1]='1';
   
   /* Konstanten vorschlagen */
   strcpy(KonAString,"-pi");
   strcpy(KonBString,"-pi");
   strcpy(KonCString,"-pi");
   strcpy(KonDString,"-pi");
   
   if(oeffne())                 /* Öffnen der Libraries, Screen, Fenster      */
    {
     LoadRGB4(viep,Farb2,4L);   /* Farben setzen                              */
     UpdateMenuText();          /* SubMenuText erneuern                       */
     UmwandlungInIntervall();   /* Intervallstrings in double umwandeln       */
     UmwandlungInKonstanten();  /* Konstantenstrings in double umwandeln      */
     MenuWahl();                /* Verwertet die Intuition-Messages           */
    }
   ende();                      /* Gibt den belegten Speicher wieder frei     */
  }
 
 
 /* Routine, die Punkt setzt. Parameter DOUBLE */
 VOID Pset(DOUBLE x1,DOUBLE y1)
  {
   Move(RastPort,Fix(Add(x1,RUNDEN))+Abstand,Fix(Add(y1,RUNDEN))+Abstand);
   Draw(RastPort,Fix(Add(x1,RUNDEN))+Abstand,Fix(Add(y1,RUNDEN))+Abstand);
  }
 
 /* Routine, die Linie zieht. Parameter DOUBLE */
 VOID DrawTo(DOUBLE x1,DOUBLE y1)
  {
   Draw(RastPort,Fix(Add(x1,RUNDEN))+Abstand,Fix(Add(y1,RUNDEN))+Abstand);
  }
 
 /* Zeichnet Linie von (x1,y1) - (x2,y2) Parameter : DOUBLE  */
 VOID Line(DOUBLE x1,DOUBLE y1,DOUBLE x2,DOUBLE y2)
  {
   /* Zum Anfang bewegen und Linie ziehen */
   Move(RastPort,Fix(Add(x1,RUNDEN))+Abstand,Fix(Add(y1,RUNDEN))+Abstand);
   Draw(RastPort,Fix(Add(x2,RUNDEN))+Abstand,Fix(Add(y2,RUNDEN))+Abstand);
  }
 
 /* Routine zum Beschriften des Koordinatenkreuzes */
 VOID zeichne(VOID)
  {
   char buffer[11];
   double i,dx,dy,x,y;
   char Zaehler;
   long xx,yy;
   
   SetDrMd(RastPort,JAM1);
   /* Bestimmt Abstand zwischen 2 Skalenunterteilungen */
   dx=Div(Sub(xmp,xmn),10.0);
   dy=Div(Sub(ymp,ymn),10.0);
   
   /* Zeichnet Unterteilung der Achsen */
   i=Sub(xmn,dx);
   yy=Fix(y0)+Abstand+12;
   for(Zaehler=0;Zaehler<=10;Zaehler++)
    {
     i=Add(i,dx);
     if(Cmp(Abs(i),Div(dx,1000.0))==-1)i=0.0000;
     x=Add(x0,Mul(i,xm));
     Line(x,Sub(y0,3.0),x,Add(y0,3.0));
     UmwFtoS(buffer,&i,2);
     xx=Fix(x)-(strlen(buffer)<<2)+Abstand;
     Print(RastPort,buffer,FARBE1,xx,yy);
    }
   
   
   i=Sub(ymn,dy);
   xx=Fix(x0)+Abstand+8;
   for(Zaehler=0;Zaehler<=10;Zaehler++)
    {
     i=Add(i,dy);
     if(Cmp(Abs(i),Div(dy,1000.0))==-1)i=0.0000;
     y=Sub(y0,Mul(i,ym));
     Line(Sub(x0,5.0),y,Add(x0,5.0),y);
     UmwFtoS(buffer,&i,2);
     yy=Fix(y)+Abstand+3;
     Print(RastPort,buffer,FARBE1,xx,yy);
    }
  }
 
 
 /* Wertet Mausklick aus */
 VOID MenuWahl(VOID)
  {
   struct MenuItem *Item;
   long menu,item;
   char ENDE=1;
   USHORT sub,menunr;
   
   while(ENDE)
    {
     /* Wartet auf Event */
     Wait(1L<<Window->UserPort->mp_SigBit);
     /* Arbeitet ab, bis keine Events mehr */
     while(EventAbfrage(Window,&msgInfo))
      {
       /* Verzweigt entsprechend der Events */
       switch(msgInfo.NachrichtenArt)
        {
         /* Menupunkt gewählt */
         case MENUPICK:
          {
           menunr=msgInfo.code;
           
           /* Wurde wirklich ein Menu gewählt ? */
           while(menunr!=MENUNULL)
            {
             /* Wenn ja, dann Menu-, Item- und SubItemNummer bestimmen */
             menu=MENUNUM(menunr);
             item=ITEMNUM(menunr);
             sub =SUBNUM (menunr);
             /* Entsprechend des Menus verzweigen */
             switch (menu)
              {
               case 0:
                {
                 /* Ein Punkt des ersten Menus wurde gewählt */
                 switch(item)
                  {
                   /* Entsprechend des Items verzweigen */
                   case 0:
                    {
                     /* Bestimmung der neuen Zeichengenauigkeit */
                     GE=sub;
                     break;
                    }
                   case 1:
                    {
                     /* Eingabe eines neuen Intervall */
                     do
                      {
                       TextFuerIntervall();     /* Gadget vorbereiten      */
                       /* */                    /* Grenzen abfragen        */
                       Grenzen(xmnstring,ymnstring,xmpstring,ympstring);
                       UmwandlungInIntervall(); /* Werte kopieren          */
                      }
                     while(Cmp(xmn,xmp)==1 || Cmp(ymn,ymp)==1);
                    }
                   case 2:
                    {
                     /* Schirm löschen */
                     /* Loeschen();    */
                     goto Einsprung_P2;
                    }
                   case 3:
                    {
                     /* Routine zum Drucken */
                     drucken();
                     /* Farben wieder zurücksetzen */
                     LoadRGB4(viep,Farb2,4L);
                     break;
                    }
                   case 4:
                    {
                     ULONG OldIDCMP;
                     if(KoordinatenKreuz_gezeichnet)
                      {
                       OldIDCMP=Window->IDCMPFlags;
                       ModifyIDCMP(Window,MOUSEMOVE|MOUSEBUTTONS);
                       
                       /* */                            /* Bereich mit Maus auswählen */
                       AusSchnitt(&xmn,&ymn,&xmp,&ymp); /* Funktion aufrufen          */
                       ModifyIDCMP(Window,OldIDCMP);
                       Einsprung_P2:
                       Loeschen();
                      }
                     break;
                    }
                   case 5:
                    {
                     /* Eingabe der Werte für die Konstanten               */
                     TextFuerKonstanten();     /* Gadget vorbereiten       */
                     /* */                     /* Werte vom Anwender holen */
                     Grenzen(KonAString,KonCString,KonBString,KonDString);
                     UmwandlungInKonstanten(); /* Werte kopieren           */
                     break;
                    }
                   case 6:
                    {
                     /* About */
                     Einsprung_P3:
                     About();
                     break;
                    }
                   case 7:
                    {
                     /* Beenden des Programms */
                     ENDE=1-request(PLOT_END,PLOT_CONT,PLOT_QUEST);
                    }
                  }
                 break;
                }
               case 1:
                {
                 /* Das nullte Menu wurde gewählt      */
                 switch (item)
                  {
                   /* Entsprechend des Items verzweigen */
                   case 7:
                    {
                     Full_Discussion(sub);
                     goto Einsprung_P3;
                    }
                   case 0:
                    {
                     /* Funktionsterm ändern */
                     do
                      {
                       Funktionseingabe(Formeln[sub]); /* Holen der neuen Vorschrift */
                      }
                     while(AnzahlKlammern((char *)Formeln[sub]));
                     UpdateMenuText();                 /* SubItemText erneuern       */
                     break;
                    }
                   case 1:
                   case 2:
                   case 3:
                    {
                     /* Entsprechend dem SubItem zeichnen   */
                     ZeichneFunktion(sub,(int)item-1);
                     break;
                    }
                   /* Item 4 ist ---------- */
                   case 5:
                    {
                     /* 1. Abl. symbolisch */
                     /* Entsprechend dem SubItem zeichnen   */
                     strcpy(Formeln[10],Ableiten(Formeln[sub]));
                     goto Einsprung_P1;
                    }
                   case 6:
                    {
                     /* 2. Abl. symbolisch */
                     strcpy(Formeln[10],Ableiten(Formeln[sub]));
                     strcpy(Formeln[10],Ableiten(Formeln[10]));
                     Einsprung_P1:
                     ZeichneFunktion(10,0);
                    }
                  }
                 break;
                }
               case 2:
                {
                 switch(item)
                  {
                   case 1:
                    {
                     Groesse=GROSS;
                     xx=969; /* Definiert, wie viele Punkte für Grafik */
                     yy=257; /* genutzt werden sollen                  */
                     break;
                    }
                   case 0:
                    {
                     Groesse=KLEIN;
                     xx=609; /* Definiert, wie viele Punkte für Grafik */
                     yy=PLOT_Y; /* genutzt werden sollen                  */
                    }
                  }
                 goto Einsprung_P2;
                }
              }
             Item=ItemAddress(Menu,(LONG)menunr);
             menunr=Item->NextSelect;
             Item->NextSelect=MENUNULL;
            }
          }
         case RAWKEY:
          {
           if(Groesse)
            {
             TastaturAbfrage();
            }
          }
        }
      }
    }
  }
 
 
 /* Öffnet Libraries, Screen, Window */
 int oeffne()
  {
   int Failed=0;
   if((ToolBase=(struct ToolBase *)OpenLibrary("tool.library",0)))
    {
     IntuitionBase=ToolBase->IntuitionBase;
     GfxBase=ToolBase->GfxBase;
     MathIeeeDoubTransBase=ToolBase->MathIeeeDoubTransBase;
     MathIeeeDoubBasBase=ToolBase->MathIeeeDoubBasBase;
     if(Konstantenstart=Init_Konst())
      {
       if((LayersBase = (struct LayersBase *)OpenLibrary("layers.library",0)))
        {
         if((Screen=(struct Screen *)OpenScreen(&Schirm)))
          {
           InitBitMap(&bitmap,2,1000,MAXPIXELY);
           
           if((bitmap.Planes[0]=AllocRaster(1000,MAXPIXELY)))
            {
             Delay(5);
             if((bitmap.Planes[1]=AllocRaster(1000,MAXPIXELY)))
              {
               Fenster.Screen=Screen; /* Fenster soll auf Screen erscheinen */
               Fenster.BitMap=&bitmap;
               if((Window=(struct Window *)OpenWindow(&Fenster)))
                {
                         /* Zuweisung von Variablen, Einfärben des Windows */
                 
                 
                 MakeMenu();                        /* Menustrukturen erzeugen     */
                 NewSetMenuStrip(Window,Menu);      /* Menus verknüpfen            */
                 
                 viep=&Screen->ViewPort;            /* ViewPort-Zeiger füllen      */
                 RastPort=Window->RPort;            /* Variablenzuweisung          */
                 layer=RastPort->Layer;             /* LayerPointer holen          */
                 layerinfo=layer->LayerInfo;        /* LayerInfo    holen          */
                 SetRast(RastPort,FARBE0);          /* Schirm löschen              */
                 
                 Fenster2.Screen=Screen;            /* Fenster2 auch auf Screen    */
                 Fenster3.Screen=Screen;            /* Fenster3 auch auf Screen    */
                 Failed=1;                          /* Nur wenn alles geklappt hat */
                }
              }
            }
          }
        }
      }
    }
   return(Failed);
  }
 
 
 /* Routine, die alles wieder schließt */
 VOID ende(VOID)
  {
   LONG H;
   Delay(20);
   if(Konstantenstart)Free_Konst(Konstantenstart);
   
   /* Wenn offen -> schließen */
   if(Window)
    {
     while(H=EventAbfrage(Window,&msgInfo));
     ReMakeMenu(Window);
     CloseWindow(Window);
    };
   if(bitmap.Planes[0])
    {
     FreeRaster(bitmap.Planes[0],1000,MAXPIXELY);
     bitmap.Planes[0]=0;
    }
   if(bitmap.Planes[1])
    {
     FreeRaster(bitmap.Planes[1],1000,MAXPIXELY);
     bitmap.Planes[1]=0;
    }
   if(Screen)CloseScreen(Screen);
   
   /* Schließt auch automatisch IntuitionBase etc. */
   if(ToolBase)CloseLibrary((struct Library *)ToolBase);
   
   if(LayersBase)CloseLibrary((struct Library *)LayersBase);
  }
 
 /* Für Intervall */
 VOID UmwandlungInIntervall(VOID)
  {
   /* Sollte nicht benutzt werden, darum ruhig undefinierter Wert */
   berechnen(&xmp,xmpstring,&x0,(struct Konstanten *)Konstantenstart,&MatheFehler);
   berechnen(&xmn,xmnstring,&x0,(struct Konstanten *)Konstantenstart,&MatheFehler);
   berechnen(&ymp,ympstring,&x0,(struct Konstanten *)Konstantenstart,&MatheFehler);
   berechnen(&ymn,ymnstring,&x0,(struct Konstanten *)Konstantenstart,&MatheFehler);
  }
 
 /* Für Konstanten */
 VOID UmwandlungInKonstanten(VOID)
  {
   /* Eine Konstante darf nicht aus dem Wert einer anderen Konstanten bestehen */
   /* Also nicht A=1+B, da B zum Zeitpunkt der Bestimmung von A nicht unbe-    */
   /* dingt den richtigen Wert haben muß.                                      */
   /* Es ist zwar prinzipiell möglich, aber man sollte keine Rekursionen be-   */
   /* nutzen, wie a=d+1 und d=a*10                                             */
   DOUBLE var;
   
   berechnen(&var,KonAString,&var,(struct Konstanten *)Konstantenstart,&MatheFehler);
   Set_Konst_P(Konstantenstart,1,&var);
   berechnen(&var,KonBString,&var,(struct Konstanten *)Konstantenstart,&MatheFehler);
   Set_Konst_P(Konstantenstart,2,&var);
   berechnen(&var,KonCString,&var,(struct Konstanten *)Konstantenstart,&MatheFehler);
   Set_Konst_P(Konstantenstart,3,&var);
   berechnen(&var,KonDString,&var,(struct Konstanten *)Konstantenstart,&MatheFehler);
   Set_Konst_P(Konstantenstart,4,&var);
  }
 
 /* Erneuert SubMenuTexte */
 VOID UpdateMenuText(VOID)
  {
   /* Füllt die SubMenuTitel mit den aktuellen Funktionsdefinitionen */
   USHORT i;
   ClearMenuStrip(Window);                        /* Menuverknüpfung aufheben  */
   for(i=0;i<=9;i++)
    {
     left(SubMenuTitle[i],Formeln[i],14L);        /* Ans Ziel kopieren         */
    }
   SetMenuStrip(Window,Menu);                     /* Wieder verknüpfen         */
  }
 
 VOID SetRXOffset(VOID)
  {
   LONG dx,dy;
   
   if(YOffset<0)YOffset=0;
   if(XOffset<0)XOffset=0;
   
   if(YOffset>(MAXPIXELY-YSCREEN))YOffset=MAXPIXELY-YSCREEN;
   if(XOffset>(1000-640))XOffset=1000-640;
   
   dx=XOffset-(layer->Scroll_X);
   dy=YOffset-(layer->Scroll_Y);
   /* Mit der Abfrage geht es schneller. Auch ein ScrollLayer(..,..,0,0) */
   /* braucht relativ viel Zeit.                                         */
   if(dx||dy)ScrollLayer(layerinfo,layer,dx,dy);
  }
 
 VOID TastaturAbfrage(VOID)
  {
   static short add=1;
   switch(msgInfo.code)
    {
     case 69:
      {
       /* ESC = Ursprung */
       XOffset=YOffset=0;
       break;
      }
     case 76:
      {
       /* Cursor up */
       YOffset-=add;
       goto Einsprung;
      }
     case 77:
      {
       /* Cursor down */
       YOffset+=add;
       goto Einsprung;
      }
     case 78:
      {
       /* Cursor right */
       XOffset+=add;
       goto Einsprung;
      }
     case 79:
      {
       /* Cursor left */
       XOffset-=add;
       
       Einsprung:
       add++;
       break;
      }
     case 204:
     case 205:
     case 206:
     case 207:
      {
       /* Damit nicht zu schnell gescrollt wird... */
       add=1;
      }
    }
   SetRXOffset();
   if(add>10)add=10;
  }
 
 VOID Loeschen(VOID)
  {
   SetRast(RastPort,0);
   /* Koordinatenkreuz beim nächsten Mal neu zeichnen */
   KoordinatenKreuz_gezeichnet=FALSE;
   ScrollLayer(layerinfo,layer,(LONG)-(layer->Scroll_X),(LONG)-(layer->Scroll_Y));
  }
 
 
 
 
