download
raw
6.55 kB
import { useRef, useState, useMemo } from 'react';
import { Canvas, useFrame, useThree } from '@react-three/fiber';
import { OrbitControls, Grid, Text } from '@react-three/drei';
import * as THREE from 'three';
// Composant pour le maillage
function Mesh({ meshData, showWireframe, showFaces }) {
const meshRef = useRef();
const geometry = useMemo(() => {
const geom = new THREE.BufferGeometry();
// Créer les vertices (avec z=0 pour un maillage 2D en 3D)
const vertices = [];
meshData.vertices.forEach(([x, y]) => {
vertices.push(x, y, 0);
});
// Créer les indices pour les triangles
const indices = [];
meshData.triangles.forEach(tri => {
indices.push(...tri);
});
geom.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
geom.setIndex(indices);
geom.computeVertexNormals();
return geom;
}, [meshData]);
return (
<group ref={meshRef}>
{/* Faces */}
{showFaces && (
<mesh geometry={geometry}>
<meshStandardMaterial
color="#3498db"
side={THREE.DoubleSide}
transparent
opacity={0.6}
/>
</mesh>
)}
{/* Wireframe */}
{showWireframe && (
<lineSegments>
<edgesGeometry args={[geometry]} />
<lineBasicMaterial color="#00ff88" linewidth={1} />
</lineSegments>
)}
</group>
);
}
// Composant pour les axes
function Axes({ bounds }) {
const { x_min, x_max, y_min, y_max } = bounds;
const cx = (x_min + x_max) / 2;
const cy = (y_min + y_max) / 2;
return (
<group position={[0, 0, -0.01]}>
{/* Axe X */}
<line>
<bufferGeometry>
<bufferAttribute
attach="attributes-position"
count={2}
array={new Float32Array([x_min - 0.2, 0, 0, x_max + 0.2, 0, 0])}
itemSize={3}
/>
</bufferGeometry>
<lineBasicMaterial color="#ff6b6b" />
</line>
{/* Axe Y */}
<line>
<bufferGeometry>
<bufferAttribute
attach="attributes-position"
count={2}
array={new Float32Array([0, y_min - 0.2, 0, 0, y_max + 0.2, 0])}
itemSize={3}
/>
</bufferGeometry>
<lineBasicMaterial color="#00ff88" />
</line>
</group>
);
}
// Composant pour les labels
function Labels({ bounds }) {
const { x_min, x_max, y_min, y_max } = bounds;
return (
<group>
<Text position={[x_max + 0.3, 0, 0]} fontSize={0.1} color="#ff6b6b">X</Text>
<Text position={[0, y_max + 0.2, 0]} fontSize={0.1} color="#00ff88">Y</Text>
<Text position={[x_min, -0.15, 0]} fontSize={0.08} color="#888">{x_min}</Text>
<Text position={[x_max, -0.15, 0]} fontSize={0.08} color="#888">{x_max}</Text>
<Text position={[-0.15, y_min, 0]} fontSize={0.08} color="#888">{y_min}</Text>
<Text position={[-0.15, y_max, 0]} fontSize={0.08} color="#888">{y_max}</Text>
</group>
);
}
// Composant Camera
function CameraSetup({ bounds }) {
const { camera } = useThree();
const { x_min, x_max, y_min, y_max } = bounds;
useMemo(() => {
const cx = (x_min + x_max) / 2;
const cy = (y_min + y_max) / 2;
const size = Math.max(x_max - x_min, y_max - y_min);
camera.position.set(cx, cy, size * 1.5);
camera.lookAt(cx, cy, 0);
}, [bounds, camera]);
return null;
}
export default function MeshViewer3D({ meshData }) {
const [showWireframe, setShowWireframe] = useState(true);
const [showFaces, setShowFaces] = useState(true);
if (!meshData) return null;
const bounds = meshData.bounds;
const cx = (bounds.x_min + bounds.x_max) / 2;
const cy = (bounds.y_min + bounds.y_max) / 2;
return (
<div className="mesh-viewer-3d">
<div className="viewer-controls">
<label>
<input
type="checkbox"
checked={showWireframe}
onChange={(e) => setShowWireframe(e.target.checked)}
/>
Wireframe
</label>
<label>
<input
type="checkbox"
checked={showFaces}
onChange={(e) => setShowFaces(e.target.checked)}
/>
Faces
</label>
<span className="info">
{meshData.num_vertices} sommets | {meshData.num_triangles} triangles
</span>
</div>
<Canvas camera={{ position: [cx, cy, 2], fov: 50 }}>
<color attach="background" args={['#1a1a2e']} />
<ambientLight intensity={0.5} />
<directionalLight position={[5, 5, 5]} intensity={1} />
<CameraSetup bounds={bounds} />
<Mesh
meshData={meshData}
showWireframe={showWireframe}
showFaces={showFaces}
/>
<Axes bounds={bounds} />
<Labels bounds={bounds} />
<OrbitControls
target={[cx, cy, 0]}
enablePan={true}
enableZoom={true}
enableRotate={true}
/>
<gridHelper
args={[4, 20, '#333', '#222']}
position={[cx, cy, -0.1]}
rotation={[Math.PI / 2, 0, 0]}
/>
</Canvas>
<div className="viewer-help">
Clic gauche: rotation | Clic droit: déplacement | Molette: zoom
</div>
</div>
);
}

Xet Storage Details

Size:
6.55 kB
·
Xet hash:
c61c57f110ac5cd9ed7b74676f6860738f4436d000c059e353a436e041eca544

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.