Streamlit / pages /5_📍_VertXtractor.py
Vertdure's picture
Update pages/5_📍_VertXtractor.py
96479f0 verified
raw
history blame
7.1 kB
import streamlit as st
import geopandas as gpd
import rasterio
import numpy as np
from pyproj import Transformer
import trimesh
import logging
from io import BytesIO
import folium
from streamlit_folium import folium_static
# Configuration du logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# Fonction pour charger le MNT de la Suisse (à implémenter)
def load_swiss_dem():
"""
Charge le MNT de la Suisse. Cette fonction devrait ĂȘtre implĂ©mentĂ©e pour charger
le MNT complet de la Suisse à partir d'une source de données appropriée.
"""
# Placeholder - à remplacer par le chargement réel du MNT suisse
return None, None
# Fonction pour extraire une partie du MNT
def extract_dem_region(dem, transform, bbox):
"""
Extrait une région spécifique du MNT basée sur une boßte englobante.
Args:
dem (numpy.array): Données du MNT complet
transform (affine.Affine): Transformation géospatiale
bbox (tuple): BoĂźte englobante (minx, miny, maxx, maxy)
Returns:
tuple: (données du MNT extraites, nouvelle transformation)
"""
# Conversion des coordonnées de la bbox en indices de pixels
minx, miny, maxx, maxy = bbox
rows, cols = rasterio.transform.rowcol(transform, [minx, maxx], [miny, maxy])
# Extraction de la région
window = ((rows[0], rows[1]), (cols[0], cols[1]))
dem_region = dem[window[0][0]:window[0][1], window[1][0]:window[1][1]]
# Calcul de la nouvelle transformation
new_transform = rasterio.transform.from_bounds(minx, miny, maxx, maxy,
dem_region.shape[1], dem_region.shape[0])
return dem_region, new_transform
def create_mesh(dem, transform, resolution):
"""
Crée un maillage 3D à partir des données du MNT.
Args:
dem (numpy.array): Données du MNT
transform (affine.Affine): Transformation géospatiale
resolution (int): RĂ©solution du maillage
Returns:
trimesh.Trimesh: Maillage 3D
"""
try:
height, width = dem.shape
x, y = np.meshgrid(np.arange(width), np.arange(height))
lon, lat = rasterio.transform.xy(transform, y, x)
vertices = np.column_stack((lon.flatten(), lat.flatten(), dem.flatten()))
faces = []
for i in range(height - 1):
for j in range(width - 1):
idx = i * width + j
faces.append([idx, idx + 1, idx + width])
faces.append([idx + 1, idx + width + 1, idx + width])
mesh = trimesh.Trimesh(vertices=vertices, faces=faces)
target_faces = (height * width) // (resolution ** 2)
mesh = mesh.simplify_quadric_decimation(target_faces)
return mesh
except Exception as e:
logger.error(f"Erreur lors de la création du maillage: {str(e)}")
st.error("Erreur lors de la création du maillage. Veuillez vérifier les paramÚtres.")
return None
def visualize_mesh(mesh):
"""
Crée une visualisation du maillage.
Args:
mesh (trimesh.Trimesh): Maillage 3D Ă  visualiser
Returns:
matplotlib.figure.Figure: Figure contenant la visualisation du maillage
"""
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_trisurf(mesh.vertices[:, 0], mesh.vertices[:, 1], mesh.vertices[:, 2],
triangles=mesh.faces, cmap='viridis')
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
return fig
def export_for_blender(mesh):
"""
Exporte le maillage dans un format compatible avec Blender.
Args:
mesh (trimesh.Trimesh): Maillage 3D Ă  exporter
Returns:
bytes: Contenu du fichier d'export
"""
try:
obj_file = BytesIO()
mesh.export(obj_file, file_type='obj')
return obj_file.getvalue()
except Exception as e:
logger.error(f"Erreur lors de l'export pour Blender: {str(e)}")
st.error("Erreur lors de l'export pour Blender. Veuillez réessayer.")
return None
# Interface Streamlit
st.title("Mesh Tiler CH - Streamlit Edition")
st.write("Sélectionnez une zone en Suisse pour créer un maillage 3D.")
# Chargement du MNT complet de la Suisse
swiss_dem, swiss_transform = load_swiss_dem()
# Sélection de la méthode d'entrée
input_method = st.radio("Choisissez la méthode de sélection de la zone :",
("Dessiner sur la carte", "Entrer les coordonnées"))
if input_method == "Dessiner sur la carte":
# Créer une carte centrée sur la Suisse
m = folium.Map(location=[46.8182, 8.2275], zoom_start=8)
# Ajouter un outil de dessin de rectangle
draw = folium.plugins.Draw(export=True)
draw.add_to(m)
# Afficher la carte
folium_static(m)
# Récupérer les coordonnées du rectangle dessiné
if st.button("Créer le maillage à partir de la sélection"):
# Ici, vous devriez récupérer les coordonnées du rectangle dessiné
# Cette partie nécessite une implémentation plus avancée avec JavaScript
st.write("Fonctionnalité en cours de développement.")
else:
# Entrer les coordonnées manuellement
col1, col2 = st.columns(2)
with col1:
minx = st.number_input("Min X", value=7.0)
miny = st.number_input("Min Y", value=46.0)
with col2:
maxx = st.number_input("Max X", value=8.0)
maxy = st.number_input("Max Y", value=47.0)
if st.button("Créer le maillage"):
bbox = (minx, miny, maxx, maxy)
dem_region, region_transform = extract_dem_region(swiss_dem, swiss_transform, bbox)
resolution = st.slider("RĂ©solution du maillage", min_value=1, max_value=100, value=10)
mesh = create_mesh(dem_region, region_transform, resolution)
if mesh is not None:
fig = visualize_mesh(mesh)
st.pyplot(fig)
if st.button("Exporter pour Blender"):
blender_file = export_for_blender(mesh)
if blender_file is not None:
st.download_button("Télécharger le fichier Blender (.obj)",
blender_file,
file_name="mesh_export.obj",
mime="application/octet-stream")
# Guide d'utilisation simplifié
st.markdown("""
## Guide d'utilisation
1. Choisissez entre dessiner sur la carte ou entrer les coordonnées manuellement.
2. SĂ©lectionnez la zone d'intĂ©rĂȘt en Suisse.
3. Cliquez sur "Créer le maillage" pour générer le modÚle 3D.
4. Ajustez la résolution du maillage si nécessaire.
5. Visualisez le maillage 3D généré.
6. Exportez le maillage au format OBJ pour Blender si souhaité.
Pour toute question ou problÚme, n'hésitez pas à contacter le support technique.
""")