0

免责声明:我不是 GIS 专家。

我们正在尝试使用 DotSpatial 库来计算线多边形交点,然后在 WPF Bing Maps 控件中显示该交点。由于某种原因,任何在 EW 方向上不完全笔直的交叉点都会从 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 回答
0

您的位置收集/交叉点测试不适合海拔高度

您遇到这种情况是因为有时多边形旁边的点(在球形地图上)不一定在多边形之外。我们正在尝试在 2D 平原上测试 3D 点。

刚用同样的问题把我的头撞在墙上几天!我想出了一个视觉上吸引人的修复,这很简单。

使用函数将所有多边形纬度/经度转换Point为屏幕上的对象LocationToViewPortpoint,以及您正在测试相交的点,并使用 X 和 Y 值而不是纬度/经度。

于 2013-07-06T05:32:21.363 回答