sijpie
Well-known Member
- Joined
- Nov 1, 2008
- Messages
- 4,266
- Office Version
- 365
- Platform
- Windows
- MacOS
This is not a question, just a post of some code to help find if a point falls within a (complex) polygon.
I found the original code written in C here:
Determining Whether A Point Is Inside A Complex Polygon
The page also explains the issues with complex polygons. But the code of course also works for simple polygons.
I have modified the code to run as a function in Excel, and so it can be called as any other function.
The function takes as arguments the point to be checked as a range with X & Y, and a range with all the points of the polygon, X & Y.
In my example I am checking if wells drilled in the past are within a certain area.
To use the function, copy the code below. In Excel press Alt-F11 to open the VBA editor. Rightclick on the workbook name in the top left panel, and select Insert/Module. In the right hand pane, paste the code. Now in the workbook you can use the function as shown above. The range holding the polygone nodes is range Stage1Poly, which is B5:C9
The function code is as follows:
<font face=Courier New><SPAN style="color:#00007F">Function</SPAN> PointInPolygon(rXY <SPAN style="color:#00007F">As</SPAN> Range, rpolyXY <SPAN style="color:#00007F">As</SPAN> Range) <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Boolean</SPAN><br> <SPAN style="color:#007F00">' Function checks if X,Y given in rXY falls within complex _<br> polygon as defined by node list rpolyXY. _<br> rXY to be 2 cell range with one X and one Y value _<br> rpolyXY to be 2 column range with for each node on the polygon _<br> the X and the Y point</SPAN><br> <br> <SPAN style="color:#00007F">Dim</SPAN> i <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Integer</SPAN>, j <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Integer</SPAN>, polySides <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Integer</SPAN><br> <SPAN style="color:#00007F">Dim</SPAN> oddNodes <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Boolean</SPAN><br> <SPAN style="color:#00007F">Dim</SPAN> x <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Double</SPAN>, y <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Double</SPAN><br> <SPAN style="color:#00007F">Dim</SPAN> aXY <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Variant</SPAN><br> <br> oddNodes = <SPAN style="color:#00007F">False</SPAN><br> x = rXY.Cells.Value2(1, 1)<br> y = rXY.Cells.Value2(1, 2)<br> aXY = rpolyXY.Value<br> <br> polySides = rpolyXY.Rows.Count<br> j = polySides - 1<br> <br> <SPAN style="color:#00007F">For</SPAN> i = 1 <SPAN style="color:#00007F">To</SPAN> polySides<br> <SPAN style="color:#00007F">If</SPAN> (((aXY(i, 2) < y And aXY(j, 2) >= y) _<br> <SPAN style="color:#00007F">Or</SPAN> (aXY(j, 2) < y And aXY(i, 2) >= y)) _<br> And (aXY(i, 1) <= x <SPAN style="color:#00007F">Or</SPAN> aXY(j, 1) <= x)) <SPAN style="color:#00007F">Then</SPAN><br> oddNodes = oddNodes Xor (aXY(i, 1) + (y - aXY(i, 2)) / (aXY(j, 2) - aXY(i, 2)) * (aXY(j, 1) - aXY(i, 1)) < x)<br> <SPAN style="color:#00007F">End</SPAN> <SPAN style="color:#00007F">If</SPAN><br> j = i<br> <SPAN style="color:#00007F">Next</SPAN> i<br> PointInPolygon = oddNodes<br><SPAN style="color:#00007F">End</SPAN> <SPAN style="color:#00007F">Function</SPAN><br></FONT>
I found the original code written in C here:
Determining Whether A Point Is Inside A Complex Polygon
The page also explains the issues with complex polygons. But the code of course also works for simple polygons.
I have modified the code to run as a function in Excel, and so it can be called as any other function.
The function takes as arguments the point to be checked as a range with X & Y, and a range with all the points of the polygon, X & Y.
In my example I am checking if wells drilled in the past are within a certain area.
Excel 2010 | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
A | B | C | D | E | F | G | H | I | |||
1 | Stage 1 Polygon | ||||||||||
2 | Well Database | SurfaceCoordinates | |||||||||
3 | Stereo70 | In Stage1 Area | |||||||||
4 | x | y | |||||||||
5 | 549926 | 313550 | Well Name | EastingY[m] | NorthingX[m] | Yes/No | |||||
6 | 549357 | 313316 | 1 A Est | 559,008.51 | 309,204.47 | FALSE | |||||
7 | 549923 | 312176 | 1 Ar Est | 550,000.30 | 313,130.16 | TRUE | |||||
8 | 550650 | 312573 | 1 Ar Vest | 543,011.50 | 313,106.58 | FALSE | |||||
9 | 551164 | 313205 | 1 I Est | 556,226.56 | 312,713.64 | TRUE | |||||
10 | 549926 | 313550 | 1 K Vest-Blejesti | 539,357.63 | 313,165.48 | FALSE | |||||
11 | 2 A Est | 559,388.41 | 309,234.32 | FALSE | |||||||
12 | 2 Ar Est | 549,925.25 | 313,140.10 | TRUE | |||||||
13 | 2 Ar Vest | 543,080.28 | 312,970.75 | FALSE | |||||||
14 | 2 I Est | 554,430.45 | 313,551.15 | FALSE | |||||||
15 | 2 P Vest | 545,170.00 | 310,055.00 | FALSE | |||||||
16 | 3 A Est | 559,722.95 | 309,279.51 | FALSE | |||||||
Wells inSt1 (2) |
Cell Formulas | ||
---|---|---|
Range | Formula | |
I6 | =PointInPolygon(G6:H6,Stage1Poly) |
Named Ranges | ||
---|---|---|
Name | Refers To | Cells |
'Wells inSt1 (2)'!Stage1Poly | ='Wells inSt1 (2)'!$B$5:$C$9 |
To use the function, copy the code below. In Excel press Alt-F11 to open the VBA editor. Rightclick on the workbook name in the top left panel, and select Insert/Module. In the right hand pane, paste the code. Now in the workbook you can use the function as shown above. The range holding the polygone nodes is range Stage1Poly, which is B5:C9
The function code is as follows:
<font face=Courier New><SPAN style="color:#00007F">Function</SPAN> PointInPolygon(rXY <SPAN style="color:#00007F">As</SPAN> Range, rpolyXY <SPAN style="color:#00007F">As</SPAN> Range) <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Boolean</SPAN><br> <SPAN style="color:#007F00">' Function checks if X,Y given in rXY falls within complex _<br> polygon as defined by node list rpolyXY. _<br> rXY to be 2 cell range with one X and one Y value _<br> rpolyXY to be 2 column range with for each node on the polygon _<br> the X and the Y point</SPAN><br> <br> <SPAN style="color:#00007F">Dim</SPAN> i <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Integer</SPAN>, j <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Integer</SPAN>, polySides <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Integer</SPAN><br> <SPAN style="color:#00007F">Dim</SPAN> oddNodes <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Boolean</SPAN><br> <SPAN style="color:#00007F">Dim</SPAN> x <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Double</SPAN>, y <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Double</SPAN><br> <SPAN style="color:#00007F">Dim</SPAN> aXY <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Variant</SPAN><br> <br> oddNodes = <SPAN style="color:#00007F">False</SPAN><br> x = rXY.Cells.Value2(1, 1)<br> y = rXY.Cells.Value2(1, 2)<br> aXY = rpolyXY.Value<br> <br> polySides = rpolyXY.Rows.Count<br> j = polySides - 1<br> <br> <SPAN style="color:#00007F">For</SPAN> i = 1 <SPAN style="color:#00007F">To</SPAN> polySides<br> <SPAN style="color:#00007F">If</SPAN> (((aXY(i, 2) < y And aXY(j, 2) >= y) _<br> <SPAN style="color:#00007F">Or</SPAN> (aXY(j, 2) < y And aXY(i, 2) >= y)) _<br> And (aXY(i, 1) <= x <SPAN style="color:#00007F">Or</SPAN> aXY(j, 1) <= x)) <SPAN style="color:#00007F">Then</SPAN><br> oddNodes = oddNodes Xor (aXY(i, 1) + (y - aXY(i, 2)) / (aXY(j, 2) - aXY(i, 2)) * (aXY(j, 1) - aXY(i, 1)) < x)<br> <SPAN style="color:#00007F">End</SPAN> <SPAN style="color:#00007F">If</SPAN><br> j = i<br> <SPAN style="color:#00007F">Next</SPAN> i<br> PointInPolygon = oddNodes<br><SPAN style="color:#00007F">End</SPAN> <SPAN style="color:#00007F">Function</SPAN><br></FONT>