Netzgraphik - Library NETZLIB

In vielen Bereichen der Naturwissenschaft und auch anderswo benötigt man dreidimensionale Funktionsdarstellungen. Gerade Darstellungen als Netzgraphik sind hier gefragt. Das hier vorgestellte Modul bietet in einfacher Weise eine Möglichkeit, solche Graphen darzustellen.

“Warum gerade ein Modul und nicht ein schönes Programm?” werden viele fragen. Ein Programm bietet, egal wie gut es auf- bzw. ausgebaut ist, beschränkte Fähigkeiten, die möglicherweise nicht ausreichen. Aber programmieren kann man selbst. Ein einfaches Programm für eigene Zwecke ist oft mit wenig Aufwand fertiggestellt. Alles schön und gut, aber jedesmal die Prozedur für Netzgraphiken neu entwerfen? Natürlich nicht! Wozu bieten höhere, moderne Entwicklungspakete wie ST Pascal Plus 2.0 Möglichkeiten wie Include-Dateien oder Programm-Module?! Beides bietet sich an, obwohl reine Include-Dateien mit kompilierbarem Programmtext unnötig den Compiler beanspruchen und somit teure Zeit verschwenden. Also bleibt als Konzept nur die Library oder das Objectcode-Modul.

Das Netzgraphik-Modul ist keine richtige Library, da es nur aus einem einzigen Modul besteht. Wer eine Library möchte, kann jede Routine in ein Modul bringen und diese sieben Module in einer Library zusammenfassen. Dies hätte natürlich den Vorteil, daß der Programmcode kürzer würde als mit einem großen Objectcode-Modul, unter der Voraussetzung, daß man nur einen Teil der Routinen benötigt. Da aber das hier vorgestellte Graphik-Modul noch eine akzeptable Länge hat, kann man auf den Library-Aufbau verzichten.

Nun aber zum Modul selbst. Das Modul besteht aus zwei Teilen, der notwendigen EXTERNAL-Deklarationen in der Include-Datei als “Schnittstelle” zum Modul und dem kompilierten Sourcecode. Die EXTERNAL-Deklarationen sind einerseits die Kopfzeilen der Routinen mit dem Wörtchen “EXTERNAL” darunter statt dem Sourcecode aus dem Modul. Andererseits sind in der Include-Datei die Typen-Deklarationen ein wichtiger Punkt. Die Typen horizontal, vertikal, winkel, hor_pkte und ver_pkte geben Einschränkungen des Integer-Zahlenbereiches. Hierbei sind horizontal und vertikal für die möglichen Pixelkoordinaten, winkel für mögliche Winkel in Grad und hor_pkte und ver_pkte für mögl. Punkte im Netz zuständig. Wichtiger sind die Typenpunkte, die die Koordinaten eines Punktes beinhalten; matrix, die einfach Matrixelemente enthält, und Netzdaten.

Die Type netzdaten ist ein wesentlicher Teil der Library. Das Record enthält alle(!) wichtigen Daten. Dadurch ist zwar der kB-Umfang recht groß (über 60 kB), aber die Übergabe der Parameter bleibt übersichtlich. Nun aber im einzelnen, kennung enthält einen String, beispielsweise den Namen des Graphen. Die vier Werte maxxlinks, maxxrechts, maxyoben und maxyunten enthalten die maximal möglichen Ausmaße des kompletten Graphen. Es handelt sich um Integer-Werte, da man ja auch ein Netz fehlerhaft berechnen kann. Es besteht somit die Möglichkeit, jederzeit zu überprüfen, ob die vom Bildschirm vorgegebenen Koordinaten eingehalten werden. In Abbildung 1 erkennt man vier Punkte (1, 2, 3, 4), die diese maximalen Koordinaten verdeutlichen sollen. Der schraffierte Bereich entspricht dem Netz ohne Funktionsdarstellung. Eine solche Überprüfung findet beispielsweise in der Prozedur ausg_netz statt. Der Punkt (x0,y0) ist der Startpunkt des Netzes.

Die Werte breite und hoehe geben die Ausmaße des Netzes (in Pixeln) ohne Funktionswerte im ungedrehten Zustand, also mit phi und psi gleich 0. Damit ist auch gleich erklärt, wofür phi und psi zuständig sind. Trotzdem noch ein Bildchen, in dem die entsprechenden Werte verzeichnet sind. Genaugenommen ist die Abbildung 2 nur ein Ausschnitt der Abbildung 1.

