diff --git a/web/pose_3d.js b/web/pose_3d.js index df2c985..a4ad9d1 100644 --- a/web/pose_3d.js +++ b/web/pose_3d.js @@ -424,6 +424,78 @@ function bindEditorButtons() { $('p3CancelBtn').addEventListener('click', onCancelClick); } +// ----- mode toggle ----- +function bindModeControls() { + for (const r of document.querySelectorAll('input[name=p3Mode]')) { + r.addEventListener('change', () => { + state.mode = r.value; + const badge = $('p3ModeBadge'); + if (state.mode === 'jog') { + badge.textContent = '🔴 JOG (live)'; + badge.classList.add('jog'); + $('p3EditorActions').style.display = 'none'; + } else { + badge.textContent = 'Editor'; + badge.classList.remove('jog'); + $('p3EditorActions').style.display = ''; + } + }); + } +} + +function bindPreciseControl() { + $('p3Precise').addEventListener('change', (e) => { + state.precise = e.target.checked; + }); +} + +// ----- jog auto-apply al mouseup gizmo ----- +function bindJogAutoApply() { + const { transform } = state.three; + transform.addEventListener('dragging-changed', async (e) => { + if (e.value) return; // inizio drag, niente + if (state.mode !== 'jog') return; + const side = state.active_side; + const tgt = state.target[side]; + if (!tgt) return; + const cur = state.current[side]; + if (!cur) return; + const dx = tgt.position[0] - cur.position[0]; + const dy = tgt.position[1] - cur.position[1]; + const dz = tgt.position[2] - cur.position[2]; + const delta = Math.sqrt(dx*dx + dy*dy + dz*dz); + if (delta > state.live_max_step_m) { + const ok = confirm( + `Movimento richiesto ${(delta*1000).toFixed(0)} mm > soglia ${(state.live_max_step_m*1000).toFixed(0)} mm.\n` + + `Procedere comunque?`, + ); + if (!ok) return; + } + clearError(); + try { + const res = await jsonFetch('/api/pose_3d/apply', { + method: 'POST', headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + side, position: tgt.position, quaternion: tgt.quaternion, + dry_run: false, precise: state.precise, + }), + }); + const r = res.result || {}; + if (r.reached_target === false || r.stalled === true) { + showError(`Move non completato: residual ${(r.position_error_mm||0).toFixed(1)} mm. ` + + `Sblocca braccia e riprova, oppure disattiva Precise.`); + } else { + $('p3Status').textContent = `✓ Jog: raggiunto (residual ${(r.position_error_mm||0).toFixed(1)} mm)`; + $('p3Status').className = 'p3-status ok'; + state.target[side] = null; + syncGhostsToTargetOrReal(); + } + } catch (e) { + showError(e.message); + } + }); +} + // ----- init triggered on first activation ----- let inited = false; function ensureInit() { @@ -436,6 +508,9 @@ function ensureInit() { bindGizmoControls(); bindGizmoEvents(); bindEditorButtons(); + bindModeControls(); + bindPreciseControl(); + bindJogAutoApply(); pollState(); pollTimer = setInterval(pollState, POLL_MS); }