geotrellis使用(十)缓冲区分析以及多种类型要素栅格化
目录
目录
一、前言
上两篇文章介绍了如何使用Geotrellis
进行矢量数据栅格化以及栅格渲染,本文主要介绍栅格化过程中常用到的缓冲区分析以及同一范围内的多种类型要素栅格化。
本文主要记录今天过程中碰到的两个问题,第一个问题就是线状要素在进行栅格化的时候只有单个像素,看不出应有的效果;第二个问题就是同一地区的数据既包含面状要素,又包含了线状要素,普通方式只能栅格化成两套数据。下面我为大家介绍解决这两个问题的方法(当然若有人有更好的方法,欢迎交流)。
二、缓冲区分析
缓冲区分析在百度百科中的定义为:
缓冲区分析是指以点、线、面实体为基础,自动建立其周围一定宽度范围内的缓冲区多边形图层,然后建立该图层与目标图层的叠加,进行分析而得到所需结果。它是用来解决邻近度问题的空间分析工具之一。邻近度描述了地理空间中两个地物距离相近的程度。
当然本文并不是教大家如何解决邻近度问题,只是简单的说明如何能够在栅格化的过程中将线状要素能够多外扩几个像素。
自己实现外扩像素
由于本人非地理信息专业出身(甚至非计算机专业出身,没办法,置身码农把青春卖!)所以在遇到问题的时候并不懂什么缓冲区分析
的高大上的词汇。首先想到的是我可以在矢量化的过程中外扩几个像素,这样不就实现了增强的效果,但是有个问题就是我如何知道线段的方向,先将就着来,我把线段点上下左右的像素全部赋予与改点相同的值,这样可以不用考虑方向,并且应该能达到效果。
说干就干,再一次认真研读Geotrellis
的Reasterizer.scala
的源代码,冥思苦想一阵之后,想到了方法,主要是要重写赋值的方法,实现代码如下:
def rasterize(geom: Geometry, rasterExtent: RasterExtent, value: Int) ={
val cols = rasterExtent.cols
val array = Array.ofDim[Int](rasterExtent.cols * rasterExtent.rows).fill(NODATA)
val f = (col: Int, row: Int) => {
array(row * cols + col) = value
if (col > 0)
array(row * cols + col - 1) = value
if (col < cols - 1)
array(row * cols + col + 1) = value
if (row > 0)
array((row - 1) * cols + col) = value
if (row < rasterExtent.rows - 1)
array((row + 1) * cols + col) = value
}
Rasterizer.foreachCellByGeometry(geom, rasterExtent)(f)
ArrayTile(array, rasterExtent.cols, rasterExtent.rows)
}
简单说来就是之前f
函数中只有array(row * cols + col) = value
一条语句,即实现当前点的像素点赋值,那么加上了判断不是边界之后,给上下左右的像素点都赋值即可实现,运行起来。
得到的结果虽然看起来有点丑,但是总算解决了这个问题,然后把结果拿给老板看,老板什么话也没说,默默的甩给我https://gitter.im/geotrellis/geotrellis/archives/2016/02/22
这么一个网址。好吧,老板果然是老板,这里也要介绍一下https://gitter.im/geotrellis/geotrellis/
,这是Github
中的Geotrellis
项目交流群,在里面咨询问题,会有懂的人甚至作者解答,有点考验英语基础。
使用buffer
函数
在那个网页中,上来就有这么一段代码:
val points = Seq(
Point(re.gridToMap(100,100)).buffer(30),
Point(re.gridToMap(200,200)).buffer(30),
Point(re.gridToMap(300,300)).buffer(30),
Point(re.gridToMap(400,400)).buffer(30),
Point(re.gridToMap(500,500)).buffer(30)
)
根据这段代码尤其是buffer
名称,可以知道其实在Geotrellis
中缓冲区分析就是使对象调用buffer
函数即可,参数表示缓冲的距离。赶紧拿来试验,非常成功,但是这里面却有几个需要注意的问题。
- 缓冲距离
此处的缓冲距离经过实际测试发现与当前数据的坐标系相一致,即如果是WGS84地理坐标系,那么此处缓冲距离就是以经纬度为单位,大地坐标系此处就是以米为单位。
- 缓冲类型
一般情况下只需要给点、线要素使用缓冲即可,这里就可以使用模式匹配,如下:
val geom = WKT.read(pro.getValue.toString) match {
case geom: Point => geom.buffer(bufferDistance)
case geom: Line => geom.buffer(bufferDistance)
case geom: MultiLine => geom.buffer(bufferDistance).toGeometry().get
case geom => geom
}
这里就仅为Point
、Line
以及MultiLine
类型进行了缓冲区设置,其他需要转换的可以用同样的方式进行匹配,展示一下最终的效果。
其实查看buffer
函数的定义,不难发现该函数实现的就是将要点线要素转换成了面要素。
以上就实现了缓冲区分析,下面进行下一个主题多种类型要素栅格化。
三、多种类型要素栅格化
同一个区域数据即包含面状要素又包含线状要素,显然在shape文件中以及数据库中我们都没有办法将其进行合并,而如果我们又不想得到两套栅格化的数据该如何是好呢?
其实方法也很简单,只需要将要素拼接到同一个GeometryCollection
中然后统一获取其RasterExtent
即可,实现代码如下:
val features = mutable.ListBuffer[Geometry]()
for (path <- paths) {
val file = new File(path)
if(file.exists()) {
val shpDataStore = new ShapefileDataStore(new File(path).toURI().toURL())
shpDataStore.setCharset(Charset.forName(charset))
val featureSource = shpDataStore.getFeatureSource()
val itertor = featureSource.getFeatures().features()
while (itertor.hasNext()) {
val feature = itertor.next()
val p = feature.getProperties()
val it = p.iterator()
while (it.hasNext()) {
val pro = it.next()
if (pro.getName.getLocalPart.equals("the_geom")) {//get all geom from shp
val geom = WKT.read(pro.getValue.toString) match {
case geom: Point => geom.buffer(resolution * bufferDistance)
case geom: Line => geom.buffer(resolution * bufferDistance)
case geom: MultiLine => geom.buffer(resolution * bufferDistance).toGeometry().get //0.0054932 * 7
case geom => geom
}
features += geom
}
}
}
itertor.close()
shpDataStore.dispose()
} else
println(s"the file ${path} isn't exist")
}
以上代码实现的是逐个循环需要栅格化的文件,然后将每个geometry
对象添加到features
中,剩下的在前面的文章中已经介绍过,不再赘述。
四、总结
以上讲述了如何进行缓冲区分析以及多种类型要素栅格化。虽然实现方法比较较难,但是在刚碰到这些问题的时候确实会让人摸不着头脑,本文简单记录之,仅为整理思路以及方便以后使用,如果能够帮助到一些苦苦探索的人当然是更好的。最后感谢在工作过程中给予了重大帮助和指导的吴老板!
五、参考链接
转载自:http://www.cnblogs.com/shoufengwei/p/5605399.html