[comp.graphics] Computational geometry

posdamer@wucs2.UUCP (Jeff Posdamer) (02/18/88)

Over the last year or two, there have been numerous inquiries and
discussions concerning topics in geometric algorithms and geometric
modeling. This raises two thoughts:

Are we ready for a computational geometry new group ? (Please, no flames!!)

Since a computational geometry course was mentioned in a recent note,
Washington University CS teaches CS506-Computational Geometry and
Geometric Modeling (every other year). I would be interested in any
comments or discussion on such courses.

(As a side note, geomtric algorithms are sneaking into some of our intro
courses and have proved of more interest and motivation to students than
some of the more traditional problems.)

				Jeff Posdamer
			    
-- 
Jeff Posdamershington University, St. Louis, MO, (314) 889-6147
UUCP:		posdamer@wucs1.UUCP   or   ...!{ihnp4,seismo}!wucs1!posdamer
ARPANET:	wucs1!posdamer@seismo.CSS.GOV  (or .ARPA)
CSNET:		wucs1!posdamer%seismo.CSS.GOV@csnet-relay

mdoerr@incas.UUCP (Michael Doerr) (04/27/89)

Although I've followed nearly all of the Point-In-Polygon and similiar
geometry-related discussions on comp.graphics I've never seen the
following subject discussed before:
	How does one determine _reliabely_ (!!!) the winding sense (clockwise
	or counter-clockwise) of the sides of an arbitrary polygon?
	By arbitrary polygon I mean the interior of a closed region of
	the plane that is defined by a circular list of vertices that
	are connected by straight line segments. The lines may touch or
	(partially) overlap, but mutual intersections are not allowed.
	Additionally one vertex may be shared by more than two line segments.
	That is, polygons may be convex or concave, but not self-overlapping.

I've come up with the following algorithm and would like to know whether
it is correct:
	1. Select an arbitrary vertex of the polgon.
	   Tranlate the polygon so that this vertex is placed into
	   the origin (0, 0).
	   Set SUM = 0.
	2. FOR each pair of vertices along the sides of the polygon DO
	   a)	Compute the ANGLE that is subtended by each side with
		respect to the reference vertex (selected in step 1).
		This usually involves an expensive arctan operation.
	   b)	Compute SUM = SUM + ANGLE
	3. IF SUM > 0 THEN   winding sense of polygon boundary is CCW
	   IF SUM < 0 THEN   winding sense of polygon boundary is CW
	   IF SUM == 0 THEN  polygon is in some way degenerate (?????)

I hope someone can answer the following questions:
	1. Does the above stated algorithm really compute
	   the correct winding sense?
	2. If question 1 has to be answered with NO:
		Please send me references, hints, programs, etc.
		for a working algorithm.
	3. If questions 1 can be answered with YES:
		How could the algorithm be improved, so that less
		expensive operations are required?
	4. In which way is the polygon degenerate, if SUM == 0?
	5. Can this algorithm also be applied or extended
	   to self-overlapping polygons?

Many thanks in advance, Michael.


Michael "The Turtle" Doerr			%% /-------\ %%
CS Department (FB Informatik)			  %  o   o  %
University of Kaiserslautern			-{ o   o   o }==O
D-6750 Kaiserslautern (West Germany)		  %  o   o  %
uucp: ...!uunet!unido!incas!mdoerr		%% \-------/ %%

rsb584@leah.Albany.Edu (Raymond S Brand) (04/30/89)

In article <5397@cs.utexas.edu>, atc@cs.utexas.edu (Alvin T. Campbell III) writes:
> In article <2053@incas.UUCP> mdoerr@incas.UUCP (Michael Doerr) writes:
> >
> >	How does one determine _reliabely_ (!!!) the winding sense (clockwise
> >	or counter-clockwise) of the sides of an arbitrary polygon?
> >
> 
> I recently had to solve the winding-sense problem myself.
> I am glad to see other people have had to deal with it as well.
> 
[ ... ]
> 
> Now for the method.  Assume that we have a polygon with n 
> vertices, numbered v1, v2, ..., vn.  First, we find the vertex,
> vtop, with the largest y-coordinate.  The angle of the polygon
> at this vertex is guaranteed to be convex.  Now we take the 
> cross-product of the vectors (vaft, vtop) and (vtop, vbef),
> where vaft is the vertex following vtop, and vbef is the vertex
> preceding vtop. If the cross-product is negative, the vertices
> are counter-clockwise.  Otherwise, the vertices are clockwise.
> 
[ ... ]
> -- 
> 				A. T. Campbell, III
> 				CS Department, University of Texas
> 				atc@cs.utexas.edu

I believe that a figure-8 is a permited shape in the original question, but
that shape can lead to different answers from your method depending on the
orientation of the figure-8.


