超图REST切片系统初探

        前些日子,由于工作需要,要在超图发布的Rest切片上做点事情,不可避免的需要了解一下超图的REST切片系统原理。于是从超图iclient for openlayers里面翻看了一下源码,今天做一个记录。

1、超图切片resFact

        这里需要说明,超图切片的0级是有一个切片组成的,但是0级的切片上只绘制了一半,

也就是0级的时候切片上经纬度分辨率为:

resFact = 180 / 256

由此展开我们就可以依次计算出每一级别下切片的经纬度分辨率为:

Resolution = resFact / Math.pow(2,zoom)

2、切片系统中心点和范围

        源码中地理坐标下的切片系统EPSG:4490被认为和EPSG:4326是一致的,至于为什么可以这么认为,可以参考这篇文章:CGCS2000坐标系和WGS84坐标系的区别联系

因此默认坐标范围取值分别为:

切片系统        范围
EPSG:4326、EPSG:4490[-180,-90,180,90]
EPSG:3857
[-20037508.3427892,-20037508.3427892,20037508.3427892,20037508.3427892]

3、根据范围和级别计算切片行列号

        首先是范围原点(origin)的计算,取左上角的点,也就是 [extent.minx,extent.maxy]

然后分别计算左下角、右上角的切片行列列号,也就是坐标最小值、最大值分别对应的最小、最大切片行列号。

        这里的reverseIntersectionPolicy 参数用来调整小数计算舍入到整数方式。

计算XY坐标相对于原点像素坐标:

xFromOrigin = Math.floor((coordX - origin.x)/resolution + adjustX)

yFromOrigin = Math.floor((coordY - origin.y)/resolution + adjustY)

根据像素坐标计算切片行列号:

tileCoordX = xFromOrigin / tileSize

tileCoordY = yFromOrigin / tileSize

private TileCoord getTileCoordForXYAndZ(Double coordX, Double coordY, Integer z, boolean reverseIntersectionPolicy, TileCoord opt_tileCoord) {
        Coordinate origin = this.getOrigin(z);

        double resolution = this.getResolution(z);
        Integer tileSize = this.getTileSize(z);

        double adjustX = reverseIntersectionPolicy ? 0.5 : 0;
        double adjustY = reverseIntersectionPolicy ? 0 : 0.5;
        double xFromOrigin = Math.floor((coordX - origin.x) / resolution + adjustX);
        double yFromOrigin = Math.floor((coordY - origin.y) / resolution + adjustY);
        double tileCoordX = xFromOrigin / tileSize;
        double tileCoordY = yFromOrigin / tileSize;

        if (reverseIntersectionPolicy) {
            tileCoordX = Math.ceil(tileCoordX) - 1;
            tileCoordY = Math.ceil(tileCoordY) - 1;
        } else {
            tileCoordX = Math.floor(tileCoordX);
            tileCoordY = Math.floor(tileCoordY);
        }

        return new TileCoord(z, (int) tileCoordX, (int) tileCoordY);
    }

这里比较难理解的地方是reverseIntersectionPolicy参数。

        其实是做了像素坐标、切片坐标在小数取整的时候避免取整后范围小于实际范围做的一个调整,具体为

 

 reverseIntersectionPolicy对地理坐标转像素坐标到实际屏幕下的像素坐标的处理:

        当地理坐标取值为最小值的时候,设置reverseIntersectionPolicy为false,使其计算像素坐标的时候x方向上向左平移,即处理的时候偏移量为0,Math.floor计算后得到的像素值位于实际(小数)像素值左侧使得这个切片像素范围完全能包含内容。在计算像素坐标时候y方向上是向上平移,这里看似应该向下平移,但是却做了向上平移操作,其实是因为屏幕坐标系跟地理坐标系X轴方向相同,Y轴方向相反,进行坐标转换的时候是用Y轴上的最大值减去当前值得到变换后的值,因此像素坐标(地理坐标直接计算、未做变换的)y值变大实际变换之后在屏幕坐标系之下值是缩小的,满足屏幕坐标系下y向右偏移,保证了像素范围完全容纳内容。

        同理,当地理坐标取值为最大值的时候,设置reverseIntersectionPolicy为true,此时X方向上偏移0.5使其像素值大于实际计算像素(带小数),起到向上取整的作用。Y方向向不偏移使其像素小于实际计算像素(带小数),再经过Y轴翻转计算,使其结果像素坐标取值大于实际计算结果值。

reverseIntersectionPolicy对切片行列号的处理:

        当地理坐标取值为最小值的时候,设置reverseIntersectionPolicy为false,在屏幕坐标系下像素坐标分别已经向左向上做了偏移,计算到切片行列号的时候整数部分即能包含该像素坐标,行列号无需做偏移处理,直接取整。

        当地理坐标取值为最大值的时候、设置reverseIntersectionPolicy为true,这里在屏幕坐标系下像素坐标已经分别做了向右向下偏移,计算到的切片行列号优先向上取整,再取前一个行列号的切片。

通过以上计算即可得到给定地理范围内的切片行列号的范围。依次遍历行列号即可得到范围内的所有切片XYZ。

4、行列号遍历

这里有一个根据zoom获取当前精度下的比例尺的算法。

scale = 1 / (resolution * dpi * (1 / 0.0254)* meterPerMapUnit)

其中投影坐标下meterPerMapUnit取值为1,地理坐标下有一个通过经纬度的换算关系:

meterPerMapUnit = (Math.PI * 2 * 6378137) / 360

 for (int i = tileRange.getMinX(), x = 0, ii = tileRange.getMaxX(); i <= ii; ++i, x++) {
                for (int j = tileRange.getMinY(), y = 0, jj = tileRange.getMaxY(); j <= jj; ++j, y++) {
                    Integer tmpJ = Math.abs(j) - 1;
                    params.put("x", i);
                    params.put("y", tmpJ);
                    params.put("scale", TileUtil.resolutionToScale(tileGrid.getResolution(zoom), 96, MapUnit.DEGREE));
                    params.put("origin", "{\"x\":" + center.x + ",\"y\":" + center.y + "}");
                    String trueUrl = urlStr + HttpUtil.toParams(params);
                    ByteArrayOutputStream os = new ByteArrayOutputStream();
                    HttpUtil.download(trueUrl, os, false);
                    InputStream in = new ByteArrayInputStream(os.toByteArray());
                    BufferedImage tmpImage = ImageIO.read(in);
                    os.close();
                    graphics2D.drawImage(tmpImage, x * tileSize, meredImg.getHeight() - y * tileSize - 256, tileSize, tileSize, null);
                }
            }

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值