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?

enter image description here

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

有帮助吗?

解决方案 2

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 polygon search.

其他提示

I wrote this article about 6 years ago. This is a simple point in polygon algorithm which is based on standard 2D geometry and is not a geospatially accurate algorithm. It works great for small polygons that cover the area of a city or smaller. Large polygons will appear to be less accurate. Note that a line between two points on a map, even though it looks straight, in reality the line is curved. A good example of this can be found here: http://alastaira.wordpress.com/2011/06/27/geodesics-on-bing-maps-v7/

As for your issue, if you want to click on a polygon simply use mouse events. If you want to check if a point is in a polygon then you make use of the powerful SQL Spatial library in WPF with will give you geospatially accurate point in polygon calculations. You don't need to connect to a database. All you need the Microsoft.SqlServer.Types.dll which is freely available through SQL Express. You can use it in .NET and with the Bing Maps WPF control. Here is a good starting point: http://ecn.channel9.msdn.com/o9/learn/SQL2008R2TrainingKit/Labs/UsingSpatialDataInManagedCode/Lab.docx

Once you have this working then you can simply create a SQLGeography object out of your polygon and check to see if your point intersects with the polygon.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top