关于屏幕坐标系和地理坐标系之间得转换

关于使用wpf加载geoserver发布得wmts图层。

准备工作,需要使用一个第三方得dll,BruTile

关于使用geoserver发布瓦片图层,可以参考https://blog.csdn.net/weixin_43311389/article/details/99979275

预备知识:关于屏幕坐标系和地理坐标系之间得转换

首先获取地理坐标系得外包络矩形,然后算出外包络矩形和控件得比例(也叫单位像素点,就是把图包络矩形平铺到控件上,控件得一像素所对应得包络矩形得像素)。举一个具体得实例。例如控件得大小是15*8,现在将一个5*4得矩形平铺到上面,所得到宽度比是0.3,意思也就是控件1像素对应矩形0.3像素,高度比是0.5,取最大得比例,因为如果取最小的,矩形的高度就会溢出控件的高度。比如说高度是1个控件像素对应0.5个矩形像素,矩形完全填充高度,需要分成8分,如果采用最小的像素比,高度就会被分成13分,超出控件所能容纳的范围。

地理坐标系转换成屏幕坐标系,首先用地理坐标系的最小值减去包络矩形的最小值,获取地理坐标系所在包络矩形的位置,根据包络矩形和屏幕的比,然后算出这段距离所在屏幕上占据的长度,此长度就是控件上的X坐标。Y则是最大值,具体逻辑和算X值是一样的。

public Point WorldToScreen(double worldX, double worldY)
        {
            return new Point((worldX - _extent.MinX) / _unitsPerPixel, (_extent.MaxY - worldY) / _unitsPerPixel);
        }

屏幕坐标系转地理坐标系,首先在控件上选中一点,获取该点所距离最左侧的长度,将该长度转换为地理坐标系矩形的长度,然后再用地理包络矩形的最小X值加上当前长度,就是该点在地理坐标系上的位置(之所以加上地理包络矩形的最小X值,是因为地理坐标系并不是和屏幕坐标系一样从左上角0.0开始的),Y同上

 public Point ScreenToWorld(double screenX, double screenY)
        {
            return new Point((_extent.MinX + screenX * _unitsPerPixel), (_extent.MaxY - (screenY * _unitsPerPixel)));
        }

现在开始做WPF加载WMTS准备工作,首先定义一个地理包络矩形。主要包括矩形四个点的坐标还有中心点的坐标,判断矩形是否相等。这个类在BruTile中有提供,了解一下就可以了。

public readonly struct Extent
    {
        public double MinX { get; }
        public double MinY { get; }
        public double MaxX { get; }
        public double MaxY { get; }

        public double CenterX => (MinX + MaxX) / 2.0;
        public double CenterY => (MinY + MaxY) / 2.0;
        
        public double Width => MaxX - MinX;
        public double Height => MaxY - MinY;
        public double Area => Width * Height;

        public Extent Intersect(Extent other)
        {
            return new Extent(
                Math.Max(MinX, other.MinX),
                Math.Max(MinY, other.MinY),
                Math.Min(MaxX, other.MaxX),
                Math.Min(MaxY, other.MaxY));
        }

        public Extent(double minX, double minY, double maxX, double maxY) : this()
        {
            MinX = minX;
            MinY = minY;
            MaxX = maxX;
            MaxY = maxY;

            if (minX > maxX || minY > maxY)
            {
                throw new ArgumentException("min should be smaller than max");
            }
        }

        public bool Intersects(Extent box)
        {
            return !(
                        box.MinX > MaxX ||
                        box.MaxX < MinX ||
                        box.MinY > MaxY ||
                        box.MaxY < MinY);
        }

        public override string ToString()
        {
            return string.Format(CultureInfo.InvariantCulture,
                                 "{0},{1},{2},{3}", MinX, MinY, MaxX, MaxY);
        }

        public override bool Equals(object obj)
        {
            if (obj is not Extent extent)
            {
                return false;
            }
            return Equals(extent);
        }

        public bool Equals(Extent extent)
        {
            if (Math.Abs(MinX - extent.MinX) > double.Epsilon)
            {
                return false;
            }

            if (Math.Abs(MinY - extent.MinY) > double.Epsilon)
            {
                return false;
            }

            if (Math.Abs(MaxX - extent.MaxX) > double.Epsilon)
            {
                return false;
            }

            if (Math.Abs(MaxY - extent.MaxY) > double.Epsilon)
            {
                return false;
            }

            return true;
        }

        public override int GetHashCode()
        {
            return MinX.GetHashCode() ^ MinY.GetHashCode() ^ MaxX.GetHashCode() ^ MaxY.GetHashCode();
        }

        public static bool operator ==(Extent extent1, Extent extent2)
        {
            return extent1.Equals(extent2);
        }

        public static bool operator !=(Extent extent1, Extent extent2)
        {
            return !extent1.Equals(extent2);
        }
    }

猜你喜欢

转载自blog.csdn.net/qq_40098572/article/details/128634125
今日推荐