0

免責事項: 私は GIS の専門家ではありません。

DotSpatial ライブラリを使用してライン ポリゴンの交点を計算し、その交点を WPF Bing Maps コントロールに表示しようとしています。何らかの理由で、東西方向に完全にまっすぐでない交点は、Bing の元の線から下にずれて表示されます。WGS1984 に投影された DotSpatial コントロールですべてを表示すると、シフトが発生しないため、これは投影の問題であると想定しています。

再作成するには、マップ ウィンドウの xaml コード ビハインドに次のコードを追加します。

using Microsoft.Maps.MapControl.WPF;
using System.Windows;
using System.Windows.Media;
using DotSpatial.Data;
using DotSpatial.Topology;
public partial class MainWindow : Window
{
    private LocationCollection _polygonLocs = new LocationCollection();

    public MainWindow ()
    {
        InitializeComponent();

        AddSquarePolygon();

        // angled line 1
        LocationCollection slantedLocs = new LocationCollection();
        slantedLocs.Add(new Microsoft.Maps.MapControl.WPF.Location(40, -97));
        slantedLocs.Add(new Microsoft.Maps.MapControl.WPF.Location(35, -86));
        AddAndIntersectLine( slantedLocs );

        // straight EW line 
        LocationCollection ewLocs = new LocationCollection();
        ewLocs.Add(new Microsoft.Maps.MapControl.WPF.Location(37, -97));
        ewLocs.Add(new Microsoft.Maps.MapControl.WPF.Location(37, -86));
        AddAndIntersectLine(ewLocs);
    }

    private void AddAndIntersectLine(LocationCollection lineLocs)
    {
        MapPolyline line = new MapPolyline() { Locations = lineLocs, Stroke = new SolidColorBrush(Colors.Black) };

        this._bingMap.Children.Add(line);

        LocationCollection inters = Intersect(lineLocs, _polygonLocs);

        MapPolyline interLine = new MapPolyline() { Locations = inters, Stroke = new SolidColorBrush(Colors.Red) };
        this._bingMap.Children.Add(interLine);

    }

    private void AddSquarePolygon()
    {
        _polygonLocs.Add(new Microsoft.Maps.MapControl.WPF.Location(39.0, -92));
        _polygonLocs.Add(new Microsoft.Maps.MapControl.WPF.Location(36.0, -92));
        _polygonLocs.Add(new Microsoft.Maps.MapControl.WPF.Location(36.0, -93));
        _polygonLocs.Add(new Microsoft.Maps.MapControl.WPF.Location(39.0, -93));

        MapPolygon square = new MapPolygon()
        {
            Locations = _polygonLocs,
            Stroke = new SolidColorBrush(Colors.Black)
        };

        this._bingMap.Children.Add(square);
    }

    public static LocationCollection Intersect(LocationCollection line, LocationCollection bounds)
    {
        Feature lineFeature = CreateFeatureFromLocations(line);
        Feature boundsFeature = CreateFeatureFromLocations(bounds);

        IFeature featureIntersection = boundsFeature.Intersection(lineFeature);

        if (featureIntersection != null)
        {
            return (CreateLocationsFromFeature(featureIntersection));
        }

        return new LocationCollection();
    }


    private static LocationCollection CreateLocationsFromFeature(IFeature feature)
    {
        LocationCollection lc = new LocationCollection();
        foreach (var coords in feature.Coordinates)
        {
            lc.Add(new Microsoft.Maps.MapControl.WPF.Location(coords.Y, coords.X));
        }

        return lc;
    }

    private static Feature CreateFeatureFromLocations(LocationCollection locs)
    {

        Coordinate[] coords = new Coordinate[locs.Count];
        long inx = 0;

        foreach (var l in locs)
        {
            Coordinate coord = new Coordinate();
            coord.X = l.Longitude;
            coord.Y = l.Latitude;
            coords[inx] = coord;
            inx++;
        }

        LineString ls = new LineString(coords);
        MultiLineString mls = new MultiLineString(ls);
        return new Feature(mls);
    }
}
4

2 に答える 2

1

これは、ラインが測地線 (つまり、ジオイド上のライン) であるためです。平らな地図にプロットすると、円弧になり、直線ではなくなります。

