Page 3 of 5 FirstFirst 12345 LastLast
Results 21 to 30 of 43

Thread: Test Whether A Point Is In A Polygon Or Not

  1. #21
    Junior Member
    Join Date
    Mar 2016
    Posts
    2
    Rep Power
    0
    Quote Originally Posted by Rick Rothstein View Post
    The Polygon argument can be either a two-dimensional VBA array or a two-dimensional range. If it is a range, assigning that range to a Variant variable converts it to a two-dimensional VBA array so that the rest of the code ends up with the same kind of array as when a real two-dimensional array is inputted. The reason the assignment has to take place within the code is because the coercion to an array does not take place via the argument itself even if that argument is a Variant. So, that line of code makes the overall function flexible enough to handle a real array (assigning such an array to the Variant variable does not change its structure) or a range (because the range gets converted to a real array).




    I wanted the function to return either TRUE or FALSE directly in case the function was to be used directly in a MessageBox or to fill a TextBox or any other number of uses besides as the argument to an IF function... the idea being the user can implement the function without having to take special steps to format the output for the occasion. As for why PtInPoly is a Variant and not a Boolean... that was so it could accommodate the error messages when called as a UDF directly on a worksheet.




    It was a design decision to help a user not make a mistake. If the user accidentally grabbed the wrong number of rows from a table of coordinates and inputted that too short range of values, the function would alert the user to the error because the last point did not equal the first point... if I made the function close the polygon automatically, it would blindly calculate values and the user would not be aware some of the answers were incorrect... by forcing the user to make sure the polygon closed, he/she could never make a mistake of accidentally inputting to few points.
    Rick, thank you for the quick response and clarifications. Anyway, if i want to include each vertex of the polygon only once, not doubling the first and last point, how should i modify the code? is it correct if
    Code:
    For x = LBound(Poly) To UBound(Poly) - 1
    is changed to
    Code:
    For x = LBound(Poly) To UBound(Poly) - 2
    ? thanks

  2. #22
    Forum Guru Rick Rothstein's Avatar
    Join Date
    Feb 2012
    Posts
    662
    Rep Power
    13
    Quote Originally Posted by qetuol View Post
    Rick, thank you for the quick response and clarifications. Anyway, if i want to include each vertex of the polygon only once, not doubling the first and last point, how should i modify the code? is it correct if
    Code:
    For x = LBound(Poly) To UBound(Poly) - 1
    is changed to
    Code:
    For x = LBound(Poly) To UBound(Poly) - 2
    ? thanks
    No, that part of the code would not change... however, you would have to add code to extend the array one additional array element in order to add the first point as a last point so that the For..Next loop would have a last side to test against. Unfortunately, you cannot use ReDim Preserve to expand the array as it is the first element that needs to be increased by one, so you will need to create a new array that is one row bigger than the passed-in array, transfer the elements of the passed-in array to the new array one element at a time and then duplication the first element into the new array's last element and change the array name in the loop to the newly created array's name. Doing this will slow down the function slightly. Personally, forcing the polygon closed before it is passed into the procedure seems more logical to me as the alternative does not seem worth the extra code that would be needed or time necessary to actually encode it. You may feel free to do so if you really think that extra array element to close the polygon is "unsightly" in some way as you have the base code to work from and the above outline of the steps that would be needed.


    https://www.youtube.com/channel/UCnxwq2aGJRbjOo_MO54oaHA
    https://www.youtube.com/watch?v=jTmVtPHtiTg&lc=Ugy_RiNN_kAqUvZ8W994AaABAg
    https://www.youtube.com/watch?v=QjEWAJ3d-jw&lc=UgxJLVpwY8fIla7G-pN4AaABAg.9BLeCWVhxdG9wgNsaS3Lp1
    https://www.youtube.com/watch?v=QjEWAJ3d-jw&lc=UgxJLVpwY8fIla7G-pN4AaABAg.9BLeCWVhxdG9wgR1EPUkhw
    https://www.youtube.com/watch?v=QjEWAJ3d-jw&lc=UgxJLVpwY8fIla7G-pN4AaABAg.9BLeCWVhxdG9wgNe_XC-jK
    https://www.youtube.com/watch?v=QjEWAJ3d-jw&lc=UgxJLVpwY8fIla7G-pN4AaABAg.9BLeCWVhxdG9wgNPOdiDuv
    https://www.youtube.com/watch?v=QjEWAJ3d-jw&lc=UgxJLVpwY8fIla7G-pN4AaABAg.9BLeCWVhxdG9wgN7AC7wAc
    https://www.youtube.com/watch?v=bs-urI_o8jo&lc=UgyBACXgNY4j_cHgH5J4AaABAg.9oTkVdzfqfm 9wlhQrYJP3M
    https://www.youtube.com/watch?v=bs-urI_o8jo&lc=UgxYgiEZuS9I3xkjJv54AaABAg
    https://www.youtube.com/watch?v=DVFFApHzYVk&lc=Ugyi578yhj9zShmhuPl4AaABAg
    https://www.youtube.com/watch?v=GqzeFYWjTxI&lc=UgxvxlnuTRWiV6MUZB14AaABAg
    https://www.youtube.com/watch?v=_8i1fVEi5WY&lc=Ugz0ptwE5J-2CpX4Lzh4AaABAg
    https://www.youtube.com/watch?v=0ltJS7uHfK4&lc=UgxoHAw8RwR7VmyVBUt4AaABAg. 9C-br0lEl8V9xI0_6pCaR9
    https://www.youtube.com/watch?v=0ltJS7uHfK4&lc=Ugz5DDCMqmHLeEjUU8t4AaABAg. 9bl7m03Onql9xI-ar3Z0ME
    https://www.youtube.com/watch?v=0ltJS7uHfK4&lc=UgxYnpd9leriPmc8rPd4AaABAg. 9gdrYDocLIm9xI-2ZpVF-q
    https://www.youtube.com/watch?v=0ltJS7uHfK4&lc=UgyjoPLjNeIAOMVH_u94AaABAg. 9id_Q3FO8Lp9xHyeYSuv1I
    https://www.reddit.com/r/windowsxp/comments/pexq9q/comment/k81ybvj/?utm_source=reddit&utm_medium=web2x&context=3
    https://www.youtube.com/watch?v=bs-urI_o8jo&lc=UgxYgiEZuS9I3xkjJv54AaABAg
    https://www.youtube.com/watch?v=bs-urI_o8jo&lc=UgyBACXgNY4j_cHgH5J4AaABAg.9oTkVdzfqfm 9wlhQrYJP3M
    ttps://www.youtube.com/watch?v=LP9fz2DCMBE
    https://www.youtube.com/watch?v=LP9fz2DCMBE&lc=UgzbPgJUMCztIOQDym14AaABAg
    https://www.youtube.com/watch?v=LP9fz2DCMBE&lc=UgzbPgJUMCztIOQDym14AaABAg. 9wdo_rWgxSH9wdpcYqrvp8
    ttps://www.youtube.com/watch?v=bFxnXH4-L1A
    https://www.youtube.com/watch?v=bFxnXH4-L1A&lc=UgxuODisjo6cvom7O-B4AaABAg.9w_AeS3JiK09wdi2XviwLG
    https://www.youtube.com/watch?v=bFxnXH4-L1A&lc=UgxBU39bTptFznDC1PJ4AaABAg
    ttps://www.youtube.com/watch?v=GqzeFYWjTxI
    https://www.youtube.com/watch?v=GqzeFYWjTxI&lc=UgwJnJDJ5JT8hFvibt14AaABAg
    https://www.youtube.com/channel/UCnxwq2aGJRbjOo_MO54oaHA
    Last edited by DocAElstein; 11-30-2023 at 03:00 PM.

  3. #23
    Junior Member
    Join Date
    Sep 2016
    Posts
    2
    Rep Power
    0
    Quote Originally Posted by Rick Rothstein View Post
    This function is not one that many will find a use for, but if you ever need its functionality, then here it is. The function can be called from other VB code or used as a UDF (user defined function) directly on a worksheet. What it does is tell you whether a point is located inside a polygon (simple or complex, convex or concave) or not. That's it... if you should ever need such a function, this is the code for it...

    Code:
    Public Function PtInPoly(Xcoord As Double, Ycoord As Double, Polygon As Variant) As Variant
      Dim x As Long, NumSidesCrossed As Long, m As Double, b As Double, Poly As Variant
      Poly = Polygon
      If Not (Poly(LBound(Poly), 1) = Poly(UBound(Poly), 1) And _
            Poly(LBound(Poly), 2) = Poly(UBound(Poly), 2)) Then
        If TypeOf Application.Caller Is Range Then
          PtInPoly = "#UnclosedPolygon!"
        Else
          Err.Raise 998, , "Polygon Does Not Close!"
        End If
        Exit Function
      ElseIf UBound(Poly, 2) - LBound(Poly, 2) <> 1 Then
        If TypeOf Application.Caller Is Range Then
          PtInPoly = "#WrongNumberOfCoordinates!"
        Else
          Err.Raise 999, , "Array Has Wrong Number Of Coordinates!"
        End If
        Exit Function
      End If
      For x = LBound(Poly) To UBound(Poly) - 1
        If Poly(x, 1) > Xcoord Xor Poly(x + 1, 1) > Xcoord Then
          m = (Poly(x + 1, 2) - Poly(x, 2)) / (Poly(x + 1, 1) - Poly(x, 1))
          b = (Poly(x, 2) * Poly(x + 1, 1) - Poly(x, 1) * Poly(x + 1, 2)) / (Poly(x + 1, 1) - Poly(x, 1))
          If m * Xcoord + b > Ycoord Then NumSidesCrossed = NumSidesCrossed + 1
        End If
      Next
      PtInPoly = CBool(NumSidesCrossed Mod 2)
    End Function
    The theory behind the function is simplicity itself... start at the point being tested and project a line from that point outward in any direction (I chose straight up as that made some of the math easier) and count how many polygon sides it crosses... if the number of sides is odd, the point lies inside the polygon and if the number of sides is even, the point lies outside of the polygon. The function will return either True, False (for inside/outside respectively) or an error message (see below). The first argument is the X-Coordinate and the second argument is the Y-Coordinate of the point you want to test for being inside the polygon or not. The third argument is either a two-dimensional array of numbers (when called from another VB code procedure) or a range of numbers consisting of two columns and as many rows as needed (when called from a worksheet). The numbers describe the nodes composing the polygon.

    NOTE #1: The polygon must be closed, meaning the first listed point and the last listed point must be the same. If they are not the same, the function will raise "Error #998 - Polygon Does Not Close!" if the function was called from other VB code or it will return #UnclosedPolygon! if called from the worksheet. Normally, if called from a worksheet, you would probably be using the function in a formula something like this...

    =IF(PtInPoly(B9,C9,E18:F37),"In Polygon","Out Polygon")

    In that case, the formula will return a #VALUE! error, not the #UnclosedPolygon! error, because the returned value to the IF function is not a Boolean; however, if you select the "PtInPoly(B9,C9,E18:F37)" part of the function in the Formula Bar and press F9, it will show you the returned value from the PtInPoly function as being #UnclosedPolygon!.

    NOTE #2: The range or array specified for the third argument must be two-dimensional. If it is not, then the function will raise "Error #999 - Array Has Wrong Number Of Coordinates!" if the function was called from other VB code or it will return #WrongNumberOfCoordinates! if called from the worksheet. Error reporting when called from the worksheet will be the same as described in NOTE #1.

    NOTE #3: Points extremely close to, or theoretically lying on, the polygon borders may or may not report back correctly... the vagrancies of floating point math, coupled with the limitations that the "significant digits limit" in VBA imposes, can rear its ugly head in those circumstances producing values that can calculate to either side of the polygon border being tested (remember, a mathematical line has no thickness, so it does not take too much of a difference in the significant digits to "move" a calculated point's position to one side or the other of such a line).

    NOTE #4: While I think error checking is a good thing, the setup for this function is rather straightforward and, with the possible exception of the requirement for the first and last point needing to be the same, easy enough for the programmer to maintain control over during coding. If you feel confident in your ability to meet the needs of NOTE #1 and NOTE #2 without having the code "looking over your shoulder", then the function can be simplified down to this compact code...

    Code:
    Public Function PtInPoly(Xcoord As Double, Ycoord As Double, Polygon As Variant) As Variant
      Dim x As Long, NumSidesCrossed As Long, m As Double, b As Double, Poly As Variant
      Poly = Polygon
      For x = LBound(Poly) To UBound(Poly) - 1
        If Poly(x, 1) > Xcoord Xor Poly(x + 1, 1) > Xcoord Then
          m = (Poly(x + 1, 2) - Poly(x, 2)) / (Poly(x + 1, 1) - Poly(x, 1))
          b = (Poly(x, 2) * Poly(x + 1, 1) - Poly(x, 1) * Poly(x + 1, 2)) / (Poly(x + 1, 1) - Poly(x, 1))
          If m * Xcoord + b > Ycoord Then NumSidesCrossed = NumSidesCrossed + 1
        End If
      Next
      PtInPoly = CBool(NumSidesCrossed Mod 2)
    End Function
    Hi Rick,

    first thanks for sharing your code, it has been very useful to me. Similar to theCloud, i work with aircraft center of gravity and needed a function similar to yours. However I had some problems:
    1- when a point was on a vertical boundarie
    2- when a point was on an horizontal boundarie
    3- when comparing two Double variable (b = Ycoord)...so I replace Double by Single and it works for now...I might need to use Double in the future, we'll see how it goes

    maybe this will help somebody, if you see any problems with my changes let me know

    thanks

    Code:
    Function PtInPoly(Xcoord As Double, Ycoord As Double, Polygon As Variant) As Variant
    Dim X As Long, NumSidesCrossed As Long, m As Single, b As Single, Poly As Variant '*********changed m and b variable type from Double to Single
    Dim btest As Single
    Poly = Polygon
    If Not (Poly(LBound(Poly), 1) = Poly(UBound(Poly), 1) And Poly(LBound(Poly), 2) = Poly(UBound(Poly), 2)) Then
        If TypeOf Application.Caller Is Range Then
            PtInPoly = "#UnclosedPolygon!"
        Else
            Err.Raise 998, , "Polygon Does Not Close!"
        End If
        Exit Function
    ElseIf UBound(Poly, 2) - LBound(Poly, 2) <> 1 Then
        If TypeOf Application.Caller Is Range Then
            PtInPoly = "#WrongNumberOfCoordinates!"
        Else
            Err.Raise 999, , "Array Has Wrong Number Of Coordinates!"
        End If
        Exit Function
    End If
    For X = LBound(Poly) To UBound(Poly) - 1
    Continu:
        If Poly(X, 1) >= Xcoord Xor Poly(X + 1, 1) >= Xcoord Then                '************changed > for >= to accomodate a point located on a vertical boundarie limit
            m = (Poly(X + 1, 2) - Poly(X, 2)) / (Poly(X + 1, 1) - Poly(X, 1))
            b = (Poly(X, 2) * Poly(X + 1, 1) - Poly(X, 1) * Poly(X + 1, 2)) / (Poly(X + 1, 1) - Poly(X, 1))
            If m = 0 And b = Ycoord Then                                         '********* added this "if statement" to check if point is on horizontal boundaries limit
                If X < UBound(Poly) - 1 Then
                    X = X + 1
                    GoTo Continu:
                Else
                    Exit For
                End If
            Else
                If m * Xcoord + b > Ycoord Then NumSidesCrossed = NumSidesCrossed + 1
            End If
        End If
    Next X
    PtInPoly = CBool(NumSidesCrossed Mod 2)
    End Function

  4. #24
    Forum Guru Rick Rothstein's Avatar
    Join Date
    Feb 2012
    Posts
    662
    Rep Power
    13
    Quote Originally Posted by hugohonda View Post
    Hi Rick,

    first thanks for sharing your code, it has been very useful to me. Similar to theCloud, i work with aircraft center of gravity and needed a function similar to yours. However I had some problems:
    1- when a point was on a vertical boundarie
    2- when a point was on an horizontal boundarie
    3- when comparing two Double variable (b = Ycoord)...so I replace Double by Single and it works for now...I might need to use Double in the future, we'll see how it goes
    For point numbers 1 and 2, I would refer you to my Note #3. You should not be overly fixated on points lying on the boundary of your polygon. Too many things can affect whether a point actually lies on the boundary. VB's floating point math is not infinite in scale, so the numbers have a limited precision (15 decimal places) and each number in a calculation theoretically degrades the accuracy of the calculated number to the point that you can never be sure if the calculated coordinate really lies on the boundary or not. For example, let's assume point is actually on the boundary... what is the significance if that is considered inside or outside the polygon on a practical level. Given that a theoretical boundary line for a polygon has zero thickness, then if the point was a millionth, trillions, zillions or whatever further away, it would be considered outside the polygon... similarly, if the point were as millionth, trillions, zillions or whatever closer in, it would be considered inside the polygon. At a practical level, either of those points (the further out one or the closer in one) could be considered the same point (what is the practical significance of two points that are a trillions of a inch, millimeter or whatever units of measurement?) So whether a real boundary point calculates inside or outside of the polygon should have absolutely no real world significance at all.

    As for changing Doubles to Singles... I would not do that as it lessens the accuracy of all calculations that take place in the routine increasing the chance that a point in the vicinity of the boundary, but not truly "next to" or "on" it might calculate to the wrong side. Rather than making Doubles into Singles, leave them as Doubles and when comparing them, round each of the values down to the same number of decimal place (you choose the number of decimal places that is significant to you) and then compare those rounded down values instead.

  5. #25
    Junior Member
    Join Date
    Sep 2016
    Posts
    2
    Rep Power
    0
    Quote Originally Posted by Rick Rothstein View Post
    For point numbers 1 and 2, I would refer you to my Note #3. You should not be overly fixated on points lying on the boundary of your polygon. Too many things can affect whether a point actually lies on the boundary. VB's floating point math is not infinite in scale, so the numbers have a limited precision (15 decimal places) and each number in a calculation theoretically degrades the accuracy of the calculated number to the point that you can never be sure if the calculated coordinate really lies on the boundary or not. For example, let's assume point is actually on the boundary... what is the significance if that is considered inside or outside the polygon on a practical level. Given that a theoretical boundary line for a polygon has zero thickness, then if the point was a millionth, trillions, zillions or whatever further away, it would be considered outside the polygon... similarly, if the point were as millionth, trillions, zillions or whatever closer in, it would be considered inside the polygon. At a practical level, either of those points (the further out one or the closer in one) could be considered the same point (what is the practical significance of two points that are a trillions of a inch, millimeter or whatever units of measurement?) So whether a real boundary point calculates inside or outside of the polygon should have absolutely no real world significance at all.

    As for changing Doubles to Singles... I would not do that as it lessens the accuracy of all calculations that take place in the routine increasing the chance that a point in the vicinity of the boundary, but not truly "next to" or "on" it might calculate to the wrong side. Rather than making Doubles into Singles, leave them as Doubles and when comparing them, round each of the values down to the same number of decimal place (you choose the number of decimal places that is significant to you) and then compare those rounded down values instead.
    Hi Rick,

    first, thanks for your quick reply. I like your idea with using the round function with Doubles...I implemented it and it works great now.

    As for my point numbers 1 and 2, I understand everything you mentioned and you are absolutely right. The thing is, I'm plotting different weight (y axis) and center of gravity (x axis) of an aircraft into a "Flight Envelope" and all point needs to be inside the envelope otherwise it isn't safe to fly. In order to find if a specific aircraft configuration (weight and CG) is dangerous to fly, I had to modify the code as mentioned before.

    I know that the specific aircraft configuration touching the boundary, theoretically, won't be exactly on the line because like you mentioned, "a line has no thickness" but it will give me, I think, a very accurate aircraft configuration at which it is dangerous to fly.

    I don't know if i'm clear but this is why i'm concerned about boundary.

    I tested my code with many case scenarios and all of them give me a good result so far

    thanks again!

  6. #26
    Forum Guru Rick Rothstein's Avatar
    Join Date
    Feb 2012
    Posts
    662
    Rep Power
    13
    Quote Originally Posted by hugohonda View Post
    As for my point numbers 1 and 2, I understand everything you mentioned and you are absolutely right. The thing is, I'm plotting different weight (y axis) and center of gravity (x axis) of an aircraft into a "Flight Envelope" and all point needs to be inside the envelope otherwise it isn't safe to fly. In order to find if a specific aircraft configuration (weight and CG) is dangerous to fly, I had to modify the code as mentioned before.
    You are talking about aircraft and you are worried about what amounts to infinitesimally small fractions of an inch? I think you are being overly trusting in the supposed accuracy of numerical calculations on a computer. All floating point calculations on a computer are approximations Unless your numbers have power of 2 factors, the conversion from the decimal system we work in to the binary system computers use will involve rounding errors out at the 15th or 16th decimal place which will propagate with each calculation you do with those numbers... that is why the "which side of the line with no thickness" problem is an issue at all... small changes out in the 15th or 16th decimal place are more than enough to move a calculated point onto either side of a line with no thickness. Just so you know, what I discussed about points near the border applies to all borders, not just horizontal or vertical ones. If you really want to be "safe" (your word, not mine), you should shrink your polygon by some percentage that you are comfortable with so that it does not matter which side of a boundary line a boundary point falls on.

    https://www.youtube.com/channel/UCnxwq2aGJRbjOo_MO54oaHA
    https://eileenslounge.com/viewtopic.php?p=318868#p318868
    https://eileenslounge.com/viewtopic.php?p=318311#p318311
    https://eileenslounge.com/viewtopic.php?p=318302#p318302
    https://eileenslounge.com/viewtopic.php?p=317704#p317704
    https://eileenslounge.com/viewtopic.php?p=317704#p317704
    https://eileenslounge.com/viewtopic.php?p=317857#p317857
    https://eileenslounge.com/viewtopic.php?p=317541#p317541
    https://eileenslounge.com/viewtopic.php?p=317520#p317520
    https://eileenslounge.com/viewtopic.php?p=317510#p317510
    https://eileenslounge.com/viewtopic.php?p=317547#p317547
    https://eileenslounge.com/viewtopic.php?p=317573#p317573
    https://eileenslounge.com/viewtopic.php?p=317574#p317574
    https://eileenslounge.com/viewtopic.php?p=317582#p317582
    https://eileenslounge.com/viewtopic.php?p=317583#p317583
    https://eileenslounge.com/viewtopic.php?p=317605#p317605
    https://eileenslounge.com/viewtopic.php?p=316935#p316935
    https://eileenslounge.com/viewtopic.php?p=317030#p317030
    https://eileenslounge.com/viewtopic.php?p=317030#p317030
    https://eileenslounge.com/viewtopic.php?p=317014#p317014
    https://eileenslounge.com/viewtopic.php?p=316940#p316940
    https://eileenslounge.com/viewtopic.php?p=316927#p316927
    https://eileenslounge.com/viewtopic.php?p=316875#p316875
    https://eileenslounge.com/viewtopic.php?p=316704#p316704
    https://eileenslounge.com/viewtopic.php?p=316412#p316412
    https://eileenslounge.com/viewtopic.php?p=316412#p316412
    https://eileenslounge.com/viewtopic.php?p=316254#p316254
    https://eileenslounge.com/viewtopic.php?p=316046#p316046
    https://eileenslounge.com/viewtopic.php?p=317050&sid=d7e077e50e904a138c794e1 f2115da95#p317050
    https://www.youtube.com/@alanelston2330
    https://www.youtube.com/watch?v=yXaYszT11CA&lc=UgxEjo0Di9-9cnl8UnZ4AaABAg.9XYLEH1OwDIA35HNIei0z-
    https://eileenslounge.com/viewtopic.php?p=316154#p316154
    https://www.youtube.com/watch?v=TW3l7PkSPD4&lc=UgwAL_Jrv7yg7WWC8x14AaABAg
    https://teylyn.com/2017/03/21/dollarsigns/#comment-191
    https://eileenslounge.com/viewtopic.php?p=317050#p317050
    https://eileenslounge.com/viewtopic.php?f=27&t=40953&p=316854#p316854
    https://www.eileenslounge.com/viewtopic.php?v=27&t=40953&p=316875#p316875
    https://eileenslounge.com/viewtopic.php?p=316057#p316057
    https://eileenslounge.com/viewtopic.php?p=315915#p315915
    https://eileenslounge.com/viewtopic.php?p=316705#p316705
    https://eileenslounge.com/viewtopic.php?p=316704#p316704
    https://eileenslounge.com/viewtopic.php?p=176255#p176255
    https://www.youtube.com/channel/UCnxwq2aGJRbjOo_MO54oaHA
    Last edited by DocAElstein; 07-27-2024 at 02:10 PM.

  7. #27
    Junior Member
    Join Date
    Jan 2017
    Posts
    4
    Rep Power
    0
    Hi Rick

    Thanks so much for the "PtInPoly" function. Awesome.

    I'm doing field data collection in a meter audit project. My field workers complete a Meter Audit FORM and attach lat/long GIS coordinates for the location of the meters. I cover many areas and most of the time I have to name the areas using my own names. This function helps me locate if the lat/long are inside designated areas.

    How I use the "PtInPoly" function is the following: I call it is inside my function in an excel spreadsheet and pass it "X-coord:lat", "Y-coord:long"d a "2-dimensional array of polygon points". My polygon is a closed polygon.

    There are about 5000 waypoints points my field database. So, for each waypoint I call the "PtInPoly" and test on which area the waypoint is located. I do this by running a loop for all areas and come out of the loop after finding the matching area.

    Wanted to ask if I'm allowed to modify you function and pass it four variables instead of three. Fourth one will be used for looping through all the areas?

    When I'm done. I will post the modified function here for you and everyone to see.

    Best
    Fikile
    Last edited by Rick Rothstein; 01-27-2017 at 03:51 PM.

  8. #28
    Forum Guru Rick Rothstein's Avatar
    Join Date
    Feb 2012
    Posts
    662
    Rep Power
    13
    Quote Originally Posted by Fikile Kentane View Post
    Hi Rick

    Thanks so much for the "PtInPoly" function. Awesome.

    I'm doing field data collection in a meter audit project. My field workers complete a Meter Audit FORM and attach lat/long GIS coordinates for the location of the meters. I cover many areas and most of the time I have to name the areas using my own names. This function helps me locate if the lat/long are inside designated areas.

    How I use the "PtInPoly" function is the following: I call it is inside my function in an excel spreadsheet and pass it "X-coord:lat", "Y-coord:long"d a "2-dimensional array of polygon points". My polygon is a closed polygon.

    There are about 5000 waypoints points my field database. So, for each waypoint I call the "PtInPoly" and test on which area the waypoint is located. I do this by running a loop for all areas and come out of the loop after finding the matching area.

    Wanted to ask if I'm allowed to modify you function and pass it four variables instead of three. Fourth one will be used for looping through all the areas?

    When I'm done. I will post the modified function here for you and everyone to see.

    Best
    Fikile
    Note... I removed your quote of my entire original post from your post... no need to burden this forum's servers with duplicate data that does not serve to any real reference purpose in your message.

    I am glad that you found my code useful to you. As to your question... sure, feel free to modify it in anyway that is useful to you. None of the code I have posted in this sub-forum is copyrighted, so you can use or modify any of it as needed.

  9. #29
    Junior Member
    Join Date
    Jan 2017
    Posts
    4
    Rep Power
    0
    Hi Rick

    I have to thank you again for the "PtInPoly" function. I need some help please. First let me explain how I use the "PtInPoly" function.

    I have a number of areas where my filed workers collect electricity meter audit data using Tablets. Each data set collected from the filed where a meter is located has a lat/long (GPS coordinates). There are a number of different areas with meters are located. I use the "PtInPoly" function to get the name of the area after checking if lat/long is in the area polygon. So for each lat/long I run a loop through all areas (18 times. There are 18 areas) and come out with the area name where the lat/long is inside an area.

    Below is an example of one of the areas involved. The area name is called "eBodi" and I have 4 points defining he polygon of the Ebodi erea.

    ---------------------------------------------------------------------------------------
    'ebodi
    areaName(totNumAreasElm - 6) = "ebodi"
    numOfPolygonPoints(totNumAreasElm - 6) = 4

    'Define the (x:y) poligon points. The shape must be closed, so there must be one array element more than shape corners and
    'the first and last coordinates must be the same

    'Initialize polygon point1
    pPoint(totNumAreasElm - 6, 0) = -31.2064891207045:
    pPoint(totNumAreasElm - 6, 1) = 28.2321971696144

    'Initialize polygon point2
    pPoint(totNumAreasElm - 6, 2) = -31.2045994633557:
    pPoint(totNumAreasElm - 6, 3) = 28.2303846938358

    'Initialize polygon point3
    pPoint(totNumAreasElm - 6, 4) = -31.2080756213509:
    pPoint(totNumAreasElm - 6, 5) = 28.2279014276724

    'Initialize polygon point4
    pPoint(totNumAreasElm - 6, 6) = -31.209143785413:
    pPoint(totNumAreasElm - 6, 7) = 28.2299482763019
    ------------------------------------------------------------------------------------------

    Before I pass these points to "PtInPoly" I first pass them into a 2 dimensional array (pP) as I understand is the requirement for the third argument of the "PtInPoly" function. I have managed t do this successfully and checked this when i was debugging my code.

    The problem is, the PtInPoly function does not work when I pass it pP in my VB code. But it works when I use and array in the worksheet. I've tested it using the same polygon points.



    Below is my code that I use to first assign my polygon points (pPoint) to Rick's two dimensional polygon (pP)
    I pass pP to the PtInPoly function together with the lat/long GPS coordinates
    -------------------------------------------------------------------------------------------------------------------------
    Dim areaCounter As Integer 'areaCounter loops through all area from 0 to 17
    Dim areaLocated As String '

    For areaCounter = 0 To totNumAreasElm Step 1 ' Loop through all the areas

    MsgBox ("testing area : " + areaName(areaCounter))

    'Array of polygon points (pP). Each point is lat/long (x/y). This is the polygon that passed to Rick function
    ReDim pP(0 To (numOfPolygonPoints(areaCounter) - 1), 0 To 1) As Double

    'Initialize the polygon Rick polygon
    Dim ppCounter As Integer
    Dim pointNumber As Integer
    pointNumberIncrement = 0

    For ppCounter = 0 To (numOfPolygonPoints(areaCounter) - 2) Step 1 'use the for loop to assign the my polygon points (pPoint) to Rick's two dimensional polygon (pP)
    pP(ppCounter, 0) = pPoint(areaCounter, 0 + pointNumberIncrement)
    pP(ppCounter, 1) = pPoint(areaCounter, 1 + pointNumberIncrement)
    If (ppCounter = 0) Then
    pP(ppCounter + (numOfPolygonPoints(areaCounter) - 1), 0) = pPoint(areaCounter, 0 + pointNumberIncrement)
    pP(ppCounter + (numOfPolygonPoints(areaCounter) - 1), 1) = pPoint(areaCounter, 1 + pointNumberIncrement)
    End If
    pointNumberIncrement = 2
    Next ppCounter

    If (PtInPoly(x, y, pP)) Then 'if the lat/long is in the area under test, PtInPoly returns a TRUE and I use this to get out of the loop

    areaLocated = areaName(areaCounter)
    loopCounter = totNumAreasElm

    End If

    areaCounter = areaCounter + 1

    Next areaCounter
    -------------------------------------------------------------------------------------------------------------------
    Please help me understand the problem that makes "PtInPoly" not to function

  10. #30
    Junior Member
    Join Date
    Jan 2017
    Posts
    4
    Rep Power
    0
    Hi Rick

    I have solved problem above.

    Had to modify my code to use the polygon array exactly the way you specified.

    Its now working

    Thanks a million

Similar Threads

  1. This is a test Test Let it be
    By Admin in forum Test Area
    Replies: 6
    Last Post: 05-30-2014, 09:44 AM
  2. This is a test of Signature Block Variable Dim
    By alansidman in forum Test Area
    Replies: 0
    Last Post: 10-17-2013, 07:42 PM
  3. Test
    By Excel Fox in forum Den Of The Fox
    Replies: 0
    Last Post: 07-31-2013, 08:15 AM
  4. Replies: 4
    Last Post: 06-10-2013, 01:27 PM
  5. Test
    By Excel Fox in forum Word Help
    Replies: 0
    Last Post: 07-05-2011, 01:51 AM

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •