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:
1 parent
652fa4b912
commit
56f8888217
2 files changed
+25
-11
No files matched your search
+24
-10
@@ -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;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user