diff --git a/web/src/components/settings/ZoneEditPane.tsx b/web/src/components/settings/ZoneEditPane.tsx index 54799db72..a7a568b01 100644 --- a/web/src/components/settings/ZoneEditPane.tsx +++ b/web/src/components/settings/ZoneEditPane.tsx @@ -80,6 +80,17 @@ export default function ZoneEditPane({ } }, [polygon, config]); + const [topWidth, bottomWidth, leftDepth, rightDepth] = useMemo(() => { + const distances = + polygon?.camera && + polygon?.name && + config?.cameras[polygon.camera]?.zones[polygon.name]?.distances; + + return Array.isArray(distances) + ? distances.map((value) => parseFloat(value) || 0) + : [0, 0, 0, 0]; + }, [polygon, config]); + const formSchema = z.object({ name: z .string() @@ -138,6 +149,35 @@ export default function ZoneEditPane({ objects: z.array(z.string()).optional(), review_alerts: z.boolean().default(false).optional(), review_detections: z.boolean().default(false).optional(), + speedEstimation: z.boolean().default(false), + topWidth: z.coerce + .number() + .min(0.1, { + message: "Distance must be greater than or equal to 0.1", + }) + .optional() + .or(z.literal("")), + bottomWidth: z.coerce + .number() + .min(0.1, { + message: "Distance must be greater than or equal to 0.1", + }) + .optional() + .or(z.literal("")), + leftDepth: z.coerce + .number() + .min(0.1, { + message: "Distance must be greater than or equal to 0.1", + }) + .optional() + .or(z.literal("")), + rightDepth: z.coerce + .number() + .min(0.1, { + message: "Distance must be greater than or equal to 0.1", + }) + .optional() + .or(z.literal("")), }); const form = useForm>({ @@ -155,6 +195,11 @@ export default function ZoneEditPane({ config?.cameras[polygon.camera]?.zones[polygon.name]?.loitering_time, isFinished: polygon?.isFinished ?? false, objects: polygon?.objects ?? [], + speedEstimation: !!(topWidth || bottomWidth || leftDepth || rightDepth), + topWidth, + bottomWidth, + leftDepth, + rightDepth, }, }); @@ -165,6 +210,11 @@ export default function ZoneEditPane({ inertia, loitering_time, objects: form_objects, + speedEstimation, + topWidth, + bottomWidth, + leftDepth, + rightDepth, }: ZoneFormValuesType, // values submitted via the form objects: string[], ) => { @@ -261,9 +311,19 @@ export default function ZoneEditPane({ loiteringTimeQuery = `&cameras.${polygon?.camera}.zones.${zoneName}.loitering_time=${loitering_time}`; } + let distancesQuery = ""; + const distances = [topWidth, bottomWidth, leftDepth, rightDepth].join( + ",", + ); + if (speedEstimation) { + distancesQuery = `&cameras.${polygon?.camera}.zones.${zoneName}.distances=${distances}`; + } else { + distancesQuery = `&cameras.${polygon?.camera}.zones.${zoneName}.distances`; + } + axios .put( - `config/set?cameras.${polygon?.camera}.zones.${zoneName}.coordinates=${coordinates}${inertiaQuery}${loiteringTimeQuery}${objectQueries}${alertQueries}${detectionQueries}`, + `config/set?cameras.${polygon?.camera}.zones.${zoneName}.coordinates=${coordinates}${inertiaQuery}${loiteringTimeQuery}${distancesQuery}${objectQueries}${alertQueries}${detectionQueries}`, { requires_restart: 0 }, ) .then((res) => { @@ -456,6 +516,105 @@ export default function ZoneEditPane({ /> + + ( + +
+ +
+ + Speed Estimation + + { + if ( + checked && + polygons && + activePolygonIndex && + polygons[activePolygonIndex].points.length !== 4 + ) { + toast.error( + "Zones with speed estimation must have exactly 4 points", + ); + return; + } + field.onChange(checked); + }} + /> +
+
+
+ + Enable speed estimation for objects in this zone. The zone + must have exactly 4 points. + +
+ )} + /> + + {form.watch("speedEstimation") && + polygons && + activePolygonIndex && + polygons[activePolygonIndex].points.length === 4 && ( + <> + ( + + Top Width + + + + + )} + /> + ( + + Bottom Width + + + + + )} + /> + ( + + Left Depth + + + + + )} + /> + ( + + Right Depth + + + + + )} + /> + + )} + ; inertia: number; loitering_time: number;