当前位置: 首页 > ds >正文

【ArcGIS技巧】根据地块、界址点图层生成界址线

"农经权二轮延包我已经写的差不多了,需要的一些生成四至、分割地块的功能也分享了替代的插件。前面刚分享完界址点的生成,今天分享界址线的生成,有需要的自取,至此,基本可以用这些功能完成出成果工作。"

1、工具使用

在使用前,先确保有地块(DK.shp)要素图层,且包含字段“DKBM”、“ZJRXM”;界址点(JZD.shp)要素图层(含字段"DKBM", "JZDH")。

插件因为生成界址线比较复杂,而且生成JZX.shp图层包含了:"DKBM"、“QZJDH”、“ZJZDH”、“JZXSM”,特别是“JZXSM”字段比较复杂,所以生成的时间稍微长些,请注意等待。

下载后记得加载py文件,不会的参考:【ArcGIS技巧】分享个判断是否基本农田的工具。

2、脚本逻辑

脚本的生成逻辑大致分为三步:1、先利用地块要素图层生成只要两个点的直线,生成DKBM、PLDWQLR字段;2、根据生成DKBM、PLDWQLR字段合并直线,因为前面界址点生成简化了面,所以要确保每个界址线的起止点都在界址线图层中,再根据界址点去截断界址线;3、根据界址点的JZDH以及界址线的长度与方位等,生成“QZJDH”、“ZJZDH”、“JZXSM”字段内容。

值得注意的是:工具的py文件,在pycharm等解析器中写完后,需要用文本文件编辑器打开,另存文件覆盖原来的.py文件,编码选ANSI格式,只有这样,其中一些中文什么的才会执行时不报错。

3、具体代码

工具的具体代码如下:

