qgis_sync_compactage.py 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  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. debug = False
  22. # # POUR TESTER, décommenter les lignes suivantes
  23. ##-----------------------------------------------
  24. ControlesDb._path = Path(r"\\h2o\local\4-transversal\BDD\mdb_test\cg67Parc_data.mdb")
  25. CSigDb.server = "TR-POSTGIS-02"
  26. CSigDb.pwd = "Am5VOMkdFHU7WwrfVOs9"
  27. COMPACTAGE_DIR = Path(__file__).parent / "resources" / "test_qgis_sync_compactage"
  28. logger.handlers = [h for h in logger.handlers if (type(h) == logging.StreamHandler)]
  29. logger.warning("<<<<<<<<<<<<<< Mode TEST >>>>>>>>>>>>>>>>>")
  30. ##-----------------------------------------------
  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. rx = re.compile(r"^(I_)?(\d{5,6})(-S?\d{1,2})?[\s_]?(.*)$") # tous
  38. rxi = re.compile(r"^(\d{5,6})(-S?\d{1,2})?[\s_]?(.*)$") # non importés
  39. a_importer = [subdir for subdir in COMPACTAGE_DIR.dirs() if rxi.search(subdir.name)]
  40. if a_importer:
  41. a_importer = select_list_dialog.exec_(a_importer, lambda x: x.name, "Sélectionnez les chantiers à importer")
  42. if not a_importer:
  43. logger.info("Aucun nouveau dossier à importer")
  44. sys.exit()
  45. chantiers = []
  46. # ** Read the data in the shapefiles and store it in memory **
  47. for chantier_dir_path in a_importer:
  48. logger.info("** %s", chantier_dir_path)
  49. # instanciate a new Chantier
  50. chantier = QGisChantier()
  51. chantier.dir_path = chantier_dir_path
  52. logger.debug("> parse path")
  53. parsed = rx.search(chantier_dir_path.name)
  54. chantier.number = parsed.group(2)
  55. chantier.complement = parsed.group(3)
  56. logger.debug("> number: %s, compl: %s", chantier.number, chantier.complement)
  57. # query for name in ControlesDb
  58. logger.debug("> Query ControlesDb for chantier's name")
  59. row = controles_db.first("""SELECT tblChantiers.lngChantierId, tblCollectivites.strNom
  60. FROM tblChantiers INNER JOIN tblCollectivites
  61. ON tblChantiers.strCollectiviteId = tblCollectivites.strCollectiviteId
  62. WHERE lngChantierId = {lngChantierId};""".format(lngChantierId=chantier.number))
  63. chantier.name = "{} {}".format(chantier.number, row.strNom)
  64. logger.debug("> {}".format(chantier.name))
  65. # importe le fichier shape dans une couche temp
  66. shp_path = chantier_dir_path / "{}_p_PointCompactage.shp".format(chantier_dir_path.name)
  67. logger.debug("Read the shapefile: %s", shp_path)
  68. sf = shapefile.Reader(shp_path)
  69. # should we check? :
  70. if sf.shapeType != 1:
  71. logger.error("Le fichier shapefile n'est pas de type POINT")
  72. sys.exit(1)
  73. sh_points = sf.shapeRecords()
  74. if not sh_points:
  75. logger.error("Le fichier shapefile ne contient aucune donnees")
  76. sys.exit(1)
  77. chantier.points = []
  78. for sh_point in sh_points:
  79. # create the Point instance
  80. point = QGisPoint()
  81. point.number = sh_point.record[0]
  82. point.name = sh_point.record[1]
  83. point.x, point.y = sh_point.shape.points[0]
  84. logger.debug("> {}".format(point))
  85. chantier.points.append(point)
  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]) - 10
  89. chantier.x1 = max([point.x for point in chantier.points]) + 10
  90. chantier.y0 = min([point.y for point in chantier.points]) - 10
  91. chantier.y1 = max([point.y for point in chantier.points]) + 10
  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}, {geom}, {archive});
  137. """.format(
  138. number=point.number,
  139. name=point.name,
  140. chantier_id=chantier.pgid,
  141. geom="ST_GeomFromText('POINT({x} {y})', {srid})".format(x=point.x, y=point.y, srid=SRID),
  142. archive="FALSE"
  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("Chantier importé")
  154. csig_db.close()