qgis_sync_compactage.py 8.9 KB

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