# -*- coding: utf-8 -*-
import arcpy
import os
from collections import defaultdict
import tempfile
import math
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
arcpy.env.workspace = u"C:\\data"
arcpy.env.overwriteOutput = True
arcpy.env.qualifiedFieldNames = Falsedk_shp = u"C:\\data\\DK.shp"
jzd_path = u"C:\\data\\JZD.shp"
output_folder = u"C:\\data\\new"# 中间文件路径
temp_folder = tempfile.mkdtemp()
jzx1_path = os.path.join(temp_folder, u"JZX1.shp")
dissolve_path = os.path.join(temp_folder, u"dissolved.shp")
rounded_points = os.path.join(temp_folder, u"rounded_points.shp")def create_jzx():# 验证必须字段存在required_fields = ["DKBM", "ZJRXM"]actual_fields = [f.name for f in arcpy.ListFields(dk_shp)]missing = [f for f in required_fields if f not in actual_fields]if missing:raise arcpy.ExecuteError(u"缺失必要字段:{}".format("/".join(missing)))# ====================== 创建输出要素 ======================sr = arcpy.Describe(dk_shp).spatialReferencearcpy.CreateFeatureclass_management(out_path=temp_folder,out_name=os.path.basename(jzx1_path),geometry_type="POLYLINE",spatial_reference=sr)# 添加字段arcpy.AddField_management(jzx1_path, "DKBM", "TEXT", field_length=100)arcpy.AddField_management(jzx1_path, "PLDWZJR", "TEXT", field_length=255)# ====================== 构建DKBM-ZJRXM映射 ======================dk_zjr_map = {}with arcpy.da.SearchCursor(dk_shp, ["DKBM", "ZJRXM"]) as cursor:for row in cursor:dk_zjr_map[row[0]] = row[1]# ====================== 主处理逻辑 ======================line_dict = defaultdict(set)arcpy.AddMessage(u"正在采集边界线段...")# 第一次遍历:收集所有边界线段with arcpy.da.SearchCursor(dk_shp, ["OID@", "SHAPE@", "DKBM"]) as cursor:for row in cursor:geom = row[1]dkbm = row[2]# 分解多边形边界线for part in geom.getPart():for i in range(len(part) - 1):pt1 = part[i]pt2 = part[i + 1]# 标准化线段方向(避免反向重复)if (pt1.X, pt1.Y) > (pt2.X, pt2.Y):pt1, pt2 = pt2, pt1# 生成唯一标识(精确到毫米)line_key = (round(pt1.X, 3), round(pt1.Y, 3),round(pt2.X, 3), round(pt2.Y, 3))line_dict[line_key].add(dkbm)# ====================== 写入结果 ======================arcpy.AddMessage(u"正在生成界址线...")with arcpy.da.InsertCursor(jzx1_path, ["SHAPE@", "DKBM", "PLDWZJR"]) as i_cursor:# 第二次遍历:处理相邻地块逻辑for line_key, dkbms in line_dict.iteritems():pt1 = arcpy.Point(line_key[0], line_key[1])pt2 = arcpy.Point(line_key[2], line_key[3])line = arcpy.Polyline(arcpy.Array([pt1, pt2]), sr)# 处理DKBM字段(按字母排序)sorted_dkbms = sorted(dkbms, key=lambda x: str(x))dkbm_str = "/".join(sorted_dkbms)# 处理PLDWZJR字段if len(sorted_dkbms) == 1:zjrxm = u"无"else:# 取"/"后面所有地块的ZJRXMzjrxm_list = []for dk in sorted_dkbms[1:]:  # 从第二个开始if dk in dk_zjr_map:zjrxm_list.append(dk_zjr_map[dk])zjrxm = "/".join(zjrxm_list) if zjrxm_list else u"无"i_cursor.insertRow([line, dkbm_str, zjrxm])arcpy.AddMessage(u"处理完成!输出路径:{}".format(jzx1_path))create_jzx()try:# ===== 阶段1:合并界址线 =====arcpy.Dissolve_management(in_features=jzx1_path,out_feature_class=dissolve_path,dissolve_field=["DKBM", "PLDWZJR"],multi_part="SINGLE_PART")# ===== 阶段2:创建精确坐标点 =====arcpy.CreateFeatureclass_management(temp_folder,os.path.basename(rounded_points),"POINT",spatial_reference=arcpy.Describe(jzd_path).spatialReference)# 插入舍入坐标点with arcpy.da.SearchCursor(jzd_path, ["SHAPE@XY"]) as sc, \arcpy.da.InsertCursor(rounded_points, ["SHAPE@XY"]) as ic:for row in sc:x, y = row[0]ic.insertRow([(round(x, 3), round(y, 3))])# ===== 阶段3:批量拆分线段 =====# 创建内存图层arcpy.MakeFeatureLayer_management(dissolve_path, "lines_lyr")arcpy.MakeFeatureLayer_management(rounded_points, "points_lyr")# 执行拆分操作split_result = arcpy.management.SplitLineAtPoint(in_features="lines_lyr",point_features="points_lyr",out_feature_class=os.path.join(output_folder, "JZX"),search_radius="0.001 Meters")
finally:# 清理临时数据for item in [dissolve_path, rounded_points]:if arcpy.Exists(item):arcpy.Delete_management(item)def calculate_direction(angle):"""根据方位角计算方向字典"""if 337.5 <= angle or angle < 22.5:return "东"elif 22.5 <= angle < 67.5:return "东南"elif 67.5 <= angle < 112.5:return "南"elif 112.5 <= angle < 157.5:return "西南"elif 157.5 <= angle < 202.5:return "西"elif 202.5 <= angle < 247.5:return "西北"elif 247.5 <= angle < 292.5:return "北"elif 292.5 <= angle < 337.5:return "东北"def get_angle(start_point, end_point):"""计算两点之间的方位角"""dx = end_point.X - start_point.Xdy = end_point.Y - start_point.Yangle = math.degrees(math.atan2(dy, dx))return (angle + 360) % 360# 创建字段
split_lines = os.path.join(output_folder, "JZX.shp")
for field in ["QZJDH", "ZJZDH", "JZXSM"]:if not arcpy.ListFields(split_lines, field):arcpy.AddField_management(split_lines, field, "TEXT", field_length=100)# 构建界址点索引
jzd_dict = defaultdict(dict)
with arcpy.da.SearchCursor(jzd_path, ["DKBM", "JZDH", "SHAPE@"]) as cursor:for row in cursor:key = (row[0], row[1])jzd_dict[key] = row[2].centroid # 获取质心坐标# ========== 处理界址线 ==========
with arcpy.da.UpdateCursor(split_lines, ["DKBM", "PLDWZJR", "SHAPE@", "QZJDH", "ZJZDH", "JZXSM"]) as cursor:for row in cursor:dkbm_line = row[0]pldwzjr = row[1] if row[1] else "无"geometry = row[2]# ===== 步骤1:调整线段方向 =====# 获取首尾点坐标first_point = geometry.firstPointlast_point = geometry.lastPoint# 查找对应的界址点号found_start = Nonefound_end = None# 建立一个DKBM与ZJDH的键值对found_sartdkbm = Nonefound_enddkbm = Nonefor (dkbm_part, jzdh), point in jzd_dict.items():set1 = set(dkbm_line.split("/"))set2 = set(dkbm_part.split("/"))if not set1.isdisjoint(set2):if (abs(point.X - first_point.X) < 0.001 andabs(point.Y - first_point.Y) < 0.001):found_start = jzdhfound_sartdkbm=dkbm_partif (abs(point.X - last_point.X) < 0.001 andabs(point.Y - last_point.Y) < 0.001):found_end = jzdhfound_enddkbm=dkbm_partline_dkbm=dkbm_line.split("/")list_qjzdh=[]list_zjzdh = []for i in line_dkbm:list_jzdh1=found_start.split("/")list_dkbm1=found_sartdkbm.split("/")for j in range(len(list_dkbm1)):if i==list_dkbm1[j]:list_qjzdh.append(int(list_jzdh1[j]))list_jzdh2 = found_end.split("/")list_dkbm2 = found_enddkbm.split("/")for j in range(len(list_dkbm2)):if i == list_dkbm2[j]:list_zjzdh.append(int(list_jzdh2[j]))def reverse_polyline(geom):array = arcpy.Array()part = geom.getPart(0)  # 获取线段的点集合reversed_part = [pnt for pnt in part][::-1]  # 反转坐标点顺序for pnt in reversed_part:array.add(pnt)return arcpy.Polyline(array)  # 重建反转后的线段# 判断是否需要反转if found_start and found_end and sum(list_qjzdh) > sum(list_zjzdh):geometry = reverse_polyline(geometry)# ===== 步骤2:生成起止点号 =====# 生成字段值str_qjzdh=''if len(list_qjzdh)==1:str_qjzdh =str_qjzdh + 'J'+str(list_qjzdh[0])else:str_qjzdh = str_qjzdh + 'J' + str(list_qjzdh[0])+u'/J'+str(list_qjzdh[1])str_zjzdh=''if len(list_zjzdh)==1:str_zjzdh =str_zjzdh + 'J'+str(list_zjzdh[0])else:str_zjzdh = str_zjzdh + 'J' + str(list_zjzdh[0])+u'/J'+str(list_zjzdh[1])row[3] =str_qjzdhrow[4] = str_zjzdh# ===== 步骤3:生成描述字段 =====# 计算长度length = round(geometry.length, 2)# 计算方向start_pt = geometry.firstPointend_pt = geometry.lastPointangle = get_angle(start_pt, end_pt)direction = calculate_direction(angle)# 构建描述desc = "{}-{}:由{}界址点沿{}宗地分界线往{}方向长度{}m至{};".format(row[3].split("/")[0], row[4].split("/")[0], row[3].split("/")[0],pldwzjr if pldwzjr != "无" else "",direction,length,row[4].split("/")[0])row[5] = desccursor.updateRow(row)print(u"处理完成!")

