【GIS】Arcpy黑臭水体脚本

106 阅读4分钟

把我做完的一个脚本完全分享给大家,包含GUI。相关黑臭水体项目的处理人员可以先用着。帮着挂属性的。

import arcpy
import tkinter as tk
from tkinter import filedialog, messagebox
from tkinter import ttk

def check_coordinate_system(shapefile):
    coordinate_system = arcpy.Describe(shapefile).spatialReference
    return coordinate_system.type == "Geographic"
    
def process_shapefile(workspace, shapefile, coordinate_system_epsg=4549):
    arcpy.env.workspace = workspace
    original_full_path = os.path.join(workspace, shapefile)
    new_shapefile_name = "BaseAttr_" + os.path.splitext(shapefile)[0] + ".shp"
    your_path = os.path.join(workspace, new_shapefile_name)
    arcpy.CopyFeatures_management(original_full_path, your_path)
    if not check_coordinate_system(your_path):
        messagebox.showerror("错误", "当前要素并非地理坐标系")
        return    
    try:
        add_fields(your_path)
        add_lat_long(your_path)
        calculate_area_length_width(your_path, coordinate_system_epsg)
        update_type_field(your_path)
        messagebox.showinfo("完成", f"所有操作已完成。生成的文件为:{your_path}")
    except Exception as e:
        messagebox.showerror("错误", f"处理过程中发生错误: {e}")

def add_fields(shapefile):
    existing_fields = {field.name for field in arcpy.ListFields(shapefile)}
    new_fields = [
        ("序号", "LONG"), ("ID", "LONG"), ("市级", "TEXT"), ("县级", "TEXT"),
        ("乡镇", "TEXT"), ("村名", "TEXT"), ("名称", "TEXT"), ("类型", "TEXT"),
        ("经度X", "DOUBLE"), ("纬度Y", "DOUBLE"), ("面积", "DOUBLE"),
        ("长度L", "DOUBLE"), ("宽度W", "DOUBLE"), ("等级", "TEXT"),
        ("核查", "TEXT"), ("快检", "TEXT"), ("黑臭", "TEXT"), ("污染源", "TEXT")
    ]
    for field_name, field_type in new_fields:
        if field_name not in existing_fields:
            arcpy.AddField_management(shapefile, field_name, field_type)
    fields_to_delete = ["Shape_Length", "Shape_Area"]
    for field_name in fields_to_delete:
        if field_name in existing_fields:
            arcpy.DeleteField_management(shapefile, field_name)

def add_lat_long(shapefile):
    with arcpy.da.UpdateCursor(shapefile, ["OID@", "Shape@", "经度X", "纬度Y"]) as cursor:
        for row in cursor:
            point = row[1].centroid
            row[2] = point.X
            row[3] = point.Y
            cursor.updateRow(row)


# 凸包
def calculate_area_length_width(shapefile, epsg_code):
    output_coordinate_system = arcpy.SpatialReference(epsg_code)
    projected_temp_file = os.path.join(arcpy.env.workspace, "temp_projected.shp")
    arcpy.Project_management(shapefile, projected_temp_file, output_coordinate_system)
    
    with arcpy.da.UpdateCursor(projected_temp_file, ["Shape@", "面积", "长度L", "宽度W"]) as cursor:
        for row in cursor:
            row[1] = row[0].getArea("PLANAR", "SQUAREMETERS")
            geom = row[0]
            convex_hull = geom.convexHull()
            extent = convex_hull.extent
            length = extent.XMax - extent.XMin
            width = extent.YMax - extent.YMin            
            row[2] = max(length, width)
            row[3] = min(length, width)
            cursor.updateRow(row)
    arcpy.Delete_management(shapefile)
    arcpy.Rename_management(projected_temp_file, shapefile)
    
def update_type_field(shapefile):
    with arcpy.da.UpdateCursor(shapefile, ["Shape@", "长度L", "宽度W", "类型"]) as cursor:
        for row in cursor:
            geometry = row[0]
            length, width = row[1], row[2]
            area = geometry.getArea("PLANAR", "SQUAREMETERS")
            perimeter = geometry.length
            compactness = (4 * 3.14159 * area) / (perimeter ** 2)
            if compactness > 0.31:  # 紧凑度越接近1,越圆
                row[3] = "坑塘"
            else:
                row[3] = "沟渠"
            
            cursor.updateRow(row)


# GUI Functions
def select_workspace():
    path = filedialog.askdirectory()
    workspace_entry.delete(0, tk.END)
    workspace_entry.insert(0, path)

def select_shapefile():
    file_path = filedialog.askopenfilename(filetypes=[("Shapefiles", "*.shp")])
    shapefile_entry.delete(0, tk.END)
    shapefile_entry.insert(0, os.path.basename(file_path))

def run_process():
    workspace = workspace_entry.get()
    shapefile = shapefile_entry.get()
    if not workspace or not shapefile:
        messagebox.showwarning("输入错误", "请选择工作区路径和Shapefile文件。")
        return
    process_shapefile(workspace, shapefile)

