import { useState } from 'react'; interface ReconItem { id: string name: string type: 'vessel' | 'pollution' status: 'complete' | 'processing' points: string polygons: string coverage: string } const reconItems: ReconItem[] = [ { id: 'V-001', name: '불명선박-A', type: 'vessel', status: 'complete', points: '980K', polygons: '38K', coverage: '97.1%' }, { id: 'V-002', name: '불명선박-B', type: 'vessel', status: 'complete', points: '1.2M', polygons: '48K', coverage: '98.4%' }, { id: 'V-003', name: '어선 #37', type: 'vessel', status: 'processing', points: '420K', polygons: '16K', coverage: '64.2%' }, { id: 'P-001', name: '유류오염-A', type: 'pollution', status: 'complete', points: '560K', polygons: '22K', coverage: '95.8%' }, { id: 'P-002', name: '유류오염-B', type: 'pollution', status: 'processing', points: '310K', polygons: '12K', coverage: '52.1%' }, ] function Vessel3DModel({ viewMode, status }: { viewMode: string; status: string }) { const isProcessing = status === 'processing' const isWire = viewMode === 'wire' const isPoint = viewMode === 'point' const [vesselPoints] = useState(() => Array.from({ length: 300 }, (_, i) => { const x = 35 + Math.random() * 355 const y = 15 + Math.random() * 160 const inHull = y > 60 && y < 175 && x > 35 && x < 390 const inBridge = x > 260 && x < 330 && y > 25 && y < 60 if (!inHull && !inBridge && Math.random() > 0.15) return null const alpha = 0.15 + Math.random() * 0.55 const r = 0.8 + Math.random() * 0.8 return { i, x, y, r, alpha } }) ) // 선박 SVG 와이어프레임/솔리드 3D 투시 return (
{/* 수선 (waterline) */} {/* 선체 (hull) - 3D 효과 */} {/* 선체 하부 */} {/* 갑판 (deck) */} {/* 선교 (bridge) */} {/* 선교 창문 */} {!isPoint && } {/* 마스트 */} {/* 연통 (funnel) */} {/* 화물 크레인 */} {/* 선체 리브 (와이어프레임 / 포인트 모드) */} {(isWire || isPoint) && {[80, 120, 160, 200, 240, 280, 320, 360].map(x => ( ))} {[80, 100, 120, 140, 160].map(y => ( ))} } {/* 포인트 클라우드 모드 */} {isPoint && {vesselPoints.map(p => p && ( ))} } {/* 선수/선미 표시 */} 선수 선미 {/* 측정선 (3D 모드) */} {viewMode === '3d' && <> 84.7m 14.2m } {/* 처리중 오버레이 */} {isProcessing && (
재구성 처리중...
)}
) } function Pollution3DModel({ viewMode, status }: { viewMode: string; status: string }) { const isProcessing = status === 'processing' const isWire = viewMode === 'wire' const isPoint = viewMode === 'point' const [pollutionPoints] = useState(() => Array.from({ length: 400 }, (_, i) => { const cx = 190, cy = 145, rx = 130, ry = 75 const angle = Math.random() * Math.PI * 2 const r = Math.sqrt(Math.random()) const x = cx + r * rx * Math.cos(angle) const y = cy + r * ry * Math.sin(angle) if (x < 40 || x > 340 || y < 50 || y > 230) return null const dist = Math.sqrt(((x - cx) / rx) ** 2 + ((y - cy) / ry) ** 2) const intensity = Math.max(0.1, 1 - dist) const color = dist < 0.4 ? `rgba(239,68,68,${intensity * 0.7})` : dist < 0.7 ? `rgba(249,115,22,${intensity * 0.5})` : `rgba(234,179,8,${intensity * 0.3})` const circleR = 0.6 + Math.random() * 1.2 return { i, x, y, r: circleR, color } }) ) return (
{/* 해수면 그리드 */} {Array.from({ length: 15 }, (_, i) => )} {Array.from({ length: 20 }, (_, i) => )} {/* 유막 메인 형태 - 불규칙 blob */} {/* 유막 두께 등고선 */} {/* 유막 최고 두께 핵심 */} {/* 확산 방향 화살표 */} ESE 0.3km/h {/* 와이어프레임 추가 등고선 */} {(isWire || isPoint) && } {/* 포인트 클라우드 */} {isPoint && {pollutionPoints.map(p => p && ( ))} } {/* 두께 색상 범례 */} {viewMode === '3d' && <> 3.2mm 1.5mm 0.3mm } {/* 측정선 (3D 모드) */} {viewMode === '3d' && <> 1.24 km 0.68 km } {/* 두께 색상 범례 바 */} {viewMode === '3d' && !isProcessing && (
0mm
3.2mm
)} {isProcessing && (
재구성 처리중...
)}
) } export function SensorAnalysis() { const [subTab, setSubTab] = useState<'vessel' | 'pollution'>('vessel') const [viewMode, setViewMode] = useState('3d') const [selectedItem, setSelectedItem] = useState(reconItems[1]) const filteredItems = reconItems.filter(r => r.type === (subTab === 'vessel' ? 'vessel' : 'pollution')) return (
{/* Left Panel */}
{/* 3D Reconstruction List */}
📋 3D 재구성 완료 목록
{filteredItems.map(item => (
setSelectedItem(item)} className={`flex items-center gap-2 px-2 py-2 rounded-sm cursor-pointer transition-colors border ${ selectedItem.id === item.id ? 'bg-[rgba(6,182,212,0.08)] border-primary-cyan/20' : 'border-transparent hover:bg-white/[0.02]' }`} >
{item.name}
{item.id} · {item.points} pts
{item.status === 'complete' ? '✅ 완료' : '⏳ 처리중'}
))}
{/* Source Images */}
📹 촬영 원본
{[ { label: 'D-01 정면', sensor: '광학', color: 'text-primary-blue' }, { label: 'D-02 좌현', sensor: 'IR', color: 'text-status-red' }, { label: 'D-03 우현', sensor: '광학', color: 'text-primary-purple' }, { label: 'D-02 상부', sensor: 'IR', color: 'text-status-red' }, ].map((src, i) => (
{src.label.split(' ')[0]}
{src.label} {src.sensor}
))}
{/* Center Panel - 3D Canvas */}
{/* Simulated 3D viewport */}
{/* Grid floor */}
{/* 3D Model Visualization */} {selectedItem.type === 'vessel' ? ( ) : ( )} {/* Axis indicator */}
X →
Y ↑
Z ⊙
{/* Title */}
3D Vessel Analysis
{selectedItem.name} 정밀분석
34.58°N, 129.30°E · {selectedItem.status === 'complete' ? '재구성 완료' : '처리중'}
{/* View Mode Buttons */}
{[ { id: '3d', label: '3D모델' }, { id: 'point', label: '포인트클라우드' }, { id: 'wire', label: '와이어프레임' }, ].map(m => ( ))}
{/* Bottom Stats */}
{[ { value: selectedItem.points, label: '포인트' }, { value: selectedItem.polygons, label: '폴리곤' }, { value: '3', label: '시점' }, { value: selectedItem.coverage, label: '커버리지' }, { value: '0.023m', label: 'RMS오차' }, ].map((s, i) => (
{s.value}
{s.label}
))}
{/* Right Panel - Analysis Details */}
{/* Ship/Pollution Info */}
📊 분석 정보
{(selectedItem.type === 'vessel' ? [ ['대상', selectedItem.name], ['선종 추정', '일반화물선 (추정)'], ['길이', '약 85m'], ['폭', '약 14m'], ['AIS 상태', 'OFF (미식별)'], ['최초 탐지', '2026-01-18 14:20'], ['촬영 시점', '3 시점 (정면/좌현/우현)'], ['센서', '광학 4K + IR 열화상'], ] : [ ['대상', selectedItem.name], ['유형', '유류 오염'], ['추정 면적', '0.42 km²'], ['추정 유출량', '12.6 kL'], ['유종', 'B-C유 (추정)'], ['최초 탐지', '2026-01-18 13:50'], ['확산 속도', '0.3 km/h (ESE 방향)'], ]).map(([k, v], i) => (
{k} {v}
))}
{/* AI Detection Results */}
🤖 AI 탐지 결과
{(selectedItem.type === 'vessel' ? [ { label: '선박 식별', confidence: 94, color: 'bg-status-green' }, { label: '선종 분류', confidence: 78, color: 'bg-status-yellow' }, { label: '손상 감지', confidence: 45, color: 'bg-status-orange' }, { label: '화물 분석', confidence: 62, color: 'bg-status-yellow' }, ] : [ { label: '유막 탐지', confidence: 97, color: 'bg-status-green' }, { label: '유종 분류', confidence: 85, color: 'bg-status-green' }, { label: '두께 추정', confidence: 72, color: 'bg-status-yellow' }, { label: '확산 예측', confidence: 68, color: 'bg-status-orange' }, ]).map((r, i) => (
{r.label} {r.confidence}%
))}
{/* Comparison / Measurements */}
📐 3D 측정값
{(selectedItem.type === 'vessel' ? [ ['전장 (LOA)', '84.7 m'], ['형폭 (Breadth)', '14.2 m'], ['건현 (Freeboard)', '3.8 m'], ['흘수 (Draft)', '5.6 m (추정)'], ['마스트 높이', '22.3 m'], ] : [ ['유막 면적', '0.42 km²'], ['최대 길이', '1.24 km'], ['최대 폭', '0.68 km'], ['평균 두께', '0.8 mm'], ['최대 두께', '3.2 mm'], ]).map(([k, v], i) => (
{k} {v}
))}
{/* Action Buttons */}
) }