-------------------------------------------------------------------------
Raymond S. Brand                 rsbx@beowulf.uucp
3A Pinehurst Ave.                rsb584@leah.albany.edu
Albany NY  12203                 FidoNet 1:7729/255 (518-489-8968)
(518)-482-8798                   BBS: (518)-489-8968

-------------------------------------------------------------------------
Raymond S. Brand                 rsbx@beowulf.uucp
3A Pinehurst Ave.                rsb584@leah.albany.edu
Albany NY  12203                 FidoNet 1:7729/255 (518-489-8968)
(518)-482-8798                   BBS: (518)-489-8968

-------------------------------------------------------------------------
Raymond S. Brand                 rsbx@beowulf.uucp
3A Pinehurst Ave.                rsb584@leah.albany.edu
Albany NY  12203                 FidoNet 1:7729/255 (518-489-8968)
(518)-482-8798                   BBS: (518)-489-8968

atc@cs.utexas.edu (Alvin T. Campbell III) (04/30/89)

In article <2053@incas.UUCP> mdoerr@incas.UUCP (Michael Doerr) writes:
>
>	How does one determine _reliabely_ (!!!) the winding sense (clockwise
>	or counter-clockwise) of the sides of an arbitrary polygon?
>
>I've come up with the following algorithm and would like to know whether
>it is correct:
>	[ALGORITHM DELETED FOR SPACE CONSIDERATIONS}


I recently had to solve the winding-sense problem myself.
I am glad to see other people have had to deal with it as well.

Michael's algorithm looks as if it will work, but it will not
be very fast. The method I devised is very simple and fast.
I believe it to be robust.  My solution is described below, 
along with source code in C.

Now for the method.  Assume that we have a polygon with n 
vertices, numbered v1, v2, ..., vn.  First, we find the vertex,
vtop, with the largest y-coordinate.  The angle of the polygon
at this vertex is guaranteed to be convex.  Now we take the 
cross-product of the vectors (vaft, vtop) and (vtop, vbef),
where vaft is the vertex following vtop, and vbef is the vertex
preceding vtop. If the cross-product is negative, the vertices
are counter-clockwise.  Otherwise, the vertices are clockwise.

/********************************CUT HERE *****************************/
/*
	file:		clockwise.c
	description:	determine if verts of a polygon are specified in 
			clockwise order
	author:		A. T. Campbell
	date:		February 8, 1989
	routines:	clockwise()
*/

#include <math.h>

#ifndef lint
static char 	sccsid[] = "%W% %G%";	/* SCCS info */
#endif lint

/******************************************************************************/

/* constants */
#define FALSE 	0
#define TRUE	1

/******************************************************************************/

int
clockwise(n, v)					/* decide if vertices are
						   clockwise */
int	n;					/* number of vertices */
float	v[][2];					/* list of vertices */
{
	float	*top; 				/* topmost point */
	float	*bef; 				/* point before topmost */
	float	*aft;				/* point after topmost */
	float	topy;				/* highest y coordinate */
	float	topaft[2];			/* vector from top vert to next */
	float	topbef[2];			/* vector from top vert to previous */
	float	prod;				/* dot product */
	int	i;				/* loop control */
	int	aftind;				/* index of pnt after top */
	int	befind;				/* index of pnt before top */
	int	topind;				/* index of topmost pnt */

	if (n < 3) return(TRUE);

	/* find topmost point */
	topy = -MAXFLOAT;
	for (i = 0; i < n; i++)
		if (v[i][1] > topy) {
			topy = v[i][1];
			topind = i;
		}

	/* find indices before and after */
	befind = (topind > 0)? topind - 1 : n - 1;
	aftind = (topind < n-1)? topind + 1 : 0;

	top = &(v[topind][0]);
	bef = &(v[befind][0]);
	aft = &(v[aftind][0]);

	/* calculate vectors */
	topaft[0] = aft[0] - top[0];
	topaft[1] = aft[1] - top[1];
	topbef[0] = bef[0] - top[0];
	topbef[1] = bef[1] - top[1];

	/* cross-multiply vectors */
	prod = topbef[0] * topaft[1] - topbef[1] * topaft[0];

	/* if cross-product is positive, then clockwise */
	return((prod >= 0.)? TRUE: FALSE);
}

/******************************************************************************/
-- 
				A. T. Campbell, III
				CS Department, University of Texas
				atc@cs.utexas.edu

ksbooth@watcgl.waterloo.edu (Kelly Booth) (04/30/89)

In article <5397@cs.utexas.edu> atc@cs.utexas.edu (Alvin T. Campbell III) writes:
>Now for the method.  Assume that we have a polygon with n 
>vertices, numbered v1, v2, ..., vn.  First, we find the vertex,
>vtop, with the largest y-coordinate.  The angle of the polygon
>at this vertex is guaranteed to be convex.

