qgis_sync_compactage.py 7.6 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. debug = True
  26. logger.handlers = [h for h in logger.handlers if (type(h) == logging.StreamHandler)]
  27. logger.warning("<<<<<<<<<<<<<< Mode TEST >>>>>>>>>>>>>>>>>")
  28. ##-----------------------------------------------
  29. Sql = SqlFormatter()
  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. rx = re.compile(r"^(I_)?(\d{5,6})(-S?\d{1,2})?[\s_]?(.*)$") # tous
  36. rxi = re.compile(r"^(\d{5,6})(-S?\d{1,2})?[\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 = rx.search(chantier_dir_path.name)
  52. chantier.number = parsed.group(2)
  53. chantier.complement = parsed.group(3)
  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, 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. # compute the chantier's rect coordinates
  85. logger.debug("Compute the chantier's rect coordinates")
  86. chantier.x0 = min([point.x for point in chantier.points])
  87. chantier.x1 = max([point.x for point in chantier.points])
  88. chantier.y0 = min([point.y for point in chantier.points])
  89. chantier.y1 = max([point.y for point in chantier.points])
  90. logger.debug("> ({}, {}, {}, {})".format(chantier.x0, chantier.x1, chantier.y0, chantier.y1))
  91. chantiers.append(chantier)
  92. # ** Insère les chantiers dans la base **
  93. for chantier in chantiers:
  94. logger.debug("** Chantier {}: {} points".format(chantier.name, len(chantier.points)))
  95. # Contrôle si un chantier portant ce nom n'existe pas déjà dans la base
  96. row = csig_db.first(u"SELECT id FROM t_chantiers WHERE nom = '{}';".format(chantier.name))
  97. if row:
  98. logger.warning("Un chantier portant ce nom existe déjà {} (id {})".format(chantier.name, row.id))
  99. if input("Voulez-vous le remplacer? (o/n)") == "o":
  100. # delete the old chantier
  101. csig_db.execute("""DELETE FROM t_points_compactage
  102. WHERE id_chantier = {};""".format(row.id))
  103. csig_db.execute("""DELETE FROM t_chantiers
  104. WHERE id = {};""".format(row.id))
  105. logger.info("> L'ancien chantier a été supprimé".format(chantier.name, row.id))
  106. else:
  107. logger.warning("Import du chantier annulé")
  108. continue
  109. # Créé le chantier
  110. q = csig_db.first("""INSERT INTO t_chantiers(id_type_chantier, numero, nom, geom, archive)
  111. VALUES ({chantier_type}, {number}, '{name}', {geom}, {archive})
  112. RETURNING id;
  113. """.format(
  114. chantier_type=2,
  115. number=chantier.number,
  116. name=chantier.name,
  117. geom="ST_GeomFromText('POLYGON(({x0} {y0}, \
  118. {x0} {y1}, {x1} {y1}, {x1} {y0}, {x0} {y0}))', {srid})".format(x0=chantier.x0,
  119. x1=chantier.x1,
  120. y0=chantier.y0,
  121. y1=chantier.y1,
  122. srid=SRID),
  123. archive="FALSE"
  124. )
  125. )
  126. # get its postgis ID
  127. logger.debug("Getting newly created ID")
  128. chantier.pgid = q.id
  129. logger.debug("> {}".format(chantier.pgid))
  130. q = None
  131. # create the points
  132. for point in chantier.points:
  133. csig_db.execute("""INSERT INTO t_points_compactage(numero, nom, id_chantier, geom, archive)
  134. VALUES ({number}, '{name}', {chantier_id}, {geom}, {archive});
  135. """.format(
  136. number=point.number,
  137. name=point.name,
  138. chantier_id=chantier.pgid,
  139. geom="ST_GeomFromText('POINT({x} {y})', {srid})".format(x=point.x, y=point.y, srid=SRID),
  140. archive="FALSE"
  141. )
  142. )
  143. csig_db.commit()
  144. # rename the directory to mark it as imported ('I_')
  145. new_path = r"{}\I_{}".format(chantier.dir_path.parent, chantier.dir_path.name)
  146. logger.debug("Rename {} to {}".format(chantier.dir_path, new_path))
  147. if not debug:
  148. try:
  149. chantier.dir_path.rename(new_path)
  150. except:
  151. logger.error("Impossible de renommer le dossier")
  152. logger.info("Chantier importé")