http://www.xdnf.cn/news/6524.html

相关文章:

  • 如何在Edge浏览器里-安装梦精灵AI提示词管理工具
  • MySQL数据类型之VARCHAR和CHAR使用详解
  • 基于大模型预测围术期麻醉苏醒时间的技术方案
  • Ubuntu 安装 Redis
  • 《Adversarial Sticker: A Stealthy Attack Method in the Physical World》论文分享(侵删)
  • A2O娱乐李秀满纪录片首映礼,A2O MAY、少女时代、崔始源、泰民齐聚祝贺
  • 脚本语言Lua
  • 使用PEFT库将原始模型与LoRA权重合并
  • 视频分辨率增强与自动补帧
  • ‌JMeter聚合报告中的任务数和并发数区别
  • 【HarmonyOS 5】鸿蒙mPaaS详解
  • MySQL 开发的智能助手:通义灵码在 IntelliJ IDEA 中的应用
  • Python网络请求利器:urllib库深度解析
  • 单片机-STM32部分:16、Git工具使用
  • 计算图存储采用矩阵吗,和张量关系
  • linux libdbus使用案例
  • 15.springboot-控制器处理参数传递
  • 2025年山东省数学建模F题思路
  • PostgreSQL MCP 使用案例
  • 动态规划问题 -- 多状态模型(买股票的最佳时机II)
  • Vue组件-霓虹灯:技术解析与实现
  • OpenCV CUDA模块中矩阵操作-----矩阵最大最小值查找函数
  • 产品销量数据爬虫通用模板
  • js关于number类型的计算问题
  • msf安卓远控木马手动捆绑正常apk
  • LLM中最后一个位置的对数概率是什么? 怎么作为LOSS实现方式
  • C++23 新特性:ranges::contains 与 ranges::contains_subrange
  • 线代第二章矩阵第九、十节:初等变换、矩阵的标准形、阶梯形与行最简阶梯形、初等矩阵
  • RPA 自动化实现自动发布
  • 基于matlab实现AUTOSAR软件开发---答疑6