Vertdure commited on
Commit
b50ab8a
·
verified ·
1 Parent(s): c287c52

Update pages/sol.py

Browse files
Files changed (1) hide show
  1. pages/sol.py +47 -95
pages/sol.py CHANGED
@@ -1,116 +1,68 @@
1
  import streamlit as st
2
  import rasterio
3
  import numpy as np
4
- from datetime import datetime, timedelta
5
- from pysolar.solar import get_altitude, get_azimuth
6
- from pytz import timezone
7
  import pyvista as pv
8
- import imageio
9
-
10
- # Lieux prédéfinis en Suisse
11
- locations = {
12
- "Genève": (46.2044, 6.1432),
13
- "Lausanne": (46.5191, 6.6323),
14
- "Berne": (46.9481, 7.4474),
15
- "Zurich": (47.3769, 8.5417),
16
- "Bâle": (47.5596, 7.5886),
17
- "Lucerne": (47.0502, 8.3093),
18
- "Lugano": (46.0037, 8.9511),
19
- "Zermatt": (46.0207, 7.7491),
20
- "Davos": (46.8024, 9.8382),
21
- "Interlaken": (46.6863, 7.8632),
22
- "Montreux": (46.4312, 6.9107),
23
- }
24
 
25
  # Fonction pour charger un raster
26
  def load_raster(file_path):
27
  with rasterio.open(file_path) as src:
28
- raster = src.read(1)
29
- transform = src.transform
30
  return raster, transform
31
 
32
- # Calcul des ombres
33
- def calculate_shadows(raster, altitude, azimuth):
34
- shadow = np.zeros_like(raster)
35
- if altitude > 0: # Si le soleil est au-dessus de l'horizon
36
- shadow[raster > altitude] = 1 # Simplifié pour cet exemple
37
- return shadow
38
-
39
- # Interface utilisateur Streamlit
40
- st.title("Simulation des Ombres en 3D - Suisse")
41
 
42
- # Chargement du raster
43
- uploaded_file = st.sidebar.file_uploader("Téléchargez un fichier raster (MES ou MNT)", type=["tif"])
44
- if uploaded_file:
45
- raster, transform = load_raster(uploaded_file)
46
- st.sidebar.write("Raster chargé avec succès !")
47
 
48
- # Menu des paramètres utilisateur
49
- st.sidebar.header("Paramètres")
50
- location_choice = st.sidebar.selectbox("Choisissez un lieu", list(locations.keys()))
51
- latitude, longitude = locations[location_choice]
 
 
52
 
53
- # Récupération des dates et heures
54
- selected_start_date = st.sidebar.date_input("Date de début", value=datetime.now().date())
55
- selected_end_date = st.sidebar.date_input("Date de fin", value=datetime.now().date() + timedelta(days=1))
56
- selected_time = st.sidebar.time_input("Heure", value=datetime.now().time())
57
- timezone_swiss = timezone("Europe/Zurich")
58
-
59
- # Combinaison avec fuseau horaire
60
- naive_start_datetime = datetime.combine(selected_start_date, selected_time)
61
- naive_end_datetime = datetime.combine(selected_end_date, selected_time)
62
- start_datetime = timezone_swiss.localize(naive_start_datetime)
63
- end_datetime = timezone_swiss.localize(naive_end_datetime)
64
 
65
- # Section de visualisation statique
66
- st.subheader("Visualisation statique")
67
- altitude = get_altitude(latitude, longitude, start_datetime)
68
- azimuth = get_azimuth(latitude, longitude, start_datetime)
69
- shadows = calculate_shadows(raster, altitude, azimuth)
70
 
71
- # Affichage 2D des ombres
72
- st.image(shadows, caption=f"Ombres pour {start_datetime}", use_column_width=True)
73
 
74
- # Rendu 3D
75
- st.subheader("Rendu 3D")
76
- grid = pv.UniformGrid()
77
- grid.dimensions = raster.shape + (1,)
78
- grid.spacing = (transform[0], transform[4], 1)
79
- grid.point_arrays["Topography"] = raster.flatten(order="F")
80
- grid.point_arrays["Shadows"] = shadows.flatten(order="F")
81
 
82
- # PyVista rendu 3D
83
  plotter = pv.Plotter(off_screen=True)
84
- plotter.add_mesh(grid, scalars="Topography", cmap="terrain", show_edges=False)
85
- plotter.add_mesh(grid, scalars="Shadows", cmap="gray", opacity=0.5)
86
- plotter.view_isometric()
87
  plotter.add_scalar_bar("Élévation (m)")
88
- plotter.show(screenshot="render_3d.png")
89
- st.image("render_3d.png", caption="Rendu 3D des ombres", use_column_width=True)
 
90
 
