About conversion between screen coordinate system and geographic coordinate system

About using wpf to load the wmts layer published by geoserver.

For preparation, you need to use a third-party dll, BruTile

About using geoserver to publish tile layers, you can refer to https://blog.csdn.net/weixin_43311389/article/details/99979275

Preliminary knowledge: about the conversion between the screen coordinate system and the geographic coordinate system

First obtain the outer envelope rectangle of the geographic coordinate system, and then calculate the ratio of the outer envelope rectangle and the control (also called unit pixel point, which is to tile the image envelope rectangle on the control, and the envelope rectangle corresponding to one pixel of the control pixels). Give a specific example. For example, the size of the control is 15*8, and now a 5*4 rectangle is tiled on it, and the resulting width ratio is 0.3, which means that 1 pixel of the control corresponds to 0.3 pixels of the rectangle, and the height ratio is 0.5, taking the largest ratio. Because if you take the smallest one, the height of the rectangle will overflow the height of the control. For example, the height is 1 control pixel corresponding to 0.5 rectangle pixels, and the rectangle needs to be divided into 8 points to completely fill the height. If the minimum pixel ratio is used, the height will be divided into 13 points, which exceeds the range that the control can accommodate.

To convert the geographic coordinate system to the screen coordinate system, first subtract the minimum value of the envelope rectangle from the minimum value of the geographic coordinate system to obtain the position of the envelope rectangle where the geographic coordinate system is located, and then calculate this section according to the ratio of the envelope rectangle to the screen The length occupied by the distance on the screen, this length is the X coordinate on the control. Y is the maximum value, and the specific logic is the same as calculating the X value.

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

To convert the screen coordinate system to the geographic coordinate system, first select a point on the control, obtain the length of the point from the far left, convert the length into the length of the geographic coordinate system rectangle, and then add the minimum X value of the geographic envelope rectangle The current length is the position of the point on the geographic coordinate system (the reason why the minimum X value of the geographic envelope rectangle is added is that the geographic coordinate system does not start from the upper left corner of 0.0 like the screen coordinate system), and Y is the same as above

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

Now start to prepare for WPF to load WMTS, first define a geographic envelope. It mainly includes the coordinates of the four points of the rectangle and the coordinates of the center point to determine whether the rectangles are equal. This class is provided in BruTile, just understand it.

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

Guess you like

Origin blog.csdn.net/qq_40098572/article/details/128634125