Difference between revisions of "IsPointInPolygon2D"

From Second Life Wiki
Jump to navigation Jump to search
m (<lsl> tag to <source>)
 
(4 intermediate revisions by 2 users not shown)
Line 5: Line 5:
|return_type=integer
|return_type=integer
|return_text=TRUE if the point lies within the described polygon, FALSE if not
|return_text=TRUE if the point lies within the described polygon, FALSE if not
|p1_type=vector|p1_name=point|p1_desc=The point to test for, described by a 2D vector (a vector using only the x and y values)
|p1_type=list|p1_name=polygon|p1_desc=A polygon described as a list of 2D vectors for its points in around the edge order.
|p2_type=list|p2_name=polygon|p2_desc=A polygon described as a list of 2D vectors for its points
|p2_type=vector|p2_name=point|p2_desc=The point to test for, described by a 2D vector (a vector using only the x and y values)
|mode=user
|mode=user
|cat1=Examples
|cat1=Examples
|cat2=Library
|cat2=Library
|examples=<lsl>if (isPointInPolygon2D(<0.5,0.5,0>, [<0,0,0>, <0,1,0>, <1,1,0>, <1,0,0>])) llOwnerSay("Point is in polygon");
|caveats=*the polygon MAY need to be a shape that can be built with triangles, it's unclear from the original if this is a requirement.
else llOwnerSay("Point is not in polygon");</lsl>
*0,0 should NOT be a regular point on the polygon list. See notes below.
|notes=*you can have polygons with holes, either by separating the polygon list of points into distinct parts and placing a 0,0 point after each part, or by making a two partt call to the function, that uses an outer and an inner detection polygon with the inner (cutout) overriding the outer.
|examples=<source lang="lsl2">if (isPointInPolygon2D( [<1,1,0>, <1,2,0>, <2,2,0>, <2,1,0>], <1.5,1.5,0> )){
llOwnerSay( "Point is in polygon" );
}else{
llOwnerSay( "Point is not in polygon" );
}</source>
<source lang="lsl2">if (isPointInPolygon2D_XY( [<1,1,0>, <1,2,0>, <2,2,0>, <2,1,0>], 1.5, 1.5 )){
llOwnerSay( "Point is in polygon" );
}else{
llOwnerSay( "Point is not in polygon" );
}</source>
}}
}}


