当前位置: 移动技术网 > IT编程>开发语言>Java > 地理坐标(WGS84),投影坐标下(Mercator)切片系统的计算Java类

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

2020年07月10日  | 移动技术网IT编程  | 我要评论

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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网