前段时间在一个专业交流群里看到这样的一个需求:有两个图层,一个线图层,一个点图层,比例尺小的时候看起来点是在线上的(相交),可是放大到一定程度的时候,点跟线是不相交的(如图1,2),现在要做的就是要把不在线上的点移动在线上。按照一般的思路就是在桌面版软件,进行要素编辑,放大到一定程度,然后一个一个点的移动在线上。但是数据量很大,几万个点,范围很大,工作量很大,这个方法明显是很不明智的。那时我在想,如果上头给我这样的一个任务,我怎么办??
图1
图2
群里也给出了很多解决方案,ARCMap里的近邻分析工具,FME数据处理,CASS插件…………最好的方法还是是用编程来解决!
这里我说说用Arcpy的解决方案:在python里分别获得者两个图层(shape文件),通过近邻分析,获得点到线上的最近的距离以及对应的线上的点的x,y坐标,并写入到点的属性表中,然后通过游标获得最近点的坐标并根据该坐标构建一个新的点,最后把对应不相交点的属性赋值给新点。
因为我电脑安装的Arcgis版本为10.0,所以只能用近邻分析工具,该工具的Arcpy的语法如下图3;如果是往后的版本会提供一个几何对象的queryPointAndDistance(in_point,{as_percentage})方法,功能与近邻分析工具差不多。建议要学Arcpy的尽量用10.1以后的版本。
图3
过程如下:先进行 近邻分析
#coding=utf-8
import arcpy
infc=r"D:\Arcpy2\Export_Output.shp" #点数据
line=r"D:\Arcpy2\Export_Output_2.shp" #线数据
#进行近邻分析
arcpy.Near_analysis(infc,line,"","true")
运行这段代码后,我们可以看到点图层的属性表中增加了三列NEAR_DIST,NEAR_X,NEAR_Y,分别表示点到线上的最短距离、线上点的X坐标、线上点的Y坐标如图4,NEAR_DIST=0表示点线已经相交。
图4
接下来通过查询游标SearchCursor遍历属性表获得线上点的X,Y坐标,利用该坐标构造新的点几何;InsertCursor游标插入新的行。
rows=arcpy.SearchCursor(infc) #点的查询游标
for row in rows:
if row.NEAR_DIST>0: #距离大于零,表示不相交
cur=arcpy.InsertCursor(infc) #插入游标
new_row = cur.newRow() #创建一个空的新行
#创建一个新的点几何
newpnt=arcpy.Point()
newpnt.X=row.NEAR_X #把线上对应点的信息赋值给新点
newpnt.Y=row.NEAR_Y
pointGeometry=arcpy.PointGeometry(newpnt)
new_row.shape = pointGeometry
#把不相交点的属性赋值给对应的新点
new_row.NEAR_DIST=row.NEAR_DIST
new_row.NEAR_X=row.NEAR_X
new_row.NEAR_Y = row.NEAR_Y
new_row.ID=row.ID
cur.insertRow(new_row) # 插入新点
#rows.deleteRow(row) #删除不相交的点
运行后的结果如图5,图6所示,图5选中部分(蓝色)就是新插入的点。可以看到新点的属性与对应的旧点的属性是一致的(FID除外),如果要把不相交的点删除,最后加上代码:rows.deleteRow(row)即可。(删除前要备份好源数据)
图5
图6
完整代码如下:
#coding=utf-8
import arcpy
infc=r"D:\Arcpy2\Export_Output.shp" #点数据
line=r"D:\Arcpy2\Export_Output_2.shp" #线数据
#进行近邻分析
arcpy.Near_analysis(infc,line,"","true")
rows=arcpy.SearchCursor(infc) #查询游标
for row in rows:
if row.NEAR_DIST>0: #距离大于零,表示不相交
cur=arcpy.InsertCursor(infc) #插入游标
new_row = cur.newRow() #创建一个空的新行
#创建一个新的点几何
newpnt=arcpy.Point()
newpnt.X=row.NEAR_X #把线上对应点的坐标赋值给新点
newpnt.Y=row.NEAR_Y
pointGeometry=arcpy.PointGeometry(newpnt)
new_row.shape = pointGeometry
#把不相交点的属性赋值给新点
new_row.NEAR_DIST=row.NEAR_DIST
new_row.NEAR_X=row.NEAR_X
new_row.NEAR_Y = row.NEAR_Y
new_row.ID=row.ID
cur.insertRow(new_row) # 插入新点
#rows.deleteRow(row) #删除不相交的点
总结:
上面的代码只是我的一个简单的实验,不到20行的代码就可以为我们解决繁重的工作,可见编程对于我们的生活是多么重要;始终都认为,不管什么行业,编程的思维,能力都能够带给我们的生活,工作带来便利。如果这要应用于实际项目的话还有很多地方需要完善;例如数据方面也是方便自己实验而设计的,所以这里只是提供一个解决问题思路而已,这个重新生成点,然后把新点的属性赋值给新点的思路其实跟移动点到线上的需求的效果是一样的。至于怎么移动还没琢磨出来,如果你有更好的解决方案,欢迎一起讨论。
反思:
其实大三时就有接触Arcpy了,可是为什么在学校时就没有好好学?那么久了还没什么进步,这也是自己一直反思的地方,经过反复的思考,可能是因为自己没有深刻了解到某个东西的作用,所以就没有动力去学,去坚持吧!一句话,没有需求就没有动力!所以建议在学校的同学,多点去了解自己的专业的工作都在干什么,看清差距,挖掘需求。这个实验也是刚好在群里看到他们的需求,然后一直想如果是我,我该怎么去便捷的完成,有了一个方向后,就认真去琢磨琢磨后还是弄出来了,过程尽管有点慢,可是还是学到东西了。
最近专栏的关注人数攀升了好多,有点“惊吓”,感觉自己就是一个菜鸟在各位大神面前班门弄斧。不管怎样,谢谢大家的关注,其实这也满足了我小小的虚荣心。起初还担心那么多人关注,接下来我该怎么办?菜鸟一个,误导了别人怎么办?后来想想,自己真的是多虑了,也太高估了自己能力了,哪有那么容易误导别人呢?另外,在这里写文章的一个好处就是可以尽早地把自己存在的问题抛出来,说不定哪路大神路过好心指导一下,那么我就可以把这个问题解决了。这也是我当时决定在知乎写东西的初衷吧。
最近实习的工作量开始加大了,有点吃力了,加上跟python没什么关系,一心很难二用,菜鸟表示很受伤;而且我暂时还没什么需求,所以接下来没什么时间更新专栏了,还是好好先搞好实习,掌握一样东西再去学另一样东西或许对于我来说会好的,貌似Arcgis engine里面的方法对象原理跟Arcpy差不多。
专栏文章会同步到微信公众号【GIS学习交流】
欢迎大家关注公众号一起交流,一起学习,一起进步!