A03.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. # -*- coding: utf-8 -*-
  2. """
  3. ***************************************************************************
  4. A03.py
  5. ---------------------
  6. Date : November 2012
  7. Copyright : (C) 2012 by Victor Olaya
  8. Email : volayaf at gmail dot com
  9. ***************************************************************************
  10. * *
  11. * This program is free software; you can redistribute it and/or modify *
  12. * it under the terms of the GNU General Public License as published by *
  13. * the Free Software Foundation; either version 2 of the License, or *
  14. * (at your option) any later version. *
  15. * *
  16. ***************************************************************************
  17. """
  18. __author__ = 'wanger'
  19. __date__ = 'November 2024'
  20. __copyright__ = '(C) 2024, wanger'
  21. import os
  22. from PyQt5.QtSql import QSqlDatabase, QSqlQuery
  23. from osgeo import ogr, gdal
  24. from PyQt5.QtGui import QIcon
  25. from PyQt5.QtWidgets import QApplication
  26. from future.moves import sys
  27. from qgis.PyQt import QtWidgets
  28. from qgis._core import QgsProcessingParameterVectorDestination, QgsVectorLayer, QgsVectorFileWriter, \
  29. QgsCoordinateTransformContext
  30. from qgis.core import (QgsProcessing,
  31. QgsProcessingParameterFeatureSource,
  32. QgsProcessingParameterString,
  33. QgsProcessingParameterFile,
  34. QgsProcessingParameterDateTime,
  35. QgsProcessingParameterEnum,
  36. QgsProcessingParameterCrs,
  37. QgsProcessingParameterField,
  38. QgsProcessingParameterExtent,
  39. QgsProcessingParameterBoolean,
  40. QgsProcessingParameterProviderConnection,
  41. QgsProcessingParameterDatabaseSchema,
  42. QgsProcessingParameterDatabaseTable,
  43. QgsProviderRegistry,
  44. QgsProcessingException,
  45. QgsProcessingParameterDefinition,
  46. QgsProviderConnectionException,
  47. QgsDataSourceUri)
  48. from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
  49. from processing.algs.gdal.GdalUtils import GdalUtils
  50. from processing.tools.PrintUtils import printStr
  51. from processing.tools.StringUtils import (getConnectionStr, getNow)
  52. from processing.tools.GeoServer.Geoserver import Geoserver
  53. from processing.tools.PostgreSQL.PostgreSQL import PostgreSQL
  54. from processing.tools.system import isWindows
  55. from processing.tools.FileUtils import getParentFolderPath
  56. from processing.tools.topology.read import (getTopoCheckSQL, getTopoCheckDescription, getTopoCheckNote)
  57. import sqlite3
  58. pluginPath = os.path.normpath(os.path.join(
  59. os.path.split(os.path.dirname(__file__))[0], os.pardir))
  60. gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES")
  61. gdal.SetConfigOption("SHAPE_ENCODING", "GBK")
  62. class A03(GdalAlgorithm):
  63. INPUTVECTOR = "INPUTVECTOR"
  64. OUTPUTVECTOR = 'OUTPUTVECTOR'
  65. TOPOLOGYTYPE = "A03"
  66. in_table = "topology_table"
  67. out_table = "topology_table_temp"
  68. TOPOLOGYPARAMS = {
  69. "intable_s": in_table,
  70. "outtable": out_table
  71. }
  72. def __init__(self):
  73. super().__init__()
  74. def initAlgorithm(self, config=None):
  75. self.addParameter(QgsProcessingParameterFeatureSource(self.INPUTVECTOR,
  76. self.tr('待检查数据'),
  77. types=[QgsProcessing.TypeVectorPolygon]))
  78. self.addParameter(QgsProcessingParameterVectorDestination(self.OUTPUTVECTOR,
  79. self.tr('输出位置(矢量数据和报告)')))
  80. def name(self):
  81. return 'A03'
  82. def icon(self):
  83. return QIcon(os.path.join(pluginPath, 'images', 'dbms', 'topology.png'))
  84. def displayName(self):
  85. return self.tr(getTopoCheckNote(self.TOPOLOGYTYPE))
  86. def shortDescription(self):
  87. return self.tr(getTopoCheckDescription(self.TOPOLOGYTYPE))
  88. def tags(self):
  89. t = self.tr('import,into,postgis,database,vector').split(',')
  90. t.extend(super().tags())
  91. return t
  92. def group(self):
  93. return self.tr('拓扑检查')
  94. def groupId(self):
  95. return 'topology'
  96. def topologycheck(self, parameters, context, feedback, executing=True):
  97. print("面不能有空隙检查开始啦")
  98. # TODO 参数设置
  99. spatialite_db_path = self.spatialite_db_path # Spatialite 数据库路径
  100. table_name = self.in_table # 导入后的表名
  101. outtable_name = self.out_table # 分析执行后的表名
  102. output_vector_path = self.parameterAsOutputLayer(parameters, self.OUTPUTVECTOR, context) # 输出的 SHP 文件路径
  103. export_layer_name = outtable_name
  104. # TODO 将 vectorlayer导入到Spatialite
  105. input_layer = self.parameterAsVectorLayer(parameters, self.INPUTVECTOR, context)
  106. if not input_layer.isValid():
  107. return {
  108. "状态": "拓扑检查失败",
  109. "错误信息": f"Failed to load SHP file."
  110. }
  111. crs = input_layer.crs().authid()
  112. # TODO 构造连接到Spatialite数据库的URI
  113. uri = QgsDataSourceUri()
  114. uri.setDatabase(spatialite_db_path)
  115. # TODO 将vectorlayer写入Spatialite 数据库
  116. options = QgsVectorFileWriter.SaveVectorOptions()
  117. options.driverName = "SQLite"
  118. options.layerName = table_name
  119. options.fileEncoding = "UTF-8"
  120. options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteLayer
  121. # TODO 将QgsVectorLayer导入到spatialite并指定表名
  122. result = QgsVectorFileWriter.writeAsVectorFormatV2(input_layer, spatialite_db_path,
  123. QgsCoordinateTransformContext(), options)
  124. if result[0] != QgsVectorFileWriter.NoError:
  125. return {
  126. "状态": "拓扑检查失败",
  127. "错误信息": f"Failed to import SHP file to Spatialite."
  128. }
  129. print(f"SHP file imported to Spatialite as table: {table_name}")
  130. # TODO 执行 SQL 语句
  131. conn = sqlite3.connect(spatialite_db_path)
  132. conn.enable_load_extension(True)
  133. cursor = conn.cursor()
  134. conn.execute("PRAGMA synchronous = OFF")
  135. conn.execute("PRAGMA cache_size = -20000") # In KB
  136. conn.execute("PRAGMA temp_store = MEMORY")
  137. try:
  138. conn.execute("SELECT load_extension('mod_spatialite');")
  139. print("mod_spatialite loaded successfully.")
  140. except sqlite3.OperationalError as e:
  141. return {
  142. "状态": "拓扑检查失败",
  143. "错误信息": f"Failed to load extension: {e}"
  144. }
  145. # TODO SQL语句
  146. sql = getTopoCheckSQL(self.TOPOLOGYTYPE, self.TOPOLOGYPARAMS)
  147. try:
  148. cursor.executescript(f"{sql}")
  149. print(f"Script executed successfully.{sql}")
  150. except sqlite3.Error as e:
  151. return {
  152. "状态": "拓扑检查失败",
  153. "错误信息": f"An error occurred: {e}"
  154. }
  155. conn.commit()
  156. conn.close()
  157. print("SQL execution completed.")
  158. # TODO 将数据导出为本地矢量文件
  159. processed_layer = QgsVectorLayer(f"{spatialite_db_path}|layername={export_layer_name}", "processed_layer",
  160. "ogr")
  161. path = getParentFolderPath(output_vector_path)
  162. csv_path = f"{path}\\report.csv"
  163. if not processed_layer.isValid():
  164. return {
  165. "状态": "拓扑检查失败",
  166. "错误信息": "Failed to load processed layer."
  167. }
  168. else:
  169. options = QgsVectorFileWriter.SaveVectorOptions()
  170. options.driverName = "CSV" # Output format
  171. options.includeGeometry = True # Include geometry
  172. # options.setLayerOptions(QgsVectorFileWriter.LayerOptions())
  173. # context = QgsCoordinateTransformContext()
  174. # options.setOutputWkt(True)
  175. context2 = QgsCoordinateTransformContext()
  176. error = QgsVectorFileWriter.writeAsVectorFormatV3(processed_layer, csv_path, context2, options)
  177. if error[0] == QgsVectorFileWriter.NoError:
  178. print(f"Exported {table_name} to {csv_path} successfully!")
  179. else:
  180. return {
  181. "状态": "拓扑检查失败",
  182. "错误信息": f"Failed to export {table_name} to CSV: {error}"
  183. }
  184. # TODO 导出矢量文件参数配置
  185. export_options = QgsVectorFileWriter.SaveVectorOptions()
  186. export_options.driverName = "ESRI Shapefile"
  187. export_options.fileEncoding = "UTF-8"
  188. result = QgsVectorFileWriter.writeAsVectorFormatV2(processed_layer, output_vector_path,
  189. QgsCoordinateTransformContext(), export_options)
  190. if result[0] != QgsVectorFileWriter.NoError:
  191. return {
  192. "状态": "拓扑检查失败",
  193. "错误信息": f"Failed to export processed layer to SHP file."
  194. }
  195. feature_count = processed_layer.featureCount()
  196. return {
  197. "状态": "拓扑检查成功",
  198. "结论": "不符合" if feature_count > 0 else "符合",
  199. "错误项": f"{feature_count}条记录",
  200. # "矢量数据输出位置": output_vector_path,
  201. "报告输出位置": csv_path
  202. }
  203. # 判断数据是否为字符串
  204. def is_string(self, var):
  205. return isinstance(var, str)
  206. def getConsoleCommands(self, parameters, context, feedback, executing=True):
  207. inputvector = self.parameterAsVectorLayer(parameters, self.INPUTVECTOR, context)
  208. print(f"拓扑检查输入矢量图层:")
  209. print(inputvector)
  210. outFile = self.parameterAsOutputLayer(parameters, self.OUTPUTVECTOR, context)
  211. print(f"拓扑检查输出文件:{outFile}")
  212. return []
  213. def contains_keys(self, obj, keys):
  214. if isinstance(obj, dict):
  215. return all(key in obj.keys() for key in keys)
  216. elif hasattr(type(obj), '__dict__'):
  217. return all(key in obj.__dict__ for key in keys)
  218. else:
  219. raise ValueError("Invalid object type")
  220. def commandName(self):
  221. return "ogr2ogr"