Point in Polygon Query

5228
8
Jump to solution
02-26-2014 08:56 AM
RichardAbram
New Contributor III
Can the File Geodatabase API used to do a point in a polygon spatial query?  If so does anyone have sample code?
0 Kudos
1 Solution

Accepted Solutions
VinceAngelo
Esri Esteemed Contributor
The table::search method takes an envelope -- have you tried using the Querying
sample with an envelope where minx==maxx and miny==maxy?  A pair of yin-
yang like shapes will tell the tale.

Worst case, you can make the envelope very small, and use a point-in-poly algorithm
to confirm that the center point is within the geometry (count the number of times a
line extended from the point to a point past the eastern [or western] edge of the shape
envelope crosses the segments [treating the second point as if it isn't part of the line,
so it isn't counted twice] -- odd crossing is within; even outside -- 20+ years ago I
solved the segments in the form Ax + By = C and used matrix algebra to locate the
point of intersection).

- V

View solution in original post

0 Kudos
8 Replies
VinceAngelo
Esri Esteemed Contributor
The table::search method takes an envelope -- have you tried using the Querying
sample with an envelope where minx==maxx and miny==maxy?  A pair of yin-
yang like shapes will tell the tale.

Worst case, you can make the envelope very small, and use a point-in-poly algorithm
to confirm that the center point is within the geometry (count the number of times a
line extended from the point to a point past the eastern [or western] edge of the shape
envelope crosses the segments [treating the second point as if it isn't part of the line,
so it isn't counted twice] -- odd crossing is within; even outside -- 20+ years ago I
solved the segments in the form Ax + By = C and used matrix algebra to locate the
point of intersection).

- V
0 Kudos
RichardAbram
New Contributor III
Thanks for your response.  I was hoping the search would return either 1 feature if it is inside it or 0 features if the point is not in the polygon.

When I do a table search (I am using the C# wrapper) setting the envelop min/max the same values as a point or even expanding the point to a small area I still get multiple results from the search. 

I did find code for a winding number algorithm to detect whether the point is in or outside of a polygon.  I reworked the c# code to deal with a MultipartShapeBuffer with parts and points.  I now make the table search and then loop the results, usually 2 or 3 rows, to find which of the returned rows is the polygon I'm looking for.
0 Kudos
EricO_Neal
New Contributor II

I am having the same issue.  I have a point that I have converted to an extremely small envelope, but I get get 3 results back from my query and should only be getting one.  This seems like a bug.

Anyone from ESRI reading these?

0 Kudos
VinceAngelo
Esri Esteemed Contributor

It's only a bug if the three returned shapes do not overlap the requested envelope.  Do they?  Can you provide a FGDB data sample and the corners of the envelope with which you're querying?

ALL application code must handle the possibility that a point-in-poly query could return zero, one, or many features.  With a simple envelope search,  the probability of multiple return rows approaches unity.

Since there's no way to alter the design without including a full geometry processing library in the FGDBAPI DLL (and that doesn't seem likely), the best possible solution is going to be a simple helper function to test point-in-polygon (and even that will need to return a ternary response -- {"IN", "OUT", "ON"}).

- V

0 Kudos
EricO_Neal
New Contributor II

THanks,  I will provide a data and code sample in the morning when I am back at my PC.

0 Kudos
EricO_Neal
New Contributor II

Attached is a small file geodatabase with one featureclass. When I query with the point shown on the attached map(expanded slightly to make an envelope), I get three results.  The correct one, David James, but also Tandy and Hamilton, which is obviously wrong.  There should be only one row returned, but I am getting three. 

Thanks

Code:

  static void Main(string[] args)
        {
            Geodatabase geodatabase = null;
            Table table = null;
            try
            {
                geodatabase = Geodatabase.Open(@"C:\Temp\test.gdb");
                Esri.FileGDB.Point pt = new Esri.FileGDB.Point();

                double x = 1204123.4375;
                double y = 273148.87152777775;

                pt.x = x;
                pt.y = y;

                Envelope envelope = new Envelope();
                envelope.xMin = x - .00001;
                envelope.yMin = y - .00001;
                envelope.xMax = x + .00001;
                envelope.yMax = y + .00001;


                table = geodatabase.OpenTable("MetroCouncil");
                RowCollection spQueryRows = table.Search("*", "", envelope, RowInstance.Recycle);


                foreach (Row spQueryRow in spQueryRows)
                {
                    Console.WriteLine(spQueryRow.GetString("COUN_NAME").ToString());
                }

                Console.ReadLine();

            }

            catch (Exception ex)
            {
            }


            finally
            {
                table.Close();
                geodatabase.Close();
            }

        }
0 Kudos
VinceAngelo
Esri Esteemed Contributor

Well, I couldn't read the FGDB, but the JPEG indicates an envelope-on-envelope search is being conducted (which is what I expected).

CouncilPoint_wEnv.jpg

The results are not incorrect, they're just imprecise. The spatial search just nominates candidates which are close enough to have a relationship (beyond envelope_overlap).  You need to do the point-in-polygon test on your own (which is what I wrote in March).

- V

EricO_Neal
New Contributor II

Thanks Vince, it all made perfect sense as soon as I saw your attached image.

I went ahead and put together the helper function earlier and am attaching this process for anyone else who finds this, its working well now:

  RowCollection spQueryRows = table.Search("*", "", envelope, RowInstance.Recycle);
                MultiPartShapeBuffer rowGeomPoly = new MultiPartShapeBuffer();
                foreach (Row spQueryRow in spQueryRows)
                {

                    //Get the row polygon
                    rowGeomPoly = spQueryRow.GetGeometry();


                    //Convert ESRI Geometry to PointF array
                    System.Drawing.PointF[] polyPts = new PointF[rowGeomPoly.Points.Length];
                    System.Drawing.PointF point;
                    for(int j = 0;j<=rowGeomPoly.Points.Length -1;j++)
                    {
                        point = new PointF { X = (float)rowGeomPoly.Points.x, Y = (float)rowGeomPoly.Points.y };
                        polyPts = point;
                    }


                    //Intersect
                    bool isIntersected = PointIsInPolygon(polyPts, new System.Drawing.PointF { X = (float)pt.x, Y = (float)pt.y });
                    if (isIntersected)
                    {
                        Console.WriteLine(spQueryRow.GetString("COUN_NAME").ToString());
                        break;
                    }
     
               
                }

       private static bool PointIsInPolygon(PointF[] polygon, PointF target_point)
        {
            // Make a GraphicsPath containing the polygon.
            GraphicsPath path = new GraphicsPath();
            path.AddPolygon(polygon);


            // See if the point is inside the path.
            return path.IsVisible(target_point);
        }