I am having a bit of a problem with the bing maps example Polygon Search found here:
Polygon search is about halfway down 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 the mouse co-ordinates and add a pin at my mouse 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);
This is where I use my polygon search to see if I clicked within the polygon.
polygonSearch(polygon.Locations, pin.Location.Latitude, pin.Location.Longitude))
As seen in the picture below, I set a label to "Within delivery area" or "Customer out of area", depending on weather polygonSearch returns true or false.
It doesn't seem to work when dealing around the edge of the polygon. Can someone more experience with this let me know where i lye wrong?
COMPLETE CODE EXAMPLE BELOW:
You will need to reference the Microsoft.Maps.MapControl.WPF.dll
to get this working.
I have made just a demo, which contains the bing map control map, a label to tell us our polygon search output, and a checkbox which allows you to search within the polygon.
To make a polygon, simply right click the map to draw, and press "Escape" to end drawing the polygon. Then you can click the "Search address by left click" checkbox and search within the polygon.
As you will see, the polygon search from MSDN returns out of area when we can see that we clicked within the polygon that 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 design will only work to create 1 polygon to search, but you can still see where my polygon search fails visually.
EDIT:
With lots of thanks from KeyboardP, we have found that issue does not exists if you fully zoom in, then draw the polygon, then search. But if we draw it, then zoom, we will see the same issue arise.
I have also debugged and confirmed that the LocationCollection polygon is the same on different zoom levels
List item
StrokeThickness
not resizing as you zoom in. – Ezana