shp文件转换为CAD文件 (改进版)

文摘   2024-09-05 21:51   广东  

上个月写了一个工具是关于shp文件转换为CAD文件,


后面被吐槽说这个工具的大小为390M。

我承认,这个是“小工具”一点也不小!


那是什么原因造成的呢?

其实这个python打包的通病问题,python作为胶水语言,可以快速开发。想要打包成二进制文件交给其他人使用,这个二进制文件一般是巨大无比的。

更底层的原因是,在代码中,我们导入了geopandas这个库,geopandas很好用,是因为它引用了非常多的第三方库,所以使用pyinstaller打包的时候,往往会把这些“无用”的第三方库也打包进去我们的项目里面。

同样是这个程序,我曾打包后的文件大小是3G多,我看了一下 ,好家伙啊,它把torch-cuda依赖也打包进去了!


针对这个shp文件转换为CAD文件小工具,我们可以改进它,主要做法是,不导入geopandas,即不使用geopandas!

经过网上冲浪查资料,我发现有个纯python包叫做ezdxf,这ezdxf可以对dxf文件读写,很符合这个小工具的要求。


我有了个大体的思路,使用ogr读取矢量文件的数据。ogr是啥?ogr就是osgeo里面的子库,ogr和gdal同一个级别,区别在于gdal读写栅格数据,ogr读写矢量数据。

好了,现在的程序处理步骤如下:

1.使用ogr读取矢量文件,获取点位数据。

2.使用ezdxf将点位数据保存为dxf文件。


好了好了,现在就差代码还需要写了。




代码



import os
import ezdxf
from osgeo import ogr


class Shp2Dxf:
   def __init__(self, in_file):
       self.in_file = in_file
       self.out_file = os.path.splitext(in_file)[0] + '.dxf'

   def read_shp_by_ogr(self):
       ds = ogr.Open(self.in_file)
       shape = ds.GetLayer()
       attribute_names = []
       ldefn = shape.GetLayerDefn()

       geom_list = []
       for i in range(shape.GetFeatureCount()):
           feature = shape.GetFeature(i)
           geom = feature.GetGeometryRef()
           geom_list.append(geom.ExportToWkt())  # 将几何信息保存为WKT格式
       return geom_list

   def shp2dxf(self) -> None:
       # 读取Shapefile中的几何信息
       geom_list = self.read_shp_by_ogr()

       # 创建一个新的DXF文件
       doc = ezdxf.new(dxfversion='R2010')
       msp = doc.modelspace()  # 获取模型空间

       # 将几何信息转换为DXF实体并添加到DXF文件中
       for geom_wkt in geom_list:
           geom = ogr.CreateGeometryFromWkt(geom_wkt)
           geom_type = geom.GetGeometryType()

           if geom_type == ogr.wkbPoint:  # 点类型
               x, y = geom.GetX(), geom.GetY()
               msp.add_point((x, y))
           elif geom_type == ogr.wkbLineString:  # 线类型
               points = geom.GetPoints()
               msp.add_lwpolyline(points)
           elif geom_type == ogr.wkbPolygon:  # 多边形类型
               ring = geom.GetGeometryRef(0)  # 获取多边形的外环
               points = ring.GetPoints()

               # 创建Hatch对象
               hatch = msp.add_hatch(color=7)  # 设置填充颜色,默认颜色为7(白色或黑色,取决于背景)

               # 添加路径
               path = hatch.paths.add_polyline_path(points, is_closed=True)

       # 保存DXF文件
       doc.saveas(self.out_file)
       print(f"Successfully converted {self.in_file} to {self.out_file}")

   def readdxf(self, file):
       doc = ezdxf.readfile(file)
       msp = doc.modelspace()
       for entity in msp:
           print(entity)

       for layer in doc.layers:
           print(layer.dxf.name)
       print()
if __name__ == '__main__':
   # in_file = r'd://temp/create_shp_by_fiona.shp'

   in_file = input("输入shp文件路径:")
   try:
       converter = Shp2Dxf(in_file)
       converter.shp2dxf()
       # converter.readdxf(converter.out_file)

       # converter.shp2dxf()
   except Exception as e:
       print(e)
   input("已完成")

这段代码定义了一个名为Shp2Dxf的类,该类用于将Shapefile (.shp) 文件转换为AutoCAD的Drawing Interchange Format (.dxf) 文件。

代码逐行解释