1) MapPolyline を複数のセグメントに分割して、現実に近い円弧をプロットする関数を追加する必要があります。

private static LocationCollection BuildGeodesicPolyline(Microsoft.Maps.MapControl.WPF.Location start, Microsoft.Maps.MapControl.WPF.Location end)
    {
        int segments = 32; // The number of line segments used to approximate the true curved route 
        LocationCollection latLongs = new LocationCollection();

        // Convert all coordinates to Radians
        double lat1 = start.Latitude * (Math.PI / 180);
        double lon1 = start.Longitude * (Math.PI / 180);
        double lat2 = end.Latitude * (Math.PI / 180);
        double lon2 = end.Longitude * (Math.PI / 180);
        // Calculate the total extent of the route
        double d = 2 * Math.Asin(Math.Sqrt(Math.Pow((Math.Sin((lat1 - lat2) / 2)), 2) + Math.Cos(lat1) * Math.Cos(lat2) * Math.Pow((Math.Sin((lon1 - lon2) / 2)), 2)));
        // Calculate the position at fixed intervals along the route
        for (double n = 0; n < segments + 1; n++)
        {
            double f = (1d / segments) * n;
            double A = Math.Sin((1 - f) * d) / Math.Sin(d);
            double B = Math.Sin(f * d) / Math.Sin(d);
            // Calculate 3D Cartesian coordinates of the point
            double x = A * Math.Cos(lat1) * Math.Cos(lon1) + B * Math.Cos(lat2) * Math.Cos(lon2);
            double y = A * Math.Cos(lat1) * Math.Sin(lon1) + B * Math.Cos(lat2) * Math.Sin(lon2);
            double z = A * Math.Sin(lat1) + B * Math.Sin(lat2);
            // Convert these to latitude/longitude
            double lat = Math.Atan2(z, Math.Sqrt(Math.Pow(x, 2) + Math.Pow(y, 2)));
            double lon = Math.Atan2(y, x);
            // Create a VELatLong representing this location (remember to convert back to degrees)
            double newLat = lat / (Math.PI / 180d);
            double newLon = lon / (Math.PI / 180d);
            Microsoft.Maps.MapControl.WPF.Location p = new Microsoft.Maps.MapControl.WPF.Location(newLat, newLon);
            // Add this to the array
            latLongs.Add(p);
        }

        return latLongs;
    }

http://www.beginningspatial.com/plotting_geography_linestrings_google_maps_and_virtual_earthから取得

これらの線を「斜めの線 1」ブロックの後に追加すると、実際には円弧である黒い点線が表示されます。

slantedLocs = BuildGeodesicPolyline(new Microsoft.Maps.MapControl.WPF.Location(35d, -86d),new Microsoft.Maps.MapControl.WPF.Location(40d, -97d)) ;
MapPolyline m = new MapPolyline() { Locations = slantedLocs, Stroke = new SolidColorBrush(Colors.Black), StrokeThickness = 2d, StrokeDashArray = new DoubleCollection(new List<double>() { 5, 5 }) };
_bingMap.Children.Add(m);

2) 赤い線 (交点の結果) は平面座標系を使用しているため、DotSpatial について読む必要があります。SQL Serverがこれについて言っていることは次のとおりです。

declare @p geography = geography::STPolyFromText('POLYGON((-92 39 , -93 39 , -93 36 ,-92 36  , -92 39 ))',4326)
declare @l1 geography = geography::STLineFromText('LINESTRING(-97 40, -86 35)',4326)

declare @pG geometry = geometry::STPolyFromText('POLYGON((-92 39 , -93 39 , -93 36 ,-92 36  , -92 39 ))',4326)
declare @l1G geometry = geometry::STLineFromText('LINESTRING(-97 40, -86 35)',4326)
select 
@p.STIntersection(@l1).ToString() as [GEODESIC] -- LINESTRING (-92.0000000179902 37.936656236067556, -93.000000053162651 38.376235391098518)
    , @pG.STIntersection(@l1G).ToString() as [PLANAR] -- LINESTRING (-93 38.18181818181818, -92 37.727272727272727)

平面ジオメトリと測地線ジオメトリ間のジオメトリ操作は、このような縮尺では異なります。

于 2013-02-13T15:12:22.987 に答える