6.3同豪开挖文件txt转KML插件
本插件的核心功能是解析同豪开挖文件中的平面坐标构成的开挖区域,转为kml面对线。 同豪的开挖文件是模型的精准边界,通过此开挖文件可以实现三维设计BIM模型和地形的精准融合。
通过本插件可了解到:
- Python中类的构建和引用
- txt文件的读取和遍历
- 坐标转化工具类TXCoordConvertUtility的使用
- 面对象TXGeoPolygon的构建
插件界面:
转换结果:
一个5000多个面对象的kml文件,示例开挖文件是20万行的文本文件。
源码及示例数据下载地址: 图新地球PythonAPI-同豪开挖文件txt转kml插件
注:示例代码并不是完整的插件,需要按照开发环境的构建流程,安装对应的依赖包。
6.1 类的构建
- 本示例插件把功能和对话框的构建封装为了一个独立的类
MyDialog
。 init_dialog
方法完成了界面的构建
6.2 txt文件的读取和遍历
- 使用os的open函数,读取txt文件
- 使用
area:\n
作为判断条件,拆解为一个一个的面对象,area开头代表一个新的面对象的开始
6.3 坐标转化工具类TXCoordConvertUtility的使用
- 根据投影文件把平面坐标转为经纬度坐标
DataToSysPnt
6.4 具体代码如下:
python
import os.path
import tkinter as tk
from tkinter import filedialog
from tkinter import Tk
from tkinter import messagebox
from TXEarthAPI import *
class MyDialog:
def __init__(self, master, app):
self.cancel_btn = None
self.ok_btn = None
self.select_prj_btn = None
self.prj_path_lineedit = None
self.prj_label = None
self.select_save_path_btn = None
self.save_path_lineedit = None
self.save_label = None
self.select_txt_btn = None
self.txt_path_lineedit = None
self.txt_label = None
self.layer = None
self.master: Tk = master
self.init_dialog()
self.globe = TXGlobeControl(app)
def init_dialog(self):
# 窗口标题
self.master.title("同豪开挖文件转KML")
# 设置窗口大小
self.master.geometry("442x206")
# 获取屏幕宽度和高度
screen_width = self.master.winfo_screenwidth()
screen_height = self.master.winfo_screenheight()
# 计算窗口显示时的左上角坐标
center_x = int((screen_width - self.master.winfo_reqwidth()) / 2)
center_y = int((screen_height - self.master.winfo_reqheight()) / 2)
# 设置窗口显示时的左上角坐标
self.master.geometry("+{}+{}".format(center_x, center_y))
self.txt_label = tk.Label(self.master)
self.txt_label["text"] = "请选择开挖文件"
self.txt_label.place(x=10, y=30, width=88, height=30)
self.txt_path_lineedit = tk.Entry(self.master)
self.txt_path_lineedit.place(x=120, y=30, width=215, height=30)
self.select_txt_btn = tk.Button(self.master)
self.select_txt_btn["text"] = "选择"
self.select_txt_btn.place(x=350, y=30, width=70, height=30)
self.select_txt_btn["command"] = self.select_txt_file
self.save_label = tk.Label(self.master)
self.save_label["text"] = "请选择保存路径"
self.save_label.place(x=10, y=70, width=84, height=30)
self.save_path_lineedit = tk.Entry(self.master)
self.save_path_lineedit.place(x=120, y=70, width=215, height=30)
self.select_save_path_btn = tk.Button(self.master)
self.select_save_path_btn["text"] = "选择"
self.select_save_path_btn.place(x=350, y=70, width=71, height=30)
self.select_save_path_btn["command"] = self.select_save_path
self.prj_label = tk.Label(self.master)
self.prj_label["text"] = "请选择prj文件"
self.prj_label.place(x=10, y=110, width=79, height=32)
self.prj_path_lineedit = tk.Entry(self.master)
self.prj_path_lineedit.place(x=120, y=110, width=215, height=30)
self.select_prj_btn = tk.Button(self.master)
self.select_prj_btn["text"] = "选择"
self.select_prj_btn.place(x=350, y=110, width=70, height=30)
self.select_prj_btn["command"] = self.select_prj_file
self.ok_btn = tk.Button(self.master)
self.ok_btn["text"] = "生成"
self.ok_btn.place(x=350, y=160, width=70, height=25)
self.ok_btn["command"] = self.ok_command
self.cancel_btn = tk.Button(self.master)
self.cancel_btn["text"] = "取消"
self.cancel_btn.place(x=260, y=160, width=70, height=25)
self.cancel_btn["command"] = self.cancel_command
def select_txt_file(self):
# 选择开挖文件
path = filedialog.askopenfilename(
initialdir='',
title="选择开挖文件",
filetypes=(("txt文件", "*.txt"),)
)
if len(path) > 0:
self.txt_path_lineedit.delete(0, "end")
self.txt_path_lineedit.insert(0, path)
name, ext = os.path.splitext(path)
self.save_path_lineedit.delete(0, "end")
self.save_path_lineedit.insert(0, name + ".kml")
def select_save_path(self):
# 选择保存路径
path = filedialog.asksaveasfilename(
initialdir='',
title="选择保存路径",
filetypes=(("kml文件", "*.kml"),)
)
if len(path) > 0:
if not path.endswith(".kml"):
path += ".kml"
self.save_path_lineedit.delete(0, "end")
self.save_path_lineedit.insert(0, path)
def select_prj_file(self):
# 选择prj文件
path = filedialog.askopenfilename(
initialdir='',
title="选择prj",
filetypes=(("prj文件", "*.prj"),)
)
if len(path) > 0:
self.prj_path_lineedit.delete(0, "end")
self.prj_path_lineedit.insert(0, path)
def ok_command(self):
# 生成
txt_path = self.txt_path_lineedit.get()
if len(txt_path) == 0:
messagebox.showinfo("请选择待转换的txt文件")
return
kml_path = self.save_path_lineedit.get()
if len(kml_path) == 0:
messagebox.showinfo("请选择转换后的图层保存路径")
return
prj_path = self.prj_path_lineedit.get()
if len(prj_path) == 0:
messagebox.showinfo("请选择prj文件")
return
self.generate_convert_file()
def cancel_command(self):
# 取消
self.master.destroy()
def generate_convert_file(self):
kml_path = self.save_path_lineedit.get()
kml_layer = self.globe.AddLayer(kml_path)
txt_path = self.txt_path_lineedit.get()
with open(txt_path, 'r', encoding='utf-8') as file_src:
# 读取所有行
all_lines = file_src.readlines()
# 总的行数
line_count = len(all_lines)
# 获取面索引
item = 'area:\n'
area_index = [i for i in range(line_count) if all_lines[i] == item]
# 索引
index = 0
# 读取每一个具体的面要素
area_count = len(area_index)
while index < area_count:
area_start = area_index[index]
if index < area_count - 1:
area_end = area_index[index + 1]
else:
area_end = line_count
# 获取每一个面的坐标点集合
points = all_lines[area_start + 1:area_end]
# 创建多边形
polygon = TXGeoPolygon()
# 设置高度模式为紧贴地表
polygon.SetAltitudeMode(AltitudeType_ClampToGround)
# prj文件路径
prj_path = self.prj_path_lineedit.get()
area_points = PointList()
for point in points:
value = point.strip().split(',')
if len(value) < 2:
continue
x = eval(value[0])
y = eval(value[1])
z = 0
# 进行坐标转换
data_pnt = TXPoint(x, y, z)
sys_pnt = TXPoint()
TXCoordConvertUtility.DataToSysPnt(data_pnt, sys_pnt, prj_path)
# 添加到点集
area_points.append(sys_pnt)
# logger.info('坐标转换结束')
# 设置多边形的坐标集合
polygon.AddPoints(area_points)
kml_layer.AddPolygon(polygon)
index += 1
kml_layer.Save()
self.globe.Refresh()
self.globe.FlyToLayer(kml_layer)