qgis_sync_compactage.py 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  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. Sql = SqlFormatter()
  31. # Connexion à ControlesSig (postgres)
  32. csig_db = CSigDb(autocommit=False)
  33. # Connexion à Controles
  34. controles_db = ControlesDb(autocommit=False)
  35. # Regex pour parser les noms de repertoires
  36. rxi = re.compile(r"^(\d{5,6})([-_]S?\d*)?[\s_]?(.*)$") # non importés
  37. a_importer = [subdir for subdir in COMPACTAGE_DIR.dirs() if rxi.search(subdir.name)]
  38. if a_importer:
  39. a_importer = select_list_dialog.exec_(a_importer, lambda x: x.name, "Sélectionnez les chantiers à importer")
  40. if not a_importer:
  41. logger.info("Aucun nouveau dossier à importer")
  42. sys.exit()
  43. chantiers = []
  44. # ** Read the data in the shapefiles and store it in memory **
  45. for chantier_dir_path in a_importer:
  46. logger.info("** %s", chantier_dir_path)
  47. # instanciate a new Chantier
  48. chantier = QGisChantier()
  49. chantier.dir_path = chantier_dir_path
  50. logger.debug("> parse path")
  51. parsed = rxi.search(chantier_dir_path.name)
  52. chantier.number = parsed.group(1)
  53. chantier.complement = parsed.group(2).replace("_", "-") if parsed.group(2) else ""
  54. logger.debug("> number: %s, compl: %s", chantier.number, chantier.complement)
  55. # query for name in ControlesDb
  56. logger.debug("> Query ControlesDb for chantier's name")
  57. row = controles_db.first("""SELECT tblChantiers.lngChantierId, tblCollectivites.strNom
  58. FROM tblChantiers INNER JOIN tblCollectivites
  59. ON tblChantiers.strCollectiviteId = tblCollectivites.strCollectiviteId
  60. WHERE lngChantierId = {lngChantierId};""".format(lngChantierId=chantier.number))
  61. chantier.name = "{}{} {}".format(chantier.number, chantier.complement, row.strNom)
  62. logger.debug("> {}".format(chantier.name))
  63. # importe le fichier shape dans une couche temp
  64. shp_path = chantier_dir_path / "{}_p_PointCompactage.shp".format(chantier_dir_path.name)
  65. logger.debug("Read the shapefile: %s", shp_path)
  66. sf = shapefile.Reader(shp_path)
  67. # should we check? :
  68. if sf.shapeType != 1:
  69. logger.error("Le fichier shapefile n'est pas de type POINT")
  70. sys.exit(1)
  71. sh_points = sf.shapeRecords()
  72. if not sh_points:
  73. logger.error("Le fichier shapefile ne contient aucune donnees")
  74. sys.exit(1)
  75. chantier.points = []
  76. for sh_point in sh_points:
  77. # create the Point instance
  78. point = QGisPoint()
  79. point.number = sh_point.record[0]
  80. point.name = sh_point.record[1]
  81. point.x, point.y = sh_point.shape.points[0]
  82. logger.debug("> {}".format(point))
  83. chantier.points.append(point)
  84. del sf, sh_points
  85. # compute the chantier's rect coordinates
  86. logger.debug("Compute the chantier's rect coordinates")
  87. chantier.x0 = min([point.x for point in chantier.points]) - 5
  88. chantier.x1 = max([point.x for point in chantier.points]) + 5
  89. chantier.y0 = min([point.y for point in chantier.points]) - 5
  90. chantier.y1 = max([point.y for point in chantier.points]) + 5
  91. logger.debug("> ({}, {}, {}, {})".format(chantier.x0, chantier.x1, chantier.y0, chantier.y1))
  92. chantiers.append(chantier)
  93. # ** Insère les chantiers dans la base **
  94. for chantier in chantiers:
  95. logger.debug("** Chantier {}: {} points".format(chantier.name, len(chantier.points)))
  96. # Contrôle si un chantier de compactage portant ce nom n'existe pas déjà dans la base
  97. qry = csig_db.read(u"SELECT id FROM t_chantiers WHERE nom = '{}' AND id_type_chantier=2;".format(chantier.name))
  98. for row in qry:
  99. logger.warning("Un chantier de compactage portant ce nom existe déjà '{}' (id {})".format(chantier.name, row.id))
  100. if input("Voulez-vous le remplacer? (o/n)") == "o":
  101. # delete the old chantier
  102. csig_db.execute("""DELETE FROM t_points_compactage
  103. WHERE id_chantier = {};""".format(row.id))
  104. csig_db.execute("""DELETE FROM t_chantiers
  105. WHERE id = {};""".format(row.id))
  106. logger.info("> L'ancien chantier a été supprimé".format(chantier.name, row.id))
  107. else:
  108. logger.warning("Import du chantier annulé")
  109. continue
  110. # Créé le chantier
  111. q = csig_db.first("""INSERT INTO t_chantiers(id_type_chantier, numero, nom, geom, archive)
  112. VALUES ({chantier_type}, {number}, '{name}', {geom}, {archive})
  113. RETURNING id;
  114. """.format(
  115. chantier_type=2,
  116. number=chantier.number,
  117. name=chantier.name,
  118. geom="ST_GeomFromText('POLYGON(({x0} {y0}, \
  119. {x0} {y1}, {x1} {y1}, {x1} {y0}, {x0} {y0}))', {srid})".format(x0=chantier.x0,
  120. x1=chantier.x1,
  121. y0=chantier.y0,
  122. y1=chantier.y1,
  123. srid=SRID),
  124. archive="FALSE"
  125. )
  126. )
  127. # get its postgis ID
  128. logger.debug("Getting newly created ID")
  129. chantier.pgid = q.id
  130. logger.debug("> {}".format(chantier.pgid))
  131. q = None
  132. # create the points
  133. for point in chantier.points:
  134. csig_db.execute("""INSERT INTO t_points_compactage(numero, nom, id_chantier, geom, archive)
  135. VALUES ({number}, '{name}', {chantier_id}, ST_GeomFromText('POINT({x} {y})', {srid}), False);
  136. """.format(
  137. number=point.number,
  138. name=point.name,
  139. chantier_id=chantier.pgid,
  140. x=point.x,
  141. y=point.y,
  142. srid=SRID
  143. )
  144. )
  145. csig_db.commit()
  146. # rename the directory to mark it as imported ('I_')
  147. new_path = r"{}\I_{}".format(chantier.dir_path.parent, chantier.dir_path.name)
  148. logger.debug("Rename {} to {}".format(chantier.dir_path, new_path))
  149. try:
  150. chantier.dir_path.rename(new_path)
  151. except:
  152. logger.error("Impossible de renommer le dossier")
  153. logger.info("Le chantier %s a été importé", chantier.name)
  154. csig_db.close()
  155. controles_db.close()