Vertdure commited on
Commit
0e20c98
‱
1 Parent(s): cfb5405

Update pages/5_📍_VertXtractor.py

Browse files
Files changed (1) hide show
  1. pages/5_📍_VertXtractor.py +118 -185
pages/5_📍_VertXtractor.py CHANGED
@@ -2,167 +2,143 @@ import streamlit as st
2
  import folium
3
  from streamlit_folium import folium_static
4
  from folium.plugins import Draw
5
- import branca
6
  import requests
7
  import json
8
  import os
9
  import urllib.request
10
  import csv
11
- import gdal_merge as gm
12
- import nested_lookup
13
  from osgeo import gdal
14
- from pyproj import Transformer
15
  import math
16
  import shutil
17
  import sys
 
18
 
19
- # Fonction pour convertir les coordonnées OSM en coordonnées décimales
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  def osm_to_decimal(tile_x, tile_y, zoom):
 
21
  n = 2.0 ** zoom
22
  lon_deg = tile_x / n * 360.0 - 180.0
23
  lat_rad = math.atan(math.sinh(math.pi * (1 - 2 * tile_y / n)))
24
  lat_deg = math.degrees(lat_rad)
25
  return lat_deg, lon_deg
26
 
27
- # Fonction pour obtenir les Ă©lĂ©ments pour une zone d'intĂ©rĂȘt
28
- def getitems(productname, LLlon, LLlat, URlon, URlat, first100):
29
- itemsrequest = requests.get(f"https://data.geo.admin.ch/api/stac/v0.9/collections/{productname}/items?bbox={LLlon},{LLlat},{URlon},{URlat}")
30
- itemsresult = json.loads(itemsrequest.content)
31
- assets = nested_lookup.nested_lookup('assets', itemsresult)
32
-
33
- morethan100 = 1 if len(itemsresult['links']) >= 6 else 0
34
-
35
- if len(itemsresult['links']) >= 6 and first100 == 0:
36
- pagination = 1
37
- while pagination == 1:
38
- nextpage = itemsresult['links'][5]['href']
39
- itemsrequest = requests.get(nextpage)
40
- itemsresult = json.loads(itemsrequest.content)
41
- assets = assets + nested_lookup.nested_lookup('assets', itemsresult)
42
-
43
- if len(itemsresult['links']) >= 6 and itemsresult['links'][5]['rel'] == 'next':
44
- pagination = 1
45
- else:
46
- pagination = 0
47
-
48
- itemsfiles = nested_lookup.nested_lookup('href', assets)
49
 
50
  # Filtrage des fichiers selon les cas spĂ©cifiques
51
- krel = [i for i in itemsfiles if "_krel_" in i]
52
- if len(krel) != 0:
53
- itemsfiles = krel
54
 
55
- highres = [i for i in itemsfiles if "_0.1_" in i]
56
- if len(highres) != 0:
57
- itemsfiles = highres
58
 
59
  if productname == 'ch.swisstopo.swissalti3d':
60
- tiff = [i for i in itemsfiles if ".tif" in i]
61
- if len(tiff) != 0:
62
- itemsfiles = tiff
63
- highres = [i for i in itemsfiles if "_0.5_" in i]
64
- if len(highres) != 0:
65
- itemsfiles = highres
66
-
67
- return itemsfiles, morethan100
68
 
69
- # Fonction pour créer un CSV pour l'importation
70
- def createCSV(productname, LLlon, LLlat, URlon, URlat):
71
  coords = f"{LLlon}_{LLlat}_{URlon}_{URlat}"
72
- CSV_filepath = os.path.join(os.getcwd(), f"{productname}{coords}.csv")
73
 
74
- itemsfiles, _ = getitems(productname, LLlon, LLlat, URlon, URlat, 0)
75
 
