3

A little about the application;

The application allows the user to draw and save polygons onto bing maps WPF api.

The piece of code we are interested in is finding weather a point is whithin the polygon or not. The following function simply loops through the LocationCollection of the polygon on the bing map, and creates a SqlGeography object (OpenGisGeographyType.Polygon) which is an instance of a polygon.

We then convert the mouse click into SqlGeography object (OpenGisGeographyType.Point) by latitude and longitude and use the SqlGeography.STIntersection to find if our point lies within the polygon.

As seen in the picture, even when the point is outside the polygon, SqlGeography.STIntersection still returns a point of intersection. (You can tell this in the picture as I set a label to "Within Delivery Area" or "Customer our of Area" depending on what polygonSearch() function returned.

The right example in the picture has the expected results when a location is tested within the polygon.

The left example in the picture contains the unexpected results - Which indicates that a point is within a polygon , when it clearly is not!

enter image description here

NOTES:

  • I Use SqlGeography (myShape) to put the shapes on the map, so I know the shape is being constructed with proper verticies.
  • I use SqlGeography (myPoint) to put the pin on the map, so I know the pin is being tested at the correct verticies.
    • THIS ONLY FAILS ON LARGE POLYGONS

Below I give the peice of code which creates the polygon in memory, as well as converts the mouse click event to lat, longitude. ( I have included the polygon verticies in comments so that this can be looked at without the need of the bing api, just replace the for loop with the comments above it ) Although, you will need to reference Microsoft.SqlServer.Types.dll to create the SqlGeography objects. Its free with SQL Express 2008 , and can be found in C:\Program Files (x86)\Microsoft SQL Server\100\SDK\Assemblies

 public bool polygonSearch2(LocationCollection points, double lat, double lon)
    {
    SqlGeography myShape = new SqlGeography();
    SqlGeographyBuilder shapeBuilder = new SqlGeographyBuilder();

    // here are the verticies for the location collection if you want to hard code and try
    //shapeBuilder.BeginFigure(47.4275329011347, -86.8136038458706);
    //shapeBuilder.AddLine(36.5102408627967, -86.9680936860962);
    //shapeBuilder.AddLine(37.4928909385966, -80.2884061860962);
    //shapeBuilder.AddLine(38.7375329179818, -75.7180936860962);
    //shapeBuilder.AddLine(48.0932596736361, -83.7161405610962);
    //shapeBuilder.AddLine(47.4275329011347, -86.8136038458706);
    //shapeBuilder.EndFigure();
    //shapeBuilder.EndGeography();

    // Here I just loop through my points collection backwards to create the polygon in the SqlGeography object
    for (int i = points.Count - 1; i >= 0; i--)
    {
        if (i == 0)
        {
            shapeBuilder.AddLine(points[i].Latitude, points[i].Longitude);
            shapeBuilder.EndFigure();
            shapeBuilder.EndGeography();

            continue;

        }
        if (i == points.Count - 1)
        {

            shapeBuilder.SetSrid(4326);
            shapeBuilder.BeginGeography(OpenGisGeographyType.Polygon);
            shapeBuilder.BeginFigure(points[i].Latitude, points[i].Longitude);

            continue;
        }
        else
        {
            shapeBuilder.AddLine(points[i].Latitude, points[i].Longitude);
        }
    }

    myShape = shapeBuilder.ConstructedGeography;

    // Here I am creating a SqlGeography object as a point (user mouse click)
    SqlGeography myPoint = new SqlGeography();
    SqlGeographyBuilder pointBuilder = new SqlGeographyBuilder();
    pointBuilder.SetSrid(4326);
    pointBuilder.BeginGeography(OpenGisGeographyType.Point);
    // Should pass, which it does
    // Lat: lat = 43.682110574649791 , Lon: -79.79005605528323
    // Should fail, but it intersects??
    // Lat: 43.682108149690094 , Lon: -79.790037277494889
    pointBuilder.BeginFigure(lat, lon); 
    pointBuilder.EndFigure();
    pointBuilder.EndGeography();


    myPoint = pointBuilder.ConstructedGeography;


    SqlGeography result = myShape.STIntersection(myPoint);

    if (result.Lat.IsNull)
        return false;
    else
        return true;



}

Any help at all is much appreciated, I am starting to drive my boss nuts with this problem >.<

Could this have anything to do with the SRID?

clamchoda
  • 4,411
  • 2
  • 36
  • 74
  • Does it always return true or only when it's close-but-still-outside? – ta.speot.is Jul 03 '13 at 21:10
  • @ta.speot.is Only when close but still outside – clamchoda Jul 03 '13 at 21:47
  • `This only fails after zooming`. Are you saying that after zooming the map, and then adding a marker, the incorrect result is returned? It's not that a pin marker at first inside the polygon is rendered outside the polygon when the image is zoomed, right? – Tim Jul 04 '13 at 18:07
  • @Tim After zooming the map, then adding the marker the incorrect result is returned - This is correct. Pretty much it seems like it only works while zoomed out because the calculations must not need to be as percise. Thank you for your time – clamchoda Jul 04 '13 at 18:16

1 Answers1

0

I fixed this by converting all my polygon lat / long to a Point object on the screen using LocationToViewPortpoint function, as well as the point I'm testing for intersection, and use the X and Y values instead of lat / long in my STIntersects.

clamchoda
  • 4,411
  • 2
  • 36
  • 74