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()