stu96art has asked for the wisdom of the Perl Monks concerning the following question:

This is not exactly a Perl question, but ya'll are some of the smartest people I know, so I thought that I would ask. I am looking to find the certroid of a part. I have a list of verticies and I read them in one at a time. I am looking to be able to distinguish between the outside and the inside of this part. The vertex are given in a continuous line (point to point) but sometimes it is clockwise and other times it is counter-clockwise. I have each part separated so I can concentrate on one part at a time, but I cannot figure a way to use the vertex points to find out where the inside is. I know that if the order was always in a clockwise motion, the the center would always be to the right. But I can't guarantee that it is. I need to do this because I am trying to put notches on the perimeter, not tabs. Any enlightenment you can give on this subject would be great. Thanks.

update (broquaint): title change (was Inside??)

Replies are listed 'Best First'.
Re: OT: point inside polyhedron test
by BrowserUk (Patriarch) on Feb 19, 2003 at 03:23 UTC

    This method works on the basis that the sum of the angles between lines drawn from the point under test, to each of the vertices of the polygon, will add up to 360 degrees, if the point is inside the polygon and be less than 360 if it is outside.

    This is easy to visualise for convex polygons,less so for concave ones. The tests below seem to indicate that this also works for them too, but my math isn't strong enough to give a rigorous proof of this.

    You'll see from the second group of results that points that lie exactly on an edge of the polygon--to the limits of perls floats to represent them accurately--are treated as being outside of it.

    #! perl -slw use strict; use constant X => 0; use constant Y => 1; use constant PI => atan2(0,-1); use constant TWOPI => 2*PI; sub mapAdjPairs (&@) { my $code = shift; map { local ($a, $b) = (shift, $_[0]); $code->() } 0 .. @_-2; } sub Angle{ my ($x1, $y1, $x2, $y2) = @_; my $dtheta = atan2($y1, $x1) - atan2($y2, $x2); $dtheta -= TWOPI while $dtheta > PI; $dtheta += TWOPI while $dtheta < - PI; return $dtheta; } sub PtInPoly{ my ($poly, $pt) = @_; my $angle=0; mapAdjPairs{ $angle += Angle( $a->[X] - $pt->[X], $a->[Y] - $pt->[Y], $b->[X] - $pt->[X], $b->[Y] - $pt->[Y] ) } @$poly, $poly->[0]; return !(abs($angle) < PI); } my @pts = ( [-1,1], [1,1], [1,-1], [-1,-1] ); print '[0,0] should be in the polygon:', PtInPoly( \@pts, [0,0]) ? 'It + is' : 'It is not'; print '[2,0] should be out of polygon:', PtInPoly( \@pts, [2,0]) ? 'It + is not' : 'It is'; my @diamond = ( [0,1], [1,2], [2,1], [1,0] ); print "[$_->[0],$_->[1]] is " , PtInPoly(\@diamond, $_) ? 'inside' : 'outside' for [0.49999999999,0.49999999999], [0.5,0.5], [0.50000000001,0.500 +00000001]; my @concave = ( [0,3],[3,0],[5,2],[4,3],[3,2],[2,3],[3,4],[2,5] ); print '[2,2] is ', PtInPoly(\@concave, [2,2]) ? 'inside' : 'outside'; print '[3,3] is ', PtInPoly(\@concave, [3,3]) ? 'inside' : 'outside'; print '[2,4] is ', PtInPoly(\@concave, [2,4]) ? 'inside' : 'outside'; print '[4,2] is ', PtInPoly(\@concave, [4,2]) ? 'inside' : 'outside'; __END__ C:\test>temp [0,0] should be in the polygon:It is [2,0] should be out of polygon:It is [0.49999999999,0.49999999999] is outside [0.5,0.5] is outside [0.50000000001,0.50000000001] is inside [2,2] is inside [3,3] is outside [2,4] is inside [4,2] is inside

    Examine what is said, not who speaks.

    The 7th Rule of perl club is -- pearl clubs are easily damaged. Use a diamond club instead.

Re: OT: point inside polyhedron test
by dpuu (Chaplain) on Feb 19, 2003 at 00:58 UTC
    I'm hoping I've read the question right: you want to check if a given point is inside a shape; and that shape is specified as a list of vertices. The shape is bounded by (straight) lines that connect those vertices.

    One approach is to consider drawing a line from your candidate point to infinity: then count the number of times it crosses the bounding lines of the shape. If the number of lines that it crosses is an odd number, then the point was inside the shape. (Infinity is any point outside the bounding box of the shape).

    --Dave

      One caveat: If the line crosses a bounding segment at one of its endpoints (a vertex), it will also cross the adjacent bounding segment at the same vertex, counting as two crosses. You will have to include a check for this condition and adjust accordingly.

      One way to do this is to count +1 if it crosses between the two endpoints, +1/2 if it intersects one endpoint, +0 if it intersects both endpoints (i.e. is coincident with the entire segment).

        An anternative is to be careful with your inequalities. If the list of verticies follows a path, then you can simply exclude the endpoint that was part of the previous segment. --Dave
Re: OT: point inside polyhedron test
by FoxtrotUniform (Prior) on Feb 19, 2003 at 01:03 UTC

    Are your parts represented in two or three dimensions? If they're 3d meshes, you can use the same techniques as others have described, but you'll need to do polygon/line intersection instead of line/line intersection. Either way, if you're doing a lot of tests like this, you might want to build a BSP tree out of your data. BSP tree intersection tests are average-case logarithmic time, and by building the structure once you might save yourself some computation.

    --
    F o x t r o t U n i f o r m
    Found a typo in this node? /msg me
    The hell with paco, vote for Erudil!

Re: OT: point inside polyhedron test
by jasonk (Parson) on Feb 19, 2003 at 00:51 UTC

    One technique that I've seen used is a raster method, starting at the upper left corner of your bounding box (assuming that point is outside the object), you draw an imaginary line from the upper left corner to the upper right corner, counting the number of times the imaginary line you are drawing crosses the lines that make up the object, at any point along the line if that count is an odd number, you are inside the object, if it is an even number you are outside the object.