qgis_sync_compactage.py 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  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. 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. # TODO: Selection des chantiers à importer
  40. pass
  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 = rx.search(chantier_dir_path.name)
  53. chantier.number = parsed.group(2)
  54. chantier.complement = parsed.group(3)
  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, 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. # 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])
  88. chantier.x1 = max([point.x for point in chantier.points])
  89. chantier.y0 = min([point.y for point in chantier.points])
  90. chantier.y1 = max([point.y for point in chantier.points])
  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 portant ce nom n'existe pas déjà dans la base
  97. row = csig_db.first(u"SELECT id FROM t_chantiers WHERE nom = '{}';".format(chantier.name))
  98. if row:
  99. logger.warning("Un chantier 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}, {geom}, {archive});
  136. """.format(
  137. number=point.number,
  138. name=point.name,
  139. chantier_id=chantier.pgid,
  140. geom="ST_GeomFromText('POINT({x} {y})', {srid})".format(x=point.x, y=point.y, srid=SRID),
  141. archive="FALSE"
  142. )
  143. )
  144. csig_db.commit()
  145. # rename the directory to mark it as imported ('I_')
  146. new_path = r"{}\I_{}".format(chantier.dir_path.parent, chantier.dir_path.name)
  147. logger.debug("Rename {} to {}".format(chantier.dir_path, new_path))
  148. if not debug:
  149. try:
  150. chantier.dir_path.rename(new_path)
  151. except:
  152. logger.error("Impossible de renommer le dossier")
  153. logger.info("Chantier importé")