= Implementations =
= Implementations =
This implementation is adapted from the original found [http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html here]. Please include the copyright comments below when using this code. See original page for indepth discussion of usage.
== Copyright ==
== Copyright ==
This implementation is adapted from one Copyright (c) 1970-2003, Wm. Randolph Franklin (see [http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html here]. Please retain the comments above the function if used.
<source lang="lsl2">/*//-- LSL Port 2009 Void Singer --//*/
/*//-- Copyright (c) 1970-2003, Wm. Randolph Franklin --//*/
/*
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
1. Redistributions of source code must retain the above copyright
  notice, this list of conditions and the following disclaimers.
2. Redistributions in binary form must reproduce the above copyright notice
  in the documentation and/or other materials provided with the distribution.
3. The name of W. Randolph Franklin may not be used to endorse or promote
  products derived from this Software without specific prior written permission
 
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/</source>


== Vectors ==
== Code ==
<lsl>// Original C code Copyright (c) 1970-2003, Wm. Randolph Franklin, ported to LSL by Haravikk Mistral
It should be noted that this vector version is typically faster (fewer function calls), and will actually use less memory (due to the overhead of list entries). It is therefore preferable to try and re-write your script to use vectors in favour of using the float-pair version unless you have no choice.
integer isPointInPolygon2D(vector point, list polygon) {
    integer l = polygon != [];
    integer i = 0; integer j = l - 1; integer inPoly = FALSE;
    vector iv; vector jv; float diffY;
    while (i < l) {
        iv = llList2Vector(polygon, i);
        jv = llList2Vector(polygon, j);
   
        diffY = (jv.y - iv.y);
        if (diffY == 0.0) diffY = 1000.0;
   
        if ((((iv.y <= point.y) &&
            (point.y < (jv.x - iv.x) * (point.y - iv.y) / diffY + iv.x))))
            inPoly = !inPoly;
       
        j = i++;
    }


    return inPoly != 0;
Vector version:
}</lsl>


== Float-pairs ==
<source lang="lsl2">integer isPointInPolygon2D( list vLstPolygon, vector vPosTesting ){
<lsl>// Original C code Copyright (c) 1970-2003, Wm. Randolph Franklin, ported to LSL by Haravikk Mistral
integer vBooInPlygn;
integer isPointInPolygon2D(float x, float y, list polygon) {
integer vIntCounter = [] != vLstPolygon;
    integer l = polygon != [];
vector  vPosVertexA = llList2Vector( vLstPolygon, vIntCounter );
    integer i = 0; integer j = l - 2; integer inPoly = FALSE;
vector  vPosVertexB;
    float ix; float iy; float jx; float jy; float diffY;
    while (i < l) {
while (vIntCounter){
        ix = llList2Float(polygon, i);
vPosVertexB = vPosVertexA;
        iy = llList2Float(polygon, ++i);
vPosVertexA = llList2Vector( vLstPolygon, ++vIntCounter );
        jx = llList2Float(polygon, j);
        jy = llList2Float(polygon, ++j);
if ((vPosVertexA.y > vPosTesting.y) ^ (vPosVertexB.y > vPosTesting.y)){
   
if (vPosTesting.x < (vPosVertexB.x - vPosVertexA.x) * (vPosTesting.y - vPosVertexA.y) /
        diffY = (jy - iy);
                    (vPosVertexB.y - vPosVertexA.y) + vPosVertexA.x ){
        if (diffY == 0.0) diffY = 1000.0;
vBooInPlygn = !vBooInPlygn;
   
}
        if ((((iy <= y) &&
}
            (y < (jx - ix) * (y - iy) / diffY + ix))))  
}
            inPoly = !inPoly;  
return vBooInPlygn;
       
}</source>
        j = i++;
    }


    return inPoly != 0;
Float Pair Version:
}</lsl>
<source lang="lsl2">integer isPointInPolygon2D_XY( list vLstPolygonXY, float vFltTesting_X, float vFltTesting_Y ){
integer vBooInPlygnXY;
integer vIntCounterXY = ([] != vLstPolygonXY);
float  vFltVertexA_X = llList2Float( vLstPolygonXY, -2 );
float  vFltVertexA_Y = llList2Float( vLstPolygonXY, -1 );
float  vFltVertexB_X;
float  vFltVertexB_Y;
while (vIntCounterXY){
vFltVertexB_X = vFltVertexA_X;
vFltVertexB_Y = vFltVertexA_Y;
vFltVertexA_X = llList2Float( vLstPolygonXY, vIntCounterXY++ );
vFltVertexA_Y = llList2Float( vLstPolygonXY, vIntCounterXY++ );
if ((vFltVertexA_Y > vFltTesting_Y) ^ (vFltVertexB_Y > vFltTesting_Y)){
if (vFltTesting_X < (vFltVertexB_X - vFltVertexA_X) * (vFltTesting_Y - vFltVertexA_Y) /
                    (vFltVertexB_Y - vFltVertexA_Y) +  vFltVertexA_X ){
vBooInPlygnXY = !vBooInPlygnXY;
}
}
}
return vBooInPlygnXY;
}</source>

Latest revision as of 15:10, 24 January 2015

Summary

Function: integer isPointInPolygon2D( list polygon, vector point );

Tests a polygon (described as a list of 2D vectors) to see if a 2D point lies within it. Useful for detecting where an event occurred within 2D space.
Returns an integer TRUE if the point lies within the described polygon, FALSE if not

• list polygon A polygon described as a list of 2D vectors for its points in around the edge order.
• vector point The point to test for, described by a 2D vector (a vector using only the x and y values)

It is possible (and fairly easy) to adapt this function to use a list of paired floats, both implementations are provided.

Caveats

  • the polygon MAY need to be a shape that can be built with triangles, it's unclear from the original if this is a requirement.
  • 0,0 should NOT be a regular point on the polygon list. See notes below.

Examples

if (isPointInPolygon2D( [<1,1,0>, <1,2,0>, <2,2,0>, <2,1,0>], <1.5,1.5,0> )){
	llOwnerSay( "Point is in polygon" );
}else{
	llOwnerSay( "Point is not in polygon" );
}
if (isPointInPolygon2D_XY( [<1,1,0>, <1,2,0>, <2,2,0>, <2,1,0>], 1.5, 1.5 )){
	llOwnerSay( "Point is in polygon" );
}else{
	llOwnerSay( "Point is not in polygon" );
}

Notes

  • you can have polygons with holes, either by separating the polygon list of points into distinct parts and placing a 0,0 point after each part, or by making a two partt call to the function, that uses an outer and an inner detection polygon with the inner (cutout) overriding the outer.

Implementations

This implementation is adapted from the original found here. Please include the copyright comments below when using this code. See original page for indepth discussion of usage.

Copyright

/*//-- LSL Port 2009 Void Singer --//*/
/*//-- Copyright (c) 1970-2003, Wm. Randolph Franklin	--//*/
/*
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimers.
2. Redistributions in binary form must reproduce the above copyright notice
   in the documentation and/or other materials provided with the distribution.
3. The name of W. Randolph Franklin may not be used to endorse or promote
   products derived from this Software without specific prior written permission

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. 
*/

Code

It should be noted that this vector version is typically faster (fewer function calls), and will actually use less memory (due to the overhead of list entries). It is therefore preferable to try and re-write your script to use vectors in favour of using the float-pair version unless you have no choice.

Vector version:

integer isPointInPolygon2D( list vLstPolygon, vector vPosTesting ){
	integer vBooInPlygn;
	integer vIntCounter = [] != vLstPolygon;
	vector  vPosVertexA = llList2Vector( vLstPolygon, vIntCounter );
	vector  vPosVertexB;
	
	while (vIntCounter){
		vPosVertexB = vPosVertexA;
		vPosVertexA = llList2Vector( vLstPolygon, ++vIntCounter );
		
		if ((vPosVertexA.y > vPosTesting.y) ^ (vPosVertexB.y > vPosTesting.y)){
			if (vPosTesting.x < (vPosVertexB.x - vPosVertexA.x) * (vPosTesting.y - vPosVertexA.y) /
			                     (vPosVertexB.y - vPosVertexA.y) +  vPosVertexA.x ){
				vBooInPlygn = !vBooInPlygn;
			}
		}
	}
	return vBooInPlygn;
}

Float Pair Version:

integer isPointInPolygon2D_XY( list vLstPolygonXY, float vFltTesting_X, float vFltTesting_Y ){
	integer vBooInPlygnXY;
	integer vIntCounterXY = ([] != vLstPolygonXY);
	float   vFltVertexA_X = llList2Float( vLstPolygonXY, -2 );
	float   vFltVertexA_Y = llList2Float( vLstPolygonXY, -1 );
	float   vFltVertexB_X;
	float   vFltVertexB_Y;
	
	while (vIntCounterXY){
		vFltVertexB_X = vFltVertexA_X;
		vFltVertexB_Y = vFltVertexA_Y;
		vFltVertexA_X = llList2Float( vLstPolygonXY, vIntCounterXY++ );
		vFltVertexA_Y = llList2Float( vLstPolygonXY, vIntCounterXY++ );
		
		if ((vFltVertexA_Y > vFltTesting_Y) ^ (vFltVertexB_Y > vFltTesting_Y)){
			if (vFltTesting_X < (vFltVertexB_X - vFltVertexA_X) * (vFltTesting_Y - vFltVertexA_Y) /
			                     (vFltVertexB_Y - vFltVertexA_Y) +  vFltVertexA_X ){
				vBooInPlygnXY = !vBooInPlygnXY;
			}
		}
	}
	return vBooInPlygnXY;
}