feat: viewer split 3D+2D — AUV depth chart + USBL XY fix

This commit is contained in:
Floppyrj45
2026-04-24 20:56:17 +02:00
parent 36c7889db1
commit 279e70a5e0
3 changed files with 159 additions and 66 deletions

View File

@@ -2,10 +2,11 @@ import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// ── Renderer ──────────────────────────────────────────────────────────────────
const viewerEl = document.getElementById('viewer');
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(Math.min(devicePixelRatio, 2));
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
renderer.setSize(viewerEl.clientWidth, viewerEl.clientHeight);
viewerEl.appendChild(renderer.domElement);
// ── Scene ─────────────────────────────────────────────────────────────────────
const scene = new THREE.Scene();
@@ -15,7 +16,7 @@ scene.add(new THREE.GridHelper(1000, 100, 0x111133, 0x0a0a22));
scene.add(new THREE.AxesHelper(5));
// ── Camera + Controls ─────────────────────────────────────────────────────────
const camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 0.1, 5000);
const camera = new THREE.PerspectiveCamera(60, viewerEl.clientWidth / viewerEl.clientHeight, 0.1, 5000);
camera.position.set(0, 150, 250);
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
@@ -101,14 +102,9 @@ fetch('/api/trajectory')
addLayer('usv_gps', makePoints(x, y, z, i => RTK_COLORS[Math.min(rtk[i], 2)]));
}
if (d.auv_depth) {
const { x, y, z } = d.auv_depth;
addLayer('auv_depth', makeLine(x, y, z, 0x44ffaa));
}
if (d.usbl) {
const { x, y, z } = d.usbl;
addLayer('usbl', makePoints(x, y, z, () => [1, 0.42, 0.21]));
if (d.auv_usbl) {
const { x, y, z } = d.auv_usbl;
addLayer('auv_usbl', makePoints(x, y, z, () => [0.27, 1.0, 0.67]));
}
const trajData = d.fused || d.lingbot_local;
@@ -149,6 +145,60 @@ fetch('/api/trajectory')
camera.position.set(cx, 50, -cy + 80);
controls.update();
}
// 2D depth/altitude chart
if (d.auv_profile) {
const { t_s, depth_m, altitude_m } = d.auv_profile;
const hasAlt = altitude_m && altitude_m.some(v => !isNaN(v) && v !== null);
const datasets = [
{
label: 'Depth (m)',
data: t_s.map((t, i) => ({ x: t, y: -depth_m[i] })),
borderColor: '#3a9fff',
backgroundColor: 'rgba(58,159,255,0.08)',
borderWidth: 1.5,
pointRadius: 0,
fill: true,
},
];
if (hasAlt) {
datasets.push({
label: 'Altitude above seafloor (m)',
data: t_s.map((t, i) => ({ x: t, y: altitude_m[i] })),
borderColor: '#44ffaa',
backgroundColor: 'transparent',
borderWidth: 1.5,
pointRadius: 0,
});
}
new Chart(document.getElementById('depth-chart'), {
type: 'line',
data: { datasets },
options: {
animation: false,
responsive: true,
maintainAspectRatio: false,
parsing: false,
plugins: {
legend: { labels: { color: '#889', font: { size: 10, family: 'Courier New' } } },
tooltip: { enabled: false },
},
scales: {
x: {
type: 'linear',
title: { display: true, text: 'Time (s)', color: '#445' },
ticks: { color: '#445', font: { size: 9 } },
grid: { color: '#111' },
},
y: {
title: { display: true, text: 'm', color: '#445' },
ticks: { color: '#445', font: { size: 9 } },
grid: { color: '#111' },
},
},
},
});
}
})
.catch(err => {
document.getElementById('status').textContent = `Error: ${err}`;
@@ -164,9 +214,9 @@ document.querySelectorAll('[data-layer]').forEach(cb => {
// ── Resize ────────────────────────────────────────────────────────────────────
window.addEventListener('resize', () => {
camera.aspect = innerWidth / innerHeight;
camera.aspect = viewerEl.clientWidth / viewerEl.clientHeight;
camera.updateProjectionMatrix();
renderer.setSize(innerWidth, innerHeight);
renderer.setSize(viewerEl.clientWidth, viewerEl.clientHeight);
});
// ── Render loop ───────────────────────────────────────────────────────────────