首先,可以参考arcpy学习视频。
https://edu.csdn.net/course/detail/25535
一、问题与解决方法
这个方法的灵感来自昨天昨天,下面来说一下实现功能。
一直以来都有对图斑(polygon)多边形四至坐标提取的需求,其实是这样的,之前在群里看到了林业部门的一个小伙伴有这样的需求,就是提取图斑(polygon)多边形最四至坐标,即一个多边形的最北点、最东点、最西点、最南点。一直以来,我也想着解决这个问题,都没有想到解决的办法,因为在多边形(polygon)中,arcgis的api接口提供的是范围(包络线),而今天我们正是利用这个范围的两个角点坐标,再由arcgis的api接口将多边形各个节点坐标提取出来,然后将坐标点一一与两个坐标的最大的X坐标XMax、最大的Y坐标YMax、最小的X坐标XMin、最小的Y坐标YMin相比较,如果多边形的节点坐标中某点的X值与XMax相等,则认为该点为最东点,如果某点的X值与XMin相等,则认为是最西点,而如果某点的Y值与YMax相等,则认为是最北点,再如果某点的Y值与YMin相等,则认为是最南点,至此整个算法就结束,相对来说是比较简单的。
当然也可以使用其他的解决办法,这里就没有去研究。
二、编写代码实现
这里使用的是arcpy,即使用的是python在arcgis中的接口进行开发。开发的编辑器使用的pycharm2018.2社区版,不得不说这个编辑器还是挺好用的,毕竟开发安卓的android studio以及java开发中比较常用的编辑器使用的是idea,这些编辑器都是出自一家公司之手。关于如何在pycharm中如果arcpy站点包的解决办法,已经在之前的博客中已经提到了,大家可以参考之前的博客即可。
在编写代码的时候,这里使用到python的类,具体的实现代码如下图所示。
# coding:utf-8
import arcpy
testData=ur"D:\Data\testPolygon.shp"
class SZInfo:
Part=[]
XMin=0
YMin=0
XMax=0
YMax=0
ID="0"
class Point:
X=0
Y=0
class SZResInfo:
ID=""
flag=""
point=Point()
SZDataset = []
for row in arcpy.da.SearchCursor(testData, ["FID", "SHAPE@"]):
print("Here comes feature {0}:".format(row[0]))
tmpSZInfo=SZInfo()
ID=row[0]
mask = row[1]
tmpSZInfo.XMin= mask.extent.XMin
tmpSZInfo.YMin= mask.extent.YMin
tmpSZInfo.XMax= mask.extent.XMax
tmpSZInfo.YMax= mask.extent.YMax
tmpSZInfo.ID=str(ID)
partnum = 0
for part in row[1]:
print("Part {0}:".format(partnum))
tempPart = []
for pnt in part:
if pnt:
point=Point()
point.X=pnt.X
point.Y=pnt.Y
tmpSZInfo.Part.append(point)
else:
print("Interior Ring:")
#SZDataset.append(tempPart)
partnum += 1
SZDataset.append(tmpSZInfo)
szResDataset=[]
for szInfo in SZDataset:
tmpRes=[]
for point in szInfo.Part:
if point.X==szInfo.XMin:#西至
tmpSZResInfo=SZResInfo()
tmpPoint=Point()
tmpPoint.X=point.X
tmpPoint.Y=point.Y
tmpSZResInfo.flag="XiZhi"
tmpSZResInfo.ID=szInfo.ID
tmpSZResInfo.point=tmpPoint
tmpRes.append(tmpSZResInfo)
elif point.X==szInfo.XMax:#东至
tmpSZResInfo = SZResInfo()
tmpPoint = Point()
tmpPoint.X = point.X
tmpPoint.Y = point.Y
tmpSZResInfo.flag = "DongZhi"
tmpSZResInfo.ID = szInfo.ID
tmpSZResInfo.point = tmpPoint
tmpRes.append(tmpSZResInfo)
elif point.Y==szInfo.YMax:#北至
tmpSZResInfo = SZResInfo()
tmpPoint = Point()
tmpPoint.X = point.X
tmpPoint.Y = point.Y
tmpSZResInfo.flag = "BeiZhi"
tmpSZResInfo.ID = szInfo.ID
tmpSZResInfo.point = tmpPoint
tmpRes.append(tmpSZResInfo)
elif point.Y==szInfo.YMin:#南至
tmpSZResInfo = SZResInfo()
tmpPoint = Point()
tmpPoint.X = point.X
tmpPoint.Y = point.Y
tmpSZResInfo.flag = "NanZhi"
tmpSZResInfo.ID = szInfo.ID
tmpSZResInfo.point = tmpPoint
tmpRes.append(tmpSZResInfo)
szResDataset.append(tmpRes)
for res in szResDataset:
for item in res:
if item.flag=="XiZhi":
print ("ID为" + str(item.ID) +"西至坐标X为:"+str(item.point.X)+"Y为:"+str(item.point.Y))
elif item.flag=="DongZhi":
print("ID为" + str(item.ID) +"东至坐标X为:" + str(item.point.X) + "Y为:" + str(item.point.Y))
elif item.flag=="BeiZhi":
print("ID为" + str(item.ID) +"北至坐标X为:" + str(item.point.X) + "Y为:" + str(item.point.Y))
elif item.flag=="NanZhi":
print("ID为" + str(item.ID) +"南至坐标X为:" + str(item.point.X) + "Y为:" + str(item.point.Y))
print("------------------------------------")
print("------------------------------------")
中间遇到调试代码两个问题。
1.python类的初始化。
Python中类的初始化必须使用括号,即obj=Object(),其中Object为我们创建的类对象,而如果使用的是obj=Object的形式,则认为obj为一个全局变量。这样造成的结果是,最新修改的数据对全局变量的修改,如下图所示,在数组中保存一个全局变量,导致所有的数据都是一样的。
而正确的使用创建类对象方式,那么每次都是新的对象,所获取值都是不一样的,具体如下图所示。
2.类对象成员变量。
Python类对象成员变量,有多种结构。之所以要把这个问题提到日程,是因为遇到如下图的错误。报错的说,str对象没有point属性,一开始我很是纳闷,明明创建的对象有point属性,还有我创建的对象怎么变成str类型去了。
来看一下问题的原因,如下图所示紫色箭头是报错的地方,很显然我创建的对象变成了一个字符,该字符对象赋值了szInfo.ID值,而szInfo.ID为一个str对象,估计是python内部已经将tmpSZResInfo对象转为了str类型了,所以导致下面的那行代码报错了。而只要代码改为红色箭头所示的形式即可。
三、结果分析
编写好代码后,我们使用pycharm启动调试模式,在控制台中查看我们的运行结果。最后打印结果如下图所示。
我们来分析一下结果,以ID为0多边形为例。下图是北至坐标点。显然和上面在pycharm控制台中打印出的结果相一致。
再对比一下其他结果。显然从图面来说,已经正确的提取出图斑(polygon)的四至坐标。
四、后记
这里讲解一般的多边形,而如果出现有空洞的多边形没有考虑在范围之内。还有一个问题,这里是使用范围(包络线)两个角点来比较的,那么会带来一个问题,在一个图形中,很有可能几个点同时落在边界上面,具体如下所示。这样就要求根据工程的需要进行取舍。
至此,整个说明就讲解完了。祝你生活愉快,工作顺利。
更多内容,请关注公众号