破损shp文件修复

news2024/9/21 4:12:37

大家中秋节快乐!

介绍

半年前写过破损shp文件修复的内容,当时写了一个简陋的小工具。

现在重新讲讲这方面的内容,这篇文章也主要围绕以下两个方面进行展开:

1、当时是怎么实现破损shp文件修复

2、现在怎么把这个功能集成到rstool软件

shp文件修复流程

说到shp文件夹修复,必然要讲讲这个问题是怎么出现的。

记得某一天,我在愉快的使用着arcgis,正在编辑图斑,由于不可抗力软件闪退了,导致shp文件的图形数量和dbf的属性表数量对不上。

shp的图形是保存在内存里,你画完了一个图形,电脑把这个点位数据自动地保存在.shp文件中,但是属性表需要手动地去完成保存。

如果在你未及时保存文件前,电脑重启了或者arcgis软件大退,就会把整个shp文件打碎,最后把这个矢量文件拖拽到arcgis,显示无法打开。

好了,理解清楚了这个问题的原因,解决思路就很清晰了。

1.修改.shp,使它的图形数量和dbf的属性表个数保持一致。

2.修改.dbf,使它的属性表个数和.shp的图形数量保持一致。

当时选择的方式是第二条,以下是shp修复的流程图

image-20240916205111961

以下代码,是上面的流程的实现(当时为了外国人也看得懂把注释改为了英文。。。)

#!/usr/bin/env python
# -*- coding: utf-8 -*- 
# @Time : 2024/1/3 20:32
# @File : RestoreShp.py
​
# 修复shp文件, shp文件中的几何数据和属性数据不一致
import os
import shutil
from struct import unpack
import dbf
​
class RestoreShp(object):
    def __init__(self, file, outpath=None):
        self.file = file
        self.outpath = outpath
        if self.outpath is None:
            self.outpath = os.path.dirname(self.file)
        if not os.path.exists(self.outpath):
            os.makedirs(self.outpath)
        if os.path.exists(self.file) is None:
            raise Exception('File does not exist')
        else:
            self.dbffile = os.path.splitext(self.file)[0] + '.dbf'
​
        self.outfile = [os.path.join(self.outpath, os.path.splitext(os.path.basename(self.file))[0] + '_restore.shp'),
                        os.path.join(self.outpath, os.path.splitext(os.path.basename(self.file))[0] + '_restore.dbf'),
                        os.path.join(self.outpath, os.path.splitext(os.path.basename(self.file))[0] + '_restore.shx'),
                        os.path.join(self.outpath, os.path.splitext(os.path.basename(self.file))[0] + '_restore.prj')]
        self.copyfile
    @property
    def copyfile(self):
        # 读取shp文件
        shutil.copyfile(self.file, self.outfile[0])
        shutil.copyfile(self.dbffile, self.outfile[1])
        shutil.copyfile(os.path.splitext(self.file)[0] + '.shx', self.outfile[2])
​
        try:
            shutil.copyfile(os.path.splitext(self.file)[0] + '.prj', self.outfile[3])
        except Exception as e:
            print(e)
        print('Copy the initial file to the output directory')
​
    def get_shp_shape_records(self):
        try:
            # First read the geometry data and attribute data of the original file, and return the number of geometric data
                self.shx = open("%s" % (self.outfile[2]), "rb")
                self.shx.seek(24)
                shxRecordLength = (unpack(">i", self.shx.read(4))[0] * 2) - 100
                self.numShapes = shxRecordLength // 8
                return self.numShapes
        except Exception as e:
            print(e)
    def get_dbf_shape_records(self):
        # db = dbf.Dbf(self.dbffile)
        with dbf.Table(self.outfile[1], codepage='utf8', default_data_types='enhanced') as table:
            pass
        return table
    def restore_shp(self):
        #  Number of records read from shp file
​
        shp_numrecords = self.get_shp_shape_records()
        #  Number of records read from dbf file
        table = self.get_dbf_shape_records()
        dbf_numrecords = len(table)