76
- with open(CSV_filepath, 'w') as f:
77
- for item in itemsfiles:
78
- f.write(f"{item}\n")
79
- return CSV_filepath
80
-
81
- # Fonction pour fusionner les rasters
82
- def mergeRaster(iteration, merged, temp_merged, filename, name, ordername, filename_ext, homedir):
83
- if iteration == 0:
84
- if os.path.exists(temp_merged):
85
- os.remove(temp_merged)
86
- else:
87
- os.rename(filename, temp_merged)
88
- else:
89
- st.text(f"Fusion du fichier : {name}")
90
-
91
- if "nonImageLayers" in name: # Remplacez par la condition appropriée
92
- gm.main(['', '-o', f"{ordername}_merged{filename_ext[1]}", f"{ordername}_temp_merged{filename_ext[1]}", name, '-co', 'COMPRESS=LZW'])
93
- else:
94
- gm.main(['', '-o', f"{ordername}_merged{filename_ext[1]}", f"{ordername}_temp_merged{filename_ext[1]}", name, '-co', 'COMPRESS=JPEG', '-co', 'PREDICTOR=2', '-co', 'TILED=YES', '-co', 'BLOCKXSIZE=512', '-co', 'BLOCKYSIZE=512', '-co', 'PHOTOMETRIC=YCBCR', '-ot', 'Byte'])
95
-
96
- os.remove(temp_merged)
97
- os.remove(filename)
98
- os.rename(merged, temp_merged)
99
-
100
- # Fonction pour découper le raster
101
- def cropRaster(inputRaster, outputRaster, bbox):
102
- transformer = Transformer.from_crs("epsg:4326", "epsg:2056")
103
- bbox95 = transformer.transform(bbox[3], bbox[0]) + transformer.transform(bbox[1], bbox[2])
104
- gdal.Translate(outputRaster, inputRaster, projWin=bbox95)
105
 
106
- # Fonction pour vérifier l'espace disque disponible
107
- def check_local_system(homedir, filename, lines):
108
- file_stats = os.stat(filename)
109
- required_space_gb = (file_stats.st_size / (1024 * 1024 * 1024)) * lines
110
- free_space = shutil.disk_usage(homedir).free
111
- free_space_gb = free_space / 1024 / 1024 / 1024
112
-
113
- if free_space_gb < required_space_gb:
114
- return f"ATTENTION : Espace disque insuffisant. {required_space_gb:.2f} GB nécessaires, {free_space_gb:.2f} GB disponibles."
115
- else:
116
- return f"{required_space_gb:.2f} GB seront téléchargés. Espace libre disponible : {free_space_gb:.2f} GB"
 
 
 
 
 
 
 
 
 
 
 
 
117
 
118
- # Fonction pour traiter le CSV
119
- def processCSV(CSV_filepath, geom):
120
- filecsv = os.path.split(os.path.abspath(CSV_filepath))
121
- downloaddir = filecsv[0]
122
- ordername = filecsv[1]
123
- os.chdir(downloaddir)
124
-
125
- with open(os.path.normpath(CSV_filepath)) as file:
126
- lines = len(file.readlines())
127
-
128
- for iteration, url in enumerate(open(os.path.normpath(CSV_filepath))):
129
- name = str.rstrip(url.rsplit('/', 1)[-1])
130
- filename = os.path.join(downloaddir, name)
131
- filename_ext = os.path.splitext(name)
132
- temp_merged = os.path.join(downloaddir, f'{ordername}_temp_merged{filename_ext[1]}')
133
- merged = os.path.join(downloaddir, f'{ordername}_merged{filename_ext[1]}')
134
- result = os.path.join(downloaddir, f'{ordername}{filename_ext[1]}')
135
 
136
  if not os.path.isfile(filename):
137
- st.text(f"Téléchargement du fichier : {iteration+1} sur {lines}")
138
- urllib.request.urlretrieve(url.strip(), filename)
139
-
140
- if iteration == 0:
141
- st.text(check_local_system(os.getcwd(), filename, lines))
142
-
143
- if not st.session_state.noMERGE:
144
- mergeRaster(iteration, merged, temp_merged, filename, name, ordername, filename_ext, os.getcwd())
145
-
146
- if geom is not None and len(geom) == 4 and not st.session_state.noCROP and not st.session_state.noMERGE:
147
- st.text("DĂ©coupage...")
148
- cropRaster(temp_merged, merged, geom)
149
- os.remove(temp_merged)
150
-
151
- if st.session_state.noMERGE:
152
- st.text(f"RĂ©sultat dans {downloaddir}")
153
  else:
