[comp.graphics] Line-Polygon Intersection

scm@onion.cs.reading.ac.uk (Stephen Marsh) (11/18/86)

        Can anyone help me with some 3D geometry? I am looking
for an algorithm which will enable me to test if a line in a
three-coordinate system with equation r=a+lambda*b intersects
a polygon with vertices v1,v2,....,vn (n>=3,v = (x,y,z)) which
lies in the plane n.r/|n| = p.
        What I need is NOT the line-plane intersection point,
but an algorithm which tests to see if the intersection point
is contained within the 3D polygon.
        Many Thanks.

garry@batcomputer.tn.cornell.edu (Garry Wiegand) (11/20/86)

In a recent article scm@onion.cs.reading.Ac.Uk (Stephen Marsh) wrote:
>...     What I need is NOT the line-plane intersection point,
>but an algorithm which tests to see if the intersection point
>is contained within the 3D polygon.

The simple minded approach is to project it down into a convenient
2-D plane and apply the usual point-in-polygon algorithms. For
example, given the 3-D intersection point and polygon, and given
(for this example) that the polygon is not perpendicular to the
XY plane, project it down into that plane. Do this by ignoring
the Z-values! 

Once there, start anywhere on the polygon and walk around. At each 
step, test to see if the edge passes above-to-below or below-to-above
with respect to the test point. (Note: For purposes of "passing", the 
start vertex of the edge does NOT count, and the end vertex DOES count.) 

If it *does* pass, figure whether it passes to the left or right of the 
test point: If the test edge is horizontal and includes the test point, 
declare it "in" and exit. If the edge is horizontal and doesn't include the
test point, forget it. If it's not horizontal, see if the edge is completely
left or right of the test point. If it's not completely left or right, then
compute the intersection with the horizontal and see whether *that* is 
left or right. If the intersection is right on top, declare the point "in" 
and exit.

Remember how many times you pass to the left, say. If this ends up odd, 
the point's in. Otherwise it's out. 

In the normal "in" case you'll need to compute maybe *one* edge/axis 
intersection.

Whew. (We need a picture.)

You can improve the computation with bounding boxes and other such
tricks. If you know the polygon's convex, you of course won't need
a counter, and you'll only need to look at at most (n+1)/2 edges 
(often far fewer) (exercise left for the reader.)

(If you're working in floating-point, be careful about tests-for-
equality!)

(If the original polygon WAS perpendicular to the XY plane, project into
the YZ plane, say, and apply a tweaked version of the above algorithm.)