Die Werte pkte_hor und pkte_ver geben an, wieviele Knoten, jeweils horizontal und vertikal, man auf dem Netz wünscht. Diese Werte werden selbstverständlich nicht in Pixeln gemessen. Das Array koord enthält alle (Pixel-) Koordinaten des Netzes und das Array fkt_werte die dazugehörigen Funktionswerte. Da verschiedene Funktionen verschiedene Maxima und Minima haben, wird noch der Verstärkungsfaktor verst benötigt, der dafür sorgt, daß zwischen Maximum und Minimum 100 Pixel Abstand sind, und der Verschiebungsfaktor versch, der die Funktion so verschiebt, daß das Maximum 50 Pixel über der Netzgrundebene liegt und das Minimum 50 darunter. Das angesprochene Maximum und ebenso das Minimum der Funktion im ausgewählten Bereich x_min bis x_max bezüglich der x-Achse und y_min bis y_max bezüglich der y-Achse ist unter den Werte f_max und f_min zu finden. Somit ist dieses Record erläutert.

Wenden wir uns jetzt dem Sourcecode zu. Das Modul besteht aus sieben Routinen, drei Initialisierungs-, zwei Ausgabe- und zwei Datei-Routinen. Die erste Routine, procedure init_netz, berechnet die Pixelkoordinaten des Grundnetzes, d. h. ohne Funktionswerte. Hier wird ein Record “netzdaten” als Variable übergeben.

Die nächste Routine, procedure init_function, berechnet die zum Netz gehörigen Funktionswerte. Neben einem Record “netzdaten” wird auch eine Funktion als Parameter übergeben.

Ähnlich aufgebaut ist die procedure init_matrix. Allerdings wird hier nicht eine Funktion, sondern eine Matrix, also bereits feste Werte, übergeben. Dies ist vorteilhaft, wenn man etwa eine Funktion nicht explizit angeben kann und nur Meßoder auch Näherungswerte vorliegen hat.

Herzstück von NETZLIB ist die Ausgabe-Routine procedure ausg_netz. Das fertig aufgebaute Netz (“netzdaten”) und ein boolescher Wert werden an diese Prozedur übergeben. Der boolesche Wert bestimmt, ob verdeckte Teile gelöscht werden sollen (TRUE) oder nicht (FALSE). Zum Zeichnen des Graphen wird dieser von hinten nach vorne auf dem Bildschirm aufgebaut. Sofern man keine Löschung verdeckter Teile benötigt, ist der Graphaufbau gleichgültig. Wünscht man allerdings eine Löschung, so ist die Reihenfolge des Aufbaus wichtig. Von den Teilen, die am weitesten hinten liegen, sieht man ja später am wenigsten. Also werden diese zuerst gezeichnet. Nun steht man nur vor dem Problem, ob man erst eine Linie zeichnen möchte und dann löscht oder umgekehrt. Eigentlich scheint es ja (vom mathematischen Standpunkt her) egal zu sein. Da aber auf dem Bildschirm keine Linien, sondern nur “Treppen” dargestellt werden können, spielt diese Frage doch eine Rolle. Der Effekt ist einfach: löscht man erst und zeichnet dann die Linie, erscheinen die Linien durchgehend. Löscht man allerdings hinterher, so kann es sein, daß Linien unterbrochen werden, was interessante, nützliche Effekte hervorrufen kann.

Bild 1
Bild 2

Es folgt noch eine Routine, mit der man die Funktionswerte in eine Textdatei ausgeben kann. Die Routine procedure ausg_function legt dieses Textfile unter dem Namen “OUTPUT.DAT” an.

Die vorletzte Routine, procedure sfile_netz, sorgt dafür, daß ein Netz abgespeichert wird. Somit kann man die Daten später weiterverwenden oder auch an andere Programme, die NETZLIB nutzen, weitergeben. Der Name der Datei wird mit dem String name übergeben.

Die Routine procedure lfile_netz schließlich bewerkstelligt das Lesen einer mit sfile_netz abgespeicherten Datei.

Das war’s nun in aller Kürze zum Sourcecode. Wichtig zu wissen ist allerdings noch, welche Teile des Records netzdaten verändert, welche von den einzelnen Routinen nur benutzt oder nicht benötigt werden. Hierzu die Tabelle in Abbildung 3 (siehe nächste Seite).

Aus dieser Tabelle wird noch einiges ersichtlich. Einige Werte bei den Routinen init_netz und init_function sind austauschbar. So kann man einerseits unter Beibehaltung des Netzes die Funktionswerte verändern, also Funktionen austauschen oder neue x- und y-Koordinaten wählen. Hier sind x_max, x_min, y_max, y_min und indirekt fkt_werte, verst, versch, f_max, f_min veränderbar. Andererseits kann man das Netz austauschen. Hier dürfen dann x0, y0, breite, hoehe, phi und psi gewechselt werden.

