rastertopostgislist.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. """
  2. ***************************************************************************
  3. ogr2ogrtopostgislist.py
  4. ---------------------
  5. Date : November 2012
  6. Copyright : (C) 2012 by Victor Olaya
  7. Email : volayaf at gmail dot com
  8. ***************************************************************************
  9. * *
  10. * This program is free software; you can redistribute it and/or modify *
  11. * it under the terms of the GNU General Public License as published by *
  12. * the Free Software Foundation; either version 2 of the License, or *
  13. * (at your option) any later version. *
  14. * *
  15. ***************************************************************************
  16. """
  17. __author__ = 'wanger'
  18. __date__ = 'November 2024'
  19. __copyright__ = '(C) 2024, wanger'
  20. import os
  21. import re
  22. from PyQt5.QtGui import QIcon
  23. from qgis._core import QgsProcessingParameterFile
  24. from qgis.core import (QgsProcessing,
  25. QgsProcessingParameterFeatureSource,
  26. QgsProcessingParameterRasterLayer,
  27. QgsProcessingParameterString,
  28. QgsProcessingParameterDateTime,
  29. QgsProcessingParameterEnum,
  30. QgsProcessingParameterCrs,
  31. QgsProcessingParameterField,
  32. QgsProcessingParameterExtent,
  33. QgsProcessingParameterBoolean,
  34. QgsProcessingParameterProviderConnection,
  35. QgsProcessingParameterDatabaseSchema,
  36. QgsProcessingParameterDatabaseTable,
  37. QgsProviderRegistry,
  38. QgsProcessingException,
  39. QgsCoordinateReferenceSystem,
  40. QgsProviderConnectionException,
  41. QgsDataSourceUri)
  42. from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
  43. from processing.algs.gdal.GdalUtils import GdalUtils
  44. from processing.tools.PrintUtils import printStr
  45. from processing.tools.PostgreSQL.PostgreSQL import PostgreSQL
  46. from processing.tools.system import isWindows
  47. from processing.tools.FileUtils import getInputFileName
  48. from processing.tools.StringUtils import getConnectionStr
  49. pluginPath = os.path.normpath(os.path.join(
  50. os.path.split(os.path.dirname(__file__))[0], os.pardir))
  51. class Ogr2PostGisList(GdalAlgorithm):
  52. DATABASE = 'DATABASE'
  53. INPUT = 'INPUT'
  54. SHAPE_ENCODING = 'SHAPE_ENCODING'
  55. GTYPE = 'GTYPE'
  56. GEOMTYPE = ['', 'NONE', 'GEOMETRY', 'POINT', 'LINESTRING', 'POLYGON', 'GEOMETRYCOLLECTION', 'MULTIPOINT',
  57. 'MULTIPOLYGON', 'MULTILINESTRING', 'CIRCULARSTRING', 'COMPOUNDCURVE', 'CURVEPOLYGON', 'MULTICURVE',
  58. 'MULTISURFACE']
  59. S_SRS = 'S_SRS'
  60. T_SRS = 'T_SRS'
  61. A_SRS = 'A_SRS'
  62. HOST = 'HOST'
  63. PORT = 'PORT'
  64. USER = 'USER'
  65. DBNAME = 'DBNAME'
  66. PASSWORD = 'PASSWORD'
  67. SCHEMA = 'SCHEMA'
  68. TABLE = 'TABLE'
  69. PK = 'PK'
  70. PRIMARY_KEY = 'PRIMARY_KEY'
  71. GEOCOLUMN = 'GEOCOLUMN'
  72. DIM = 'DIM'
  73. DIMLIST = ['2', '3', '4']
  74. SIMPLIFY = 'SIMPLIFY'
  75. SEGMENTIZE = 'SEGMENTIZE'
  76. SPAT = 'SPAT'
  77. CLIP = 'CLIP'
  78. WHERE = 'WHERE'
  79. GT = 'GT'
  80. OVERWRITE = 'OVERWRITE'
  81. APPEND = 'APPEND'
  82. ADDFIELDS = 'ADDFIELDS'
  83. LAUNDER = 'LAUNDER'
  84. INDEX = 'INDEX'
  85. SKIPFAILURES = 'SKIPFAILURES'
  86. PRECISION = 'PRECISION'
  87. PROMOTETOMULTI = 'PROMOTETOMULTI'
  88. OPTIONS = 'OPTIONS'
  89. # TODO 三亚项目新追加入库属性
  90. VECTOR_YEAR = 'VECTOR_YEAR'
  91. VECTOR_XZQH = 'VECTOR_XZQH'
  92. VECTOR_XMLX = 'VECTOR_XMLX'
  93. VECTOR_SJLY = 'VECTOR_SJLY'
  94. VECTOR_YWLX = 'VECTOR_YWLX'
  95. SOURCE_TYPE = 'SOURCE_TYPE'
  96. VECTOR_GLBM = 'VECTOR_GLBM'
  97. VECTOR_ZYML = 'VECTOR_ZYML'
  98. VECTOR_NODATA = 'VECTOR_NODATA'
  99. XZQH_FIELD = 'XZQH_FIELD'
  100. Metadata_storage = 'Metadata_storage'
  101. selectedValue = "selectedValue"
  102. Raster_T = "Raster_T"
  103. Raster_T_List = ['不分块', '128', '256', '512']
  104. def __init__(self):
  105. super().__init__()
  106. def initAlgorithm(self, config=None):
  107. # self.addParameter(QgsProcessingParameterFile(self.INPUT,
  108. # self.tr('栅格数据'),
  109. # optional=False, fileFilter='Tif files (*.tif *.tiff)', ))
  110. self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT,
  111. self.tr('栅格数据'),
  112. [QgsProcessing.TypeRaster]))
  113. db_param = QgsProcessingParameterProviderConnection(
  114. self.DATABASE,
  115. self.tr('数据库'), provider='postgres',
  116. defaultValue=self.pgcoon["host"])
  117. self.addParameter(db_param)
  118. schema_param = QgsProcessingParameterDatabaseSchema(
  119. self.SCHEMA,
  120. self.tr('模式'), defaultValue=self.pgcoon["schema"], connectionParameterName=self.DATABASE,
  121. optional=False)
  122. self.addParameter(schema_param)
  123. table_param = QgsProcessingParameterString(
  124. self.TABLE,
  125. self.tr('表名'), defaultValue="", optional=True)
  126. self.addParameter(table_param)
  127. # 数据来源
  128. self.addParameter(QgsProcessingParameterString(self.VECTOR_SJLY,
  129. self.tr('数据来源'), "",
  130. optional=False))
  131. self.addParameter(
  132. QgsProcessingParameterDateTime(self.VECTOR_YEAR, '数据时效', type=QgsProcessingParameterDateTime.Type.Date,
  133. defaultValue=None, optional=False))
  134. pgconn = PostgreSQL(schema='base')
  135. rows = pgconn.getVectorYwlx()
  136. self.ywlxs = []
  137. for row in rows:
  138. self.ywlxs.append(row[0])
  139. self.addParameter(QgsProcessingParameterEnum(name=self.VECTOR_YWLX,
  140. description=self.tr('业务类型'), options=self.ywlxs,
  141. optional=False))
  142. rows = pgconn.getDeptList()
  143. self.depts = []
  144. for row in rows:
  145. self.depts.append(row[0])
  146. self.addParameter(QgsProcessingParameterEnum(name=self.VECTOR_GLBM,
  147. description=self.tr('管理部门'), options=self.depts))
  148. # self.addParameter(QgsProcessingParameterString(self.VECTOR_XMLX,
  149. # self.tr('项目类型'), "",
  150. # optional=False))
  151. rows = pgconn.getVectorZyml()
  152. self.zymls = []
  153. for row in rows:
  154. self.zymls.append(row[1])
  155. self.addParameter(QgsProcessingParameterEnum(name=self.VECTOR_ZYML,
  156. description=self.tr('资源目录'), options=self.zymls))
  157. self.addParameter(QgsProcessingParameterString(self.VECTOR_NODATA,
  158. self.tr('无效值'), "0,0,0,0,0,0",
  159. optional=True))
  160. crs = QgsCoordinateReferenceSystem("EPSG:4525")
  161. crs_parameter = QgsProcessingParameterCrs(self.T_SRS,
  162. self.tr('指定入库坐标系'),
  163. defaultValue=crs,
  164. optional=False)
  165. self.addParameter(crs_parameter)
  166. self.addParameter(QgsProcessingParameterEnum(self.Raster_T,
  167. self.tr('分块存储大小,如栅格文件大于1G必须分块存储'),
  168. options=self.Raster_T_List,
  169. optional=False, defaultValue=3))
  170. string = QgsProcessingParameterString(self.SOURCE_TYPE,
  171. self.tr('数据源类型'), "raster",
  172. optional=False)
  173. # string.setFlags(QgsProcessingParameterString.FlagReadOnly)
  174. self.addParameter(string)
  175. metadata = QgsProcessingParameterBoolean(self.Metadata_storage,
  176. self.tr('元数据入库'), defaultValue=True)
  177. # metadata.setEnable(False)
  178. self.addParameter(metadata)
  179. self.addParameter(QgsProcessingParameterBoolean(self.INDEX,
  180. self.tr('不创建数据索引'), defaultValue=False))
  181. pgconn.close()
  182. def name(self):
  183. return 'importrasterintopostgisdatabase'
  184. def icon(self):
  185. return QIcon(os.path.join(pluginPath, 'images', 'dbms', 'importimage.png'))
  186. def displayName(self):
  187. return self.tr('栅格数据入库')
  188. def shortDescription(self):
  189. return self.tr('栅格数据入库')
  190. def tags(self):
  191. t = self.tr('import,into,postgis,database,raster').split(',')
  192. t.extend(super().tags())
  193. return t
  194. def group(self):
  195. return self.tr('数据入库工具')
  196. def groupId(self):
  197. return 'vector2postgis'
  198. def setSelectedValue(self, v):
  199. printStr(v)
  200. self.selectedValue = v
  201. def getSelectedValue(self):
  202. return self.selectedValue
  203. def getConsoleCommands(self, parameters, context, feedback, executing=True):
  204. connection_name = self.parameterAsConnectionName(parameters, self.DATABASE, context)
  205. if not connection_name:
  206. raise QgsProcessingException(
  207. self.tr('No connection specified'))
  208. try:
  209. md = QgsProviderRegistry.instance().providerMetadata('postgres')
  210. conn = md.createConnection(connection_name)
  211. except QgsProviderConnectionException:
  212. raise QgsProcessingException(
  213. self.tr('Could not retrieve connection details for {}').format(connection_name))
  214. uri = conn.uri()
  215. # 获取输入栅格图层
  216. raster_layer = self.parameterAsRasterLayer(parameters, self.INPUT, context)
  217. file = raster_layer.source()
  218. print(file)
  219. # file = self.parameterAsString(parameters, self.INPUT, context)
  220. tsrs = self.parameterAsCrs(parameters, self.T_SRS, context)
  221. table = self.parameterAsDatabaseTableName(parameters, self.TABLE, context)
  222. schema = self.parameterAsSchema(parameters, self.SCHEMA, context)
  223. nodata = self.parameterAsString(parameters, self.VECTOR_NODATA, context)
  224. arguments = []
  225. if tsrs.isValid():
  226. arguments.append('-s')
  227. arguments.append(GdalUtils.gdal_crs_string(tsrs).replace("EPSG:", ""))
  228. # 创建索引
  229. index = self.parameterAsBoolean(parameters, self.INDEX, context)
  230. if index == False:
  231. arguments.append('-I')
  232. # 分块存储
  233. t = self.parameterAsInt(parameters, self.Raster_T, context)
  234. if t > 0:
  235. arguments.append('-t')
  236. tv = self.Raster_T_List[t]
  237. arguments.append(tv + 'x' + tv)
  238. # raster2pgsql -s 4326 -t 256x256 -I -C -M D:\gisdata\HEBEI\HebeiDEM.tif gis.tif | psql -h localhost -p 5432 -U postgres -d webgistest -W
  239. # nodata
  240. if nodata != "":
  241. arguments.append('-N {}'.format(nodata))
  242. arguments.append('-C -M')
  243. if len(table) == 0:
  244. table = f'{schema}.{getInputFileName(file)}'
  245. else:
  246. table = f'{schema}.{table}'
  247. arguments.append(f'"{file}"')
  248. arguments.append(f'"{table}"')
  249. # postgis相关
  250. arguments.append('|')
  251. arguments.append('psql')
  252. connection_parts = QgsDataSourceUri(uri).connectionInfo(executing).split(' ')
  253. print(connection_parts)
  254. arguments.append(f'-d {getConnectionStr(connection_parts, 0)}')
  255. arguments.append(f'-h {getConnectionStr(connection_parts, 1)}')
  256. arguments.append(f'-p {getConnectionStr(connection_parts, 2)}')
  257. arguments.append(f'-U {getConnectionStr(connection_parts, 3)}')
  258. # TODO wanger 配置postgresql数据库密码
  259. # TODO wanger -W表示需要再次输入密码
  260. # TODO wanger 不加则需要将pg密码配置到系统环境变量 PGPASSWORD
  261. # arguments.append('-W')
  262. # return ['ogrinfo D:\gisdata\HaiNanXZQ\XZQH3857.shp']
  263. if isWindows():
  264. return ['cmd.exe', '/C ', 'raster2pgsql.exe',
  265. self.escapeAndJoin(arguments)]
  266. else:
  267. return ['raster2pgsql', self.escapeAndJoin(arguments)]
  268. def escapeAndJoin(self, strList):
  269. escChars = [' ', '&', '(', ')', '"', ';']
  270. joined = ''
  271. for s in strList:
  272. if not isinstance(s, str):
  273. s = str(s)
  274. # don't escape if command starts with - and isn't a negative number, e.g. -9999
  275. if s and re.match(r'^([^-]|-\d)', s) and any(c in s for c in escChars):
  276. escaped = s
  277. # escaped = '"' + s.replace('\\', '\\\\').replace('"', '"""') \
  278. # + '"'
  279. else:
  280. escaped = s
  281. if escaped is not None:
  282. joined += escaped + ' '
  283. return joined.strip()
  284. def commandName(self):
  285. return "raster2pgsql"