Bing Maps Polygon Inaccurate Search

I have a problem with an example of bing cards. Polygon search found here:

Search for a polygon about half this link.

public bool polygonSearch(LocationCollection points, double lat, double lon) { MapPolygon poly = new MapPolygon(); int i = 0; int j = points.Count - 1; bool inPoly = false; for (i = 0; i < points.Count; i++) { if (points[i].Longitude < lon && points[j].Longitude >= lon || points[j].Longitude < lon && points[i].Longitude >= lon) { if (points[i].Latitude + (lon - points[i].Longitude) / (points[j].Longitude - points[i].Longitude) * (points[j].Latitude - points[i].Latitude) < lat) { inPoly = !inPoly; } } j = i; } return inPoly; } 

I use ViewportPointToLocation to get mouse coordinates and add pins when I click.

  Point mousePosition = e.GetPosition(myMap); Microsoft.Maps.MapControl.WPF.Location pinLocation = myMap.ViewportPointToLocation(mousePosition); // Convert the mouse coordinates to a location on the map // The pushpin to add to the map. Pushpin pin = new Pushpin(); pin.Location = pinLocation; pin.Content = "Cust"; pin.Heading = 0; // Adds the pushpin to the map myMap.Children.Add(pin); 

Here I use my polygon search to see if I clicked in the polygon.

 polygonSearch(polygon.Locations, pin.Location.Latitude, pin.Location.Longitude)) 

As shown in the figure below, I have set the label "Within the delivery area" or "Client out of zone", depending on the weather polygonSearch returns true or false.

This does not seem to work when traversing the edge of the polygon. Can anyone experience this more, let me know where I am wrong?

enter image description here

FULL CODE EXAMPLE BELOW:

You will need to reference Microsoft.Maps.MapControl.WPF.dll to make this work.

I did only a demo containing the bing card management card, a shortcut to tell us our output of the polygon search, and a flag that allows us to search within the polygon.

To make a polygon, simply right-click on the map to draw, and press "Escape" to finish drawing the polygon. Then you can click on the "Left Click Search" button and search in the polygon.

As you will see, the polygon search from MSDN returns from the area when we see that we clicked inside the polygon we just drew!

MainWindow.xaml

 <Window x:Class="PolygonSearch.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:m="clr-namespace:Microsoft.Maps.MapControl.WPF;assembly=Microsoft.Maps.MapControl.WPF" Title="MainWindow" Height="350" Width="525" KeyDown="Window_KeyDown"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="100*"/> </Grid.RowDefinitions> <StackPanel> <Label Content="Label" Height="28" HorizontalAlignment="Left" Margin="10,10,0,0" Name="lbl_arearsult" Grid.Row="0" VerticalAlignment="Top" /> <CheckBox Content="Search Address by left click" Height="16" HorizontalAlignment="Left" Margin="10,10,0,0" Name="chk_search" VerticalAlignment="Top" /> </StackPanel> <m:Map x:Name="myMap" Grid.Row="1" CredentialsProvider="your_bing_map_key" Mode="AerialWithLabels" MouseLeftButtonDown="myMap_MouseDown" MouseRightButtonDown="myMap_MouseRightButtonDown" KeyDown="myMap_KeyDown" /> </Grid> </Window> 

