home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************
- * *
- * Filename : NivL2.c *
- * *
- *****************************************************************
- * *
- * Comment : Diese Datei beinhaltet die verschiedenen *
- * Funktionen für die Darstellung der Niveaukurven. *
- * *
- * Funktionen *
- * ========== *
- * *
- * DrawNivCurves() zeichnet Niveaukurven *
- * CalcRect() berechnet ein Rechteck *
- * CheckCorner() kontrolliert zugehörige Ecke *
- * CheckNiv() zählt verschiedene Niveaus *
- * CalcStyle() berechnet nächstes Muster *
- * *
- * Rev : V1.0 *
- * *
- * History : V1.0 erstellen dieses Files 01/01/90 *
- * *
- * Doc : Plotlibrary User's Guide *
- * *
- * Bugs : keine bekannten *
- * *
- * Autor : Oesch Silvano *
- * *
- * Datum : 01/01/90 *
- * *
- ****************************************************************/
-
- /****************************************************************
- * *
- * allgemeine Includedateien *
- * *
- ****************************************************************/
-
- #include <math.h>
-
- /****************************************************************
- * *
- * Plotlibrary Includedateien *
- * *
- ****************************************************************/
-
- #include "Plot.h"
- #include "PlotL2.h"
- #include "SuppL2.h"
- #include "DispL2.h"
- #include "NivL2.h"
-
- /****************************************************************
- * *
- * Globale statische Variablen *
- * *
- ****************************************************************/
-
- static int xpicmin, /* Grenzwerte für xmin,xmax */
- xpicmax, /* ymin,ymax */
- ypicmin,
- ypicmax;
-
- static int bxs, /* Rechteckdim. für die */
- bys; /* Beschriftung */
-
- /****************************************************************
- * *
- * externe Variablen *
- * *
- ****************************************************************/
-
- extern struct Plot *plot;
- extern int plerr;
-
- /****************************************************************
- * *
- * Function : drawnivcurves() *
- * *
- *****************************************************************
- * *
- * Input : void *
- * *
- * Output : int returnset allg Rückgabewert *
- * != FALSE alles klar *
- * == FALSE Fehler *
- * *
- *****************************************************************
- * *
- * Comment : Diese Funktion zeichnet und beschriftet alle *
- * Niveaukurven. Das Vorgehen dieser komplexen *
- * Funktion ist vereinfacht in dem nachfolgenden *
- * Ablauf erklärt. Da diese Funktion ein Flächen- *
- * clipping durchführen muss, sollte eigentlich *
- * der Sutherland-Hodgman Algorithmus verwendet *
- * werden. Dieser Algorithmus ist jedoch sehr rechen- *
- * intensiv und nicht einfach zu programmieren. Aus *
- * Zeitgründen wurde auf den Cohen-Sutherland *
- * Algorithmus zurückgegriffen. Mithilfe des Rück- *
- * gabewertes könnte so ein einfaches und schnelles *
- * Flächenclipping durchgeführt werden. Für eine *
- * nähere Beschreibung des Clippings wird auf die *
- * Diplomarbeit verwiesen. *
- * *
- ****************************************************************/
-
- int drawnivcurves()
- {
-
- register GPT *iarray1, /* aktueller Punkt */
- *iarray2; /* vorhergehender Punkt */
-
- GPT *iarray; /* Speicher Arraystart */
-
- int set,set1, /* Startwertflags */
- count, /* Schleifenzähler */
- ptc, /* Anzahl Punkte Polygon */
- tris, /* Translation Status */
- xs,xe,xe1, /* X-Koordinaten */
- ys,ye,ye1, /* Y-Koordinaten */
- returnset=TRUE, /* allg. Rückgabewert */
- fill, /* Polygon Rückgabewert */
- beschx, /* horiz. Beschriftung */
- len, /* länge des Niveautextes */
- oldcol=NULL; /* Farbenspeicher */
-
- char cstat, /* Clipping Status */
- cstat1, /* Clipp Status Speicher */
- buffer[20]; /* für Niveautext */
-
- DATA *x,*y, /* X und Y Wert */
- *array, /* Zeiger auf Daten */
- value; /* Niveauwert */
-
- struct Curve *curve; /* Kurvenzeiger */
-
- /****************************************************************
- * *
- * Das zeichnen der Niveaukurven ist nicht mehr so einfach wie *
- * dass der 2d-Kurven. Der Hauptunterschied liegt darin, das *
- * für jedes Niveau eine Fläche und keine Linie gezeichnet wird. *
- * Das nachfolgende Ablaufdiagramm zeigt vereinfacht die *
- * verschiedenen Abschnitte auf, welche für eine Niveau- *
- * Darstellung benötigt werden. *
- * *
- * Bis alle Niveaus gezeichnet *
- * hole Integerarray *
- * Bis alle Werte dieses Niveau gezeichnet *
- * Konvertieren des Punktes *
- * Wenn Startwert berechnet *
- * Wenn clipping *
- * clippen *
- * status Flächenclippen *
- * Ecke zuweisen *
- * status line *
- * Wenn Startwert nicht vorhanden diesen setzen *
- * Evt doch noch Flächenclippen *
- * Punkt addieren *
- * else *
- * Wenn Startwert nicht vorhanden diesen setzen *
- * Neuer Punkt addieren *
- * Startwert auf Endwert setzen *
- * Berechne evt letzten Punkt des Polygones *
- * Zeichne Polygon *
- * Beschrifte Niveau wenn noch nicht vorhanden *
- * zurück mit dem Status dieser Funktion *
- * *
- ****************************************************************/
-
- trans2d(&plot->xmin,&plot->ymin,&xpicmin,&ypicmin);
- trans2d(&plot->xmax,&plot->ymax,&xpicmax,&ypicmax);
- /* init. der Grenzwerte */
- bxs = (RECTSIZE)*plot->xtext; /* Länge des Rechteckes */
- bys = 3*plot->ytext/2; /* Höhe des Rechteckes */
- beschx = plot->xpic1; /* Start der Beschriftung */
- curve = plot->first; /* erste Kurve */
- value = curve->zmin+1; /* Value sicher ungleich */
- /* erstem Niveau */
- while (curve != NULL) /* Für alle Kurven */
- {
- set = FALSE; /* Für jede Kurve neu */
- set1 = FALSE; /* setzten */
- cstat1 = 0x00;
-
- ptc = curve->count+2; /* Grösse des Feldes */
- if (plot->clipp == CLIPP) /* berechnen, auch für */
- ptc = 5*ptc/3; /* clipping */
- iarray = malloc(ptc*valsize()*sizeof(GPT));
- if (iarray == NULL) /* speicher bekommen */
- { /* Nein */
- seterror(GRAPHMEM); /* Fehler setzten und */
- return(FALSE); /* zurück */
- }
-
- iarray1 = iarray; /* Arraypointer init. */
- iarray2 = iarray;
- if (value != curve->zmin) /* Farbe und Muster für */
- { /* neues Niveau berechnen */
- calccolor(curve->color);
- calcstyle();
- }
- else
- SetFgColor(oldcol); /* Farbe rücksetzten */
-
-
- array = curve->val; /* Datenzeiger init. */
- for (count = 0;count<curve->count;count++)
- { /* für alle Datenpaare */
- x = array++; /* x und y zuweisen */
- y = array++; /* immer noch DATA */
-
- tris = trans2d(x,y,&xe,&ye); /* und konvertieren */
- if (tris != TRUE) /* Fehler */
- { /* Ja,dann neue Grenz- */
- if ( tris & XTRANS) /* koordinaten zuweisen */
- xe = plot->xpic1; /* ACHTUNG! Darstellung */
- if ( tris & YTRANS) /* stimmt nicht 100% */
- ye = plot->ypic2;
- }
-
- if (set == TRUE) /* Startwert gesetzt */
- { /* Ja */
- if (plot->clipp == CLIPP) /* nur bei clippen */
- { /* der komplexe Prozess */
- xe1 = xe; /* speichern der orginal- */
- ye1 = ye; /* endkoordinaten */
- cstat = doclipp(&xs,&ys,&xe1,&ye1);
-
- /****************************************************************
- * *
- * Die Clipping Routine liefert nur dann einen Status von NULL, *
- * wenn die Linie gezeichnet werden muss. Ansonsten ist dieser *
- * ungleich NULL. Dieser Status wird nun mit dem vorhergehenden *
- * Status auf gleichheit kontrolliert. Nur wenn dieser Vergleich *
- * negativ ausfällt, d.h. die Seite wurde gewechselt, muss die *
- * dazwischenliegende Ecke gezeichnet werden. *
- * *
- ****************************************************************/
-
- if (cstat) /* Status gegeben */
- { /* also clippen */
- if ((cstat1) and /* vorhergehender gesetzt */
- (cstat != cstat1)) /* und ungleich */
- { /* dann Ecke zeichnen */
- switch (cstat | cstat1) /* welcher Seitenwechsel */
- {
- case (C_L | C_B): /* unten links */
- *iarray1++ = plot->xpic1;
- *iarray1++ = plot->ypic2;
- break;
- case (C_L | C_T): /* oben links */
- *iarray1++ = plot->xpic1;
- *iarray1++ = plot->ypic1;
- break;
- case (C_R | C_B): /* unten rechts */
- *iarray1++ = plot->xpic2;
- *iarray1++ = plot->ypic2;
- break;
- case (C_R | C_T): /* oben rechts */
- *iarray1++ = plot->xpic2;
- *iarray1++ = plot->ypic1;
- break;
- }
- iarray2 +=2;
- }
- cstat1 = cstat; /* Status speichern */
- }
- else /* also kein spez. clipp. */
- {
- cstat1 = 0x00; /* löschen alter Status */
- if (set1 == FALSE) /* Start schon gesetzt ? */
- { /* Nein, dann schreibe */
- *iarray1++ = xs; /* diese Werte in das */
- *iarray1++ = ys; /* Array */
- set1 = TRUE; /* Startwert gesetzt */
- }
-
- /****************************************************************
- * *
- * Wenn die gespeicherten Startwerte ungleich den eff. *
- * Startwerten sind, müssen diese die Startwerte in das Array *
- * eingefügt werden. Dies ist dann der Fall, wenn xs1 bzw. ys1 *
- * geclippt wurden und xs und ys auch. Wenn nun der Unterschied *
- * zwischen diesen Werten grösser gleich ein Punkt ist, dann *
- * muss dieser Punkt zusätzlich eingefügt werden. *
- * *
- ****************************************************************/
-
- if ((iarray2[0] != xs) or (iarray2[1] != ys))
- { /* Punkte ungleich */
- *iarray1++ = xs; /* dann speichern dieser */
- *iarray1++ = ys; /* Werte */
- iarray2 +=2;
- }
-
- *iarray1++ = xe1; /* Endwerte in das Array */
- *iarray1++ = ye1; /* eintragen */
- iarray2 +=2;
- }
- }
- else /* kein Clipping */
- {
- if (set1==FALSE) /* Startwert gesetzt */
- { /* Nein */
- *iarray1++ = xs; /* Also Startwerte */
- *iarray1++ = ys; /* speichern und Flag */
- set1 = TRUE; /* setzten */
- }
- *iarray1++ = xe; /* Endwerte speichern */
- *iarray1++ = ye;
- }
- }
- xs = xe; /* Startwerte auf orginal */
- ys = ye; /* Endwerte setzen */
- set = TRUE; /* und Flag setzen */
- }
-
- /****************************************************************
- * *
- * Ab dieser Stelle ist das Polygon mit den vorhandenen Daten *
- * berechnet worden. Es geht jetzt darum, ein evt. nicht *
- * geschlossenes Polygon über den dazugehörigen Ecken oder *
- * Kante zu schliessen. Der Zustand eines offenen Polygones ist *
- * normalerweise nicht legal. Es kann jedoch vorkommen, wenn *
- * ein Niveau abgetastet wird, dass dies nur in einem Bereich *
- * erfolgt. Danach ist ein offener Zustand möglich und dieser *
- * wird hier beseitigt. *
- * *
- ****************************************************************/
-
- xs = iarray[0]; /* hole 1. Koordinate */
- ys = iarray[1];
-
- if (plot->clipp == CLIPP) /* Wenn geclippt, hole */
- { /* letzte Koordinate */
- xe = iarray2[0];
- ye = iarray2[1];
- }
-
- if ((xs != xe) or (ys != ye)) /* sind die Punkte gleich */
- { /* Nein, es ist offen */
- if ((xs != xe) and /* sind x-werte und */
- (ys != ye)) /* y-werte ungleich */
- { /* dann muss es Ecke sein */
- switch(checkcorner(xs,ys,xe,ye))
- { /* welche ist es denn */
- case TOP_LEFT: /* die entsprechenden */
- *iarray1++ = xpicmin; /* min- bzw. max-werte */
- *iarray1++ = ypicmax; /* werden in das Array */
- break; /* hinzugefügt. */
- case BOT_LEFT: /* Am Ende kommt noch die */
- *iarray1++ = xpicmin; /* Startkoordinate für */
- *iarray1++ = ypicmin; /* alle dre Fälle hinzu. */
- break;
- case TOP_RIGHT:
- *iarray1++ = xpicmax;
- *iarray1++ = ypicmax;
- break;
- case BOT_RIGHT:
- *iarray1++ = xpicmax;
- *iarray1++ = ypicmin;
- break;
- }
- *iarray1++ = xs; /* auch für die Kanten- */
- *iarray1++ = ys; /* fälle */
- }
- }
-
- /****************************************************************
- * *
- * Nun ist alles berechnet und gespeichert in einem Array. *
- * Bevor nun das Polygon gezeichnet werden kann, muss die *
- * Anzahl der Koordinaten bestimmt werden. Danach wird es *
- * gezeichnet und beschriftet. Für jedes Niveau wird am unteren *
- * Bildrand ein kleines Rechteck mit dem entsprechenden Muster *
- * gezeichnet. In der mitte diese Rechteckes steht dann der *
- * Niveauwert. Die Beschriftung erfolgt jedoch nur dann, wenn *
- * der alte Niveauwert nicht mit den aktuellen übereinstimmt. *
- * *
- ****************************************************************/
-
- ptc = (iarray1 - iarray)/valsize();
- /* Berechne Anzahl Punkte */
- fill = FillPolyLine(ptc,iarray); /* und zeichne es */
- if (fill == FALSE) /* hat es funktioniert */
- { /* Nein */
- seterror(GRAPHFILL); /* Fehler */
- setreturn(FALSE);
- free(iarray); /* speicher freigeben */
- break; /* und WHILE verlassen */
- }
-
- if (value != curve->zmin) /* beschriften ? */
- { /* Ja */
- value = curve->zmin; /* akt. Wert speichern */
- len = sprintf(buffer,"%.4lg",value);
- /* Niveauwert konv. */
- calcrect(beschx,plot->cpt+plot->yht,len);
- /* und Rechteck zeichnen */
- oldcol = GetFgColor(); /* speichern von color */
- SetFgColor(TEXTCOL); /* und für Text setzten */
- printtextabs( buffer, /* Wert schreiben */
- beschx+bxs/2,
- plot->cpt+plot->yht/2,
- T_CX|T_T);
- beschx += bxs; /* Beschriftungswert */
- if (beschx > plot->xpic2-bxs) /* am Ende einer Teile */
- { /* Ja */
- beschx = plot->xpic1; /* dann nächste Zeile */
- plot->cpt += bys+plot->yht; /* nehmen */
- }
- }
- free(iarray); /* Array freigeben */
- curve = curve->next; /* und nächste Kurve */
- } /* Ende von WHILE */
- return(returnset); /* endlich fertig */
- }
-
- /****************************************************************
- * *
- * Function : calcrect() *
- * *
- *****************************************************************
- * *
- * Input : x,y *
- * int x obere *
- * int y linke Ecke *
- * *
- * Output : void *
- * *
- *****************************************************************
- * *
- * Comment : CalcRect berechnet die Koordinaten der *
- * Beschriftungsrechtecke und schreibt diese in das *
- * Koordinatenarray Rect. Danach wird das Rechteck *
- * mit der gleichen Farbe und dem gleichen Muster *
- * gezeichnet. *
- * *
- ****************************************************************/
-
- static void calcrect(x,y,len)
- int x,
- y,
- len;
- {
-
- int transa[] = /* Koordinatenpunkte */
- {
- 0,0,1,0,1,1,0,1,0,0
- },
- i,j, /* Schleifenzähler */
- size,
- rsize;
- GPT rect[10]; /* Koordinatenarray */
-
- size = (len+2)*plot->xtext;
- rsize = (bxs-size)/2;
-
- for (j=0;j<2;j++)
- {
- for (i=0;i<10;i+=2) /* 4+Startpunkt */
- {
- rect[i] = x+transa[i]*rsize+j*(rsize+size);
- /* X-Koordinate */
- rect[i+1] = y+transa[i+1]*bys; /* Y-Koordinate */
- }
- FillPolyLine(5,rect); /* und zeichnen */
- }
- DrawRectangle(x+rsize,y,x+rsize+size,y+bys);
- }
-
- /****************************************************************
- * *
- * Function : CheckCorner() *
- * *
- *****************************************************************
- * *
- * Input : xs,ys,xe,ye *
- * int xs X Startkoordinate *
- * int ys Y Startkoordinate *
- * int xe X Endkoordinate *
- * int ye Y Endkoordinate *
- * *
- * Output : int corner zugehörige Ecke *
- * *
- *****************************************************************
- * *
- * Comment : Diese Funktion berechnet die zugehörige Ecke einer *
- * Niveaukurve wenn diese nicht geschlossen vorhanden *
- * ist. Normalerweise muss eine geschlossen Kurve *
- * vorhanden sein. Wenn jedoch eine Kurve bei den *
- * min- oder maxwerten beginnt oder aufhört, kann *
- * diese Kurve nicht geschlossen sein. Es wird hier *
- * dann die entsprechende Flächenecke gesucht. *
- * Danach kann diese diese Ecke in die Fläche ein- *
- * gefügt werden. Es ist also zu beachten, dass nicht *
- * geschlossene Kurven immer über eine Ecke verbunden *
- * werden. Dadurch kann es zu einer nicht korrekten *
- * Darstellung kommen. *
- * Weiter muss das Integerarray für diese *
- * zusätzlichen Punkte ( 2 ) vorbereitet sein. *
- * *
- ****************************************************************/
-
- static int checkcorner(xs,ys,xe,ye)
- int xs,ys,xe,ye;
- {
- int temp, /* Zwischenspeicher */
- returnset; /* all. Rückgabewert */
-
- if (xs > xe) /* Von einer Seite her */
- { /* betrachten */
- swap(xs,xe,temp); /* tausche die Koordinaten */
- swap(ys,ye,temp);
- }
-
- if (xs <= xpicmin) /* linke Seite ? */
- if (ye >= ypicmin) /* untere Seite ? */
- setreturn(BOT_LEFT); /* setzte Ecke */
- else /* sonst */
- setreturn(TOP_LEFT); /* obere Ecke */
- else /* also rechte Seite */
- if (ys >= ypicmin) /* untere Seite */
- setreturn(BOT_RIGHT); /* setzte Ecke */
- else /* sonst */
- setreturn(TOP_RIGHT); /* obere Ecke */
- return(returnset); /* und zurück */
- }
-
- /****************************************************************
- * *
- * Function : checkniv() *
- * *
- *****************************************************************
- * *
- * Input : void *
- * *
- * Output : int niveaus Anzahl verschiedener Niveaus *
- * *
- *****************************************************************
- * *
- * Comment : Diese Funktion zählt die verschiedenen Niveau *
- * welche im Speicher geladen sind. Der Niveauwert *
- * wird beim Laden der Daten in den zmin Wert *
- * geschrieben. *
- * *
- ****************************************************************/
-
- int checkniv()
- {
- DATA value; /* Niveauwert */
- int count = 1; /* Niveaucount */
- struct Curve *curve; /* Kurvenzeiger */
-
- curve = plot->first; /* Erste Kurve */
- value = curve->zmin; /* Wert der ersten Kurve */
- while (curve != NULL) /* solange Kurven vorhanden */
- {
- if (curve->zmin != value) /* neuer Wert ? */
- { /* Ja */
- value = curve->zmin; /* Neuer Wert zuweisen */
- count++; /* und Zähler erhöhen */
- }
- curve = curve->next; /* nächste Kurve */
- }
- return(count); /* zurück mit Zähler */
- }
-
- /****************************************************************
- * *
- * Function : calcstyle() *
- * *
- *****************************************************************
- * *
- * Input : void *
- * *
- * Output : void *
- * *
- *****************************************************************
- * *
- * Comment : Diese Funktion berechnet das nächste verfügbare *
- * Füllmuster. In der Styletab sind die gewünschten *
- * Muster aufgeführt welche angewählt werden können. *
- * Wenn kein Muster mehr vorhanden ist, dann wird *
- * wieder bei dem ersten Muster begonnen. *
- * *
- ****************************************************************/
-
- static void calcstyle()
- {
-
- int styletab[5] = /* Mustertabelle */
- { 4,5,7,8,10 };
-
- if (plot->style == NOSTYLE) /* keine füllen erwünscht */
- SetFillStyle(0); /* setzte NOFILL */
- else /* sonst berechne neues */
- { /* Muster */
- if (plot->style > 4) /* letztes Muster erreicht */
- plot->style = 0; /* Ja, dann von neuem */
- SetFillStyle(styletab[plot->style++]);
- } /* setzte Muster */
- }
-
-