File size: 9,623 Bytes
d0334cd 9e8e93e cb00c19 d0334cd 91c174c b6b6ea7 9e642ab d0334cd 57fb324 331c3ea 4d8332b 331c3ea 968c2ae 331c3ea 4d8332b 968c2ae 57fb324 9e642ab 57fb324 9e642ab 4d8332b 57fb324 1f10f5c 9e642ab 1f10f5c 9e642ab a11723d 0826f29 a11723d 0826f29 a11723d 331c3ea a11723d 331c3ea a11723d 331c3ea 6fba3a8 331c3ea 0826f29 6fba3a8 0826f29 6fba3a8 0826f29 fa4ff30 6fba3a8 fa4ff30 6fba3a8 331c3ea 0826f29 6fba3a8 0826f29 6fba3a8 0826f29 fa4ff30 6fba3a8 fa4ff30 6fba3a8 fa4ff30 5abcc84 cb00c19 5abcc84 195f57b 968c2ae b6b6ea7 16af22d 5abcc84 968c2ae 5abcc84 968c2ae 16af22d 968c2ae 3f40f5f 9e642ab 3f40f5f 968c2ae 1f10f5c 9e642ab 3f40f5f 1f10f5c 3f40f5f 1f10f5c 968c2ae 9e642ab 1f10f5c 9e642ab 1f10f5c 968c2ae 9e642ab 968c2ae 9e642ab 968c2ae 9e642ab 968c2ae 1f63971 cb00c19 16af22d |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 |
import streamlit as st
import geopandas as gpd
import folium
from streamlit_folium import folium_static, st_folium
from folium.plugins import Draw
import requests
from shapely.geometry import box
import json
import pyproj
st.set_page_config(layout="wide", page_title="Extracteur de données géospatiales")
ESRI_SERVICES = {
'World_Imagery' : 'https://services.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer',
'World_Topo_Map' : 'https://services.arcgisonline.com/arcgis/rest/services/World_Topo_Map/MapServer',
'World_Shaded_Relief' : 'https://services.arcgisonline.com/arcgis/rest/services/World_Shaded_Relief/MapServer',
'World_Terrain_Base' : 'https://services.arcgisonline.com/arcgis/rest/services/World_Terrain_Base/MapServer',
'World_Street_Map' : 'https://services.arcgisonline.com/arcgis/rest/services/World_Street_Map/MapServer',
'World_Elevation' : 'https://elevation.arcgis.com/arcgis/rest/services/WorldElevation/Terrain/ImageServer',
'World_Elevation3D' : 'https://services.arcgisonline.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer',
}
LAYERS = {
"Swisstopo - SWISSIMAGE 10 cm": {"id": "ch.swisstopo.swissimage-dop10", "source": "swisstopo", "type": "image"},
"Swisstopo - Carte nationale 1:25'000": {"id": "ch.swisstopo.pixelkarte-farbe-pk25.noscale", "source": "swisstopo", "type": "image"},
"Swisstopo - MNT": {"id": "ch.swisstopo.swissalti3d", "source": "swisstopo", "type": "raster"},
"Swisstopo - Carte géologique": {"id": "ch.swisstopo.geologie-geologische_karte", "source": "swisstopo", "type": "image"},
"Swisstopo - Limites administratives": {"id": "ch.swisstopo.swissboundaries3d-gemeinde-flaeche.fill", "source": "swisstopo", "type": "vector"},
"Swisstopo - RĂ©seau hydrographique": {"id": "ch.bafu.vec25-gewaessernetz", "source": "swisstopo", "type": "vector"},
"Swisstopo - swissBUILDINGS3D 3.0 Beta": {"id": "ch.swisstopo.swissbuildings3d_3_0", "source": "swisstopo", "type": "3d"},
"ESRI - World Imagery": {"id": "World_Imagery", "source": "esri", "type": "image"},
"ESRI - World Elevation": {"id": "World_Elevation", "source": "esri", "type": "raster"},
"ESRI - World Elevation3D": {"id": "World_Elevation3D", "source": "esri", "type": "raster"},
"ESRI - World Topographic": {"id": "World_Topo_Map", "source": "esri", "type": "image"},
"ESRI - World Street Map": {"id": "World_Street_Map", "source": "esri", "type": "image"},
"ESRI - World Terrain": {"id": "World_Terrain_Base", "source": "esri", "type": "image"},
}
# Définir les systÚmes de coordonnées
wgs84 = pyproj.CRS('EPSG:4326')
ch1903 = pyproj.CRS('EPSG:2056')
# Créer un transformateur
transformer = pyproj.Transformer.from_crs(wgs84, ch1903, always_xy=True)
def draw_box_on_map():
m = folium.Map(location=[46.8, 8.2], zoom_start=8)
Draw(draw_options={'polyline': False, 'polygon': False, 'circle': False, 'marker': False, 'circlemarker': False},
edit_options={'edit': False}).add_to(m)
return st_folium(m, width=700, height=500)
def create_geojson_from_box(bbox):
gdf = gpd.GeoDataFrame({'geometry': [bbox]}, crs="EPSG:4326")
return json.loads(gdf.to_json())
@st.cache_data
def get_download_url(bbox, layer_info):
if layer_info["source"] == "swisstopo":
# Convertir les coordonnées WGS84 en CH1903+ pour Swisstopo
xmin, ymin = transformer.transform(bbox[0], bbox[1])
xmax, ymax = transformer.transform(bbox[2], bbox[3])
swiss_bbox = (xmin, ymin, xmax, ymax)
return get_swisstopo_url(swiss_bbox, layer_info)
else: # ESRI
return get_esri_url(bbox, layer_info)
def get_swisstopo_url(bbox, layer_info):
width = bbox[2] - bbox[0]
height = bbox[3] - bbox[1]
ratio = width / height
if ratio > 1:
size = f'1000,{int(1000/ratio)}'
else:
size = f'{int(1000*ratio)},1000'
# Ajout d'un petit buffer
buffer = min(width, height) * 0.01
bbox_buffered = (bbox[0]-buffer, bbox[1]-buffer, bbox[2]+buffer, bbox[3]+buffer)
api_url = f"https://data.geo.admin.ch/api/stac/v0.9/collections/{layer_info['id']}/items"
params = {
"bbox": ",".join(map(str, bbox_buffered)),
"limit": 1,
"width": size.split(',')[0],
"height": size.split(',')[1]
}
response = requests.get(api_url, params=params)
data = response.json()
if data['features']:
feature = data['features'][0]
asset_keys = feature['assets'].keys()
data_key = 'rgb' if 'rgb' in asset_keys else 'data' if 'data' in asset_keys else next(iter(asset_keys))
return feature['assets'][data_key]['href']
return None
def get_esri_url(bbox, layer_info):
service_url = ESRI_SERVICES.get(layer_info["id"])
if not service_url:
return None
if layer_info["type"] == "image":
return get_esri_image_url(bbox, service_url)
elif layer_info["type"] == "raster":
return get_esri_terrain_url(bbox, service_url)
return None
def get_esri_image_url(bbox, service_url):
width = bbox[2] - bbox[0]
height = bbox[3] - bbox[1]
ratio = width / height
if ratio > 1:
size = f'1000,{int(1000/ratio)}'
else:
size = f'{int(1000*ratio)},1000'
# Ajout d'un petit buffer
buffer = min(width, height) * 0.01
bbox_buffered = (bbox[0]-buffer, bbox[1]-buffer, bbox[2]+buffer, bbox[3]+buffer)
params = {
'bbox': f'{bbox_buffered[0]},{bbox_buffered[1]},{bbox_buffered[2]},{bbox_buffered[3]}',
'bboxSR': 4326,
'size': size,
'imageSR': 4326,
'format': 'png',
'f': 'html',
'transparent': 'true'
}
return f"{service_url}/export?{'&'.join([f'{k}={v}' for k, v in params.items()])}"
def get_esri_terrain_url(bbox, service_url):
width = bbox[2] - bbox[0]
height = bbox[3] - bbox[1]
ratio = width / height
if ratio > 1:
size = f'1000,{int(1000/ratio)}'
else:
size = f'{int(1000*ratio)},1000'
# Ajout d'un petit buffer
buffer = min(width, height) * 0.01
bbox_buffered = (bbox[0]-buffer, bbox[1]-buffer, bbox[2]+buffer, bbox[3]+buffer)
params = {
'bbox': f'{bbox_buffered[0]},{bbox_buffered[1]},{bbox_buffered[2]},{bbox_buffered[3]}',
'bboxSR': 4326,
'size': size,
'imageSR': 4326,
'format': 'tiff',
'pixelType': 'F32',
'noDataInterpretation': 'esriNoDataMatchAny',
'interpolation': '+RSP_BilinearInterpolation',
'f': 'image'
}
return f"{service_url}/exportImage?{'&'.join([f'{k}={v}' for k, v in params.items()])}"
def main():
st.title("Extracteur de données Swisstopo et ESRI")
col1, col2 = st.columns([1, 2])
with col1:
st.subheader("SĂ©lection des couches")
selected_layers = st.multiselect("Couches Ă extraire", list(LAYERS.keys()))
st.subheader("DĂ©finir la zone d'intĂ©rĂȘt")
method = st.radio("MĂ©thode", ["Dessiner", "GeoJSON"], horizontal=True)
if method == "GeoJSON":
uploaded_file = st.file_uploader("GeoJSON", type="geojson")
if uploaded_file:
gdf = gpd.read_file(uploaded_file)
st.session_state['geojson'] = json.loads(gdf.to_crs(4326).to_json())
st.success("GeoJSON chargé!")
if st.button("Obtenir les liens de téléchargement"):
if 'geojson' not in st.session_state:
st.error("DĂ©finissez d'abord une zone d'intĂ©rĂȘt.")
elif not selected_layers:
st.error("SĂ©lectionnez au moins une couche Ă extraire.")
else:
for layer_name in selected_layers:
layer_info = LAYERS[layer_name]
bbox = gpd.GeoDataFrame.from_features(st.session_state['geojson']).total_bounds
st.write(f"Traitement de la couche : {layer_name}")
st.write(f"Bbox (WGS84): {bbox}")
download_url = get_download_url(bbox, layer_info)
if download_url:
st.markdown(f"[Télécharger {layer_name}]({download_url})")
else:
st.error(f"Impossible d'obtenir le lien pour {layer_name}")
st.markdown("---")
st.markdown("## à propos\nExtracteur de données géospatiales Swisstopo et ESRI.\nDéveloppé par Vertdure")
with col2:
if 'bbox' not in st.session_state:
map_data = draw_box_on_map()
if map_data['last_active_drawing']:
coords = map_data['last_active_drawing']['geometry']['coordinates'][0]
bbox = box(min(c[0] for c in coords), min(c[1] for c in coords),
max(c[0] for c in coords), max(c[1] for c in coords))
st.session_state['bbox'] = bbox
st.session_state['geojson'] = create_geojson_from_box(bbox)
st.success("Zone sélectionnée!")
else:
st.success("Zone déjà sélectionnée. Utilisez le bouton ci-dessous pour redessiner.")
if st.button("Redessiner la zone"):
del st.session_state['bbox']
del st.session_state['geojson']
st.experimental_rerun()
else:
m = folium.Map(location=[46.8, 8.2], zoom_start=8)
folium.GeoJson(st.session_state['geojson']).add_to(m)
st_folium(m, width=700, height=500)
if __name__ == "__main__":
main() |