No.  This is a common mistake.  The "top" vertex may be co-linear with
the previous and next vertices.  Then the cross product that this
algorithm calculates becomes zero.  If the original data had no
co-linear vertices, floating-point operations used in the various
transformations could result in co-linear vertices.  Any transformation
to integer-based coordinates runs this risk.

For the application here (winding numbers) the algorithm can be fixed
by just looking for a vertex of maximum y with a predecessor having a
lower y value.  But of course this presumes that all of the vertices
have "correct" coordinates (i.e., that they have not been mangled by
floating-point transformations).

There have been many (too many to repeat) postings about this in this
newsgroup.  Computational geometry problems are deceptively simple to
state.  The solutions are often quite tricky, and extremely tricky if
all of the vagaries of floating-point representation are taken into
account.

Aside:  A similar algorithm is often presented for computing the normal
to a polygon (this is in fact what the cross product gives).  It fails
for the cases above.  Newell's formula (you can find it in one of the
appendices of Newman & Sproull's text, second edition) gives a much
more robust version of this technique.  This is more a less a
paraphrase of the version in N&S taken from a recent midterm exam.

| Newell's  formula  for  determining  surface  normals of a planar
| 
| polygon is given by
| 
|           n
|        a= > (y -y   )(z +z   )
|          k=0  k  k+1   k  k+1
| 
|           n
|        b= > (z -z   )(x +x   )
|          k=0  k  k+1   k  k+1
| 
|           n
|        c= > (x -x   )(y +y   )
|          k=0  k  k+1   k  k+1
| 
| In  these  equations, the planar polygon is defined by n vertices
| 
| whose coordinates are (x ,y ,z ), with k ranging from 0 to n-1.
|                         k  k  k
| 
| The subscript k+1 is evaluted modulo n.  The vector (a,b,c) is
| 
| perpendicular to the surface.

You can derive Newell's formula from the formula for a cross product
and induction on n, the number of vertices (for n=3, Newell's formula
IS the cross product).

The advantage of Newell's formula is that it is relatively insensitive
to perturbations in the coordinate values, since it effectively takes a
weighted average of all the cross products you might have computed.

The sign of c will give the orientation of the polygon (which is the
application on the midterm question -- determining when to cull
back-facing polygons).  If a, b, and c are subsequently normalized, the
true surface normal is obtained.

turk@Apple.COM (Ken "Turk" Turkowski) (05/01/89)

In article <9455@watcgl.waterloo.edu> ksbooth@watcgl.waterloo.edu (Kelly Booth) writes:
>You can derive Newell's formula from the formula for a cross product
>and induction on n, the number of vertices (for n=3, Newell's formula
>IS the cross product).

Newell's formula is also related to the area of the polygon
projected onto each of the coordinate planes.
-- 
Ken Turkowski @ Apple Computer, Inc., Cupertino, CA
Internet: turk@apple.com
Applelink: TURKOWSKI1
UUCP: sun!apple!turk

cnsy@vax5.CIT.CORNELL.EDU (05/01/89)

In article <2053@incas.UUCP> mdoerr@incas.UUCP (Michael Doerr) writes:

[ ...much about the summation of angles test for calculating the winding
      number deleted...]

>	3. If questions 1 can be answered with YES:
>		How could the algorithm be improved, so that less
>		expensive operations are required?

Michael,

	Simply use the most popular inside outside test: move your test point
to the origin (along with the polygon, of course), shoot a ray along the
+X axis, and count the intersections of this ray with the polygon's line
segments.  One important case is to consider all vertices with a Y component
of zero (after the transform to the origin) to be ABOVE the +X axis: this
gets rid of all the special cases where the vertices are on the axis, and
still gives the right answer.  Comparing line segments is much faster than
doing angle summations (are both of the y components of the line segment the
same sign? If so, then we know that it won't cross the +X axis.  Then, are
both of the x components negative?  If so, again it won't cross.  If both
these quick tests fail, then you have to do a little work to get the
intersection).

	Now, about extending this to get the winding number.  Marching along
the vertex list we look at the sign of the Y component whenever we find that
a segment crosses +X.  Add this sign to a running total.  At the end, if the
sum is even, the test point is outside the polygon, else inside.  However,
the sum is also the winding number, and the sign tells the direction!  For
example, if you use the usually +X is pointing right, +Y pointing up, then
a winding number of +3 would mean three winds in a clockwise direction.

	For a complete description, see my section in the "Introduction to
Ray Tracing" course notes, SIGGRAPH '88, or wait until August for the book
by Academic Press.

Eric Haines