home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume38
/
tessel
/
part01
/
tessel.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-06-20
|
12KB
|
344 lines
/*+-----------------------------------------------------------------------+
*| This file contains subroutines used to tesselate convex and concave |
*| N-point polygons into triangles. At present, it does not handle |
*| complex polygons. |
*| |
*| Author: Michael S. A. Robb Version: 1.1 Date: 29/05/93 |
*+-----------------------------------------------------------------------+
*/
#include <stdio.h>
#include <stdlib.h>
#include "triangle.h"
#include "tessel.h"
/*
*+-----------------------------------------------------------------------+
*| These global variables are used to reference the polygon vertex list. |
*+-----------------------------------------------------------------------+
*/
void (*polygon_proc)( COORD *triangle ); /* User defined function. */
/*
*+-----------------------------------------------------------------------+
*| This subroutine is used to set the user-defined procedure called to |
*| render a triangle. |
*+-----------------------------------------------------------------------+
*/
void polygon_setproc( proc )
void (*proc)();
{
polygon_proc = proc; /* Set the polygon procedure. */
}
/*
*+-----------------------------------------------------------------------+
*| This subroutine is used to reverse the coordinates in the polygon |
*| vertex list. Used to handle anti-clockwise ordering of vertices. |
*+-----------------------------------------------------------------------+
*/
void polygon_reverse( nverts, vlist )
int nverts;
COORD *vlist;
{
COORD temp; /* Used for copying. */
int from = 0, to = nverts; /* Start and finish of list. */
while ( ++from < --to ) /* Swap until both ends meet. */
{
temp = vlist[from];
vlist[from] = vlist[to];
vlist[to] = temp;
}
}
/*
*+------------------------------------------------------------------------+
*| This suboutine is used to determine the intersection between the line |
*| vectors from P1 to P2 and P3 to P4. A result of TRUE is returned if |
*| the two vectors intersect within the end-points, and <point> is filled |
*| with the point of intersection. Otherwise, a result of FALSE occurs. |
*+------------------------------------------------------------------------+
*/
int coord_intersection( point, p1, p2, p3, p4 )
COORD *point,
*p1, *p2,
*p3, *p4;
{
MATDATA val_det, val_t, val_s; /* Determinants of matrices. */
val_det = MATRIX_DET_2X2( *p1, *p2, *p3, *p4 );
if ( val_det != 0 ) /* Intersection point exists? */
{
val_t = MATRIX_DET_2X2( *p1, *p3, *p3, *p4 )
* CONSTANT_ONE / val_det;
val_s = MATRIX_DET_2X2( *p1, *p2, *p3, *p1 )
* CONSTANT_ONE / val_det;
if ( val_t <= 0L && val_s >= CONSTANT_ONE || /* Within range of edge */
val_s <= 0L && val_t >= CONSTANT_ONE ) /* segments? */
/* Do nothing */
{}
else
if ( val_t >= 0 && val_t <= CONSTANT_ONE && /* Are results within */
val_s >= 0 && val_s <= CONSTANT_ONE ) /* bounds of the two */
{ /* edges? */
point -> c_xpos /* Calculate X coordinate. */
= p1 -> c_xpos
+ (int)( val_t * ( p2 -> c_xpos - p1 -> c_xpos ) / CONSTANT_ONE );
point -> c_ypos /* Calculate Y coordinate. */
= p1 -> c_ypos
+ (int)( val_t * ( p2 -> c_ypos - p1 -> c_ypos ) / CONSTANT_ONE );
return( 1 );
}
}
return( 0 );
}
/*
*+-----------------------------------------------------------------------+
*| This subroutine is used to determine whether the given polygon is |
*| bow-tied or not (has edges which cross over ie. bow-tie). A result of |
*| TRUE is returned if the polygon is bow-tied. Otherwise, a result of |
*| FALSE is returned. |
*+-----------------------------------------------------------------------+
*/
int polygon_complex( nverts, vertlist )
int nverts;
COORD *vertlist;
{
int m, n, i, j; /* Loop counters */
static COORD point; /* Point of intersection. */
if ( nverts <= 3 ) /* Triangles can never be */
return( 0 ); /* bow-tied. */
for ( m = 0, n = 1; n < nverts; m++, n++) /* First edge segment. */
for ( i = n; i < nverts; i++ ) /* Second edge segment. */
{
j = ( i+1 == nverts ? 0 : i+1 );
if ( coord_intersection( &point, /* Check for intersection of */
vertlist+m, vertlist+n, /* edges. */
vertlist+i, vertlist+j ) )
return( 1 ); /* Intersection exists, so */
} /* the polygon is bow-tied. */
return( 0 ); /* Polygon is not bow-tied. */
}
/*
*+-----------------------------------------------------------------------+
*| This subroutine is used to determine whether the vertices of the |
*| polygon are ordered clockwise or anticlockwise. A result of TRUE is |
*| returned for clockwise polygons. A result of FALSE is returned for |
*| anticlockwise polygons. |
*+-----------------------------------------------------------------------+
*/
int polygon_clockwise( nverts, vlist )
int nverts;
COORD *vlist;
{
int n, p, q = 0, r; /* Vertex indices/counters. */
MATDATA lowx_val = vlist[0].c_xpos; /* Used for X coord. checks. */
MATDATA lowy_val = vlist[0].c_ypos; /* Used for Y coord. checks. */
for ( n = 1; n < nverts; n++ ) /* For each vertex. */
if ( vlist[n].c_xpos < lowx_val ) /* Vertex has lower X coord? */
{
q = n; /* Yes, so set index and */
lowx_val = vlist[n].c_xpos; /* the best X coordinate. */
lowy_val = vlist[n].c_ypos;
}
else
if (vlist[n].c_xpos == lowx_val && /* No, but is X coord. equal */
vlist[n].c_ypos < lowy_val ) /* and Y coordinate lower? */
{
q = n; /* Yes, so set index and the */
lowy_val = vlist[n].c_ypos; /* best Y coordinate. */
}
p = ( q > 0 ? q-1 : nverts-1 ); /* Find index values of the */
r = ( q < nverts-1 ? q+1 : 0 ); /* adjacent vertices. */
return( ANGLE_CONVEX( vlist, p, q, r ) ); /* Then return the result of */
} /* the convex angle test. */
/*
*+-----------------------------------------------------------------------+
*| This subroutine is used to determine whether the polygon is convex or |
*| not. It returns a Boolean value of TRUE for convex polygons. FALSE is |
*| returned for concave polygons. |
*+-----------------------------------------------------------------------+
*/
int polygon_convex( nverts, vlist )
int nverts;
COORD *vlist;
{
int p = 0, q = 1, r = 2; /* Vertex indices/counters. */
if ( nverts == 3 ) /* Triangle is always convex */
return( 1 ); /* So return immediately. */
for ( p = 0; p < nverts; p++ ) /* For each vertex. */
{
if ( ANGLE_NONCONVEX( vlist, p, q, r) ) /* Is angle <= 90 degrees? */
return( 0 ); /* Yes, polygon is concave. */
q = ( ++q == nverts ? 0 : q ); /* Update second vertex. */
r = ( ++r == nverts ? 0 : r ); /* Update third vertex. */
}
return( 1 ); /* Polygon is convex. */
}
/*
*+-----------------------------------------------------------------------+
*| This subroutine is used to render the polygon in the display buffer. |
*+-----------------------------------------------------------------------+
*/
void store_triangle( vlist, p, q, r )
COORD *vlist;
int p, q, r;
{
static COORD triangle_table[3]; /* Used to render triangle. */
triangle_table[0] = vlist[p]; /* Copy the three vertices. */
triangle_table[1] = vlist[q];
triangle_table[2] = vlist[r];
(*polygon_proc)( triangle_table ); /* Call the user process. */
}
/*
*+-----------------------------------------------------------------------+
*| This subroutine is used to process simple (convex) polygons. |
*+-----------------------------------------------------------------------+
*/
void polygon_tesselate_convex( nverts, vlist )
int nverts;
COORD *vlist;
{
int n, p = 0, q = 1, r = 2; /* Vertex indices/counters. */
for ( n = 0; n < nverts - 2; n++ ) /* For each vertex. */
{
store_triangle( vlist, p, q, r ); /* Render triangle PQR. */
q = ( q+1 == nverts ? 0 : q+1 ); /* P remains the same, but Q */
r = ( r+1 == nverts ? 0 : r+1 ); /* and R are incremented. */
}
}
/*
*+-----------------------------------------------------------------------+
*| This subroutine is used to process complex (concave) polygons. |
*+-----------------------------------------------------------------------+
*/
#define REMOVE_VERTEX( CL, I, N )\
{ int v; for ( v = (I); v < (N); v++ ) CL[v] = CL[v+1]; }
void polygon_tesselate_concave( n, cl )
int n;
COORD *cl;
{
int h, i, j, k, m;
i = n-1;
while (n > 3 )
{
h = i;
i = (i == n-1 ? 0 : i+1);
j = (i == n-1 ? 0 : i+1);
if ( ANGLE_NONCONVEX( cl, h, i, j ) )
continue;
k = (j == n-1 ? 0 : j+1); /* k is vertex after j */
m = n-3;
while (m--)
if ( COORD_OUTSIDE_TRIANGLE( cl, h, i, j, k ) )
k = (k == n-1 ? 0 : k+1);
else
break;
if (k != h) /* Vertex k not outside */
continue; /* triangle PhPiPj */
store_triangle( cl, h, i, j );
REMOVE_VERTEX( cl, i, n );
n--;
i = (i == 0 ? n-1 : i-1);
}
store_triangle( cl, 0, 1, 2 ); /* Final triangle. */
}
/*
*+-----------------------------------------------------------------------+
*| This subroutine is used to render non-complex polygons. |
*+-----------------------------------------------------------------------+
*/
void polygon_tesselate_noncomplex( num, vl )
int num;
COORD *vl;
{
if ( !polygon_clockwise( num, vl ) )
polygon_reverse( num, vl );
if ( polygon_convex( num, vl ) )
polygon_tesselate_convex( num, vl );
else
polygon_tesselate_concave( num, vl );
}
/*
*+-----------------------------------------------------------------------+
*| This subroutine is used to render complex polygons. |
*+-----------------------------------------------------------------------+
*/
void polygon_tesselate_complex( num, vl )
int num;
COORD *vl;
{
/* ... to be implemented in the near future ... */
}
/*
*+-----------------------------------------------------------------------+
*| This subroutine is used to render all types of polygon. |
*+-----------------------------------------------------------------------+
*/
void polygon_tesselate( num, vl )
int num;
COORD *vl;
{
if ( polygon_complex( num, vl ) )
polygon_tesselate_complex( num, vl );
else
polygon_tesselate_noncomplex( num, vl );
}