Bei Nutzung der Prozedur init_matrix ist darauf zu achten, daß init_netz erst anschließend aufzurufen ist. Dies ist darin begründet, daß Werte, die von init_netz benötigt werden, erst noch von init_matrix verändert werden müssen. Daher hat man bei Verwendung von Matrizen auch nicht die freie Wahl des Austausches wie bei Verwendung von Funktionen.

Der Wert kennung steht dem Programmierer jederzeit zur freien Verfügung. Da er nur als Hilfsmittel benutzt wird, findet er bei dem Netz keine Verwendung.

Nachdem nun alles erklärt ist, kann das eigentliche Programmieren beginnen. Nehmen wir also an, das Modul ist als ASCII-File fertig. Es muß nur noch kompiliert werden. Ist auch dieses geschehen, kann man bei Bedarf die Endung .O löschen. Es wird so der Eindruck erweckt, es läge eine echte Library vor. Die auf diese Weise entstandene Datei wird unter “Linkeroptionen” als zusätzlich zu linkende Datei eingetragen, womit alle Vorbereitungen abgeschlossen sein sollten.

Jetzt geht’s an die Entwicklung eines Programmes. Zu beachten ist, daß neben den Include-Dateien für die GEM-Funktionen (GEM/CONST/TYPE/SUBS.INC) auch die Include-Datei für NETZLIB (NETZ.INC) nach der program-Zeile aufgeführt wird. Dank einer Änderung in ST Pascal Plus ist es ja jetzt möglich, Konstanten-, Typen-, Variablen-, Label- und Routinendeklarationen in einer Include-Datei zusammenzufassen.

Für die Anwendung von NETZLIB sind noch vier kleine Beispiele angeführt. Beispiel 1 entwirft nur eine Graphik, gibt sie aber nicht an den Monitor weiter, sondern speichert sie lediglich ab. Beispiel 2 liest nur eine Datei und zeichnet sie auf den Bildschirm. Das Programm läßt sich am besten nutzen, wenn man eine Anwendung anmeldet. Dies geschieht auf dem Desktop unter dem Menüpunkt “Anwendung anmelden”. Hier wird die benutzte Endung der NETZGRAPHIK-Dateien eingetragen, beispielsweise .DAT oder .NTZ. Möchte man nun eine Graphik sehen, so braucht man nur die Datei anzuklicken, und das Programm wird automatisch aufgerufen. Der Dateiname wird aus der Kommandozeile gelesen. Ebensogut läßt sich auch ein Command-Line-Interpreter verwenden. Notfalls kann man sogar den Dateinamen direkt eingeben.

Die beiden letzten Beispielprogramme zeigen, wie man Netz oder Funktion auswechseln kann.

Mir bleibt nur, Ihnen viel Freude mit dem Modul zu wünschen. Es möge die Programmiererei hilfreich unterstützen.

  init_netz init_function init_matrix ausg_netz ausg_function sfile_netz lfile_netz
kennung B V
maxxlinks V B B V
maxxrechts V B B V
maxyoben V B B V
maxyunten V B B V
breite B B V
hoehe B B V
phi B B V
psi B B V
x0 B B V
y0 B B V
pkte_hor B B V B B B V
pkte_ver B B V B B B V
koord V B B V
fkt_werte V V B B B V
verst V V B B V
versch V V B B V
f_max V V B B V
f_min V V B B V
x_max B V B B V
x_min B V B B V
y_max B V B B V
y_min B V B B V

(Bezeichnungen: B = benötigt, V = verändert)

Tabelle 1


{* Deklarationen NETZGRAPHIK *}

{ (c) 1987 by D. Rabich, Dülmen.
      Entw. mit ST Pascal+ V2.0 (CCD, Eltville) }

{-<<<<< Typendeklarationen NETZGRAPHIK >>>>>-}

type horizontal = 0..639;
     vertikal   = 0..399;
     winkel     = -89..89;
     hor_pkte   = 1..100;
     ver_pkte   = 1..60;
     punkte     = record
                    x : short_integer; 
                    y : short_integer; 
                  end;
    netzdaten   = record
                    kennung     : string[80]; 
                    maxxlinks,maxxrechts : short_integer; 
                    maxyoben,maxyunten   : short_integer; 
                    breite      : horizontal; 
                    hoehe       : vertikal; 
                    phi,psi     : winkel; 
                    x0          : horizontal;
                    y0          : vertikal;
                    pkte_hor    : hor_pkte; 
                    pkte_ver    : ver_pkte; 
                    koord       : array [hor_pkte,ver_pkte] of punkte;
                    fkt_werte   : array [hor_pkte,ver_pkte] of real; 
                    verst       : real;
                    versch      : short_integer;
                    f_max,f_min : real;
                    x_max,x_min : real; 
                    y_max,y_min : real;
                  end;
    matrix      = array [1..50,1..50] of real;