​
​
        # Check whether the number of shp and dbf records is equal
        if shp_numrecords != dbf_numrecords:
            num = shp_numrecords - dbf_numrecords
            if num > 0:
                print('The shp file has {} more records than the dbf file'.format(num))
                for i in range(num):
                    table.open(mode=dbf.READ_WRITE)
                    table.append()
                table.pack()
​
            else:
                print('The dbf file has {} more records than the shp file'.format(abs(num)))
                table.open(mode=dbf.READ_WRITE)
                for record in table[shp_numrecords:]:
                    dbf.delete(record)
                table.pack()
​
if __name__ == '__main__':
    file = input('Please enter the path of the shp file: ')
    outpath = input('Please enter the path of the output file: ')
​
    if os.path.exists(file) :
        record_num = RestoreShp(file, outpath).restore_shp()
        print('complete')
    else:
        print('File does not exist')
    input()
​
​

破损的shp文件的产生过程

现在手头上没有一个破损的shp文件,但是,但是我们可以构造一个破损的shp文件

1,复制一个dbf作为临时文件。这个文件待会用到。

image-20240916214319512

2,在arcgis打开刚刚那个shp,右键它,选择编辑要素,选择开始编辑,如下图

image-20240916210718118

3,画了个圆,点击保存,然后退出arcgis

image-20240916212025033

4,把原先的dbf删除,再把一开始的复制的dbf改名为被删除的dbf名字,完成替换。

image-20240916222411856

5,自此,shp文件就变成了破损的shp文件,拖拽到arcgis,就打不开了。

image-20240916225220983

集成rstool的步骤

1、在Qt Designer上画好插曲的ui

image-20240916231317010

2、将这个ui文件保存为restoreshp.ui

image-20240916231553730

3、在命令行输入:

 pyuic5 -o restoreshp.py restoreshp.ui

image-20240916231628737

结果如下:

image-20240916231704251

4、在rstool项目中,修改相关代码。我们查看一下rstool整体的结构,如下:

image-20240916232601690

5、在ui文件夹,创建一个叫做ui_restoreshp.py的文件(我直接复制其他已有的文件,这样在已有的基础上进行修改,更节省时间)

image-20240916233351656

先建立一个restore_shpWidget的类,待会用到。剩下的都是体力活了,修改正确的Ui_Form文件的名字,这里不再细说。

image-20240916234757878

6、修改function文件夹下的messages.py文件,这个文件负责前端界面的提示功能

image-20240917001451160

7、修改主程序入口的文件rstool.py,在开头添加一行代码,导入第5步的创建的restore_shpWidget类

image-20240917000619718

8、在rstool.py中的window类中,增加一行代码,将restoreshpWidget类实例化

image-20240916234655925

9、在rstool.py中的window类中的window_signals函数增加这句,把shp修复界面的按钮以另一个线程的方式串联起来。就是当你点击运行按钮,就在另一个线程运行后端shp修复的函数,这样做的好处是,前端界面不卡顿。

image-20240916235154486

10、在rstool.py中的window类中的init_navigation函数增加这句,目的是在前端的导航栏添加shp修复的菜单。

image-20240917001622600

11、在rstool.py中的window类中的click_prompt_signal函数,添加一行代码,把第6步所创建的新增的shp修复的提示功能加载到rstool中。

image-20240917000410424

12、运行rstool.py进行测试,如果遇到报错,则一个错误一个错误去解决。如果没报错,应是如下界面:

image-20240917001740726

点击“用前必看”按钮,应是如下界面:

image-20240917001923303

接下来进行功能测试。rstool有两种输入参数的方法:

一、点击获取文件按钮,会弹出对话框,让用户选择对应的破损shp文件。

二、直接复制粘贴shp文件的路径到“ 获取文件”按钮的左侧的空白输入框

image-20240917002302432

如果你输出的参数有问题,rstool不允许你点击 “开始修复”按钮

image-20240917002445734

shp修复的速度极快,若完成了数据修复,会弹出一个窗口提示 完成数据修复。

image-20240917002640183

修复后的shp保存在D:\temp\破损\out文件夹中,如下所示。此文件夹不需要提前建立。

image-20240917003503894

我们把修复后的shp拖拽到arcgis,测试是否完成修复。