def black_water_gui():
    global workspace_entry, shapefile_entry

    sub_root = tk.Toplevel()
    sub_root.title("黑臭水体治理项目")
    sub_root.geometry("700x400")
    sub_root.configure(bg='#f0f0f0')

    title_frame = tk.Frame(sub_root, bg='#f0f0f0')
    title_frame.pack(pady=10)
    title_label = tk.Label(title_frame, text="黑臭水体解译程序", font=("Microsoft YaHei", 20, "bold"), bg='#f0f0f0')
    title_label.pack()

    main_frame = tk.Frame(sub_root, padx=20, pady=20, bg='#f0f0f0')
    main_frame.pack(pady=20)

    tk.Label(main_frame, text="选择工作区路径:", font=("Microsoft YaHei", 12), bg='#f0f0f0').grid(row=0, column=0, padx=10, pady=10, sticky='w')
    workspace_entry = tk.Entry(main_frame, width=40, font=("Microsoft YaHei", 12))
    workspace_entry.grid(row=0, column=1, padx=10, pady=10)
    tk.Button(main_frame, text="选择路径", command=select_workspace, font=("Microsoft YaHei", 12), bg='#4CAF50', fg='white').grid(row=0, column=2, padx=10, pady=10)

    tk.Label(main_frame, text="选择Shapefile文件:", font=("Microsoft YaHei", 12), bg='#f0f0f0').grid(row=1, column=0, padx=10, pady=10, sticky='w')
    shapefile_entry = tk.Entry(main_frame, width=40, font=("Microsoft YaHei", 12))
    shapefile_entry.grid(row=1, column=1, padx=10, pady=10)
    tk.Button(main_frame, text="选择文件", command=select_shapefile, font=("Microsoft YaHei", 12), bg='#4CAF50', fg='white').grid(row=1, column=2, padx=10, pady=10)

    run_button = tk.Button(main_frame, text="运行", command=run_process, font=("Microsoft YaHei", 14, "bold"), bg='#FF5722', fg='white', width=15)
    run_button.grid(row=2, column=1, pady=20)

    footer_frame = tk.Frame(sub_root, bg='#f0f0f0')
    footer_frame.pack(side=tk.BOTTOM, fill=tk.X, padx=10, pady=10)
    copyright_label = tk.Label(footer_frame, text="© 唐山市环境规划科学研究院—双碳中心", font=("Microsoft YaHei", 10), fg='#888888', bg='#f0f0f0')
    copyright_label.pack(anchor='e')

    sub_root.update_idletasks()
    screen_width = sub_root.winfo_screenwidth()
    screen_height = sub_root.winfo_screenheight()
    x = (screen_width - sub_root.winfo_width()) // 2
    y = (screen_height - sub_root.winfo_height()) // 2
    sub_root.geometry(f"+{x}+{y}")

# Main GUI Code
root = tk.Tk()
root.title("唐山市环境规划科学研究院-双碳研究中心")
root.geometry("500x300")
root.configure(bg='#f0f0f0')

title_frame = tk.Frame(root, bg='#f0f0f0')
title_frame.pack(pady=10)
title_label = tk.Label(title_frame, text="双碳研究中心自动化工作台", font=("Microsoft YaHei", 20, "bold"), bg='#f0f0f0')
title_label.pack()

button_frame = tk.Frame(root, bg='#f0f0f0')
button_frame.pack(pady=20)

def show_unlock_message():
    messagebox.showinfo("功能需要联系我", "联系moonless0222@gmail.com")

style = ttk.Style()
style.configure("TButton", padding=5, relief="raised", background="#4CAF50", foreground="black")
style.map("TButton", background=[("active", "#3e8e41"), ("disabled", "#a2a2a2")], foreground=[("active", "blue"), ("disabled", "grey")])

buttons = [
    ("黑臭水体", black_water_gui),
    ("数据处理", show_unlock_message),
    ("深度学习", show_unlock_message),
    ("后续项目", show_unlock_message),
    ("后续项目", show_unlock_message),
    ("后续项目", show_unlock_message),
    ("后续项目", show_unlock_message),
    ("后续项目", show_unlock_message),
    ("后续项目", show_unlock_message)
]

for i, (text, command) in enumerate(buttons):
    row = i // 3
    col = i % 3
    btn = ttk.Button(button_frame, text=text, command=command, style="TButton")
    btn.grid(row=row, column=col, padx=15, pady=15, sticky="nsew")

for i in range(3):
    button_frame.grid_rowconfigure(i, weight=1)
    button_frame.grid_columnconfigure(i, weight=1)

root.update_idletasks()
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
x = (screen_width - root.winfo_width()) // 2
y = (screen_height - root.winfo_height()) // 2
root.geometry(f"+{x}+{y}")

root.mainloop()