Buckets:
| import { useState, useEffect, useRef } from 'react'; | |
| import { poissonApi } from '../../api'; | |
| import PoissonForm from './PoissonForm'; | |
| import MeshViewer3D from './MeshViewer3D'; | |
| import SolutionViewer from './SolutionViewer'; | |
| import AnimationPlayer from './AnimationPlayer'; | |
| import SimulationHistory from './SimulationHistory'; | |
| import '../../styles/poisson.css'; | |
| export default function PoissonApp({ onBack }) { | |
| const [simulations, setSimulations] = useState([]); | |
| const [selectedSimulation, setSelectedSimulation] = useState(null); | |
| const [loading, setLoading] = useState(false); | |
| const [viewMode, setViewMode] = useState('mesh'); // 'mesh', 'solution', 'animation' | |
| const [meshPreview, setMeshPreview] = useState(null); | |
| // Charger les simulations existantes | |
| useEffect(() => { | |
| loadSimulations(); | |
| }, []); | |
| const loadSimulations = async () => { | |
| try { | |
| const data = await poissonApi.getSimulations(); | |
| setSimulations(data); | |
| } catch (err) { | |
| console.error('Erreur chargement simulations:', err); | |
| } | |
| }; | |
| const handlePreviewMesh = async (params) => { | |
| try { | |
| const preview = await poissonApi.previewMesh(params); | |
| setMeshPreview(preview); | |
| setViewMode('mesh'); | |
| } catch (err) { | |
| console.error('Erreur preview:', err); | |
| } | |
| }; | |
| const handleSimulationCreated = async (simulation) => { | |
| setSelectedSimulation(simulation); | |
| setMeshPreview(null); | |
| setViewMode('solution'); | |
| await loadSimulations(); | |
| }; | |
| const handleSelectSimulation = async (sim) => { | |
| setLoading(true); | |
| try { | |
| const full = await poissonApi.getSimulation(sim.id); | |
| setSelectedSimulation(full); | |
| setMeshPreview(null); | |
| setViewMode('solution'); | |
| } catch (err) { | |
| console.error('Erreur:', err); | |
| } | |
| setLoading(false); | |
| }; | |
| const handleDeleteSimulation = async (id) => { | |
| try { | |
| await poissonApi.deleteSimulation(id); | |
| if (selectedSimulation?.id === id) { | |
| setSelectedSimulation(null); | |
| } | |
| await loadSimulations(); | |
| } catch (err) { | |
| console.error('Erreur suppression:', err); | |
| } | |
| }; | |
| const getCurrentMeshData = () => { | |
| if (meshPreview) return meshPreview; | |
| if (selectedSimulation?.mesh_data) return selectedSimulation.mesh_data; | |
| return null; | |
| }; | |
| const getCurrentSolutionData = () => { | |
| console.log('getCurrentSolutionData called'); | |
| console.log('selectedSimulation:', selectedSimulation); | |
| console.log('result_data:', selectedSimulation?.result_data); | |
| console.log('mesh_data:', selectedSimulation?.mesh_data); | |
| if (selectedSimulation?.result_data) { | |
| const data = { | |
| mesh: selectedSimulation.mesh_data, | |
| solution: selectedSimulation.result_data, | |
| }; | |
| console.log('Returning solution data:', data); | |
| return data; | |
| } | |
| console.log('No result_data, returning null'); | |
| return null; | |
| }; | |
| return ( | |
| <div className="poisson-app"> | |
| <header className="poisson-header"> | |
| <button className="back-btn" onClick={onBack}>← Retour</button> | |
| <h1>Simulation de l'Équation de Poisson</h1> | |
| <p className="subtitle">-Δu = f avec conditions aux limites</p> | |
| </header> | |
| <main className="poisson-main"> | |
| {/* Panneau de contrôle */} | |
| <aside className="control-panel"> | |
| <PoissonForm | |
| onPreviewMesh={handlePreviewMesh} | |
| onSimulationCreated={handleSimulationCreated} | |
| loading={loading} | |
| setLoading={setLoading} | |
| /> | |
| <SimulationHistory | |
| simulations={simulations} | |
| selectedId={selectedSimulation?.id} | |
| onSelect={handleSelectSimulation} | |
| onDelete={handleDeleteSimulation} | |
| /> | |
| </aside> | |
| {/* Zone de visualisation */} | |
| <section className="visualization-panel"> | |
| {/* Onglets de visualisation */} | |
| <div className="view-tabs"> | |
| <button | |
| className={`tab ${viewMode === 'mesh' ? 'active' : ''}`} | |
| onClick={() => setViewMode('mesh')} | |
| > | |
| Maillage 3D | |
| </button> | |
| <button | |
| className={`tab ${viewMode === 'solution' ? 'active' : ''}`} | |
| onClick={() => setViewMode('solution')} | |
| disabled={!selectedSimulation?.result_data} | |
| > | |
| Solution | |
| </button> | |
| <button | |
| className={`tab ${viewMode === 'animation' ? 'active' : ''}`} | |
| onClick={() => setViewMode('animation')} | |
| disabled={!selectedSimulation?.animation_frames} | |
| > | |
| Animation | |
| </button> | |
| </div> | |
| {/* Conteneur de visualisation */} | |
| <div className="viewer-container"> | |
| {loading && ( | |
| <div className="loading-overlay"> | |
| <div className="spinner"></div> | |
| <p>Calcul en cours...</p> | |
| </div> | |
| )} | |
| {viewMode === 'mesh' && getCurrentMeshData() && ( | |
| <MeshViewer3D meshData={getCurrentMeshData()} /> | |
| )} | |
| {viewMode === 'solution' && getCurrentSolutionData() && ( | |
| <SolutionViewer data={getCurrentSolutionData()} /> | |
| )} | |
| {viewMode === 'animation' && selectedSimulation?.animation_frames && ( | |
| <AnimationPlayer | |
| meshData={selectedSimulation.mesh_data} | |
| frames={selectedSimulation.animation_frames} | |
| solutionRange={{ | |
| min: selectedSimulation.solution_min, | |
| max: selectedSimulation.solution_max, | |
| }} | |
| /> | |
| )} | |
| {!getCurrentMeshData() && !loading && ( | |
| <div className="placeholder"> | |
| <p>Configurez les paramètres et cliquez sur</p> | |
| <p><strong>"Aperçu du maillage"</strong> ou <strong>"Lancer la simulation"</strong></p> | |
| </div> | |
| )} | |
| </div> | |
| {/* Statistiques */} | |
| {selectedSimulation?.status === 'completed' && ( | |
| <div className="stats-bar"> | |
| <div className="stat"> | |
| <span className="label">Min</span> | |
| <span className="value">{selectedSimulation.solution_min?.toFixed(6)}</span> | |
| </div> | |
| <div className="stat"> | |
| <span className="label">Max</span> | |
| <span className="value">{selectedSimulation.solution_max?.toFixed(6)}</span> | |
| </div> | |
| <div className="stat"> | |
| <span className="label">Temps</span> | |
| <span className="value">{selectedSimulation.computation_time?.toFixed(3)}s</span> | |
| </div> | |
| <div className="stat"> | |
| <span className="label">DDL</span> | |
| <span className="value">{selectedSimulation.mesh_data?.num_vertices}</span> | |
| </div> | |
| </div> | |
| )} | |
| </section> | |
| </main> | |
| </div> | |
| ); | |
| } | |
Xet Storage Details
- Size:
- 8.85 kB
- Xet hash:
- 4931c2cf69894ad1510a8b38c212e0cf983b71c6f2d17999847eaeed61bb502d
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.