I trust I've been complete. Wonder if it's right - I've never gotten 
around to reading about this subject (who said computer graphics 
wasn't ffun ? :-)

garry wiegand   (garry%cadif-oak@cu-arpa.cs.cornell.edu)

poslfit@utcs.UUCP (11/20/86)

In article <90@onion.cs.reading.ac.uk> scm@onion.cs.reading.Ac.Uk (Stephen Marsh) writes:
> 
>         Can anyone help me with some 3D geometry? I am looking
> for an algorithm which will enable me to test if a line in a
> three-coordinate system with equation r=a+lambda*b intersects
> a polygon with vertices v1,v2,....,vn (n>=3,v = (x,y,z)) which
> lies in the plane n.r/|n| = p.
>         What I need is NOT the line-plane intersection point,
> but an algorithm which tests to see if the intersection point
> is contained within the 3D polygon.

As far as I can tell, this is a 2-D problem.

Unless the polygon is perpendicular to the x-y plane (i.e. its normal is //z)
project it and the line-polygon intersection point into said plane by dropping
z co-ordinates.  Then treat it as a two-dimensional problem.  Remember that if
the line and polygon are generally independently chosen and the polygon is
nice and convex, you'd probably save comparisons by testing non-consecutive
polygon edges (n-s-e-w rather than n-e-s-w order).  Of course, if the polygon
is _|_ to x-y, just project it onto the x-z or y-z plane.
--
from the serial port of john j. chew (v3.0) a/k/a poslfit@utcs.UUCP
just another ninja toad dicing with death and looking for that Talisman
-- 
*** THIS LINE HAS BEEN REPLACED BY...
from the serial port of john j. chew (v3.0) a/k/a poslfit@utcs.UUCP
just another ninja toad dicing with death and looking for that Talisman

brad@gcc-milo.UUCP (11/21/86)

> 
>         Can anyone help me with some 3D geometry? I am looking
> for an algorithm which will enable me to test if a line in a
> three-coordinate system with equation r=a+lambda*b intersects
> a polygon with vertices v1,v2,....,vn (n>=3,v = (x,y,z)) which
> lies in the plane n.r/|n| = p.

Last time I did this was for ray tracing polygons (where is Jim Kajia
when you need him?). And the easiest way I found was to find the point
of intersection between the line and the plane formed by three of the
vertices (let's assume they're co-planer) . This yields a 3d point.
Then, I translated the point and verticies into 2d (actually, I just translated
the point as the plane was defined via a plane equation) and then performed
the following:

	Calculate the sum of the angles formed by two adjacent verticies
	and the point. i.e. draw lines from the point to two adjacent 
	vertices. Do this for all the sets of vertices. If the sum of the
	angles is != 360, you are outside of the polygon.

Does this make sense? The idea is correct, but the particulars may be off.

Anyone have a better way to do this?
-- 

J Bradford Parker
General Computer (HyperDrive Beach, 3rd Cabana)
harvard!gcc-milo!brad

Good Sex is easier than a good slow roll. ("Left Stick! Right Rudder!...")

falk@sun.UUCP (11/23/86)

> > 
> >         Can anyone help me with some 3D geometry? I am looking
> > for an algorithm which will enable me to test if a line in a
> > three-coordinate system with equation r=a+lambda*b intersects
> > a polygon with vertices v1,v2,....,vn (n>=3,v = (x,y,z)) which
> > lies in the plane n.r/|n| = p.
> 
> Last time I did this was for ray tracing polygons (where is Jim Kajia
> when you need him?). And the easiest way I found was to find the point
> of intersection between the line and the plane formed by three of the
> vertices (let's assume they're co-planer) . This yields a 3d point.
> Then, I translated the point and verticies into 2d (actually, I just translated
> the point as the plane was defined via a plane equation) and then performed
> the following:
> 
> 	Calculate the sum of the angles formed by two adjacent verticies
> 	and the point. i.e. draw lines from the point to two adjacent 
> 	vertices. Do this for all the sets of vertices. If the sum of the
> 	angles is != 360, you are outside of the polygon.
> 
> Does this make sense? The idea is correct, but the particulars may be off.

This is one of the classic ways to test for point-inside-polygon.  The
problem is that it requires some trigonometry for each vertex of the
polygon (inverse tangent).  That's kind of expensive.  Also, you're dealing
with real numbers and approximations, so there's going to be an error
that has to be tolerated. I.e. the sum will never be EXACTLY 360 or 0.

A faster, but harder to implement algorithm is where you project half-lines
from the point being tested to infinity (preferably along one of the
axes).  Intersect this half-line with all of the edges of the polygon
and count the intersections.  If it's odd, the point is inside the polygon.
When the half-line exactly intersects a vertex, you have a special case
because that's only supposed to count as one intersection.  The solution
to this special case is to only count vertex intersections at the "endpoint"
of the edges and not the "startpoint".

Note that you don't actually have to compute the points of intersection,
just test for their existance (method left to the student).

If the polygon is known to be convex, it becomes a much simpler problem.
For instance, take the dot-products of all of the pairs of vectors from
the test point to adjecent vertices.  These dot-products will be strictly
negative or strictly positive if the test point is inside the polygon.

> Good Sex is easier than a good slow roll. ("Left Stick! Right Rudder!...")

Yeah, but right after a slow roll, you're ready for another.

-- 
		-ed falk, sun microsystems
terrorist, cryptography, DES, drugs, cipher, secret, decode, NSA, CIA, NRO.
(The above is food for the NSA line eater.)

garry@batcomputer.tn.cornell.edu (Garry Wiegand) (11/24/86)

In a recent article falk@sun.uucp (Ed Falk) wrote:
>A faster, but harder to implement algorithm is where you project half-lines
>from the point being tested to infinity (preferably along one of the
>axes).  Intersect this half-line with all of the edges of the polygon
>and count the intersections...
>...
>Note that you don't actually have to compute the points of intersection,
>just test for their existance (method left to the student).

Yes, I think you do have to compute the intersection in one special
case - the case where you *know* the full-line intersects but the half-
line begins somewhere within the edge in question. See the method I posted 
a few days ago for the glitch point. (Or am I not seeing something?)

>If the polygon is known to be convex, it becomes a much simpler problem.
>For instance, take the dot-products of all of the pairs of vectors from
>the test point to adjecent vertices.  These dot-products will be strictly
>negative or strictly positive if the test point is inside the polygon.

Yes, this is simpler, but it involves more computation than the half-line
method. Specifically, the half-line method requires two or three comparisons
per point, and only looking at half the points (average convex case), while the
dot-products require 4 subtracts and 2 multiplies per point, and looking
at *every* point. Also, if you're working in floating-point you still have
to worry about roundoff errors, and if you're in integers you probably have 
to use long ints to avoid overflows.

Anyhow, I've noticed since my first posting that if the points are stored
in an array rather than a list, and if there are enough of them to make
more computation per step worthwhile, then the convex case can be reduced 
from O(n) to O(log n)!   (Do a binary search.)

garry wiegand   (garry%cadif-oak@cu-arpa.cs.cornell.edu)