13、在miniconda环境下,使用pyinstaller进行打包,再进行测试。

打包命令是:

pyinstaller -F -w -i G:\code\rstool\resources\images\icon.ico rstool.py

image-20240917002800318

打包完成后,会在dist文件夹生成ratool.exe文件。

image-20240917003005783

我们再次重复第12步的测试。

最后暂时无报错。

测试过程如下:

shpfixing

小结

在后台回复1111获取这个rstool的下载链接。

rstool暂时集成了四个功能分别是植被色彩增强、shp转kml、shp转dxf、shp修复。

image-20240917004602688

rstool正在开发中,不定期更新,开源地址是GitHub - ytkz11/rs-tool

欢迎来白嫖。

由于这个项目是个人项目,我的业余时间不大可能全部都投入到rstool的开发中,在我的预想中rstool集成的功能最好具备以下几个特点

1、具有通用性,尽可能地帮助到更多的同行

2、具有实用性,确确实实解决实际问题

3、具有稀少性,比如说现在这四个功能是比较少见的,其他软件没有具体的实现,若是其他的软件可以实现,那就使用其他的软件就好了,不要重复造轮子。

如果你有其他想实现的功能,集成到rstool中,可以在下方留言区留下你宝贵的建议。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2151081.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LINUX网络编程:TCP(1)

目录 1.认识Tcp的报头 2.确认应答机制(ACK) 序号与确认序号 捎带应答 3.超时重传机制 4.Tcp连接管理 三次握手 为什是三次握手 四次挥手 理解TIMEWAIT 1.认识Tcp的报头 源端口和目的端口号没什么说的 32位的序号和确认序号,之后会介…

如何使用ssm实现毕业生学历证明系统+vue

TOC ssm651毕业生学历证明系统vue 绪论 1.1 课题背景 二十一世纪互联网的出现,改变了几千年以来人们的生活,不仅仅是生活物资的丰富,还有精神层次的丰富。在互联网诞生之前,地域位置往往是人们思想上不可跨域的鸿沟&#xff0…

Linux C# DAY3

作业 1、 #!/bin/bash mkdir -p ~/dir/dir1 mkdir ~/dir/dir2 cp ./* ~/dir/dir1 cp ./*.sh ~/dir/dir2 cd ~/dir/ tar -cvJf dir2.tar.xz ./dir2 mv dir2.tar.xz ~/dir/dir1/ cd ~/dir/dir1/ tar -xvf dir2.tar.xz 2、 #!/bin/bash head -5 /etc/group | tail -1 sudo mkdi…

Docker安装mysql并配置主从,超详细

简介: 本文使用docker安装mysql,并创建master节点,slave节点用于实现主从。废话不多说,直接开始。 1.docker下载镜像,这里我以5.7版本为例。 docker pull mysql:5.7 2.在宿主机上新建如下目录,进行文件挂…

Lichee NanoKVM基本使用环境

Lichee NanoKVM基本使用环境 本文章主要记录一些自己在初期的使用,以及自己的一些经验 ,非常感谢sipeed NanoKVM官方使用教程 外观(博主自己的是lite版本,非常感谢sipeed) Lichee NanoKVM 是基于 LicheeRV Nano 的 I…

专为GOA TFT-LCD面板设计的16ch水平移位器-iML7272A

GOA是Gate on Array的简写,简单可以理解为gate IC集成在玻璃上了,面板就可以不用gate ic了,窄边框面板大多数都用了GOA技术。随着窄边框设计的日益流行,面板设计的周边空间被逐渐压缩,在传统的GOA电路设计中&#xff0…

Python学习——【3.1】函数

