qgis_sync_compactage.py 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. """
  2. Importe les données géographiques des essais de compactage depuis les fichiers Shapefile
  3. recus des exploitants vers la base Postgis de ControlesSig
  4. - Ajoute de nouveaux chantiers / points de compactage à la base POSTGIS
  5. - Les chantiers créés sont issus des dossiers du répertoire 'compactage_dir'
  6. - Une fois importés, ces dossiers sont renommés 'XXXXXX' > 'I_XXXXXX'
  7. - Les noms complets des chantiers sont récupérés dans la base Controles
  8. @author: olivier.massot, mai 2018
  9. """
  10. import logging
  11. import re
  12. import sys
  13. from path import Path
  14. import shapefile
  15. from core import logconf, select_list_dialog
  16. from core.pde import ControlesDb, CSigDb, COMPACTAGE_DIR, QGisChantier, \
  17. QGisPoint, SRID
  18. from core.sqlformatter import SqlFormatter
  19. logger = logging.getLogger("qgis_sync_compactage")
  20. logconf.start("qgis_sync_compactage", logging.DEBUG)
  21. # # POUR TESTER, décommenter les lignes suivantes
  22. ##-----------------------------------------------
  23. # ControlesDb._path = Path(r"\\h2o\local\4-transversal\BDD\mdb_test\cg67Parc_data.mdb")
  24. # CSigDb.server = "TR-POSTGIS-02"
  25. # CSigDb.pwd = "Am5VOMkdFHU7WwrfVOs9"
  26. # COMPACTAGE_DIR = Path(__file__).parent / "resources" / "test_qgis_sync_compactage"
  27. # logger.handlers = [h for h in logger.handlers if (type(h) == logging.StreamHandler)]
  28. # logger.warning("<<<<<<<<<<<<<< Mode TEST >>>>>>>>>>>>>>>>>")
  29. ##-----------------------------------------------
  30. def main():
  31. Sql = SqlFormatter()
  32. # Connexion à ControlesSig (postgres)
  33. csig_db = CSigDb(autocommit=False)
  34. # Connexion à Controles
  35. controles_db = ControlesDb(autocommit=False)
  36. # Regex pour parser les noms de repertoires
  37. rxi = re.compile(r"^(\d{5,6})([-_]S?\d*)?[\s_]?(.*)$") # non importés
  38. a_importer = [subdir for subdir in COMPACTAGE_DIR.dirs() if rxi.search(subdir.name)]
  39. if a_importer:
  40. a_importer = select_list_dialog.exec_(a_importer, lambda x: x.name, "Sélectionnez les chantiers à importer")
  41. if not a_importer:
  42. logger.info("Aucun nouveau dossier à importer")
  43. sys.exit()
  44. chantiers = []
  45. # ** Read the data in the shapefiles and store it in memory **
  46. for chantier_dir_path in a_importer:
  47. logger.info("** %s", chantier_dir_path)
  48. # instanciate a new Chantier
  49. chantier = QGisChantier()
  50. chantier.dir_path = chantier_dir_path
  51. logger.debug("> parse path")
  52. parsed = rxi.search(chantier_dir_path.name)
  53. chantier.number = parsed.group(1)
  54. chantier.complement = parsed.group(2).replace("_", "-") if parsed.group(2) else ""
  55. logger.debug("> number: %s, compl: %s", chantier.number, chantier.complement)
  56. # query for name in ControlesDb
  57. logger.debug("> Query ControlesDb for chantier's name")
  58. row = controles_db.first("""SELECT tblChantiers.lngChantierId, tblCollectivites.strNom
  59. FROM tblChantiers INNER JOIN tblCollectivites
  60. ON tblChantiers.strCollectiviteId = tblCollectivites.strCollectiviteId
  61. WHERE lngChantierId = {lngChantierId};""".format(lngChantierId=chantier.number))
  62. chantier.name = "{}{} {}".format(chantier.number, chantier.complement, row.strNom)
  63. logger.debug("> {}".format(chantier.name))
  64. # importe le fichier shape dans une couche temp
  65. shp_path = chantier_dir_path / "{}_p_PointCompactage.shp".format(chantier_dir_path.name)
  66. logger.debug("Read the shapefile: %s", shp_path)
  67. sf = shapefile.Reader(shp_path)
  68. # should we check? :
  69. if sf.shapeType != 1:
  70. logger.error("Le fichier shapefile n'est pas de type POINT")
  71. sys.exit(1)
  72. sh_points = sf.shapeRecords()
  73. if not sh_points:
  74. logger.error("Le fichier shapefile ne contient aucune donnees")
  75. sys.exit(1)
  76. chantier.points = []
  77. for sh_point in sh_points:
  78. # create the Point instance
  79. point = QGisPoint()
  80. point.number = sh_point.record[0]
  81. point.name = sh_point.record[1]
  82. point.x, point.y = sh_point.shape.points[0]
  83. logger.debug("> {}".format(point))
  84. chantier.points.append(point)
  85. del sf, sh_points
  86. # compute the chantier's rect coordinates
  87. logger.debug("Compute the chantier's rect coordinates")
  88. chantier.x0 = min([point.x for point in chantier.points]) - 5
  89. chantier.x1 = max([point.x for point in chantier.points]) + 5
  90. chantier.y0 = min([point.y for point in chantier.points]) - 5
  91. chantier.y1 = max([point.y for point in chantier.points]) + 5
  92. logger.debug("> ({}, {}, {}, {})".format(chantier.x0, chantier.x1, chantier.y0, chantier.y1))
  93. chantiers.append(chantier)
  94. # ** Insère les chantiers dans la base **
  95. for chantier in chantiers:
  96. logger.debug("** Chantier {}: {} points".format(chantier.name, len(chantier.points)))
  97. # Contrôle si un chantier de compactage portant ce nom n'existe pas déjà dans la base
  98. qry = csig_db.read(u"SELECT id FROM t_chantiers WHERE nom = '{}' AND id_type_chantier=2;".format(chantier.name))
  99. for row in qry:
  100. logger.warning("Un chantier de compactage portant ce nom existe déjà '{}' (id {})".format(chantier.name, row.id))
  101. if input("Voulez-vous le remplacer? (o/n)") == "o":
  102. # delete the old chantier
  103. csig_db.execute("""DELETE FROM t_points_compactage
  104. WHERE id_chantier = {};""".format(row.id))
  105. csig_db.execute("""DELETE FROM t_chantiers
  106. WHERE id = {};""".format(row.id))
  107. logger.info("> L'ancien chantier a été supprimé".format(chantier.name, row.id))
  108. else:
  109. logger.warning("Import du chantier annulé")
  110. continue
  111. # Créé le chantier
  112. q = csig_db.first("""INSERT INTO t_chantiers(id_type_chantier, numero, nom, geom, archive)
  113. VALUES ({chantier_type}, {number}, '{name}', {geom}, {archive})
  114. RETURNING id;
  115. """.format(
  116. chantier_type=2,
  117. number=chantier.number,
  118. name=chantier.name,
  119. geom="ST_GeomFromText('POLYGON(({x0} {y0}, \
  120. {x0} {y1}, {x1} {y1}, {x1} {y0}, {x0} {y0}))', {srid})".format(x0=chantier.x0,
  121. x1=chantier.x1,
  122. y0=chantier.y0,
  123. y1=chantier.y1,
  124. srid=SRID),
  125. archive="FALSE"
  126. )
  127. )
  128. # get its postgis ID
  129. logger.debug("Getting newly created ID")
  130. chantier.pgid = q.id
  131. logger.debug("> {}".format(chantier.pgid))
  132. q = None
  133. # create the points
  134. for point in chantier.points:
  135. csig_db.execute("""INSERT INTO t_points_compactage(numero, nom, id_chantier, geom, archive)
  136. VALUES ({number}, '{name}', {chantier_id}, ST_GeomFromText('POINT({x} {y})', {srid}), False);
  137. """.format(
  138. number=point.number,
  139. name=point.name,
  140. chantier_id=chantier.pgid,
  141. x=point.x,
  142. y=point.y,
  143. srid=SRID
  144. )
  145. )
  146. csig_db.commit()
  147. # rename the directory to mark it as imported ('I_')
  148. new_path = r"{}\I_{}".format(chantier.dir_path.parent, chantier.dir_path.name)
  149. logger.debug("Rename {} to {}".format(chantier.dir_path, new_path))
  150. try:
  151. chantier.dir_path.rename(new_path)
  152. except:
  153. logger.error("Impossible de renommer le dossier")
  154. logger.info("Le chantier %s a été importé", chantier.name)
  155. csig_db.close()
  156. controles_db.close()
  157. if __name__ == "__main__":
  158. main()
  159. logger.info("-- Fin --")