{-<<<<< Prozedurdeklarationen NETZGRAPHIK >>>>>-}

procedure init_netz(var netz : netzdaten);
EXTERNAL;

procedure init_function(function f(x,y : real) : real; var netz : netzdaten);
EXTERNAL;

procedure init_matrix(a : matrix; m,n : short_integer; var netz : netzdaten);
EXTERNAL;

procedure ausg_netz(netz : netzdaten; ausf boolean);
EXTERNAL;

procedure ausg_function(netz : netzdaten);
EXTERNAL;

procedure sfile_netz(netz : netzdaten; name : string);
EXTERNAL;

procedure lfile_netz(var netz : netzdaten; name : string);
EXTERNAL;

Listing: NETZINC


{-<<<<< Programm - Modul: NETZGRAPHIK >>>>>-}
{$M+,D-,P-,R-}
PROGRAM netzgraphik;

{ (c) 1987 by Dietmar Rabich, Dövelingsweg 2, 4408 Dülmen }
{ Datum     : 24. Oktober 1987 }
{ Version   : 1.0 }
{ Entwickelt mit ST Pascal Plus Version 2.0 }


{----***** Konstanten und Typen *****------}
CONST pi = 3.141592653589; (* globale Definition *;
      {$I \INCLUDE\GEMCONST.INC } (* für GEM *)

TYPE ($I \INCLUDE\GEMTYPE.INC ) 
     horizontal = 0..639;
     vertikal   = 0..399;
     winkel     = -89..89;
     hor_pkte   = 1..100;
     ver_pkte   = 1..60;
     punkte     = RECORD
                    x : short_integer; 
                    y : short_integer;
                  END;
    netzdaten   = RECORD
        kennung              : string[80];
        maxxlinks,maxxrechts : short_integer;
        maxyoben,maxyunten   : short_integer; 
        breite               : horizontal;
        hoehe                : vertikal;
        phi,psi              : winkel;
        x0                   : horizontal;
        y0                   : vertikal;
        pkte_hor             : hor_pkte;
        pkte_ver             : ver_pkte;
        koord     : ARRAY [hor_pkte,ver_pkte] OF punkte; 
        fkt_werte : ARRAY [hor_pkte,ver_pkte] OF real; 
        verst                : real;
        versch               : short_integer;
        f_max,f_min          : real;
        x_max,x_min          : real;
        y_max,y_min          : real;
                END;
    matrix      = ARRAY [1..50,1..50] OF real;

{—--***** Prozeduren und Funktionen *****—--}

{$I \INCLUDE\GEMSUBS.INC } (* für GEM *)

{$E+}
(* Netz - Initialisierung *)
PROCEDURE init_netz(VAR netz : netzdaten);

VAR mdx1,mdx2,mdy1,mdy2 : real; 
    dx1,dx2,dy1,dy2     : real;
    xs,ys,xs2,ys2       : real;
    i,j,dummy           : short_integer;

    (* Umrechnung Grad -> Bogen *)
    FUNCTION bogen(x : real) : real;

      BEGIN
          bogen:=x*pi/180;
      END;

      (* notwendige Zwischenwerte *)

    PROCEDURE zwischenwerte;

      BEGIN
        WITH netz DO 
          BEGIN
            mdx1:=breite*cos(bogen(phi)); 
            mdx2:=-hoehe*sin(bogen(psi)); 
            mdy1:=breite*sin(bogen(phi)); 
            mdy2:=hoehe*cos(bogen(psi));
            dx1:=mdx1/pkte_hor; 
            dx2:=mdx2/pkte_ver; 
            dy1:=mdy1/pkte_hor; 
            dy2:=mdy2/pkte_ver;
          END;
      END;

    (* Ausmaß des Graphen *)
    PROCEDURE ausmass;

      BEGIN
        WITH netz DO 
          BEGIN 
            IF psi>=0 THEN 
              BEGIN
                maxxlinks :=x0+round(mdx2); 
                maxxrechts:=x0+round(mdx1);
              END 
            ELSE
              BEGIN 
                maxxlinks :=x0;
                maxxrechts:=x0+round(mdx1+mdx2);
              END;
            IF phi>=0 THEN 
              BEGIN
                maxyunten :=y0+round(mdy1+mdy2)+50; 
                maxyoben  :=y0-50;
              END
            ELSE
              BEGIN
                maxyunten :=y0+round(mdy2)+50; 
                maxyoben  :=y0+round(mdy1)-50;
              END;
          END;
      END;

  BEGIN
    WITH netz DO 
      (* Abbruch bei zu dichter Punktwahl! *)
      IF (breite/pkte_hor<3) OR (hoehe/pkte_ver<3) THEN
        dummy:=do_alert('[3][ Zu viele | Punkte !][ABBRUCH]',1)
      ELSE 
        BEGIN 
          zwischenwerte; 
          i:=1; 
          xs:=x0; 
          ys:=y0;
          REPEAT 
            j:=1; 
            xs2:=xs; 
            ys2:=ys;
            REPEAT
              koord[i,j].x:=round(xs2); 
              koord[i,j].y:=round(ys2); 
              xs2:=xs2+dx1; 
              ys2:=ys2+dy1;
              j:=j+1;
            UNTIL j>pkte_hor; 
            xs:=xs+dx2; 
            ys:=ys+dy2; 
            i:=i+l;
          UNTIL i>pkte_ver; 
          ausmass;
        END;
END;

(* Funktion - Initialisierung *)
PROCEDURE init_function (FUNCTION f(x,y : real) : real; VAR netz : netzdaten);

  VAR i,j                   : short_integer;
      schritt_x, schritt_y  : real;
      xs,ys                 : real;

  BEGIN
    WITH netz DO
      BEGIN
        schritt_x:=abs(x_max-x_min)/(pkte_hor-1); 
        schritt_y:=abs(y_max-y_min)/(pkte_ver-1); 
        f_max:=f(x_min,y_max); 
        f_min:=f(x_min,y_max); 
        i:=1;
        ys:=y_max;
        REPEAT
          j:=1;
          xs:=x_min;
          REPEAT
            fkt_werte[i,j]:=f(xs,ys);
            IF fkt_werte[i,j]>f_max THEN f_max:=fkt_werte[i,j];
            IF fkt_werte[i,j]<f_min THEN f_min:=fkt_werte[i,j];
            j:=j+i;
            xs:=xs+schritt_x;
          UNTIL j>pkte_hor; 
          i:=i+1;
          ys:=ys-schritt_y;
        UNTIL i>pkte_ver;
        IF f_max<>f_min THEN
          verst:=100/abs(f_max-f_min)
        ELSE 
          verst:=0;
        versch:=round(verst*(f_max+f_min)/2);
      END;
  END;

  (* Matrix - Initialisierung *)
  PROCEDURE init_matrix(a : matrix; m,n : short_integer; VAR netz : netzdaten);

    VAR i,j : short_integer;

    BEGIN
      WITH netz DO 
        BEGIN 
          x_min:=1; 
          x_max:=n; 
          y_min:=1; 
          y_max:=m; 
          pkte_hor:=n; 
          pkte_ver:=m; 
          f_max:=a[1,1]; 
          f_min:=a[1,1]; 
          i:=1;
          REPEAT
            j:=1;
            REPEAT
              fkt_werte[i,j]:=a[i,j];
              IF fkt_werte[i,j]>f_max THEN f_max:=fkt_werte[i,j]; 
              IF fkt_werte[i,j]<f_min THEN f_min:=fkt_werte[i,j];
              j:=j+1;
            UNTIL j>pkte_hor; 
            i:=i+1;
          UNTIL i>pkte_ver;
          IF f_max<>f_min THEN
            verst:=100/abs(f_max-f_min)
          ELSE 
            verst:=0;
          versch:=round(verst*(f_max+f_min)/2);
        END;
    END;

  (* Ausgabe - Netzgraphik (Bildschirm) *)
  PROCEDURE ausg_netz(netz : netzdaten; ausf : boolean);

    VAR i,j     : short_integer;
        control : ctrl_parms; 
        int_in  : int_in_parms; 
        int_out : int_out_parms; 
        pts_in  : pts_in_parms; 
        pts_out : pts_out_parms;
        dummy   : short_integer;

  (* Unregelmäßiges Viereck VDI-Funktion FILLED AREA *) 
  PROCEDURE Viereck(x0,y0,x1,y1,x2,y2,x3,y3 : short_integer);

    BEGIN
        pts_in[0]:=x0; pts_in[1]:=y0; 
        pts_in[2]:=x1; pts_in[3]:=y1; 
        pts_in[4]:=x2; pts_in[5]:=y2; 
        pts_in[6]:=x3; pts_in[7]:=y3; 
        pts_in[8]:=x0; pts_in[9]:=y0; 
        vdi_call(9,0,0,5,control,int_in,int_out,pts_in,pts_out,false);
    END;

  (* Ausgabe mit Löschen verdeckter Teile *) 
  PROCEDURE ausg_m;

    VAR i,j : short_integer;

    BEGIN
      WITH netz DO 
        BEGIN 
          paint_color(white); 
          paint_style(0);
          FOR i:=1 TO pkte_ver DO 
            BEGIN
              FOR j:=1 TO pkte_hor-1 DO 
                BEGIN
                  viereck(koord[i,j].x,
                          koord[i,j].y-round (verte[i,j]1)+versch,
                          koord[i,j+1].x, 
                          koord[i,j+1].y-round (verst*fkt_werte[i,j+1]1)+versch, 
                          koord[i,j+1].x, 
                          maxyunten, 
                          koord[i,j].x, 
                          maxyunten); 
                  pline(koord[i,j].x,
                        koord[i,j].y-round(verst*fkt_werte[i,j])+versch, 
                        koord[i,j+1].x, 
                        koord[i,j+1].y-round (verst*fkt_werte[i,j+1])+versch);
                END;
              IF i<pkte_ver THEN
                FOR j:=1 TO pkte_hor DO 
                  BEGIN
                    viereck(koord[i,j].x,
                            koord[i,j].y-round (verst*fkt_werte[i,j]-1)+versch, 
                            koord[i+1,j].x, 
                            koord[i+1,j].y-round (verst*fkt_werte[i+1,j]1)+versch, 
                            koord[i+1,j].x, 
                            maxyunten, 
                            koord[i,j].x, 
                            maxyunten); 
                    pline(koord[i,j].x,
                          koord[i,j].y-round (verst*fkt_werte[i,j])+versch, 
                          koord[i+1,j].x, 
                          koord[i+1,j].y-round (verst*fkt_werte[i+1,j])+versch);
                  END;
            END;
        END;
  END;

  (* Ausgabe ohne Löschen verdeckter Teile *) 
  PROCEDURE ausg_o;

    VAR i, j : short_integer;

    BEGIN
      WITH netz DO 
        FOR i:=1 TO pkte_ver DO 
          BEGIN
            FOR j:=1 TO pkte_hor-1 DO 
              pline(koord[i,j].x,
                    koord[i,j].y-round (verst*fkt_werte[i,j])+versch, 
                    koord[i,j+1].x, 
                    koord[i,j+1].y-round (verst*fkt_werte[i,j+1])+versch); 
              IF i<pkte_ver THEN
                FOR j:=1 TO pkte_hor DO 
                  pline(koord[i,j].x,
                        koord[i,j].y-round (verst*fkt_werte[i,j])+versch, 
                        koord[i+1,j].x,
                        koord[i+1,j].y-round (verst*fkt_werte[i+1,j])+versch);
          END;
    END;

  BEGIN
    WITH netz DO
    (* Plausibilitätsprüfung *)
    IF (maxxlinks<0) OR (maxxrechts>639) OR (maxyoben<0) OR (maxyunten>399) THEN 
      dummy:=do_alert('[3][Koordinaten falsch!][ABBRUCH]',1)
    ELSE 
      IF ausf THEN 
        ausg_m 
      ELSE 
        ausg_o;
  END;

  (* Ausgabe - Funktion (Datei OUTPUT.DAT) *) 
  PROCEDURE ausg_function(netz : netzdaten);

    VAR i,j                   : short_integer;
        schritt_x, schritt_y  : real;
        xs,ys                 : real;
        ausgabe               : text;

    BEGIN
      WITH netz DO 
        BEGIN
          rewrite(ausgabe,'output.dat'); 
          schritt_x:=abs(x_max-x_min)/(pkte_hor-1); 
          schritt_y:=abs(y_max-y_min)/(pkte_ver-1); 
          writeln(ausgabe,'x_min=',x_min); 
          writeln(ausgabe,'x_max=',x_max); 
          writeln(ausgabe,'y_min=',y_min); 
          writeln(ausgabe,'y_max=',y_max); 
          writeln(ausgabe,'f_min=',f_min); 
          writeln(ausgabe,'f_max=',f_max); 
          writeln(ausgabe);
          i:=1;
          ys:=y_max;
          REPEAT
            j:=1;
            xs:=x_min;
            REPEAT
              writeln(ausgabe,'f(',xs,',',ys,')=',fkt_werte[i,j]);
              j:=j+1;
              xs:=xs+schritt_x;
            UNTIL j>pkte_hor; 
            i:=i+1;
            ys:=ys-schritt_y;
          UNTIL i>pkte_ver; 
          close(ausgabe);
        END;
  END;

  (* Speicher - Funktion (schreiben) *)

  PROCEDURE sfile_netz(netz : netzdaten; name : string);

    TYPE ausgabe = FILE OF netzdaten;

    VAR datei : ausgabe;

    BEGIN
      rewrite(datei,name); 
      write(datei,netz); 
      close(datei);
    END;

  (* Speicher - Funktion (lesen) *)
  PROCEDURE lfile_netz(VAR netz : netzdaten; name : string);

    TYPE ausgabe = FILE OF netzdaten;

    VAR datei : ausgabe;

    BEGIN
      reset(datei,name); 
      read(datei,netz); 
      close(datei);
    END;

  {—***** Hauptprogramm *****—}
  BEGIN END.

Listing 2: NETZLIB


{ - Eingabeprogramm für NETZGRAPHIK - )

program eingabe_netz;

{(c) 1987 by Dietmar Rabich.
     Entw. mit ST Pascal+ 2.0. }

const {$I \INCLUDE\GEMCONST.INC } 
type  {$I \INCLUDE\GEMTYPE.INC  }

{$I NETZ.INC }

var netz  : netzdaten;
    aplid : short_integer; 
    dummy : short_integer;

{$I \INCLUDE\GEMSUBS.INC }

function f(x,y:real):real;

  begin
    f:=cos(x+y)*sin(x*y); 
  end;

  begin 
    aplid:=init_gem; 
    if aplid>=0 then 
      begin

        (* Meldung, die Beginn kennzeichnet *) 
        dummy:=do_alert(concat('[0]
                        [Eingabeprogramm NETZGRAPHIK|',
                        '~~~~~~~~~~~~~~~~~~~~~~~~~~~|',
                        '      Entwickelt mit |',
                        '   ST Pascal Plus V 2.0.][Los geht',
                        chr(39),'s!]'),1);

        (* Netz - Daten *) 
        netz.breite   :=400;
        netz.hoehe    :=180;
        netz.phi      :=  5;
        netz.psi      := 10;
        netz.x0       :=100;
        netz.y0       :=100;
        netz.pkte_hor := 30; 
        netz.pkte_ver := 20; 
        netz.x_min    := -3;
        netz.x_max    :=  3;
        netz.y_min    := -3;
        netz.y_max    :=  3;
        netz.kennung  :='Graph der Funktion f(x,y)=cos(x+y)*sin(x*y).';

        (* Netzinitialisierung *) 
        init_netz(netz);

        (* Funktionsinitialisierung *) 
        init_function(f,netz);

        (* Daten in File schreiben *) 
        sfile_netz(netz,'netz.dat');

        (* Ende kennzeichnen *)
        dummy:=do_alert(concat('[0][File erstellt.|',
                                   '--------------|',
                                   'Ausgabedatei: |',
                                   '  NETZ.DAT ][Alles klar]'),1);

        exit_gem; 
      end; 
    end.

Listing 3: Eingabeprogramm für Netzgraphik


{ - Ausgabeprogramm für NETZGRAPHIK - }

program ausgabe_netz;

{(c) 1987 by Dietmar Rabich.
     Entw. mit ST Pascalt 2.0. }

const {$I \INCLUDE\GEMCONST.INC ) 
type  {$I \INCLUDE\GEMTYPE.INC }

{$I NETZ.INC }

var netz  : netzdaten;
    aplid : short_integer;
    datei : string;

{$I \INCLUDE\GEMSUBS.INC }

function conin(dev:short_integer):char;
  BIOS (2);

procedure eingabe_datei;

  var name : string;

  begin
    (* Argument aus Command-Line lesen *) 
    cmd_getarg(1,name); 
    if name<>'' then 
      datei:=name 
    else 
      begin
        writeln(chr(27),'E *** Ausgabe NETZGRAPHIK***'); 
        writeln('(Entwickelt mit ST Pascal Plus V 2.0)'); 
        write('Bitte Dateinamen eingeben:'); 
        readln(datei); 
      end; 
  end;

  begin 
    aplid:=init_gem; 
    if aplid>=0 then 
      begin 
        init_mouse; 
        hide_mouse; 
        eingabe_datei;

        (* Netz - Daten aus File lesen *) 
        lfile_netz(netz,datei);

        clear_screen;

        (* Kennung des Netzes als Text ausgeben *) 
        draw_string(0,13,netz.kennung);

        (* Netz ausgeben, m.Löschen verdeckter Teile *) 
        ausg_netz(netz,true);

        repeat until conin(2)='  ';

        (* Netz ausgeben, o.Löschen verdeckter Teile *) 
        ausg_netz(netz,false);

        repeat until conin(2)='  '; 
        show_mouse; 
      end; 
    exit_gem; 
  end.

Listing 4: Ausgabeprogramm für Netzgraphik


{ - Ausgabeprogramm für NETZGRAPHIK - }

program netz_1;

{(c) 1987 by Dietmar Rabich.
     Entw. mit ST Pascal* 2.0. }

const {$I \INCLUDE\GEMCONST.INC } 
type  {$I \INCLUDE\GEMTYPE.INC  }

{$I NETZ.INC }

var netz  : netzdaten;
    aplid : short_integer;

{$I \INCLUDE\GEMSUBS.INC }

function conin(dev:short_integer):char; 
  BIOS (2);

function f(x,y:real):real;

  begin 
    f:=sin(abs(x*y)/3); 
  end;

  begin 
    aplid:=init_gem; 
    if aplid>=0 then 
      begin 
        init_mouse; 
        hide_mouse; 
        clear_screen;

        (* Netz - Daten *) 
        netz.breite   :=400; 
        netz.hoehe    :=200; 
        netz.phi      :=  0;
        netz.psi      :=  0;
        netz.x0       :=100;
        netz.y0       :=100;
        netz.pkte_hor := 30; 
        netz.pkte_ver := 20; 
        netz.x_min    := -5; 
        netz.x_max    :=  5;
        netz.y_min    := -5; 
        netz.y_max    :=  5;

        (* Initialisierung *) 
        init_netz(netz); 
        init_function(f,netz);

        (* Ausgabe *) 
        ausg_netz(netz,false);

        repeat until conin(2)='  '; 
        clear_screen;

        (* Änderung des Netzes *) 
        netz.breite   :=200; 
        netz.hoehe    :=100; 
        netz.phi      :=-10;
        netz.psi      :=  0;
        netz.x0       :=150;
        netz.y0       :=150;

        (* Neuinitialisierung *) 
        init_netz(netz);

        (* Neuausgabe *) 
        ausg_netz(netz,false);

        repeat until conin(2)='  ';
        show_mouse; 
        exit_gem; 
      end; 
    end.

Listing 5: Ausgabeprogramm für Netzgraphik/program netz_l


{ - Ausgabeprogramm für NETZGRAPHIK - }

program netz_2;

{(c) 1987 by Dietmar Rabich.
     Entw. mit ST Pascal+ 2.0. }

const {$I \INCLUDE\GEMCONST.INC } 
type  {$I \INCLUDE\GEMTYPE.INC  }

{$I NETZ.INC }

var netz,netz_alt : netzdaten;
    aplid         : short_integer;

{$I \INCLUDE\GEMSUBS.INC }

function conin(dev:short_integer):char; 
  BIOS(2);

function f(x,y:real):real;

  begin f:=cos(abs(x*y)/3); end;

function g(x,y:real):real;

  begin g:=exp(abs(x*y)/2); end;

begin 
  aplid:=init_gem; 
  if aplid>=0 then 
    begin 
      init_mouse; 
      hide_mouse; 
      clear_screen;

      (* Netz - Daten *) 
      netz.breite   :=400; 
      netz.hoehe    :=200; 
      netz.phi      :=  5;
      netz.psi      :=  5;
      netz.x0       :=100;
      netz.y0       :=100;
      netz.pkte_hor := 30; 
      netz.pkte_ver := 20; 
      netz.x_min    := -5; 
      netz.x_max    :=  5;
      netz.y_min    := -5; 
      netz.y_max    :=  5;

      (* Initialisierung *) 
      init_netz(netz); 
      init_function(f,netz);

      (* Ausgabe des Netzes *) 
      ausg_netz(netz,true);

      repeat until conin(2)='  ';
      clear_screen;
      netz_alt:=netz;   (* für evtl.spätere Verwendung *)

      (* Änderung der Funktion *) 
      netz.x_min  := -2;
      netz.x_max  :=  2;
      netz.y_min  := -1;
      netz.y_max  :=  1;

      (* Neuinitialisierung der Funktion *) 
      init_function(g,netz);

      (* Neuausgabe *) 
      ausg_netz(netz,true);

      repeat until conin(2)='  '; 
      show_mouse; 
      exit_gem; 
    end; 
  end.

Listing 6: Ausgabeprogramm für Netzgraphik/program netz_2


Dietmar Rabich
Aus: ST-Computer 04 / 1989, Seite 59

Links

Copyright-Bestimmungen: siehe Über diese Seite