欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

地理坐标(WGS84),投影坐标下(Mercator)切片系统的计算Java类

程序员文章站 2022-04-19 13:31:22
1、地理坐标下切片系统的计算地理坐标下切片系统的计算,主要适用于google地球中切片系统,以及目标底图参考系统为EPSG:4326的情况。public class GlobalGeodetic { private int tileSize; private double resFact; public GlobalGeodetic(String tmscompa......

1、地理坐标下切片系统的计算

地理坐标下切片系统的计算,主要适用于google地球中切片系统,以及目标底图参考系统为EPSG:4326的情况。

public class GlobalGeodetic {
    private int tileSize;
    private double resFact;

    public GlobalGeodetic(String tmscompatible, int tileSize) {
        this.tileSize = tileSize;
        if (tmscompatible != null && tmscompatible.length() > 0) {
        	// Defaults the resolution factor to 0.703125 (2 tiles @ level 0)
            this.resFact = 180.0D / (double)this.tileSize;
        } else {
        	//Defaults the resolution factor to 1.40625 (1 tile @ level 0)
            this.resFact = 360.0D / (double)this.tileSize;
        }

    }

    public double[] lonlatToPixels(double lon, double lat, int zoom) {
        double res = this.resFact / Math.pow(2.0D, (double)zoom);
        return new double[]{(180.0D + lon) / res, (90.0D + lat) / res};
    }

    public int[] pixelsToTile(double px, double py) {
        int tx = (int)(Math.ceil(px / (double)this.tileSize) - 1.0D);
        int ty = (int)(Math.ceil(py / (double)this.tileSize) - 1.0D);
        return new int[]{tx, ty};
    }

    public int[] lonlatToTile(double lon, double lat, int zoom) {
        double[] pxpy = this.lonlatToPixels(lon, lat, zoom);
        return this.pixelsToTile(pxpy[0], pxpy[1]);
    }

    public double resolution(int zoom) {
        return this.resFact / Math.pow(2.0D, (double)zoom);
    }

    public int zoomForPixelSize(double pixelSize) {
        for(int i = 0; i < 32; ++i) {
            if (pixelSize > this.resolution(i)) {
                if (i != 0) {
                    return i - 1;
                }

                return 0;
            }
        }

        return 0;
    }

    public double[] tileBounds(int tx, int ty, int zoom) {
        double res = this.resFact / Math.pow(2.0D, (double)zoom);
        return new double[]{(double)(tx * this.tileSize) * res - 180.0D, (double)(ty * this.tileSize) * res - 90.0D, (double)((tx + 1) * this.tileSize) * res - 180.0D, (double)((ty + 1) * this.tileSize) * res - 90.0D};
    }

    public double[] tileLatLonBounds(int tx, int ty, int zoom) {
        double[] b = this.tileBounds(tx, ty, zoom);
        return new double[]{b[1], b[0], b[3], b[2]};
    }
}

2、投影坐标系下计算类

目前绝大多数切片系统内部实现都是采用这种方式实现。

public class GlobalMercator {
    private int tileSize;
    private double initialResolution;
    private double originSh;
   //6378137 为地球半径		
   public GlobalMercator(int tileSize) {
        this.tileSize = tileSize;
        this.initialResolution = 2 * Math.PI * 6378137 / this.tileSize;
        this.originShift = 2 * Math.PI * 6378137 / 2.0;
    }

    public double[] latLonToMeters(double lat, double lon) {
        double mx = lon * this.originShift / 180.0;
        double my = Math.log(Math.tan((90 + lat) * Math.PI / 360.0)) / (Math.PI / 180.0);
        my = my * this.originShift / 180.0;
        return new double[]{mx, my};
    }

    public double[] metersToLatLon(double mx, double my) {
        double lon = (mx / this.originShift) * 180.0;
        double lat = (my / this.originShift) * 180.0;
        lat = 180 / Math.PI * (2 * Math.atan(Math.exp(lat * Math.PI / 180.0)) - Math.PI / 2.0);
        return new double[]{lat, lon};
    }

    public double[] pixelsToMeters(int px, int py, int zoom) {
        double res = this.resolution(zoom);
        double mx = px * res - this.originShift;
        double my = py * res - this.originShift;
        return new double[]{mx, my};
    }

    public double[] metersToPixels(double mx, double my, int zoom) {
        double res = this.resolution(zoom);
        double px = (mx + this.originShift) / res;
        double py = (my + this.originShift) / res;
        return new double[]{px, py};
    }

    public int[] pixelsToTile(double px, double py) {
        int tx = (int) (Math.ceil(px / (float) (this.tileSize)) - 1);
        int ty = (int) (Math.ceil(py / (float) (this.tileSize)) - 1);
        return new int[]{tx, ty};
    }

    public double[] pixelsToRaster(double px, double py, int zoom) {
        double mapSize = this.tileSize << zoom;
        return new double[]{px, mapSize - py};
    }

    public int[] metersToTile(double mx, double my, int zoom) {
        double[] coordinate = this.metersToPixels(mx, my, zoom);
        return this.pixelsToTile(coordinate[0], coordinate[1]);
    }

    public double[] tileBounds(int tx, int ty, int zoom) {
        double[] minxy = pixelsToMeters(tx * this.tileSize, ty * this.tileSize, zoom);
        double[] maxxy = pixelsToMeters((tx + 1) * this.tileSize, (ty + 1) * this.tileSize, zoom);
        return new double[]{minxy[0], minxy[1], maxxy[0], maxxy[1]};
    }

    public double[] tileLatLonBounds(int tx, int ty, int zoom) {
        double[] bounds = this.tileBounds(tx, ty, zoom);
        double[] minLatLon = this.metersToLatLon(bounds[0], bounds[1]);
        double[] maxLatlon = this.metersToLatLon(bounds[2], bounds[3]);
        return new double[]{minLatLon[0], minLatLon[1], maxLatlon[0], maxLatlon[1]};
    }

    public double resolution(int zoom) {
        return this.initialResolution / (Math.pow(2, zoom));
    }

    public int zoomForPixelSize(double pixelSize) {
        for (int i = 0; i < 32; i++) {
            if (pixelSize > this.resolution(i)) {
                if (i != 0) {
                    return i - 1;
                } else return 0;
            }
        }
        return 0;
    }
	//XYZ切片系统转googleTSM切片系统,其实就是坐标系的Y轴的变换,由原点左上角变换为原点左下角。
    public int[] googleTile(int tx, int ty, int zoom) {
        return new int[]{tx, ((int) (Math.pow(2, zoom)) - 1) - ty};
    }

    public String quadTree(int tx, int ty, int zoom) {
        String quadKey = "";
        ty = (int) (Math.pow(2, zoom) - 1 - ty);
        for (int i = zoom; i > 0; i--) {
            int digit = 0;
            int mask = 1 << (i - 1);
            if ((tx & mask) != 0) {
                digit += 1;
            }
            if ((ty & mask) != 0) {
                digit += 2;
                quadKey += digit;
            }
        }
        return quadKey;
    }
	//XYZ转换为geohash编码
    public String tileXYToQuadKey(int tileX, int tileY, int levelOfDetail) {
        StringBuilder quadKey = new StringBuilder();
        for (int i = levelOfDetail; i > 0; i--) {
            char digit = '0';
            int mask = 1 << (i - 1);
            if ((tileX & mask) != 0) {
                digit++;
            }
            if ((tileY & mask) != 0) {
                digit++;
                digit++;
            }
            quadKey.append(digit);
        }
        return quadKey.toString();
    }
	//geohash编码转换为XYZ
    public int[] quadKeyToTileXY(String quadKey) throws Exception {
        int tileX = 0, tileY = 0;
        int levelOfDetail = quadKey.length();
        for (int i = levelOfDetail; i > 0; i--) {
            int mask = 1 << (i - 1);
            switch (quadKey.charAt(levelOfDetail - i)) {
                case '0':
                    break;
                case '1':
                    tileX |= mask;
                    break;
                case '2':
                    tileY |= mask;
                    break;
                case '3':
                    tileX |= mask;
                    tileY |= mask;
                    break;
                default:
                    throw new Exception("Invalid QuadKey digit sequence.");
            }
        }
        return new int[]{tileX, tileY, levelOfDetail};
    }
}

3、使用例子

  • 根据XYZ计算经纬度范围
//地理坐标(EPSG:4326)下计算方式
double[] bbox = new GlobalGeodetic("", 256).tileLatLonBounds(x, y, z);
 //投影坐标(EPSG:3857)下的计算方式
double[] bboxs = new GlobalMercator(256).tileLatLonBounds(x, y, z);
  • 根据经纬度范围计算XYZ
//地理坐标(EPSG:4326)下计算方式
……待补充

//投影坐标(EPSG:3857)下的计算方式
Envelope envelope = new Envelope(xmin, xmax, ymin, ymax);
GlobalMercator mercator = new GlobalMercator(256);
double[] min = mercator.latLonToMeters(envelope.getMinY(), envelope.getMinX());
double[] max = mercator.latLonToMeters(envelope.getMaxY(), envelope.getMaxX());

//#region 计算
for (int tz = tmaxz; tz > tminz - 1; tz--) {
    int[] tminxy = mercator.metersToTile(min[0], min[1], tz);
    int[] tmaxxy = mercator.metersToTile(max[0], max[1], tz);
    tminxy = new int[]{Math.max(0, tminxy[0]), Math.max(0, tminxy[1])};
    tmaxxy = new int[]{(int) Math.min(Math.pow(2, tz) - 1, tmaxxy[0]), (int) Math.min(Math.pow(2, tz) - 1, tmaxxy[1])};
    for (int tx = tminxy[0]; tx < tmaxxy[0] + 1; tx++) {
         for (int ty = tmaxxy[1]; ty > tminxy[1] - 1; ty--) {
   				//z,x,y坐标
   		}
    }
}
//endregion

本文地址:https://blog.csdn.net/polixiaohai/article/details/85986173

相关标签: GIS