7

ここにあるポリゴン検索の例のビングマップに少し問題があります:

ポリゴン検索は、このリンクの中ほどにあります。

  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;



}

ViewportPointToLocationマウスの座標を取得し、マウスのクリックでピンを追加するために使用します。

            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);

ここで、ポリゴン検索を使用して、ポリゴン内をクリックしたかどうかを確認します。

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

下の図のように、ラベルを「配達エリア内」または「顧客エリア外」に設定すると、天候に応じて polygonSearch は true または false を返します。

ポリゴンのエッジ周辺を扱うときはうまくいかないようです。これについてもっと経験のある人は、私が間違っている場所を教えてもらえますか?

ここに画像の説明を入力

以下の完全なコード例:

これを機能させるには、 を参照する必要がありますMicrosoft.Maps.MapControl.WPF.dll

bing マップ コントロール マップ、ポリゴン検索出力を示すラベル、およびポリゴン内を検索できるチェックボックスを含むデモを作成しました。

多角形を作成するには、マップを右クリックして描画し、[Esc] を押して多角形の描画を終了します。次に、「左クリックで住所を検索」チェックボックスをクリックして、ポリゴン内を検索できます。

ご覧のとおり、描画したばかりのポリゴン内をクリックしたことがわかると、MSDN からのポリゴン検索が領域外に返されます!

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);
        }
    }
}

注: このデザインは、検索するポリゴンを 1 つ作成する場合にのみ機能しますが、ポリゴン検索がどこで失敗したかを視覚的に確認できます。

編集:

  • KeyboardP からの多くの感謝により、完全にズームインし、ポリゴンを描画してから検索すると、問題が存在しないことがわかりました。しかし、それを描画してからズームすると、同じ問題が発生することがわかります。

  • また、LocationCollection ポリゴンが異なるズーム レベルで同じであることをデバッグして確認しました

  • リスト項目

4

2 に答える 2

6

この記事を書いたのは約6年前。これは、標準の 2D ジオメトリに基づくポリゴン アルゴリズムの単純なポイントであり、地理空間的に正確なアルゴリズムではありません。都市またはそれ以下の領域をカバーする小さなポリゴンに最適です。大きなポリゴンは精度が低くなります。地図上の 2 点間の線は、まっすぐに見えますが、実際には曲がっていることに注意してください。これの良い例はここにあります: http://alastaira.wordpress.com/2011/06/27/geodesics-on-bing-maps-v7/

あなたの問題に関しては、ポリゴンをクリックしたい場合は、単にマウスイベントを使用してください。ポイントがポリゴン内にあるかどうかを確認する場合は、WPF の強力な SQL Spatial ライブラリを使用して、ポリゴン計算で地理空間的に正確なポイントを取得します。データベースに接続する必要はありません。必要なのは、SQL Express から無料で入手できる Microsoft.SqlServer.Types.dll だけです。.NET および Bing Maps WPF コントロールで使用できます。良い出発点は次のとおりです: http://ecn.channel9.msdn.com/o9/learn/SQL2008R2TrainingKit/Labs/UsingSpatialDataInManagedCode/Lab.docx

これが機能したら、ポリゴンから SQLGeography オブジェクトを作成し、ポイントがポリゴンと交差するかどうかを確認するだけです。

于 2013-07-03T12:50:37.657 に答える