154
- if os.path.exists(result):
155
- st.text(f"Le résultat {result} existe déjà, supprimez-le si vous voulez le retraiter")
156
- else:
157
- if os.path.exists(temp_merged):
158
- os.rename(temp_merged, result)
159
- if os.path.exists(merged):
160
- os.rename(merged, result)
161
- st.text(f"RĂ©sultat dans {result}")
162
- os.chdir(os.getcwd())
163
 
164
- # Fonction pour dessiner la carte
165
- def draw_map():
 
 
 
 
 
 
 
166
  m = folium.Map(location=[46.8182, 8.2275], zoom_start=8)
167
  draw = Draw(
168
  draw_options={
@@ -176,69 +152,26 @@ def draw_map():
176
  edit_options={'edit': False}
177
  )
178
  draw.add_to(m)
179
-
180
- output = folium_static(m)
181
- return output
182
-
183
- # Fonction pour obtenir les coordonnées de la bbox
184
- def get_bbox_coordinates(draw_data):
185
- if draw_data:
186
- bbox = draw_data['features'][0]['geometry']['coordinates'][0]
187
- lons = [coord[0] for coord in bbox]
188
- lats = [coord[1] for coord in bbox]
189
- return min(lons), min(lats), max(lons), max(lats)
190
- return None
191
-
192
- # Fonction principale
193
- def main():
194
- st.title("SwissTopo Downloader")
195
 
196
- # Initialisation des variables de session
197
- if 'noCROP' not in st.session_state:
198
- st.session_state.noCROP = False
199
- if 'noMERGE' not in st.session_state:
200
- st.session_state.noMERGE = False
201
- if 'draw_data' not in st.session_state:
202
- st.session_state.draw_data = None
203
-
204
- # SĂ©lection du produit
205
- products = {
206
- 'Luftbild 10cm': 'ch.swisstopo.swissimage-dop10',
207
- 'Landeskarte 1:10': 'ch.swisstopo.landeskarte-farbe-10',
208
- 'Landeskarte 1:25': 'ch.swisstopo.pixelkarte-farbe-pk25.noscale',
209
- 'Landeskarte 1:50': 'ch.swisstopo.pixelkarte-farbe-pk50.noscale',
210
- 'Landeskarte 1:100': 'ch.swisstopo.pixelkarte-farbe-pk100.noscale',
211
- 'Landeskarte 1:200': 'ch.swisstopo.pixelkarte-farbe-pk200.noscale',
212
- 'Höhenmodell': 'ch.swisstopo.swissalti3d',
213
- }
214
- selected_product = st.selectbox("SĂ©lectionnez un produit", list(products.keys()))
215
-
216
- # Carte interactive pour dessiner la bbox
217
- st.subheader("Dessinez une boĂźte englobante sur la carte")
218
- map_data = draw_map()
219
 
220
  # RĂ©cupĂ©ration des coordonnĂ©es de la bbox
221
- if map_data:
222
- st.session_state.draw_data = map_data
223
-
224
- bbox_coords = get_bbox_coordinates(st.session_state.draw_data)
225
-
226
- if bbox_coords:
227
- LLlon, LLlat, URlon, URlat = bbox_coords
228
- st.write(f"Coordonnées de la bbox : {LLlon:.4f}, {LLlat:.4f}, {URlon:.4f}, {URlat:.4f}")
229
- else:
230
- st.write("Aucune bbox dessinée. Veuillez dessiner une boßte sur la carte.")
231
 
232
  # Options
233
- st.session_state.noCROP = st.checkbox("Ne pas découper", value=st.session_state.noCROP)
234
- st.session_state.noMERGE = st.checkbox("Ne pas fusionner", value=st.session_state.noMERGE)
235
 
236
  if st.button("TĂ©lĂ©charger") and bbox_coords:
237
- product = products[selected_product]
238
- CSV_filepath = createCSV(product, str(LLlon), str(LLlat), str(URlon), str(URlat))
239
- bbox = (LLlon, LLlat, URlon, URlat)
240
- processCSV(CSV_filepath, bbox)
241
- st.success("Téléchargement terminé!")
242
  elif st.button("TĂ©lĂ©charger") and not bbox_coords:
243
  st.error("Veuillez dessiner une boĂźte englobante sur la carte avant de tĂ©lĂ©charger.")
244
 
 
2
  import folium
3
  from streamlit_folium import folium_static
4
  from folium.plugins import Draw
 
5
  import requests
6
  import json
7
  import os
8
  import urllib.request
9
  import csv
 
 
10
  from osgeo import gdal
11
+ import numpy as np
12
  import math
13
  import shutil
14
  import sys
15
+ import glob
16
 
17
+ # Configuration de la page Streamlit
18
+ st.set_page_config(page_title="SwissTopo Downloader", layout="wide")
19
+
20
+ # Constantes
21
+ PRODUCTS = {
22
+ 'Luftbild 10cm': 'ch.swisstopo.swissimage-dop10',
23
+ 'Landeskarte 1:10': 'ch.swisstopo.landeskarte-farbe-10',
24
+ 'Landeskarte 1:25': 'ch.swisstopo.pixelkarte-farbe-pk25.noscale',
25
+ 'Landeskarte 1:50': 'ch.swisstopo.pixelkarte-farbe-pk50.noscale',
26
+ 'Landeskarte 1:100': 'ch.swisstopo.pixelkarte-farbe-pk100.noscale',
27
+ 'Landeskarte 1:200': 'ch.swisstopo.pixelkarte-farbe-pk200.noscale',
28
+ 'Höhenmodell': 'ch.swisstopo.swissalti3d',
29
+ }
30
+
31
+ # Fonctions utilitaires
32
  def osm_to_decimal(tile_x, tile_y, zoom):
33
+ """Convertit les coordonnées OSM en coordonnées décimales."""
34
  n = 2.0 ** zoom
35
  lon_deg = tile_x / n * 360.0 - 180.0
36
  lat_rad = math.atan(math.sinh(math.pi * (1 - 2 * tile_y / n)))
37
  lat_deg = math.degrees(lat_rad)
38
  return lat_deg, lon_deg
39
 
40
+ def get_items(productname, LLlon, LLlat, URlon, URlat, first100=False):
41
+ """RĂ©cupĂšre les Ă©lĂ©ments pour une zone d'intĂ©rĂȘt donnĂ©e."""
42
+ url = f"https://data.geo.admin.ch/api/stac/v0.9/collections/{productname}/items?bbox={LLlon},{LLlat},{URlon},{URlat}"
43
+ response = requests.get(url)
44
+ items_result = json.loads(response.content)
45
+ assets = items_result.get('features', [])
46
+
47
+ items_files = []
48
+ for asset in assets:
49
+ asset_url = asset.get('assets', {}).get('data', {}).get('href')
50
+ if asset_url:
51
+ items_files.append(asset_url)
 
 
 
 
 
 
 
 
 
 
52
 
53
  # Filtrage des fichiers selon les cas spĂ©cifiques
54
+ if "_krel_" in productname:
55
+ items_files = [i for i in items_files if "_krel_" in i]
 
56
 
57
+ if "0.1" in productname:
58
+ items_files = [i for i in items_files if "_0.1_" in i]
 
59
 
60
  if productname == 'ch.swisstopo.swissalti3d':
61
+ items_files = [i for i in items_files if i.endswith(".tif")]
62
+ items_files = [i for i in items_files if "_0.5_" in i]
63
+
64
+ return items_files
 
 
 
 
65
 
66
+ def create_csv(productname, LLlon, LLlat, URlon, URlat):
67
+ """Crée un fichier CSV contenant les URLs des données à télécharger."""
68
  coords = f"{LLlon}_{LLlat}_{URlon}_{URlat}"
69
+ csv_filepath = os.path.join(os.getcwd(), f"{productname}{coords}.csv")
70
 
71
+ items_files = get_items(productname, LLlon, LLlat, URlon, URlat)
72
 
73
+ with open(csv_filepath, 'w', newline='') as f:
74
+ writer = csv.writer(f)
75
+ for item in items_files:
76
+ writer.writerow([item])
77
+
78
+ return csv_filepath
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
 
80
+ def merge_rasters(input_files, output_file, compress_method='JPEG'):
81
+ """Fusionne plusieurs rasters en un seul."""
82
+ gdal.UseExceptions()
83
+
84
+ # Ouvrir le premier fichier pour obtenir les métadonnées
85
+ src_ds = gdal.Open(input_files[0])
86
+ driver = gdal.GetDriverByName("GTiff")
87
+
88
+ # Créer le fichier de sortie
89
+ dst_ds = driver.CreateCopy(output_file, src_ds, 0,
90
+ options=[f"COMPRESS={compress_method}",
91
+ "TILED=YES",
92
+ "BIGTIFF=YES"])
93
+
94
+ # Fermer le premier fichier
95
+ src_ds = None
96
+
97
+ # Fusionner les autres fichiers
98
+ for file in input_files[1:]:
99
+ gdal.Warp(output_file, file, format="GTiff", options=[f"COMPRESS={compress_method}"])
100
+
101
+ # Fermer le fichier de sortie
102
+ dst_ds = None
103
 
104
+ def process_csv(csv_filepath, no_merge=False):
105
+ """Traite le fichier CSV pour télécharger et fusionner les données."""
106
+ download_dir = os.path.dirname(csv_filepath)
107
+ order_name = os.path.basename(csv_filepath).split('.')[0]
108
+
109
+ with open(csv_filepath, 'r') as file:
110
+ urls = file.readlines()
111
+
112
+ downloaded_files = []
113
+ for i, url in enumerate(urls):
114
+ url = url.strip()
115
+ filename = os.path.join(download_dir, url.split('/')[-1])
 
 
 
 
 
116
 
117
  if not os.path.isfile(filename):
118
+ st.text(f"Téléchargement du fichier : {i+1} sur {len(urls)}")
119
+ urllib.request.urlretrieve(url, filename)
120
+
121
+ downloaded_files.append(filename)
122
+
123
+ if not no_merge:
124
+ output_file = os.path.join(download_dir, f"{order_name}_merged.tif")
125
+ st.text("Fusion des fichiers téléchargés...")
126
+ merge_rasters(downloaded_files, output_file)
127
+ st.text(f"Résultat fusionné dans : {output_file}")
 
 
 
 
 
 
128
  else:
129
+ st.text(f"Fichiers téléchargés dans : {download_dir}")
130
+
131
+ return output_file if not no_merge else download_dir
 
 
 
 
 
 
132
 
133
+ # Interface utilisateur Streamlit
134
+ def main():
135
+ st.title("SwissTopo Downloader")
136
+
137
+ # SĂ©lection du produit
138
+ selected_product = st.selectbox("SĂ©lectionnez un produit", list(PRODUCTS.keys()))
139
+
140
+ # Carte interactive pour dessiner la bbox
141
+ st.subheader("Dessinez une boĂźte englobante sur la carte")
142
  m = folium.Map(location=[46.8182, 8.2275], zoom_start=8)
143
  draw = Draw(
144
  draw_options={
 
152
  edit_options={'edit': False}
153
  )
154
  draw.add_to(m)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
 
156
+ output = folium_static(m)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
 
158
  # RĂ©cupĂ©ration des coordonnĂ©es de la bbox
159
+ bbox_coords = None
160
+ if 'last_active_drawing' in st.session_state:
161
+ bbox = st.session_state.last_active_drawing['geometry']['coordinates'][0]
162
+ lons = [coord[0] for coord in bbox]
163
+ lats = [coord[1] for coord in bbox]
164
+ bbox_coords = [min(lons), min(lats), max(lons), max(lats)]
165
+ st.write(f"Coordonnées de la bbox : {bbox_coords}")
 
 
 
166
 
167
  # Options
168
+ no_merge = st.checkbox("Ne pas fusionner les fichiers téléchargés")
 
169
 
170
  if st.button("TĂ©lĂ©charger") and bbox_coords:
171
+ product = PRODUCTS[selected_product]
172
+ csv_filepath = create_csv(product, *bbox_coords)
173
+ result = process_csv(csv_filepath, no_merge)
174
+ st.success(f"Téléchargement terminé ! Résultat : {result}")
 
175
  elif st.button("TĂ©lĂ©charger") and not bbox_coords:
176
  st.error("Veuillez dessiner une boĂźte englobante sur la carte avant de tĂ©lĂ©charger.")
177