基于SpatialHadoop库实现ArcGIS方案下的地图切片及加载

1、ArcGIS切片原理介绍

    具体的切片原理可以参考这个ArcGIS 地图切图系列之(一)切片原理解析,本文也是研究了这篇文章,进一步学习总结,从而有了这个文的。
    总的来讲ArcGIS基于以下图完成切图实现:

在这里插入图片描述
    如果不对世界坐标系进行平移的话就会造成不同范围下,同一个坐标系下的给定坐标范围所在的切片的row,col序号不一致,因此不同的切片不能进行叠加。为了能在地理坐标系(WGS84),投影坐标系(WKID:3857)下切片能完美叠加。分别对坐标系进行了平移处理,将原点固定在了:

    地理坐标系(WGS84):(-400,400)
    投影坐标系(WKID:3857):(-20037508.342787001,20037508.342787001)

2、ArcGIS切片的思路

1. 确定数据范围或者查询范围

    数据整体范围为envelop = [(x1,y1),(x2,y2)],测试下面遍历shape的时候需要全部遍历,如果输入的只是查询范围,则需要根据该范围进行查询,得到切片绘制的矢量数据。

2. 计算当前级别下的切片数量(精度比例尺给定的情况下不参与计算)

t i l e C o u n t = 1 < < l e v e l = 2 l e v e l tileCount= 1<<level = 2^{level} tileCount=1<<level=2level

3. 计算当前图形的像素范围

    思路推导过程是在屏幕坐标系下进行的,屏幕坐标系跟世界坐标系直接除了有缩放比例尺外还有,他们的Y轴不一样。
    当前图形的地理范围,我们可以通过计算他的MBR得到,这里假设为[xMin,yMin,xMax,yMax]。
在这里插入图片描述
    计算像素坐标既计算屏幕坐标系中的【x1,y1,x2,y2】。
x 1 s c r e e n = Δ x / r e s o l u t i o n = ( x 1 r e c t g l e − O r i g i n X ) / r e s o l u t i o n x1_{screen}= Δx/resolution=(x1_{rectgle}-OriginX)/resolution x1screen=Δx/resolution=(x1rectgleOriginX)/resolution

    这里的Δx跟图上标出来的不一样,这里的需要从平移后的坐标原点计算。其他坐标类似,可以计算

这里需要注意,resolution是是跟屏幕的DPI有关的,具体ArcGIS中规定的地理坐标系和投影坐标系下精度和比例尺的关系参考类TileParam

5. 根据坐标范围计算切片序号及宽度、高度

x 1 t i l e = x 1 s c r e e n / 256 x1_{tile}= x1_{screen}/256 x1tile=x1screen/256
    至此可以计算出一个图形的行、列的开始序号,已经宽度、高度(也就是总共占有多少个切片)。

6. 根据当前图形的范围计算所在切片序号及范围创建画布、计算该切片对应的地理范围

    首先根据计算得到一个切片对应的地理范围大小如下:
t i l e g e o m = r e s o l u t i o n ∗ 256 tile_{geom}= resolution*256 tilegeom=resolution256
然后计算当前切片下的地理坐标范围:
x 1 t i l e M b r = O r i g i n X + t i l e g e o m ∗ T i l e N u m b e r x x1_{tileMbr}=OriginX+ tile_{geom}*TileNumber_x x1tileMbr=OriginX+tilegeomTileNumberx

x 2 t i l e M b r = O r i g i n X + t i l e g e o m ∗ ( T i l e N u m b e r x + 1 ) x2_{tileMbr}=OriginX+ tile_{geom}*(TileNumber_x+1) x2tileMbr=OriginX+tilegeom(TileNumberx+1)
同理可以得到y的情况,是是这里处理y的时候涉及到y轴反转的问题,在坐标系变换中,镜像变换,其实就是目标系得 y t a r g e t = y m a x − y y_{target}=y_{max}-y ytarget=ymaxy,于是有:
y 1 t i l e M b r = O r i g i n Y − t i l e g e o m ∗ T i l e N u m b e r y y1_{tileMbr}=OriginY- tile_{geom}*TileNumber_y y1tileMbr=OriginYtilegeomTileNumbery

y 2 t i l e M b r = O r i g i n Y − t i l e g e o m ∗ ( T i l e N u m b e r y + 1 ) y2_{tileMbr}=OriginY- tile_{geom}*(TileNumber_y+1) y2tileMbr=OriginYtilegeom(TileNumbery+1)

3、屏幕坐标处理

1. 地理坐标到屏幕坐标的计算

上面得到了一个切片得地理坐标范围,由此可以直接得到地理坐标到屏幕坐标的缩放因子。

s c a l e x = ( x 2 t i l e M b r − x 1 t i l e M b r ) / 256 scale_x=(x2_{tileMbr}-x1_{tileMbr})/256 scalex=(x2tileMbrx1tileMbr)/256
s c a l e y = ( y 2 t i l e M b r − y 1 t i l e M b r ) / 256 scale_y=(y2_{tileMbr}-y1_{tileMbr})/256 scaley=(y2tileMbry1tileMbr)/256

x s c r e e n = x g e o m ∗ s c a l e x x_{screen}=x_{geom}*scale_x xscreen=xgeomscalex y s c r e e n = y g e o m ∗ s c a l e y y_{screen}=y_{geom}*scale_y yscreen=ygeomscaley

2. 画图的处理

画布处理的原因有两个
1、计算出来的屏幕坐标是基于整个屏幕坐标系的,需要转换到对应切片的屏幕坐标系。

    这里通过对graphic的坐标原点进行平移得到,我们使用graphics.translate方法。设置画布绘制的起点为
[ ( i n t ) ( − t i l e M b r . x 1 ∗ s c a l e x ) , ( i n t ) ( − t i l e M b r . y 1 ∗ s c a l e y ) ] [(int)(-tileMbr.x1 * scale_x), (int)(-tileMbr.y1 * scale_y)] [(int)(tileMbr.x1scalex),(int)(tileMbr.y1scaley)]既,将绘图的原点设置为切片的左上角位置。这为什么是负值,没有搞明白,有清楚的朋友可以留言告诉我
2、需要处理由于Y轴反转都带来的差异。
    经过上面的步骤得到的图片Y坐标还没有进行反转,因为我们只处理了切片的地理范围的反转,对于图形的坐标没有进行处理。通过以下步骤实现image的y轴反转。

	BufferedImage img;
	//进行一步y轴反转变换
	AffineTransform tx = AffineTransform.getScaleInstance(1.0D, -1.0D);
	//反转结束后,需要对坐标原点进行平移操作。
	tx.translate(0.0D, (double)(-img.getHeight()));
	AffineTransformOp op = new AffineTransformOp(tx, 1);
	img = op.filter(img, (BufferedImage)null);

    完成以上步骤之后,我们应该能切出想要的切片:
在这里插入图片描述
接下来就可以使用jsapi加载。

2、切片的加载(arcgis js api)

参见程序:基于SpatialHadoop库的arcgis切片实现

    最终效果如下:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/polixiaohai/article/details/107674948
今日推荐