Buckets:
| import React, { useState } from 'react'; | |
| import { | |
| Box, | |
| Typography, | |
| TextField, | |
| Button, | |
| Slider, | |
| Divider, | |
| Alert, | |
| CircularProgress, | |
| } from '@mui/material'; | |
| import { Memory as MeshIcon, Refresh as RefineIcon } from '@mui/icons-material'; | |
| import { api } from '../services/api'; | |
| import { MeshInfo } from '../types'; | |
| interface MeshPanelProps { | |
| geometryId: string; | |
| } | |
| const MeshPanel: React.FC<MeshPanelProps> = ({ geometryId }) => { | |
| const [elementSize, setElementSize] = useState(0.01); | |
| const [loading, setLoading] = useState(false); | |
| const [refining, setRefining] = useState(false); | |
| const [error, setError] = useState<string | null>(null); | |
| const [meshInfo, setMeshInfo] = useState<MeshInfo | null>(null); | |
| const handleGenerateMesh = async () => { | |
| setLoading(true); | |
| setError(null); | |
| try { | |
| const info = await api.generateMesh(geometryId, elementSize); | |
| setMeshInfo(info); | |
| } catch (err: any) { | |
| setError(err.message || 'Erreur lors de la génération du maillage'); | |
| } finally { | |
| setLoading(false); | |
| } | |
| }; | |
| const handleRefineMesh = async () => { | |
| if (!meshInfo) return; | |
| setRefining(true); | |
| setError(null); | |
| try { | |
| const info = await api.refineMesh(meshInfo.id); | |
| setMeshInfo(info); | |
| } catch (err: any) { | |
| setError(err.message || 'Erreur lors du raffinement'); | |
| } finally { | |
| setRefining(false); | |
| } | |
| }; | |
| return ( | |
| <Box sx={{ p: 2 }}> | |
| <Typography variant="subtitle2" color="primary" sx={{ mb: 2 }}> | |
| Maillage | |
| </Typography> | |
| <Typography variant="caption" color="textSecondary"> | |
| Taille des éléments (m) | |
| </Typography> | |
| <Slider | |
| value={elementSize} | |
| onChange={(_, value) => setElementSize(value as number)} | |
| min={0.001} | |
| max={0.1} | |
| step={0.001} | |
| valueLabelDisplay="auto" | |
| valueLabelFormat={(v) => `${(v * 1000).toFixed(1)} mm`} | |
| sx={{ mt: 1 }} | |
| /> | |
| <TextField | |
| fullWidth | |
| size="small" | |
| type="number" | |
| value={elementSize} | |
| onChange={(e) => setElementSize(Number(e.target.value))} | |
| sx={{ mt: 1 }} | |
| /> | |
| <Button | |
| fullWidth | |
| variant="contained" | |
| startIcon={loading ? <CircularProgress size={16} /> : <MeshIcon />} | |
| onClick={handleGenerateMesh} | |
| disabled={loading || !geometryId} | |
| sx={{ mt: 2 }} | |
| > | |
| Générer le maillage | |
| </Button> | |
| {meshInfo && ( | |
| <> | |
| <Divider sx={{ my: 2 }} /> | |
| <Typography variant="caption" color="textSecondary"> | |
| Informations maillage | |
| </Typography> | |
| <Box sx={{ mt: 1 }}> | |
| <Typography variant="body2"> | |
| Nœuds : {meshInfo.num_nodes.toLocaleString()} | |
| </Typography> | |
| <Typography variant="body2"> | |
| Éléments : {meshInfo.num_elements.toLocaleString()} | |
| </Typography> | |
| <Typography variant="body2"> | |
| Taille : {(meshInfo.mesh_size * 1000).toFixed(2)} mm | |
| </Typography> | |
| </Box> | |
| <Button | |
| fullWidth | |
| variant="outlined" | |
| startIcon={refining ? <CircularProgress size={16} /> : <RefineIcon />} | |
| onClick={handleRefineMesh} | |
| disabled={refining} | |
| sx={{ mt: 2 }} | |
| > | |
| Raffiner le maillage | |
| </Button> | |
| </> | |
| )} | |
| {error && ( | |
| <Alert severity="error" sx={{ mt: 2 }}> | |
| {error} | |
| </Alert> | |
| )} | |
| </Box> | |
| ); | |
| }; | |
| export default MeshPanel; | |
Xet Storage Details
- Size:
- 3.63 kB
- Xet hash:
- 6c376f3c1a5ab7439abfe8d7e08484955299aa1dc6db14536de4d71c35488ee5
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.