什么是泰森多边形
由于制作镶嵌六边的最后一步是创建泰森多边形,所以这里简单介绍一下什么是泰森多边形。
泰森多边形多是用点图生成的。
泰森多边形有以下几个性质:
每个泰森多边形内仅包含一个控制点。
且泰森多边形内的点与相应多边形内的控制点的距离最近。
边上的任一点到两边的控制点的距离一样。
所以使用距离位置合适的点生成的泰森多边形,就能生成蜂窝六边形。
Python 实现
在《最完美的蜂窝六边形的实现方法-gpk实现》中,介绍使用打包好的 .gpk 工具实现制作蜂窝六边形要素类。
在该章节中,我们将完全使用 Python 来实现这一功能。
实现原理:
首先获取输入的矢量数据的坐标位置等信息 info1;
使用坐标位置信息 info1 计算出合适的偏移坐标位置信息 info2;
使用 info1 和 info2 各自生成渔网,包括其中的点;
合并点,生成泰森多边形;
按位置选择,导出结果。
直接上代码(HexagonCreator.py)及其注释说明:
-- coding:utf-8 --
---------------------------------------------------------------------------
Author: LiaoChenchen
Created on: 2021/4/18 18:00
Reference:
“”"
Description:
Usage:
“”"
---------------------------------------------------------------------------
from future import absolute_import
from future import unicode_literals
import os
import arcpy
import math
class HexPolygon(object):
def __init__(self, in_f, out_f, width=100):
"""
创建镶嵌六边形
:param in_f: 输入要素
:param out_f: 输出要素
:param width: 六边形的宽,注意不是边长
"""
self.in_f = in_f
self.out_f = out_f
self.width = float(width)
descinput = arcpy.Describe(self.in_f)
self.ref = arcpy.Describe(self.in_f).spatialReference
#___Function___
result = self.cal_extent()
self.create_flow(*result)
def cal_extent(self):
"""
计算出两幅渔网的坐标信息
:return: 返回两幅渔网矢量的信息
"""
desc = arcpy.Describe(self.in_f)
ext = desc.extent
x_min = ext.XMin
x_max = ext.XMax
y_min = ext.YMin
y_max = ext.YMax
# calculate offset value
self.height = self.width * math.sqrt(3)
self.width, self.height = self.height, self.width
# Calculate new offset origin, opposite corner and
# Y axis point coordinates
factor1 = -2.0 #▶注释1◀
origin_x = x_min + self.width * factor1
origin_y = y_min + self.height * factor1
origin = str(origin_x) + " " + str(origin_y)
# The opposite corner of the fishnet set
factor2 = 2.0
corner_coordx = x_max + self.width * factor2
corner_coordy = y_max + self.height * factor2
corner_coord=str(corner_coordx) + " " +str(corner_coordy)
# 新原点
factor3 = 0.5
new_origin_x = str(origin_x + self.width * factor3)
new_origin_y = str(origin_y + self.height * factor3)
new_origin = new_origin_x + " " + new_origin_y
# new opposite corner
corner_coordx2 = str(corner_coordx + self.width * factor3)
corner_coordy2 = str(corner_coordy + self.height * factor3)
corner_coord2 = corner_coordx2 + " " + corner_coordy2
# note: 使用的是 str
y_coord1 = str(origin_x) + " " + str(corner_coordy)
y_coord2 = new_origin_x + " " + corner_coordy2
# Calculate Length, hexagonal area and number of columns
hexg_len = float(self.height) / math.sqrt(3)
# 等边六边形面积计算公式:根号3 * 3 / 2 * 边长 * 边长
hexg_area = math.sqrt(3)*3/2*pow(hexg_len, 2)
arcpy.AddMessage("One Hexagon Cell Area: " + str(hexg_area))
vector1 = (origin, y_coord1, corner_coord)
vector2 = (new_origin, y_coord2, corner_coord2)
return vector1, vector2
def create_flow(self, vector1, vector2):
"""
开始创建六边形
:param vector1: 用于创建渔网的坐标数据
:param vector2: 另一个用于创建渔网的坐标数据
:return:
"""
workspace = os.path.dirname(self.out_f)
arcpy.env.scratchWorkspace = workspace
# arcpy.env.overwriteOutput = True
#------ first fishnet ------
# fishnet1_point -> fishnet1_p point
# fishnet1_result -> fishnet1_res
# fishnet1_label -> fishnet1_lb
CF = arcpy.CreateFishnet_management
fishnet1_path = (os.path.join(workspace, "Fishnet1"))
fishnet1 = CF(fishnet1_path, vector1[0], vector1[1],
self.width, self.height, "0", "0",
vector1[2],"LABELS")
#------ second fishnet ------
fishnet2_path = (os.path.join(workspace, "Fishnet2"))
fishnet2 = CF(fishnet2_path, vector2[0], vector2[1],
self.width, self.height, "0", "0",
vector2[2], "LABELS")
# label point
fishnet1_lb = fishnet1.getOutput(1)
fishnet2_lb = fishnet2.getOutput(1)
arcpy.DefineProjection_management(fishnet1_lb, self.ref)
arcpy.DefineProjection_management(fishnet2_lb, self.ref)
# 将新旧标注点(label)合并
#▶注释2◀
full_pt = arcpy.Append_management(fishnet2_lb, fishnet1_lb)
# Create Thiessen Polygons
#▶注释3◀
full_theissen = arcpy.CreateThiessenPolygons_analysis(
full_pt,(os.path.join(workspace, "FullTheissen")))
# 1.将完整的泰森多边形创建为要素图层
# 2.按位置选择出和输入目标图层相交的部分
# 3.导出要素图层
f_lyr = "_lyr"
arcpy.MakeFeatureLayer_management(full_theissen,f_lyr)
arcpy.SelectLayerByLocation_management(
f_lyr,"INTERSECT", self.in_f)
#▶注释4◀
arcpy.CopyFeatures_management(f_lyr, self.out_f)
# Delete intermediate data
arcpy.Delete_management(fishnet1)
arcpy.Delete_management(fishnet2)
arcpy.Delete_management(fishnet1_lb)
arcpy.Delete_management(fishnet2_lb)
arcpy.Delete_management(full_theissen)
arcpy.Delete_management(f_lyr)
arcpy.AddMessage("Completed hexagonal polygons.")
整个工具封装成了一个类。
类中共有三个方法包括初始化方法。
cal_extent 方法:
主要是计算出两套渔网坐标。
每一套坐标包含一个起始原点、y轴坐标、渔网的对角坐标。
渔网坐标是用于生成渔网的,参数详情可以看:
创建渔网-帮助 | ArcGIS for Desktop
desktop.arcgis.com/zh-cn/arcmap/10.3/tools/data-management-toolbox/create-fishnet.htm
▶注释1◀:
各个偏移参数,我从网上偷来的。
create_flow 方法:
后续的创建渔网、泰森多边形生成镶嵌六边形的过程。
▶注释2◀:
arcpy.Append_management 和 arcpy.Merge_management 方法类似,都是合并。两者的主要差异是前者是在自己的基础上追加合并。不会生成新的要素类;
而后者是生成一个新的合并图层。
▶注释3◀:
调用 ArcPy 中的泰森多边形创建工具。注意事项:泰森多边形的输出位置必须使用地址全称。包括官网示例都是使用的完整地址。
在脚本模式下,如果输出地址仅仅只是一个名词的话,哪怕你设置了默认工作空间,也会报错。
所以我在这里使用 os.path.join(workspace, “FullTheissen”) 来设置完整地址。
▶注释4◀:
在脚本模式下,使用 arcpy.CopyFeatures_management 进行要素类的保存时,必须提前设置默认工作空间,否则无法保存。
工具箱封装
ArcGIS 自身提供多种工具箱的封装方式。
封装接口
写好的代码需要按照 ArcGIS 的封装规范加入对应的参数(接口)代码。
…
if name == ‘main’:
# toolbox
arcpy.env.overwriteOutput = True
argv = tuple(arcpy.GetParameterAsText(i)
for i in range(arcpy.GetArgumentCount()))
HexPolygon(*argv)
该代码紧接上面的主要代码
arcpy.GetParameterAsText(i) 方法用于参数传递。
创建好自定义工具箱、导入脚本、设置输入输出参数接口。然后运行。
封装完成的成果长这样:
点击打开
然后就可以输入参数,运行,成功、关闭。
添加自定义工具箱
Note: 后文我会放出自制工具箱的下载方式,如果以后有其他的脚本工具放出的话,也会封装进这一个工具箱。
右键点击 ArcToolBox ,点击添加工具箱。
在打开的添加工具箱对话框中,选择自制工具箱即可添加到 ArcGIS 右侧的工具栏中。