RGB live · 2 click = angoli del rettangolo ROI · 3° click ricomincia
Vista 3D (frame camera)
@@ -198,12 +198,13 @@
Calibrazione
- Disegna con shift+drag un rettangolo sul tavolo (senza oggetti), poi
- clicca Calcola piano. Regola l'offset finché i punti
- gialli rappresentano l'oggetto e i rossi spariscono. Poi Salva piano.
+ Clicca due angoli opposti sul tavolo (senza oggetti) per definire il
+ rettangolo ROI, poi clicca Calcola piano. Regola
+ l'offset finché i punti gialli rappresentano l'oggetto e i rossi
+ spariscono. Poi Salva piano.
-
+
diff --git a/web/work_plane.js b/web/work_plane.js
index 259a901..8be14cc 100644
--- a/web/work_plane.js
+++ b/web/work_plane.js
@@ -21,7 +21,7 @@ function setChip(text, level) {
function setRoiInfo() {
const el = $('wpRoiInfo');
- if (!roi) { el.textContent = '— · disegna con shift+drag'; el.classList.add('dim'); return; }
+ if (!roi) { el.textContent = "— · clicca 2 angoli sull'RGB"; el.classList.add('dim'); return; }
el.classList.remove('dim');
el.textContent = `u=${roi.u0}…${roi.u1} v=${roi.v0}…${roi.v1} (${roi.u1 - roi.u0}×${roi.v1 - roi.v0} px)`;
}
@@ -68,6 +68,19 @@ function startRgbLoop() {
}
img.addEventListener('load', syncOverlaySize);
+ // Two-click ROI: 1st click = corner A, 2nd click = corner B (rectangle
+ // defined). 3rd click starts a new selection.
+ let firstCorner = null;
+
+ function drawCross(ctx, u, v) {
+ ctx.strokeStyle = '#9b6dff';
+ ctx.lineWidth = 2;
+ ctx.beginPath();
+ ctx.moveTo(u - 8, v); ctx.lineTo(u + 8, v);
+ ctx.moveTo(u, v - 8); ctx.lineTo(u, v + 8);
+ ctx.stroke();
+ }
+
function drawOverlay() {
const ctx = overlay.getContext('2d');
ctx.clearRect(0, 0, overlay.width, overlay.height);
@@ -75,32 +88,51 @@ function startRgbLoop() {
ctx.strokeStyle = '#9b6dff';
ctx.lineWidth = 2;
ctx.strokeRect(roi.u0, roi.v0, roi.u1 - roi.u0, roi.v1 - roi.v0);
+ drawCross(ctx, roi.u0, roi.v0);
+ drawCross(ctx, roi.u1, roi.v1);
+ } else if (firstCorner) {
+ drawCross(ctx, firstCorner.u, firstCorner.v);
}
}
- viewport.addEventListener('mousedown', (e) => {
- if (!e.shiftKey) return; // shift+drag = ROI; plain drag = pan (no-op here)
+ viewport.addEventListener('click', (e) => {
const p = imgPixelFromEvent(e);
- drawing = { u0: p.u, v0: p.v, u1: p.u, v1: p.v };
- e.preventDefault();
- });
- viewport.addEventListener('mousemove', (e) => {
- if (!drawing) return;
- const p = imgPixelFromEvent(e);
- drawing.u1 = p.u;
- drawing.v1 = p.v;
- roi = {
- u0: Math.min(drawing.u0, drawing.u1),
- v0: Math.min(drawing.v0, drawing.v1),
- u1: Math.max(drawing.u0, drawing.u1),
- v1: Math.max(drawing.v0, drawing.v1),
- };
+ if (firstCorner === null && roi === null) {
+ // First click: place corner A.
+ firstCorner = p;
+ drawOverlay();
+ setChip('punto 1/2 piazzato — clicca il secondo angolo');
+ return;
+ }
+ if (firstCorner !== null) {
+ // Second click: complete the rectangle.
+ roi = {
+ u0: Math.min(firstCorner.u, p.u),
+ v0: Math.min(firstCorner.v, p.v),
+ u1: Math.max(firstCorner.u, p.u),
+ v1: Math.max(firstCorner.v, p.v),
+ };
+ firstCorner = null;
+ // Reject degenerate rectangles (<10 px on either side).
+ if (roi.u1 - roi.u0 < 10 || roi.v1 - roi.v0 < 10) {
+ roi = null;
+ setChip('rettangolo troppo piccolo, riprova', 'err');
+ } else {
+ setChip('ROI pronto — clicca "Calcola piano"', 'ok');
+ }
+ drawOverlay();
+ setRoiInfo();
+ updateButtonStates();
+ return;
+ }
+ // ROI already set: start a new selection on the next click.
+ roi = null;
+ firstCorner = p;
drawOverlay();
setRoiInfo();
updateButtonStates();
+ setChip('punto 1/2 piazzato — clicca il secondo angolo');
});
- viewport.addEventListener('mouseup', () => { drawing = null; });
- viewport.addEventListener('mouseleave', () => { drawing = null; });
})();
// ---------------- Three.js 3D viewer ----------------