Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor export vecteur #386

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/lint-python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ jobs:

- name: Analysing the code with pylint
run: |
pylint scripts/update_cache.py scripts/create_cache.py scripts/cache.py scripts/cache_def.py scripts/export_mtd.py scripts/prep_vectorise_graph.py scripts/vectorise_graph.py scripts/create_qgis_view.py scripts/process_requests.py scripts/process_qlayers.py
pylint scripts/update_cache.py scripts/create_cache.py scripts/cache.py scripts/cache_def.py scripts/export_mtd.py scripts/export_graph/prep_vectorise_graph.py scripts/export_graph/vectorise_graph.py scripts/export_graph/export_graph.py scripts/create_qgis_view.py scripts/process_requests.py scripts/process_qlayers.py

continue-on-error: true

- name: Analysing the code with flake8
run: |
flake8 --max-line-length 100 scripts/update_cache.py scripts/create_cache.py scripts/cache.py scripts/cache_def.py scripts/export_mtd.py scripts/prep_vectorise_graph.py scripts/vectorise_graph.py scripts/create_qgis_view.py scripts/process_requests.py scripts/process_qlayers.py
flake8 --max-line-length 100 scripts/update_cache.py scripts/create_cache.py scripts/cache.py scripts/cache_def.py scripts/export_mtd.py scripts/export_graph/prep_vectorise_graph.py scripts/export_graph/vectorise_graph.py scripts/export_graph/export_graph.py scripts/create_qgis_view.py scripts/process_requests.py scripts/process_qlayers.py
76 changes: 17 additions & 59 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -492,87 +492,45 @@ gdal_translate "WMTS:http://[serveur]:[port]/[idBranch]/wmts?SERVICE=WMTS&REQUES
gdal_translate -of Jpeg ortho.xml ortho.jpg
````


## Export d'un graphe vecteur à partir d'un cache