91
- # Timelapse
92
- st.subheader("Génération d'un Timelapse")
93
- if st.button("Générer un timelapse"):
94
- current_time = start_datetime
95
- frames = []
96
- while current_time <= end_datetime:
97
- altitude = get_altitude(latitude, longitude, current_time)
98
- azimuth = get_azimuth(latitude, longitude, current_time)
99
- shadows = calculate_shadows(raster, altitude, azimuth)
100
-
101
- # Ajout des ombres comme une frame
102
- grid.point_arrays["Shadows"] = shadows.flatten(order="F")
103
- plotter = pv.Plotter(off_screen=True)
104
- plotter.add_mesh(grid, scalars="Topography", cmap="terrain", show_edges=False)
105
- plotter.add_mesh(grid, scalars="Shadows", cmap="gray", opacity=0.5)
106
- plotter.view_isometric()
107
- plotter.add_scalar_bar("Élévation (m)")
108
- filename = f"frame_{current_time.strftime('%Y%m%d%H%M')}.png"
109
- plotter.show(screenshot=filename)
110
- frames.append(imageio.imread(filename))
111
- current_time += timedelta(hours=1) # Intervalle d'une heure
112
 
113
- # Création du GIF
114
- gif_path = "timelapse.gif"
115
- imageio.mimsave(gif_path, frames, duration=0.5) # 0.5s par frame
116
- st.image(gif_path, caption="Timelapse des ombres", use_column_width=True)
 
 
 
 
 
1
  import streamlit as st
2
  import rasterio
3
  import numpy as np
 
 
 
4
  import pyvista as pv
5
+ from pyvistaqt import BackgroundPlotter
6
+ import tempfile
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
 
8
  # Fonction pour charger un raster
9
  def load_raster(file_path):
10
  with rasterio.open(file_path) as src:
11
+ raster = src.read(1) # Lecture de la première bande
12
+ transform = src.transform # Transformation affine du raster
13
  return raster, transform
14
 
15
+ # Fonction pour créer un modèle 3D
16
+ def create_3d_model(raster, transform, vertical_exaggeration=1.0):
17
+ rows, cols = raster.shape
18
+ x = np.linspace(transform[2], transform[2] + transform[0] * cols, cols)
19
+ y = np.linspace(transform[5], transform[5] + transform[4] * rows, rows)
20
+ z = raster * vertical_exaggeration
 
 
 
21
 
22
+ # Création des coordonnées
23
+ xx, yy = np.meshgrid(x, y)
24
+ xx = xx.flatten()
25
+ yy = yy.flatten()
26
+ zz = z.flatten()
27
 
28
+ # Création de la grille structurée
29
+ points = np.c_[xx, yy, zz]
30
+ grid = pv.StructuredGrid()
31
+ grid.points = points
32
+ grid.dimensions = (cols, rows, 1) # Dimensions de la grille
33
+ return grid
34
 
35
+ # Streamlit App
36
+ st.title("Maquette 3D à partir d'un Raster")
37
+ uploaded_file = st.file_uploader("Téléchargez un fichier raster (MNT ou MES)", type=["tif"])
 
 
 
 
 
 
 
 
38
 
39
+ if uploaded_file:
40
+ raster, transform = load_raster(uploaded_file)
41
+ st.success("Raster chargé avec succès!")
 
 
42
 
43
+ # Configuration utilisateur
44
+ vertical_exaggeration = st.slider("Échelle verticale (exagération)", 0.1, 10.0, 1.0)
45
 
46
+ # Création du modèle 3D
47
+ st.subheader("Modèle 3D")
48
+ grid = create_3d_model(raster, transform, vertical_exaggeration)
 
 
 
 
49
 
50
+ # Visualisation avec PyVista
51
  plotter = pv.Plotter(off_screen=True)
52
+ plotter.add_mesh(grid, scalars=raster.flatten(), cmap="terrain", show_edges=False)
 
 
53
  plotter.add_scalar_bar("Élévation (m)")
54
+ plotter.view_isometric()
55
+ screenshot_path = tempfile.NamedTemporaryFile(suffix=".png").name
56
+ plotter.show(screenshot=screenshot_path)
57
 
58
+ # Affichage dans Streamlit
59
+ st.image(screenshot_path, caption="Modèle 3D", use_column_width=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
 
61
+ # Exportation du modèle
62
+ st.subheader("Exportation du Modèle")
63
+ export_format = st.selectbox("Format d'exportation", ["STL", "OBJ"])
64
+ if st.button("Exporter"):
65
+ export_file = tempfile.NamedTemporaryFile(suffix=f".{export_format.lower()}", delete=False).name
66
+ grid.save(export_file)
67
+ st.success(f"Modèle exporté sous forme de fichier {export_format}.")
68
+ st.download_button("Télécharger le fichier exporté", data=open(export_file, "rb").read(), file_name=f"model.{export_format.lower()}")