文章目录 【3.1】函数一、函数的定义二、函数的参数三、函数的返回值(一)函数返回值的定义(二)None类型 四、函数的说明文档五、函数的嵌套调用六、函数中变量的作用域(一)局部变量(二&#xff…

(数组) LeetCode 1184. 公交站间的距离

原题链接 一. 题目描述 环形公交路线上有 n 个站,按次序从 0 到 n - 1 进行编号。我们已知每一对相邻公交站之间的距离,distance[i] 表示编号为 i 的车站和编号为 (i 1) % n 的车站之间的距离。 环线上的公交车都可以按顺时针和逆时针的方向行驶。 …

解决:The play() request was interrupted by a call to pause().报错

前言: 最近在公司中实现进入页面之后点击单词直接播放音频的时候,发现音频并不会播放声音,并且控制台报错: 研究之后找到了解决方案,与小伙伴们进行分享 原因: 首先看这句话的意思: 在调用 …

【C++】C++ STL探索:Priority Queue与仿函数的深入解析

C语法相关知识点可以通过点击以下链接进行学习一起加油!命名空间缺省参数与函数重载C相关特性类和对象-上篇类和对象-中篇类和对象-下篇日期类C/C内存管理模板初阶String使用String模拟实现Vector使用及其模拟实现List使用及其模拟实现容器适配器Stack与Queue 这篇文…

中国数据中心服务器CPU行业发展概述

2024中国服务器CPU行业概览:信创带动服务器CPU国产化 AA体系是一种基于ARM指令系统和Android操作系统的体系结构,主要用于移动设备。与Wintel体系不同,AA体系中CPU厂商对芯片或系统厂商进行指令系统或IP核授权,操作系统厂商提供基…

Ansbile-变量

文章目录 一、Ansible的常量(内置的变量)有哪些???????????????&#xff1…

八、explicit关键字在C++中的用法

使用方法:修饰单参构造函数 作用:explicit修饰构造函数,禁止类型转换 使用Date d2 19; 这样的方式来进行d2对象的实例化。 在程序上是可以进行下去的,但不符合语法、也不合逻辑。 class Date { public:Date(int day)…

sqlite数据库设计工具

下载 开发环境 VS2022 + Qt5.14.2 CMake修改 add_subdirectory(sqlite3-cmake) include_directories(${CMAKE_SOURCE_DIR}/sqlite3-cmake/src) target_link_libraries(${PROJECT_NAME} sqlite3) 效果 参考 https://github.com/sqlitebrowser/sqlitebrowser

Java之封装

文章目录 1.封装1.1 什么是封装1.2 访问限定符1.3 包1.3.1 什么是包1.3.2 导包1.3.3 自定义包 2. static2.1 static 修饰成员变量2.2 static 修饰成员方法2.3 static成员变量初始化 3. 代码快3.1 普通代码块3.2 实例代码块3.3 静态代码块 4. 对象的打印 1.封装 1.1 什么是封装…

【JPCS出版】第四届电气工程与计算机技术国际学术会议(ICEECT 2024,9月27-29)

会议信息 会议官网:www.iceect.com 2024 4th International Conference on Electrical Engineering and Computer Technologywww.iceect.com 时间地点:2024年9月27日-29日 | 线上(ZOOM) 最终截稿时间:9月23日 主办…

【GVINS】

【GVINS】 1. GVINS的系统特点2. GVINS的融合导航存在问题3. GVINS的信号的组成4. GVINS的信号的组成 原理推导知乎 1. GVINS的系统特点 概述了一种名为GVINS的系统,它旨在解决视觉-惯性里程计(VIO)在长时间运行时出现的漂移问题。GVINS通过…

neo4j导入csv数据

neo4j数据可视化实践 手动输入数据 - 官方democsv数据导入准备数据数据处理导入步骤① 导入疾病表格② 导入药物表格③导入疾病-药物关系表格 爬虫的csv文件 手动输入数据 - 官方demo 点击之后,按照左边10张图中的代码,复制粘贴熟悉语法 效果如下 csv数据…

(undone) 学习语音学中关于 i-vector 和 x-vector

来源:https://ieeexplore.ieee.org/stamp/stamp.jsp?tp&arnumber8461375 (这是一篇跟 X-vector 有关的论文) 这里有更适合初学者的两个资料: 1.https://www.youtube.com/watch?vR3rzN6JYm38 (MIT教授的youtube视频) 2.https://people.c…

JavaScript高级——组合继承

1、借用构造函数继承(假的) (1)套路: ① 定义父类型构造函数 ② 定义子类型构造函数 ③ 在子类型构造函数中调用父类型构造 (2)关键:在子类型构造函数中通用 call(&…