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=(x1rectgle−OriginX)/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=resolution∗256
然后计算当前切片下的地理坐标范围:
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+tilegeom∗TileNumberx
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=ymax−y,于是有:
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=OriginY−tilegeom∗TileNumbery
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=OriginY−tilegeom∗(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=(x2tileMbr−x1tileMbr)/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=(y2tileMbr−y1tileMbr)/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=xgeom∗scalex 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=ygeom∗scaley
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.x1∗scalex),(int)(−tileMbr.y1∗scaley)]既,将绘图的原点设置为切片的左上角位置。这为什么是负值,没有搞明白,有清楚的朋友可以留言告诉我。
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切片实现。
最终效果如下: