jmn@cbnewsh.att.com (john.b.medamana) (07/28/90)
I am posting this article for a friend who works in the field of Urban Planning. I am looking for software which determines whether an arbitrary point lies within or outside a polygon. Please e-mail or post replys. Thanks in advance. John Medamana AT&T email: att!arch3!johnm
dga@cs.brown.edu (Daniel Gerardo Aliaga) (07/28/90)
In article <1990Jul27.201939.17816@cbnewsh.att.com> jmn@cbnewsh.att.com (john.b.medamana) writes: >I am posting this article for a friend who works in the field of >Urban Planning. > >I am looking for software which determines whether an arbitrary >point lies within or outside a polygon. Please e-mail or post >replys. > >Thanks in advance. > >John Medamana >AT&T >email: att!arch3!johnm One very simple algorithm (from some paper in SigGraph '89 I believe) is take the dot product of the normal of each side of the polygon and the vector formed by the point in question and a vertex of the current side. If all of these dot products are negative, the point is inside the object. This of course can be generalized to the 3-D case. The disadvantage is that this only works for convex polygons. graphically: | n | <---| /p | / |/v If all the dot products <n,(p-v)> < 0, then p is inside convex polygon. Alternatively, you could use an even odd rule if you have non convex polygons. Imagine the 2-D case, take a polygon and draw a line through the point. If that line intersects an even number of sides, it is inside else outside. This may produce some hairy cases when the point is right on a side, or when the line you draw coincides exactly with one of the sides. You will have to check for these cases. graphically: _____ / \ --- \_____ | \ | --- | xxxxxxxxx p xxxxxxxxxxxxxxxxx \_______/ \___| Notice that the line crosses the sides. It also coincides with a side. These should work, good luck ! P.S. I have software for the first method, though it uses a in house polyhedra representation package, I could give you a copy ... XXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXX Daniel G. Aliaga '91 XXX XXX XXXXX Brown University XXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXX "Real men write self modifying code"
BOYDJ@QUCDN.QueensU.CA (Jeff Boyd) (07/29/90)
What information have you on the polygon ? Eg. how is it defined ? Do you have a set of ordered co-ordinates for the vertices ? Is the polygon always convex ?
gordon@cs.tamu.edu (Dan Gordon) (07/30/90)
In article <46093@brunix.UUCP] dga@cs.brown.edu (Daniel Gerardo Aliaga) writes: ]In article <1990Jul27.201939.17816@cbnewsh.att.com> jmn@cbnewsh.att.com (john.b.medamana) writes: ]>I am posting this article for a friend who works in the field of ]>Urban Planning. ]> ]>I am looking for software which determines whether an arbitrary ]>point lies within or outside a polygon. Please e-mail or post ]>replys. ]> ]>John Medamana ]>AT&T ]>email: att!arch3!johnm ] ]One very simple algorithm (from some paper in SigGraph '89 I believe) is ]take the dot product of the normal of each side of the polygon and the ]vector formed by the point in question and a vertex of the current side. ]If all of these dot products are negative, the point is inside the object. ]This of course can be generalized to the 3-D case. The disadvantage is that ]this only works for convex polygons. In 2-D, this algorithm takes time O(N), where N is the no. of points. If you assume that the coordinates of the polygon are in arrays, then there is a method of doing it in O(logN) time. It is only advantageous if your polygons have "lots" of vertices, where "lots" depends on your computing environment and on how often you need to solve this problem.
gordon@cs.tamu.edu (Dan Gordon) (07/30/90)
I forgot to mention in my previous post that the logarithmic-time solution works only for convex polygons.
phil@hpsmdca.HP.COM (Philip Walden) (07/30/90)
For 2D, I sum the absolute angles from THE POINT to all the vertices on the polygon. It the sum will be either 2pi: point is inside 0: point is outside
gordon@cs.tamu.edu (Dan Gordon) (07/31/90)
Subject: Re:: Algorithm needed to determine if a point is inside a polygon >> I forgot to mention... >> works only for convex polygons. >You also forgot to mention the name of the algorithm and where to obtain >information on it. I, for one, would be interested in finding this out. >Thanks, >Lem Davis >lem@nosc.mil Oh, dear; me and my big mouth. To begin with, turn to "Computational Geometry" by Preparata & Shamos, Section 2.2.1. Theorem 2.2 shows how to do it in O(logN) time using O(N) preprocessing time. The idea in this proof is to divide the polygon into wedges and do a circular binary search on the wedges. The division into wedges takes O(N) time, but it is a one-time piece of work. The actual binary search, which can be expected to be repeated many times, takes O(logN) time. My variation on this scheme works on arrays. We assume that the coordinates are in arrays X[1..N], Y[1..N], with the vertices of the polygon in circular order (clockwise or anticlockwise). Preprocessing step: find index of vertex with maximal Y, and index of vertex with minimal Y. This can be easily done in O(N) time, and this is probably good enough for most applications. However, it can also be done in O(logN) time. Query step: Given a point (a,b), is it in the polygon? Geometrically, this is done by the parity method: consider the horizontal line y=b. If the line is above the maximal Y or below the minimal Y, the answer is no. Otherwise, find the edges of the polygon which the line intersects. Count the no. of intersections to the left of (a,b) - if it is one, then the point is inside; otherwise (0 or 2), it is outside. The logarithmic time is obtained by finding the edges intersecting y=b by doing a circular binary on the array Y. Assume for simplicity that the minimum Y is at Y[1] and the maximum is Y[m], where 1<m<=N. One intersection is found by doing a binary search of b among Y[1..m], and the other by doing a binary search on Y[m],Y[m+1],...,Y[N],Y[1]. Y[m] * / \ / \ * * | \ --------------------------*----------- y=b | \ (a,b) | \ Y[2]* *Y[N] \ / \ / \ / \ / \* Y[1] I hope this helps.
jcs@crash.cts.com (John Schultz) (07/31/90)
/* Here's a line/convex polygon intersection routine. I haven't fully tested it, so if you spot a bug, let me know. This code is set up for 32 bit integer fixed point, but can easily be modified for floats by removing the shifts and declaring floats. Another trick is to rotate and translate the *ray* (two points) and not the polygons/normals. The ray transform matrix is the inverse of the polygon (local) transform. See the Siggraph article for more info. John */ /* Collision.c */ /* Created by John C. Schultz 18-July-90 */ /* Idea from Siggraph Computer Graphics Vol 21, Number 4, July '87, page 126 */ #include <math.h> #include <stdio.h> #define sgn(x) ((x)>0 ? 1: ((x)<0 ? -1: (0))) #define FBITS 14 typedef struct point3d {long defx,defy,defz,x,y,z;} point3d; /* Prototypes */ short linepolyint(point3d * ip,point3d * b,point3d * d,point3d * n, point3d * poly,short count); /* Functions */ short linepolyint(point3d * ip,point3d * b,point3d * d,point3d * n, point3d * poly,short count) { long k,t; /* k = Plane constant, t = parametric var */ long sn; /* sign max normal */ long absx,absy,absz; /* abs x,y,z of normal */ long nd; /* N dot D */ long beta; /* Result of cross product */ short i,i1; point3d p,q; /* temps */ /* Compute: t = parametric variable k = plane constant. N = normal (plane equation). B,D = line base, direction. k - (N dot B) t = ----------- (N dot D) */ /* Compute plane contant k */ k = poly[0].x*n->x + poly[0].y*n->y + poly[0].z*n->z; /* Keep upshifted */ nd = (n->x*d->x + n->y*d->y + n->z*d->z) >> FBITS; if (nd) { /* Compute parametric variable */ t = (k - (n->x*b->x + n->y*b->y + n->z*b->z)) / nd; } else { return 0; /* Line is parallel to plane */ } /* if nd */ /* Now see if point is within polygon */ absx = abs(n->x); absy = abs(n->y); absz = abs(n->z); /* Find max of normal{x,y,z}, do specific case */ if (absx > absy) { if (absx > absz) { /************ X CASE ************/ sn = sgn(n->x); /* Compute only intersection points being checked */ ip->y = b->y + ((t*d->y) >> FBITS); ip->z = b->z + ((t*d->z) >> FBITS); for (i=0; i<count; i++) { if ( (i1 = i+1) >= count) i1 = 0; /* Modulo count */ p.y = poly[i1].y - poly[i].y; p.z = poly[i1].z - poly[i].z; q.y = ip->y - poly[i].y; q.z = ip->z - poly[i].z; beta = (p.y*q.z - p.z*q.y); /* cross product: makes an x */ /* beta == 0 when on polygon boundary */ if ((beta) && (sgn(beta) != sn)) return 0; /* The above line may need to be modified to implement: 0 <= beta <= 1, if n->x is positive and -1 <= beta <= 0, if n->x is negative. I simplified it for speed. The above code occurs twice more below. */ }/* for i */ /* Success, now compute last point */ ip->x = b->x + ((t*d->x) >> FBITS); } else { goto zmax; /* For speed and non-redunancy */ } /* if x */ } else { if (absy > absz) { /************ Y CASE ************/ sn = sgn(n->y); /* Compute only intersection points being checked */ ip->x = b->x + ((t*d->x) >> FBITS); ip->z = b->z + ((t*d->z) >> FBITS); for (i=0; i<count; i++) { if ( (i1 = i+1) >= count) i1 = 0; p.x = poly[i1].x - poly[i].x; p.z = poly[i1].z - poly[i].z; q.x = ip->x - poly[i].x; q.z = ip->z - poly[i].z; beta = (p.z*q.x - p.x*q.z); /* cross product: makes a y */ /* beta == 0 when on polygon boundary */ if ((beta) && (sgn(beta) != sn)) return 0; }/* for i */ /* Success, now compute last point */ ip->y = b->y + ((t*d->y) >> FBITS); } else { zmax: /************ Z CASE ************/ sn = sgn(n->z); /* Compute only intersection points being checked */ ip->x = b->x + ((t*d->x) >> FBITS); ip->y = b->y + ((t*d->y) >> FBITS); for (i=0; i<count; i++) { if ( (i1 = i+1) >= count) i1 = 0; p.x = poly[i1].x - poly[i].x; p.y = poly[i1].y - poly[i].y; q.x = ip->x - poly[i].x; q.y = ip->y - poly[i].y; beta = (p.x*q.y - p.y*q.x); /* cross product: makes a z */ /* beta == 0 when on polygon boundary */ if ((beta) && (sgn(beta) != sn)) return 0; }/* for i */ /* Success, now compute last point */ ip->z = b->z + ((t*d->z) >> FBITS); } /* if y/z */ } /* if x/y */ return 1; /* Line intersected polygon */ } /* end raypolyint */ void main(long argc,char ** argv) { point3d b,d,n,ip,p1,p2; point3d poly[3]; short count = 3; short hit; /* Initialize intersection point */ ip.x = 0; ip.y = 0; ip.z = 0; /* Start of line */ p1.x = 0; p1.y = -1000; p1.z =-9992; /* End of line */ p2.x = 0; p2.y = 1000; p2.z = -10002; /* Normal */ n.x = 0; n.y = -((1<<FBITS)-1); /* -1.0 */ n.z = 0; /* Line base is p1 */ b = p1; /* Line direction is p2 - p1 */ d.x = p2.x - p1.x; d.y = p2.y - p1.y; d.z = p2.z - p1.z; /* Define polygon */ poly[0].x = 0; poly[0].y = 500; poly[0].z = 10000; poly[2].x = 10000; poly[2].y = 500; poly[2].z = -10000; poly[1].x = -10000; poly[1].y = 500; poly[1].z = -10000; /* Test the code */ hit = linepolyint(&ip,&b,&d,&n,poly,count); printf("hit %d, x %d y %d z %d\n",hit,ip.x,ip.y,ip.z); } /* end main */ /* end collision.c */