/***** ** Duesseldorf, den 10.4.1995. ** chull.C: Berechnung der Konvexen Huelle von Punkten im R^2. ** Wenn die Eingabedaten exakt in einfacher Genauigkeit darstellbar sind, dann ** arbeitet chull ohne Rundungsfehler. *****/ #include #include #include #include #include "fpu_ctrl.h" #include "sgnsum.h" // ESSA #include "interval.h" // Intervall-Paket mit einfacher Genauigkeit. /*---------------------------------------------------------------------------- type tStat: Beschreibung: Struktur zur Aufnahme der Statistik. ----------------------------------------------------------------------------*/ typedef struct { int n, // Anzahl der Punkte nHull, // Anzahl der Punkte der berechneten Huelle. nGraham, // Anzahl der nach dem Loeschen an Graham ueberg. Pkt. time, // Gesamtlaufzeit. nSgnsumPre, // Anzahl der Aufrufe von ESSA im Preprocessing. nSgnsumGR, // Anzahl der Aufrufe von ESSA in Graham-Scan. timeSgnsumPre, // Laufzeit fuer ESSA im Preprocessing. timeSgnsumGR; // Laufzeit fuer ESSA in Graham-Scan. } tStat; tStat st; // globale Statistikvariable. /*---------------------------------------------------------------------------- class cPoint: Beschreibung: Darstellung der Punkte in R^2. ----------------------------------------------------------------------------*/ class cPoint { public: cPoint(); cPoint(float,float); cPoint(cPoint&); cPoint &operator=(cPoint&); float x,y; }; cPoint::cPoint() { x=y=0; } cPoint::cPoint(float _x, float _y) { x= _x; y= _y; } cPoint::cPoint(cPoint &p) { x= p.x; y= p.y; } cPoint &cPoint::operator=(cPoint &p) { x= p.x; y= p.y; return *this; } /*---------------------------------------------------------------------------- class cIntStack: Beschreibung: Realisierung eines Stacks zur Aufnahme von Integern. ----------------------------------------------------------------------------*/ typedef struct sIntStack { int i; struct sIntStack *next; }tIntStack; class cIntStack { public: cIntStack(); // Initialisierung. ~cIntStack(); // Destructor. int IsEmpty(void); // Test, ob Stack leer ist. void Push(int p); // Einfuegen in Stack. void Pop(void); // Erstes Element aus Stack entfernen. int Get(int n=0); // n=0: Erstes Element lesen, n=1 zweites Element lesen. tIntStack *top; }; cIntStack::cIntStack() { top=NULL; } cIntStack::~cIntStack() { while (!IsEmpty()) Pop(); } cIntStack::IsEmpty(void) { return top==NULL; } void cIntStack::Push(int p) { tIntStack *IS; IS= new tIntStack; IS->i= p; IS->next= top; top= IS; } void cIntStack::Pop(void) { tIntStack *IS; if (top!=NULL) { IS=top; top= top->next; free(IS); } } int cIntStack::Get(int n) { if (n==0) return top->i; else return top->next->i; } /*---------------------------------------------------------------------------- Funktion swap: Beschreibung: Vertauscht a und b. ----------------------------------------------------------------------------*/ void swap(cPoint &a, cPoint &b) { cPoint tmp= a; a= b; b= tmp; } /*---------------------------------------------------------------------------- Funktion LeftTest: Input: a,b,c: cPoint, ESSA..Anzahl der ESSA-Aufrufe, tESSA..Laufzeit der ESSA-Aufrufe Output: 1 oder 0. Beschreibung: Es wird getestet, ob die Drehung von b nach y im Ursprung a eine Linksdrehung ist. Fuehrt der Test mit Hilfe von Intervallarithmetik nicht zum Ergebnis, wird ESSA aufgerufen. Dies garantiert immer eine exakte Lösung. ----------------------------------------------------------------------------*/ int LeftTest(cPoint a, cPoint b, cPoint y, int &ESSA, int &tESSA) { interval d,Si[9]; int i,CPUT; double S[9]; //** Die Summanden: Si[1]= interval(y.x)*interval(a.y); Si[2]= interval(a.x)*interval(b.y); Si[3]= interval(b.x)*interval(y.y); Si[4]= -interval(y.x)*interval(b.y); Si[5]= -interval(a.x)*interval(y.y); Si[6]= -interval(b.x)*interval(a.y); d=0; for (i=1;i<=6;i++) d+= Si[i]; // printf("d: %e %e, w(d): %e\n",d.Inf(),d.Sup(),d.Diam()); if (d.Inf()>0) return 1; if (d.Sup()<0) return -1; if (d.Inf==0&&d.Sup==0) return 0; //** Vorbereitungen fuer den Aufruf von ESSA. S[1]= (double)y.x*(double)a.y; S[2]= (double)a.x*(double)b.y; S[3]= (double)b.x*(double)y.y; S[4]= -(double)y.x*(double)b.y; S[5]= -(double)a.x*(double)y.y; S[6]= -(double)b.x*(double)a.y; ESSA++; CPUT=-GetCPUUsage(); // printf("sgnsum %i\n",st.nSgnsum); i=sgnsum(S,6); CPUT+=GetCPUUsage(); tESSA+=CPUT; return i; } /*---------------------------------------------------------------------------- Funktion FindLowest: Beschreibung: Suche nach dem am weitesten unten rechts gelegenen Punkt in P. Dieser wird nach P[0] kopiert. ----------------------------------------------------------------------------*/ //** FindLowest. cPoint FindLowest(int &n, cPoint *P) { int i,m,j; m=0; for (i=1;iP[m].x) ) m=i; swap(P[m],P[0]); j=1; for (i=1;i> 1)+1; ir=n; for(;;) { if (l>1) rra=ra[--l]; else { rra=ra[ir]; ra[ir]=ra[1]; if (--ir==1) { ra[1]=rra; return; } } /* (l<=1) */ i=l; j=l<<1; while (j<=ir) { if ( j0 ) ++j; if ( LeftTest(P0,rra,ra[j],st.nSgnsumPre,st.timeSgnsumPre)>0 ) { ra[i]=ra[j]; j+=(i=j); } else j=ir+1; } ra[i]=rra; } /* for(;;) */ } /*---------------------------------------------------------------------------- Funktion DeleteDoubles: Beschreibung: Wenn zwei Punkte auf einer Geraden durch P[0] liegen, dann wird der jeweils P[0] naehere Punkt geloescht. ----------------------------------------------------------------------------*/ void DeleteDoubles(int &n, cPoint *P) { int i,j=1,k,CPUT; interval Si[13],d; cPoint a,b,c; // printf("nDelete: %i\n",n); a=P[0]; for (i=2;ic.x) P[j]= P[i]; } else if (b.y0 ) { ST.Push(i); i++; } else ST.Pop(); } } /*---------------------------------------------------------------------------- Funktion ComputeHull: Beschreibung: Berechnung der konvexen Huelle der Punkte in der Liste P mit der Laenge n. Die Liste Hull der Laenge m enthaelt die entgegen dem Uhrzeigersinn sortierten Punkte der Huelle. ----------------------------------------------------------------------------*/ void ComputeHull(cPoint *P, int n, cPoint *Hull, int &m) { cIntStack ST; int i; //** Initialisierung der Statistik. st.nSgnsumPre=0; st.nSgnsumGR=0; st.nHull= 0; st.timeSgnsumPre=0; st.timeSgnsumGR=0; st.time=-GetCPUUsage(); st.n= n; //** Suche der am weitesten rechts unten gelegenen Punkt. FindLowest(n,P); // printf("Lowest: %e, %e\n",P[0].x, P[0].y); //** Sortiere die Punkte gegen den Uhrzeigersinn mit Ursprung P[0]. SortCounterClockwise(n-1,P,P[0]); // printf("Sorted List:\n"); // for (i=0;i". An Dateiname wird die Endung ".points" angehaengt. In der Datei "Dateiname.points" sollten die Punkte zu dennen die Huelle berechnet werden soll stehen. Dabei muss in jeder Zeile ein Punkt stehen. Die Huelle wird in der Datei "Dateiname.hull" gespeichert. Die Statistik wird in der Datei "Dateiname.stat" gespeichert. ----------------------------------------------------------------------------*/ int main(int al, char **a) { cPoint P[10010],Hull[10010]; int i,n,m; char c[1000],cc[1000],*ccc; cPoint P0,P1,P2; float x,y; FILE *f; if (al>2) { switch(**(a+1)) { case 't': //** Einlesen der Punkte im Textformat strcpy(c,*(a+2)); strcat(c,".points"); if ( (f=fopen(c,"rt"))==NULL ) { printf("Die Datei %s konnte nicht geoeffnet werden.\n",c); exit(1); } n=0; for (;;) { if (fgets(c,900,f)==NULL) break; ccc= strstr(c," "); ccc++; P[n]= cPoint((float)atof(c),(float)atof(ccc)); n++; } fclose(f); printf("%i Punkte gelesen\n",n); break; case 'b': //** Einlesen der Punkte im Binaerformat strcpy(c,*(a+2)); strcat(c,".bpoints"); if ( (f=fopen(c,"r"))==NULL ) { printf("Die Datei %s konnte nicht geoeffnet werden.\n",c); exit(1); } fread(&n,1,sizeof(int),f); for (i=0;i\n"); exit(1); } }