diff --git a/src/presa_mano/api/work_plane_routes.py b/src/presa_mano/api/work_plane_routes.py index 111a267..99f3382 100644 --- a/src/presa_mano/api/work_plane_routes.py +++ b/src/presa_mano/api/work_plane_routes.py @@ -31,7 +31,10 @@ class FitReq(BaseModel): v_min: int = Field(..., ge=0) u_max: int = Field(..., gt=0) v_max: int = Field(..., gt=0) - offset_mm: float = Field(5.0, ge=0.0, le=200.0) + # offset_mm può essere negativo: valore <0 esclude un buffer SOPRA il + # piano (toglie noise depth della superficie); valore >0 è permissivo + # (mantieni un buffer sotto il piano). Range esteso simmetricamente. + offset_mm: float = Field(5.0, ge=-200.0, le=200.0) max_preview_points: int = Field(5000, ge=100, le=20000) diff --git a/web/index.html b/web/index.html index 3f92714..dde0087 100644 --- a/web/index.html +++ b/web/index.html @@ -205,7 +205,7 @@
- +
diff --git a/web/work_plane.js b/web/work_plane.js index a224ccc..3325b65 100644 --- a/web/work_plane.js +++ b/web/work_plane.js @@ -246,6 +246,21 @@ function renderDetails(plane) { $('wpDetails').textContent = JSON.stringify(plane, null, 2); } +// FastAPI 422 returns `detail` as an array of validation errors: +// [{loc, msg, type, ...}, ...] +// Plain HTTPException returns it as a string. Render either case usefully so +// the status chip never says "[object Object]". +function formatDetail(detail) { + if (typeof detail === 'string') return detail; + if (Array.isArray(detail)) { + return detail.map(e => { + const loc = Array.isArray(e.loc) ? e.loc.join('.') : e.loc; + return loc ? `${loc}: ${e.msg}` : (e.msg || JSON.stringify(e)); + }).join('; '); + } + return JSON.stringify(detail); +} + async function doFit() { if (!roi) return; setChip('fit…'); @@ -259,7 +274,7 @@ async function doFit() { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }).then((r) => r.json()); - if (r.detail) throw new Error(r.detail); + if (r.detail) throw new Error(formatDetail(r.detail)); previewPlane = r.plane; previewPoints = r.points_camera; three.setPlane(previewPlane); @@ -282,7 +297,7 @@ async function doSave() { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ plane: previewPlane }), }).then((r) => r.json()); - if (r.detail) throw new Error(r.detail); + if (r.detail) throw new Error(formatDetail(r.detail)); savedPlane = r.plane; previewPlane = null; $('wpStateBlock').innerHTML = `piano salvato · RMS ${savedPlane.fit_rms_mm.toFixed(1)} mm · n_inliers ${savedPlane.n_inliers} · offset ${savedPlane.offset_mm} mm`;