Le traitement permettant d'exporter un graphe vecteur à partir d'un cache PackO est divisé en deux parties :
- une première partie pour créer les paramétrages pour les traitements qui sont parallélisables (fichier JSON compatible avec le service gpao de l'IGN) : ***prep_vectorise_graph.py***
- une deuxième partie qui permet d'exécuter tous les traitements parallélisables via le service gpao de l'IGN : ***vectorise_graph.py***

Pour le bon fonctionnement du script *prep_vectorise_graph.py*, il est impératif de mettre la variable d'environnement **GDAL_VRT_ENABLE_PYTHON** à **YES** avant de le lancer.
Le traitement permettant d'exporter un graphe vecteur à partir d'un cache PackO est le script *export_graph.py*.
Ce script va générer un fichier json utilisable par le service de gpao de l'IGN.
Pour le bon fonctionnement de ce script, il est impératif de mettre la variable d'environnement **GDAL_VRT_ENABLE_PYTHON** à **YES** avant de le lancer.

````
usage: prep_vectorise_graph.py [-h] -i INPUT -o OUTPUT [-b BRANCH] -p PATCHES [-t TILESIZE] [-v VERBOSE]
usage: export_graph.py [-h] -c CACHE -o OUTPUT -b BRANCH [-u URL] [-t TILESIZE] [--bbox BBOX BBOX BBOX BBOX] [--shapefile SHAPEFILE] [-v VERBOSE]

optional arguments:
-h, --help show this help message and exit
-i INPUT, --input INPUT
input cache folder
-c CACHE, --cache CACHE
path of input cache
-o OUTPUT, --output OUTPUT
output folder
-b BRANCH, --branch BRANCH
id of branch of cache to use as source for patches (default: None)
-p PATCHES, --patches PATCHES
file containing patches on the branch to export
id of branch of cache to use as source for patches
-u URL, --url URL http://[serveur]:[port] (default: http://localhost:8081)
-t TILESIZE, --tilesize TILESIZE
tile size (in pixels) for vectorising graph tiles (default: 100000)
tile size (in pixels) for vectorising graph tiles (default: 5000)
--bbox BBOX BBOX BBOX BBOX
bbox for export (in meters), xmin ymin xmax ymax
--shapefile SHAPEFILE
filepath of shapefile containing extent of export
-v VERBOSE, --verbose VERBOSE
verbose (default: 0)
````

La variable "-b" est optionnelle. Si elle n'est pas donnée, alors elle prend la valeur de la branche du fichier json d'export de retouches dans le cas où des retouches ont été effectuées, sinon le calcul se fait sur le graphe initial.

A l'heure actuelle, il faut utiliser des chemins absolus pour que le script fonctionne correctement.

Il est nécessaire de recourir à l'API pour pouvoir renseigner deux de ces informations :
- l'id de la branche à partir de laquelle on souhaite exporter le graphe vecteur.
- et le résultat de la route GET /{idBranch}/patches sur celle-ci (au format json).
Les chemins donnés en paramètre doivent être absolus.
Il est nécessaire d'utiliser l'API pour récupérer l'id de la branche à partir de laquelle on souhaite exporter le graphe.

Le résultat du script *prep_vectorise_graph.py* est un dossier contenant des fichiers vrt temporaires et un sous-dossier (./tiles) avec les dalles de graphe nécessaires pour le script *vectorise_graph.py*.

Le script vectorise_graph.py crée un fichier json, utilisable avec le service gpao de l'IGN, pour créer deux chantiers : le premier (chantier_polygonize), le deuxième (chantier_merge) qui dépend du premier.
Les options *bbox* et *shapefile* ne peuvent pas être utilisées simultanément.

Sous Windows, l'environnement recommandé pour avoir accès aux scripts Gdal et Gdal/Ogr est par le moyen de QGis (qui contient une version de Gdal supérieure ou égale à la version minimale demandée, voir plus haut).
Il faut initialiser l'environnement QGis via le script qui est à l'emplacement : **{QGis_DIR}\bin\o4w_env.bat**
Pour exécuter *vectorise_graph.py* sous Windows, il est nécessaire d'avoir configuré la variable d'environnement OSGEO4W_ROOT qui doit pointer vers la racine de QGis.
Il est également nécessaire d'ajouter dans le PATH les emplacements des exécutables et scripts utilisant Gdal et Gdal/Ogr de QGis : *%OSGEO4W_ROOT%\bin* ainsi que *%OSGEO4W_ROOT%\apps\Python\*\Scripts*. * étant la version de Python embarqué par QGis.

````
usage: vectorise_graph.py [-h] -i INPUT -o OUTPUT [-g GRAPH] [-v VERBOSE]

optional arguments:
-h, --help show this help message and exit
-i INPUT, --input INPUT
input data folder (created by prep_vectorise_graph.py)
-o OUTPUT, --output OUTPUT
output json gpao filepath
-g GRAPH, --graph GRAPH
output vectorised graph pathfile (default: OUTPUT.gpkg)
-v VERBOSE, --verbose VERBOSE
verbose (default: 0)
````

Le résultat final du calcul gpao de vectorisation, GRAPH_final.gpkg, est au format GeoPackage.

### Récupération des métadonnées dans le graphe

Le script export_mtd.py crée un fichier json, utilisable avec le service gpao de l'IGN pour ajouter les métadonnées au graphe vecteur exporté précédemment. L'environnement nécessaire à son exécution est le même que pour les deux premiers scripts.

````
usage: export_mtd.py [-h] -g GRAPH -c CACHE -o OUTPUT [-v VERBOSE]

optional arguments:
-h, --help show this help message and exit
-g GRAPH, --graph GRAPH
input graph
-c CACHE, --cache CACHE
cache associated with the graph
-o OUTPUT, --output OUTPUT
output json gpao filepath
-v VERBOSE, --verbose VERBOSE
verbose (default: 0)
````
Le résultat final du calcul gpao de vectorisation, GRAPH_mtd.gpkg, est au format GeoPackage.

## Raccourcis clavier

Expand Down
Empty file added scripts/__init__.py
Empty file.
Empty file.
190 changes: 190 additions & 0 deletions scripts/export_graph/export_graph.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
# -*- coding: utf-8 -*-
"""
Script d'export du graphe a partir d'un cache
"""
import os
import sys
import re
import argparse
import prep_vectorise_graph as prep
import vectorise_graph as vect
from osgeo import ogr

current = os.path.dirname(os.path.realpath(__file__))
parent = os.path.dirname(current)
sys.path.append(parent)

from process_requests import check_get_post, response2pyobj # noqa: E402


def read_args():
"""Gestion des arguments"""

parser = argparse.ArgumentParser()
parser.add_argument("-c", "--cache", required=True, type=str, help="path of input cache")
parser.add_argument("-o", "--output", required=True, help="output folder")
parser.add_argument("-b", "--branch", required=True, type=int,
help="id of branch of cache to use as source for patches")
parser.add_argument('-u', '--url',
help="http://[serveur]:[port] (default: http://localhost:8081)",
type=str, default='http://localhost:8081')
parser.add_argument("-t", "--tilesize",
help="tile size (in pixels) for vectorising graph tiles (default: 5000)",
type=int, default=5000)
parser.add_argument("--bbox", help="bbox for export (in meters), xmin ymin xmax ymax",
type=int, nargs=4)
parser.add_argument("--shapefile", help="filepath of shapefile containing extent of export")
parser.add_argument("-v", "--verbose", help="verbose (default: 0)", type=int, default=0)
args_prep = parser.parse_args()

if args_prep.verbose >= 1:
print("\nArguments: ", args_prep)

# check input cache
if not os.path.exists(args_prep.cache):
raise SystemExit(f"ERROR: folder '{args_prep.cache}' does not exist")

# check branch -> voir create_qgis_view

# check input url
url_pattern = r'^https?:\/\/[0-9A-z.]+\:[0-9]+$'
if not re.match(url_pattern, args_prep.url):
raise SystemExit(f"ERROR: URL '{args_prep.url}' is invalid")

# check tilesize > 0
if args_prep.tilesize <= 0:
raise SystemExit("ERROR: tilesize must be greater that zero")

# check if bbox and extent are not both used
if args_prep.bbox is not None and args_prep.shapefile is not None:
raise SystemExit("ERROR: bbox and extent options were used, incompatible")

# check bbox
if args_prep.bbox is not None:
coords = str(args_prep.bbox).split(' ')
if any(elem is None for elem in coords) and any(elem is not None for elem in coords):
raise SystemError("ERROR: all bbox coordinates must be specified")

# check extent, only shapefile
if args_prep.shapefile is not None:
if not os.path.exists(args_prep.shapefile):
raise SystemExit(f"ERROR: file {args_prep.shapefile} does not exist")
ext = os.path.splitext(args_prep.shapefile)[1]
if ext != '.shp':
raise SystemExit(f"ERROR: wrong extent file extension expected .shp, got {ext}")
driver = ogr.GetDriverByName("ESRI Shapefile")
data = driver.Open(args_prep.shapefile, 0) # 0 = read-only
if data is None:
raise SystemExit("ERROR: data is null in ", args_prep.shapefile)

# verifier tous les parametres

return args_prep


args = read_args()

# TODO : gérer des dalles de NODATA en bord de chantier
# TODO : pouvoir ajouter un tag gpao dans le chantier
# TODO : export mtd optionnel si cache n'en contient pas ? Tester comportement sans mtd || OK

# recuperer les patches correspondant a la branche desiree (requete curl)
patches_files = os.path.join(args.output, 'patches.json')
req_get_patches = f'{args.url}/{args.branch}/patches'
resp_get_patches = check_get_post(req_get_patches)
list_patches_api = response2pyobj(resp_get_patches)

# creation du repertoire de sortie si necessaire
try:
os.mkdir(args.output)
except FileExistsError:
print("ALERTE : Le dossier de sortie existe déjà.")

# define working dir
os.chdir(args.output)
print(f"INFO : Le répertoire de travail est '{os.getcwd()}'")
# redefine input directory
try:
cache_path = os.path.relpath(args.cache, start=args.output)
except ValueError:
print("No relative path, absolute path is used instead")
cache_path = os.path.abspath(args.cache)
print("Updated input path relative to working dir: '" + cache_path + "'")

# check if input dir exists
if not os.path.exists(cache_path):
raise SystemExit("ERREUR : Le répertoire " + cache_path + " n'existe pas.")

# on verifie si l'overviews utilise est bien correct
path_depth, level, resol, proj, overviews = prep.check_overviews(cache_path)

# recupere la liste des dalles impactees par les retouches sur le chantier
list_patches, id_branch_patch = prep.list_patches(list_patches_api, cache_path, path_depth, level)

# create correct path out
if os.path.basename(cache_path) != "..":
path_out = os.path.join(args.output, os.path.basename(cache_path))
else:
path_out = os.path.join(args.output, os.path.basename(args.output))

# on verifie que la branch donne est correcte
# encore necessaire vu qu'on va chercher les patches via id_branch ?
# verif dans argsparser, a supprimer
prep.check_branch_patch(args.branch, id_branch_patch)

# on recupere l'emprise du chantier si necessaire
extent = None
if args.bbox:
x_min = args.bbox[0]
y_min = args.bbox[1]
x_max = args.bbox[2]
y_max = args.bbox[3]

extent = prep.get_extent(x_min, x_max, y_min, y_max)
elif args.shapefile:
# actuellement on prend seulement la bbox du chantier
driver = ogr.GetDriverByName("ESRI Shapefile")
data = driver.Open(args.shapefile, 0) # 0 = read-only

layer = data.GetLayer()
layer_extent = layer.GetExtent()
x_min = layer_extent[0]
x_max = layer_extent[1]
y_min = layer_extent[2]
y_max = layer_extent[3]

extent = prep.get_extent(x_min, x_max, y_min, y_max)

# on recupere la liste des dalles impactees par les patches
prep.create_list_slabs(cache_path, level, args.branch, path_out, list_patches, extent)

# creation des vrt intermediaires
prep.build_full_vrt(path_out, resol)
prep.build_vrt_emprise(path_out)
prep.build_vrt_32bits(path_out)

# creation des dalles de vrt pour la vectorisation
prep.create_tiles_vrt(args.output, path_out, resol, args.tilesize)

# preparation du fichier pour la gpao
dict_cmd = {"projects": []}
project_name = os.path.basename(args.output.split('.')[0])

# chantier polygonize
vect.create_chantier_polygonize(dict_cmd, args.output, project_name)

# chantier merge
vect.add_chantier_merge(dict_cmd, project_name)
merge_path, tmp_dir = vect.add_job_merge(dict_cmd, args.output, project_name, proj)
dissolve_path = vect.add_job_dissolve(dict_cmd, project_name, merge_path, tmp_dir)

# chantier mtd
vect.add_chantier_mtd(dict_cmd, project_name)
vect.add_table_mtd(dissolve_path)
mtd_file = vect.create_mtd_dico(tmp_dir, overviews)
vect.add_job_gpkg_to_fgb(dict_cmd, dissolve_path)
vect.add_job_join_mtd(dict_cmd, dissolve_path, mtd_file)
vect.add_job_fbg_to_gpkg(dict_cmd, dissolve_path, args.output, project_name)

# ecriture du json de gpao
vect.write_json_file(dict_cmd, args.output, project_name)
Loading
Loading