diff --git a/web/index.html b/web/index.html
index a309b2e..4dfeea2 100644
--- a/web/index.html
+++ b/web/index.html
@@ -192,7 +192,7 @@
- piano viola · verde = inlier · giallo = sopra piano+offset · rosso = sotto piano-offset · grigio = buffer · drag = ruota · wheel = zoom
+ vista camera · piano viola · ciano = punti tenuti · rosso = esclusi (sotto piano−offset) · drag = ruota · wheel = zoom
Calibrazione
diff --git a/web/work_plane.js b/web/work_plane.js
index 8be14cc..00f33f4 100644
--- a/web/work_plane.js
+++ b/web/work_plane.js
@@ -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;
}