Skip to content
本页目录

6.3同豪开挖文件txt转KML插件

本插件的核心功能是解析同豪开挖文件中的平面坐标构成的开挖区域,转为kml面对线。 同豪的开挖文件是模型的精准边界,通过此开挖文件可以实现三维设计BIM模型和地形的精准融合。

通过本插件可了解到:

  • Python中类的构建和引用
  • txt文件的读取和遍历
  • 坐标转化工具类TXCoordConvertUtility的使用
  • 面对象TXGeoPolygon的构建

插件界面:

image.png

转换结果:

一个5000多个面对象的kml文件,示例开挖文件是20万行的文本文件。

image.png

image.png

源码及示例数据下载地址: 图新地球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)