下面是对代码每一部分的逐行解释:

  1. import os: 导入os模块,用于处理文件路径和其他操作系统交互功能。

  2. import ezdxf: 导入ezdxf库,用于创建和读取DXF文件。

  3. from osgeo import ogr: 导入GDAL库中的ogr模块,用于读取GIS数据,如Shapefile。


  4. class Shp2Dxf:: 定义一个名为Shp2Dxf的类。

  5. def __init__(self, in_file):: 初始化方法,接收一个参数in_file表示输入的Shapefile路径。

  6. self.in_file = in_file: 将输入文件路径存储为类实例的一个属性。

  7. self.out_file = os.path.splitext(in_file)[0] + '.dxf': 根据输入文件路径创建输出文件名,扩展名改为.dxf


  8. def read_shp_by_ogr(self):: 定义一个方法来通过ogr读取Shapefile。

  9. ds = ogr.Open(self.in_file): 打开输入的Shapefile文件。

  10. shape = ds.GetLayer(): 获取文件的第一个图层。

  11. attribute_names = []: 初始化一个空列表,用于存储属性名称。

  12. ldefn = shape.GetLayerDefn(): 获取图层定义。

  13. geom_list = []: 初始化一个空列表,用于存储几何对象。

  14. for i in range(shape.GetFeatureCount()):: 遍历图层中的所有要素。

  15. feature = shape.GetFeature(i): 获取当前索引i的要素。

  16. geom = feature.GetGeometryRef(): 获取要素的几何对象。

  17. geom_list.append(geom.ExportToWkt()): 将几何对象以WKT格式添加到列表中。

  18. return geom_list: 返回包含所有要素几何信息的列表。


  19. def shp2dxf(self) -> None:: 定义一个方法将Shapefile转换为DXF文件。

  20. geom_list = self.read_shp_by_ogr(): 调用方法获取Shapefile的几何信息。

  21. doc = ezdxf.new(dxfversion='R2010'): 创建一个新的DXF文档,版本为R2010。

  22. msp = doc.modelspace(): 获取文档的模型空间。

  23. for geom_wkt in geom_list:: 遍历从Shapefile获取的所有几何信息。

  24. geom = ogr.CreateGeometryFromWkt(geom_wkt): 从WKT字符串创建几何对象。

  25. geom_type = geom.GetGeometryType(): 获取几何对象的类型。

  26. if geom_type == ogr.wkbPoint:: 如果几何对象是点类型。

  27. x, y = geom.GetX(), geom.GetY(): 获取点的坐标。

  28. msp.add_point((x, y)): 在模型空间中添加一个点。

  29. elif geom_type == ogr.wkbLineString:: 如果几何对象是线类型。

  30. points = geom.GetPoints(): 获取线的坐标点集合。

  31. msp.add_lwpolyline(points): 在模型空间中添加一个轻量级多段线。

  32. elif geom_type == ogr.wkbPolygon:: 如果几何对象是多边形类型。

  33. ring = geom.GetGeometryRef(0): 获取多边形的外环。

  34. points = ring.GetPoints(): 获取多边形外环的坐标点集合。

  35. hatch = msp.add_hatch(color=7): 在模型空间中添加带有填充的边界。

  36. path = hatch.paths.add_polyline_path(points, is_closed=True): 为边界添加闭合的多段线路径。

  37. doc.saveas(self.out_file): 保存DXF文件。

  38. print(f"Successfully converted {self.in_file} to {self.out_file}"): 输出转换成功的信息。


  39. def readdxf(self, file):: 定义一个方法用于读取DXF文件。

  40. doc = ezdxf.readfile(file): 读取DXF文件。

  41. msp = doc.modelspace(): 获取模型空间。

  42. for entity in msp:: 遍历模型空间中的所有实体。

  43. print(entity): 输出实体信息。

  44. for layer in doc.layers:: 遍历文档中的所有图层。

  45. print(layer.dxf.name): 输出图层名称。

  46. print(): 输出一个换行。


  47. if __name__ == '__main__':: 当脚本作为主程序运行时执行以下代码。

  48. in_file = input("输入shp文件路径:"): 请求用户输入Shapefile路径。

  49. try:: 尝试执行以下代码块。

  50. converter = Shp2Dxf(in_file): 创建Shp2Dxf类的实例。

  51. converter.shp2dxf(): 转换Shapefile为DXF。

  52. # converter.readdxf(converter.out_file): 注释掉的代码,用于读取生成的DXF文件。

  53. except Exception as e:: 捕获异常。

  54. print(e): 输出异常信息。

  55. input("已完成"): 输出“已完成”并等待用户按键继续。




打包程序

我除了用pyinstaller打包之外,还使用了nuitka打包。但是nuitka打包的文件大小还比pyinstaller的大。。。

如果有人需要用这个小工具,请在公众号回复dxf   获取链接。


至此,我们完成了shp文件转换为CAD文件。还有....


remote sensing
一个专注于测绘、地信、遥感的公众号
 最新文章