MainWindow.xaml.cs

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using Microsoft.Maps.MapControl.WPF; namespace PolygonSearch { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { LocationCollection drawPolyPoints = new LocationCollection(); public MainWindow() { InitializeComponent(); } public bool polygonSearch(LocationCollection points, double lat, double lon) { MapPolygon poly = new MapPolygon(); int i = 0; int j = points.Count - 1; bool inPoly = false; for (i = 0; i < points.Count; i++) { if (points[i].Longitude < lon && points[j].Longitude >= lon || points[j].Longitude < lon && points[i].Longitude >= lon) { if (points[i].Latitude + (lon - points[i].Longitude) / (points[j].Longitude - points[i].Longitude) * (points[j].Latitude - points[i].Latitude) < lat) { inPoly = !inPoly; } } j = i; } return inPoly; } private void myMap_KeyDown(object sender, KeyEventArgs e) { if (e.Key == System.Windows.Input.Key.Escape) { MapPolygon polygon = new MapPolygon(); polygon.Fill = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.Blue); polygon.Stroke = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.Green); polygon.StrokeThickness = 5; polygon.Opacity = 0.7; polygon.Locations = drawPolyPoints; polygon.Tag = "1388_q3_polygon_5"; myMap.Children.Add(polygon); //drawPolyPoints.Clear(); for (int p = 0; p < myMap.Children.Count; p++) { object entity = myMap.Children[p]; if (entity is Microsoft.Maps.MapControl.WPF.Pushpin) { if (((Microsoft.Maps.MapControl.WPF.Pushpin)entity).Content.ToString() == "Vertice") myMap.Children.Remove(((Microsoft.Maps.MapControl.WPF.Pushpin)entity)); } } } } private void myMap_MouseDown(object sender, MouseButtonEventArgs e) { if (chk_search.IsChecked == true) { Point mousePosition = e.GetPosition(myMap); Microsoft.Maps.MapControl.WPF.Location pinLocation = myMap.ViewportPointToLocation(mousePosition); // Convert the mouse coordinates to a location on the map // The pushpin to add to the map. Pushpin pin = new Pushpin(); pin.Location = pinLocation; pin.Content = "Cust"; pin.Heading = 0; // Adds the pushpin to the map myMap.Children.Add(pin); bool inArea = false; for (int p = 0; p < myMap.Children.Count; p++) { object entity = myMap.Children[p]; if (entity is Microsoft.Maps.MapControl.WPF.MapPolygon) { if (polygonSearch(((Microsoft.Maps.MapControl.WPF.MapPolygon)entity).Locations, pin.Location.Latitude, pin.Location.Longitude)) { string[] quadAttributes = ((Microsoft.Maps.MapControl.WPF.MapPolygon)entity).Tag.ToString().Split('_'); lbl_arearsult.Content = "Within delivery area "; inArea = true; break; } else { inArea = false; } } } if (inArea != true) lbl_arearsult.Content = "Customer out of area. "; } } private void myMap_MouseRightButtonDown(object sender, MouseButtonEventArgs e) { Point mousePosition = e.GetPosition(myMap); Microsoft.Maps.MapControl.WPF.Location pinLocation = myMap.ViewportPointToLocation(mousePosition); // Convert the mouse coordinates to a location on the map // The pushpin to add to the map. Pushpin pin = new Pushpin(); pin.Location = pinLocation; pin.Content = "Vertice"; // Adds the pushpin to the map myMap.Children.Add(pin); drawPolyPoints.Add(pin.Location); } private void Window_KeyDown(object sender, KeyEventArgs e) { myMap_KeyDown(sender, e); } } } 

Note. This project will only work to create 1 polygon to search, but you can still see where my polygon search does not work out visually.

EDIT:

  • With great thanks from KeyboardP, we found that the problem does not exist if you zoom in fully, then draw a polygon, then do a search. But if we draw it, and then zoom in, we will see that the problem arises.

  • I also debugged and confirmed that the LocationCollection polygon is the same at different zoom levels.

  • List item

+7
source share
2 answers

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

+1
source

I wrote this article about 6 years ago. This is a simple point in a polygonal algorithm that is based on standard 2D geometry and is not a geospatially accurate algorithm. It is great for small polygons that cover a city or less. Larger polygons will seem less accurate. Notice that the line between the two points on the map, although it looks straight, is actually a curved line. A good example of this can be found here: http://alastaira.wordpress.com/2011/06/27/geodesics-on-bing-maps-v7/

As for your problem, if you want to click on the polygon, just use mouse events. If you want to check if a point is in a polygon, you use the powerful SQL spatial library in WPF, which will give you a geospatial exact point in polygon calculations. You do not need to connect to the database. All you need is Microsoft.SqlServer.Types.dll, which is freely available through SQL Express. You can use it in .NET and using the WPF control for Bing Maps. Here is a good starting point: http://ecn.channel9.msdn.com/o9/learn/SQL2008R2TrainingKit/Labs/UsingSpatialDataInManagedCode/Lab.docx

After that, you can simply create an SQLGeography object from your polygon and check if your point intersects with the polygon.

+5
source

All Articles