fix(gui): work_plane 3D view = camera POV + red = excluded points

- Camera at origin (CV frame) looking at +Z with screen-up = CV −Y, so
  the rendered scene matches the camera's vantage point. OrbitControls
  retargets to the plane centroid on fit so rotation feels natural.
- Simplify scatter coloring to two tones: red for filter-excluded points
  (signed_distance < −offset_mm/1000), cyan-white for everything kept.
  Matches the backend filter contract exactly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Adriano Dal PastroandClaude Opus 4.7 committed 2026-05-11 17:41:03 +02:00
1 parent 652fa4b912
commit 56f8888217
2 files changed
+25 -11

No files matched your search

+1 -1
View File
@@ -192,7 +192,7 @@
<div class="canvas-wrap" style="width:min(100%,720px)">
<canvas id="wp3dCanvas" width="720" height="360" style="display:block;background:#0a0d11;border:1px solid var(--border);border-radius:4px"></canvas>
</div>
<div class="marker-info">piano viola · verde = inlier · giallo = sopra piano+offset · rosso = sotto piano-offset · grigio = buffer · drag = ruota · wheel = zoom</div>
<div class="marker-info">vista camera · piano viola · ciano = punti tenuti · rosso = esclusi (sotto piano−offset) · drag = ruota · wheel = zoom</div>
</div>
<div>
<h2>Calibrazione</h2>
+24 -10
View File
@@ -135,16 +135,26 @@ function startRgbLoop() {
});
})();
// ---------------- Three.js 3D viewer ----------------
// ---------------- Three.js 3D viewer — camera-POV ----------------
//
// CV camera frame: X right, Y down, Z forward.
// We render the scene so the user sees it from the camera's vantage point:
// camera at the origin, looking at +Z, with screen-up = CV -Y. OrbitControls
// can rotate around the scene centroid once it's defined; before any fit the
// view stays at camera-POV.
const three = (function setupThree() {
const canvas = $('wp3dCanvas');
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(45, canvas.width / canvas.height, 0.01, 20);
camera.position.set(0.5, -0.5, -1.2);
camera.lookAt(0, 0, 1);
// Camera-POV: stand just behind the camera origin so OrbitControls has a
// non-zero distance to its target. Screen-up = CV -Y.
camera.up.set(0, -1, 0);
camera.position.set(0, 0, -0.001);
const renderer = new THREE.WebGLRenderer({ canvas, antialias: true });
renderer.setSize(canvas.width, canvas.height);
const controls = new OrbitControls(camera, canvas);
controls.target.set(0, 0, 1);
controls.update();
scene.add(new THREE.AxesHelper(0.1));
const planeMesh = new THREE.Mesh(
new THREE.PlaneGeometry(0.4, 0.4),
@@ -165,6 +175,9 @@ const three = (function setupThree() {
// Align plane to its normal.
planeMesh.lookAt(c[0] + n[0], c[1] + n[1], c[2] + n[2]);
planeMesh.visible = true;
// Move the orbit target onto the plane centroid so rotation feels natural.
controls.target.set(c[0], c[1], c[2]);
controls.update();
}
function setScatter(pointsCv, plane, offsetMm) {
@@ -178,17 +191,18 @@ const three = (function setupThree() {
const nz = plane ? plane.normal[2] : 0;
const d = plane ? plane.offset : 0;
const offsetM = (offsetMm || 0) / 1000.0;
const rmsM = plane ? (plane.fit_rms_mm / 1000.0) * 2.0 : 0.01;
// Two-tone colouring: filter-excluded points (signed < -offset_m) red,
// everything else cyan-white. This matches the backend filter contract
// (keep == signed >= -offset_m).
for (let i = 0; i < n; i++) {
const x = pointsCv[i][0], y = pointsCv[i][1], z = pointsCv[i][2];
positions[3 * i] = x; positions[3 * i + 1] = y; positions[3 * i + 2] = z;
const signed = plane ? (nx * x + ny * y + nz * z + d) : 0;
let r = 0.5, g = 0.5, b = 0.5;
if (plane) {
if (signed > offsetM) { r = 1.0; g = 0.83; b = 0.31; } // yellow: above plane+offset
else if (signed < -offsetM) { r = 0.93; g = 0.27; b = 0.27; } // red: below plane-offset
else if (Math.abs(signed) <= rmsM) { r = 0.30; g = 0.78; b = 0.40; } // green: inlier
else { r = 0.55; g = 0.55; b = 0.55; } // grey: buffer
let r, g, b;
if (plane && signed < -offsetM) {
r = 0.93; g = 0.27; b = 0.27; // red: excluded by below-plane filter
} else {
r = 0.75; g = 0.92; b = 1.00; // cyan-white: kept
}
colors[3 * i] = r; colors[3 * i + 1] = g; colors[3 * i + 2] = b;
}