home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Resource Library: Graphics
/
graphics-16000.iso
/
general
/
raytrace
/
renaisnc
/
delaunay.lha
/
Delaunay
/
.‾GrahamHull.c
next >
Wrap
C/C++ Source or Header
|
1992-01-04
|
3KB
|
127 lines
/*
File: GrahamHull.c
Authors: K.R. Sloan
Last Modified: 5 January 1987
Purpose: calculates the convex hull of a set of <x,y> points,
using the Graham Scan method.
*/
#include <malloc.h>
#include "DCEL.h"
#include "GrahamHull.h"
typedef struct HeapKeyRecord HeapKey;
struct HeapKeyRecord
{
REAL A;
int P;
};
static void Heapify(V, Root, Last)
HeapKey V[];
int Root, Last;
{
int r,s;
HeapKey t;
t = V[Root]; r = Root;
for (s=r;r==s;)
{
s = r+r;
if (s < Last) if (V[s].A < V[s+1].A) s = s+1;
if (s <= Last) if (t.A < V[s].A ) { V[r] = V[s]; r = s; }
}
V[r] = t;
}
void HeapSort(V, LastElement)
HeapKey V[];
int LastElement;
{
int i;
HeapKey t;
for (i = LastElement / 2; i > 1; i--) Heapify(V,i,LastElement);
for (i = LastElement; i > 1; i--)
{ /* 2..i form a Heap */
Heapify(V, 1,i);
t = V[1]; V[1] = V[i]; V[i] = t;
}
}
PointSetPointer GrahamHull(Points, LastPoint)
Point Points[];
int LastPoint;
{
HeapKey *Heap;
int i;
PointSetPointer Hull, H, X, FirstHullPoint;
REAL Ax, Ay, Bx, By, Cx, Cy, Ox, Oy;
Heap = (HeapKey *) malloc( (LastPoint+1) * sizeof(HeapKey) );
Ax = Points[0].x; Ay = Points[0].y;
Bx = Points[1].x; By = Points[1].y;
for (i=2;;i++)
{
Cx = Points[i].x; Cy = Points[i].y;
if (((Ax-Bx)*(Ay-Cy) - (Ay-By)*(Ax-Cx)) != 0.0) break; /* not colinear */
}
Ox = (Ax+Bx+Cx) / 3.0; Oy = (Ay+By+Cy) / 3.0; /* an internal point */
/* Points[LastPoint] is reserved for just such emergencies */
Points[LastPoint].x = Ox; Points[LastPoint].y = Oy;
for (i=1; i<=LastPoint; i++)
{
Heap[i].P = i-1; /* off by one to help HeapSort */
Heap[i].A = FowlerAngle(LastPoint, i-1);
}
HeapSort(Heap, LastPoint);
Hull = NewPoint();
Hull->P = Heap[1].P;
Hull->Previous = Hull; Hull->Next = Hull; /* circular */
for (i=2; i<=LastPoint; i++)
{
H = NewPoint();
H->P = Heap[i].P; H->Previous = Hull->Previous; H->Next = Hull;
Hull->Previous->Next = H; Hull->Previous = H;
}
/*
All points are now in a doubly-linked, circular list, sorted
by angle about O
*/
H = Hull;
FirstHullPoint = Hull;
for(;;)
{
H = H->Next;
if (Points[H->P].x < Points[FirstHullPoint->P].x) FirstHullPoint = H;
if (H == Hull) break;
}
/*
FirstHullPoint is on the hull - now find the others
*/
for(H=FirstHullPoint; H->Next != FirstHullPoint; )
{
if (LeftTurn(H->P, H->Next->P, H->Next->Next->P))
H = H->Next;
else
{ /* next point is internal */
X = H->Next;
H->Next = X->Next;
X->Next->Previous = H;
DisposePoint(X);
if (H != FirstHullPoint)
H = H->Previous; /* back up, maybe */
} /* next point is internal */
}
free(Heap);
return (FirstHullPoint);
}