mirror of
https://github.com/PhotonVision/photonvision
synced 2026-07-05 03:21:40 +00:00
Remove camera index in ui (#1677)
With the new camera matching, this is SUPER BAD! Convert to using camera uuid. --------- Co-authored-by: Matt <matthew.morley.ca@gmail.com>
This commit is contained in:
@@ -34,8 +34,8 @@ if (!is_demo) {
|
||||
if (data.updatePipelineResult !== undefined) {
|
||||
useStateStore().updateBackendResultsFromWebsocket(data.updatePipelineResult);
|
||||
}
|
||||
if (data.mutatePipelineSettings !== undefined && data.cameraIndex !== undefined) {
|
||||
useCameraSettingsStore().changePipelineSettingsInStore(data.mutatePipelineSettings, data.cameraIndex);
|
||||
if (data.mutatePipelineSettings !== undefined && data.cameraUniqueName !== undefined) {
|
||||
useCameraSettingsStore().changePipelineSettingsInStore(data.mutatePipelineSettings, data.cameraUniqueName);
|
||||
}
|
||||
if (data.calibrationData !== undefined) {
|
||||
useStateStore().updateCalibrationStateValuesFromWebsocket(data.calibrationData);
|
||||
|
||||
@@ -20,7 +20,8 @@ const mdAndUp = computed<boolean>(() => getCurrentInstance()?.proxy.$vuetify.bre
|
||||
|
||||
const needsCamerasConfigured = computed<boolean>(() => {
|
||||
return (
|
||||
useCameraSettingsStore().cameras.length === 0 || useCameraSettingsStore().cameras[0] === PlaceholderCameraSettings
|
||||
Object.values(useCameraSettingsStore().cameras).length === 0 ||
|
||||
useCameraSettingsStore().cameras["PlaceHolder Name"] === PlaceholderCameraSettings
|
||||
);
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import PvSelect from "@/components/common/pv-select.vue";
|
||||
import PvSelect, { type SelectItem } from "@/components/common/pv-select.vue";
|
||||
import PvNumberInput from "@/components/common/pv-number-input.vue";
|
||||
import { useCameraSettingsStore } from "@/stores/settings/CameraSettingsStore";
|
||||
import { useStateStore } from "@/stores/StateStore";
|
||||
@@ -121,7 +121,7 @@ const openExportSettingsPrompt = () => {
|
||||
const yesDeleteMySettingsText = ref("");
|
||||
const deleteThisCamera = () => {
|
||||
const payload = {
|
||||
cameraUniqueName: useCameraSettingsStore().cameraUniqueNames[useStateStore().currentCameraIndex]
|
||||
cameraUniqueName: useStateStore().currentCameraUniqueName
|
||||
};
|
||||
|
||||
axios
|
||||
@@ -152,6 +152,12 @@ const deleteThisCamera = () => {
|
||||
});
|
||||
showDeleteCamera.value = false;
|
||||
};
|
||||
const wrappedCameras = computed<SelectItem[]>(() =>
|
||||
Object.keys(useCameraSettingsStore().cameras).map((cameraUniqueName) => ({
|
||||
name: useCameraSettingsStore().cameras[cameraUniqueName].nickname,
|
||||
value: cameraUniqueName
|
||||
}))
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -159,9 +165,9 @@ const deleteThisCamera = () => {
|
||||
<v-card-title>Camera Settings</v-card-title>
|
||||
<div class="ml-5">
|
||||
<pv-select
|
||||
v-model="useStateStore().currentCameraIndex"
|
||||
v-model="useStateStore().currentCameraUniqueName"
|
||||
label="Camera"
|
||||
:items="useCameraSettingsStore().cameraNames"
|
||||
:items="wrappedCameras"
|
||||
:select-cols="8"
|
||||
/>
|
||||
<pv-number-input
|
||||
@@ -213,9 +219,7 @@ const deleteThisCamera = () => {
|
||||
|
||||
<v-dialog v-model="showDeleteCamera" dark width="1500">
|
||||
<v-card dark class="dialog-container pa-6" color="primary" flat>
|
||||
<v-card-title
|
||||
>Delete camera "{{ useCameraSettingsStore().cameraNames[useStateStore().currentCameraIndex] }}"</v-card-title
|
||||
>
|
||||
<v-card-title>Delete camera "{{ useCameraSettingsStore().currentCameraName }}"</v-card-title>
|
||||
<v-row class="pl-3 align-center pa-6">
|
||||
<v-col cols="12" md="6">
|
||||
<span class="mt-3"> This will delete ALL OF YOUR SETTINGS and restart PhotonVision. </span>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { computed } from "vue";
|
||||
import TooltippedLabel from "@/components/common/pv-tooltipped-label.vue";
|
||||
|
||||
interface SelectItem {
|
||||
export interface SelectItem {
|
||||
name: string | number;
|
||||
value: string | number;
|
||||
disabled?: boolean;
|
||||
@@ -14,7 +14,7 @@ const props = withDefaults(
|
||||
tooltip?: string;
|
||||
selectCols?: number;
|
||||
// TODO fully update v-model usage in custom components on Vue3 update
|
||||
value: number;
|
||||
value: any;
|
||||
disabled?: boolean;
|
||||
items: string[] | number[] | SelectItem[];
|
||||
}>(),
|
||||
@@ -25,7 +25,7 @@ const props = withDefaults(
|
||||
);
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "input", value: number): void;
|
||||
(e: "input", value: string): void;
|
||||
}>();
|
||||
|
||||
const localValue = computed({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import PvSelect from "@/components/common/pv-select.vue";
|
||||
import PvSelect, { type SelectItem } from "@/components/common/pv-select.vue";
|
||||
import { useStateStore } from "@/stores/StateStore";
|
||||
import { useCameraSettingsStore } from "@/stores/settings/CameraSettingsStore";
|
||||
import { WebsocketPipelineType } from "@/types/WebsocketDataTypes";
|
||||
@@ -9,10 +9,10 @@ import PvInput from "@/components/common/pv-input.vue";
|
||||
import { PipelineType } from "@/types/PipelineTypes";
|
||||
import { useSettingsStore } from "@/stores/settings/GeneralSettingsStore";
|
||||
|
||||
const changeCurrentCameraIndex = (index: number) => {
|
||||
useCameraSettingsStore().setCurrentCameraIndex(index, true);
|
||||
const changeCurrentCameraUniqueName = (cameraUniqueName: string) => {
|
||||
useCameraSettingsStore().setCurrentCameraUniqueName(cameraUniqueName, true);
|
||||
|
||||
switch (useCameraSettingsStore().cameras[index].pipelineSettings.pipelineType) {
|
||||
switch (useCameraSettingsStore().cameras[cameraUniqueName].pipelineSettings.pipelineType) {
|
||||
case PipelineType.Reflective:
|
||||
pipelineType.value = WebsocketPipelineType.Reflective;
|
||||
break;
|
||||
@@ -86,7 +86,7 @@ const cancelCameraNameEdit = () => {
|
||||
};
|
||||
|
||||
// Pipeline Name Edit
|
||||
const pipelineNamesWrapper = computed<{ name: string; value: number }[]>(() => {
|
||||
const pipelineNamesWrapper = computed<SelectItem[]>(() => {
|
||||
const pipelineNames = useCameraSettingsStore().pipelineNames.map((name, index) => ({ name: name, value: index }));
|
||||
|
||||
if (useCameraSettingsStore().isDriverMode) {
|
||||
@@ -212,7 +212,7 @@ const duplicateCurrentPipeline = () => {
|
||||
|
||||
// Change Props whenever the pipeline settings are changed
|
||||
useCameraSettingsStore().$subscribe((mutation, state) => {
|
||||
const currentCameraSettings = state.cameras[useStateStore().currentCameraIndex];
|
||||
const currentCameraSettings = state.cameras[useStateStore().currentCameraUniqueName];
|
||||
|
||||
switch (currentCameraSettings.pipelineSettings.pipelineType) {
|
||||
case PipelineType.Reflective:
|
||||
@@ -232,6 +232,12 @@ useCameraSettingsStore().$subscribe((mutation, state) => {
|
||||
break;
|
||||
}
|
||||
});
|
||||
const wrappedCameras = computed<SelectItem[]>(() =>
|
||||
Object.keys(useCameraSettingsStore().cameras).map((cameraUniqueName) => ({
|
||||
name: useCameraSettingsStore().cameras[cameraUniqueName].nickname,
|
||||
value: cameraUniqueName
|
||||
}))
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -240,10 +246,10 @@ useCameraSettingsStore().$subscribe((mutation, state) => {
|
||||
<v-col cols="10" class="pa-0">
|
||||
<pv-select
|
||||
v-if="!isCameraNameEdit"
|
||||
v-model="useStateStore().currentCameraIndex"
|
||||
v-model="useStateStore().currentCameraUniqueName"
|
||||
label="Camera"
|
||||
:items="useCameraSettingsStore().cameraNames"
|
||||
@input="changeCurrentCameraIndex"
|
||||
:items="wrappedCameras"
|
||||
@input="changeCurrentCameraUniqueName"
|
||||
/>
|
||||
<pv-input
|
||||
v-else
|
||||
|
||||
@@ -2,6 +2,7 @@ import { defineStore } from "pinia";
|
||||
import type { LogMessage, VsmState } from "@/types/SettingTypes";
|
||||
import type { AutoReconnectingWebsocket } from "@/lib/AutoReconnectingWebsocket";
|
||||
import type { MultitagResult, PipelineResult } from "@/types/PhotonTrackingTypes";
|
||||
import { useCameraSettingsStore } from "@/stores/settings/CameraSettingsStore";
|
||||
import type {
|
||||
WebsocketCalibrationData,
|
||||
WebsocketLogMessage,
|
||||
@@ -22,7 +23,7 @@ interface StateStore {
|
||||
showLogModal: boolean;
|
||||
sidebarFolded: boolean;
|
||||
logMessages: LogMessage[];
|
||||
currentCameraIndex: number;
|
||||
currentCameraUniqueName: string;
|
||||
|
||||
backendResults: Record<number, PipelineResult>;
|
||||
multitagResultBuffer: Record<string, MultitagResult[]>;
|
||||
@@ -48,6 +49,7 @@ interface StateStore {
|
||||
|
||||
export const useStateStore = defineStore("state", {
|
||||
state: (): StateStore => {
|
||||
const cameraStore = useCameraSettingsStore();
|
||||
return {
|
||||
backendConnected: false,
|
||||
websocket: undefined,
|
||||
@@ -59,7 +61,7 @@ export const useStateStore = defineStore("state", {
|
||||
sidebarFolded:
|
||||
localStorage.getItem("sidebarFolded") === null ? false : localStorage.getItem("sidebarFolded") === "true",
|
||||
logMessages: [],
|
||||
currentCameraIndex: 0,
|
||||
currentCameraUniqueName: Object.keys(cameraStore.cameras)[0],
|
||||
|
||||
backendResults: {
|
||||
0: {
|
||||
@@ -97,11 +99,12 @@ export const useStateStore = defineStore("state", {
|
||||
},
|
||||
getters: {
|
||||
currentPipelineResults(): PipelineResult | undefined {
|
||||
return this.backendResults[this.currentCameraIndex.toString()];
|
||||
return this.backendResults[this.currentCameraUniqueName.toString()];
|
||||
},
|
||||
currentMultitagBuffer(): MultitagResult[] | undefined {
|
||||
if (!this.multitagResultBuffer[this.currentCameraIndex]) this.multitagResultBuffer[this.currentCameraIndex] = [];
|
||||
return this.multitagResultBuffer[this.currentCameraIndex];
|
||||
if (!this.multitagResultBuffer[this.currentCameraUniqueName])
|
||||
this.multitagResultBuffer[this.currentCameraUniqueName] = [];
|
||||
return this.multitagResultBuffer[this.currentCameraUniqueName];
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
|
||||
@@ -18,17 +18,18 @@ import axios from "axios";
|
||||
import { resolutionsAreEqual } from "@/lib/PhotonUtils";
|
||||
|
||||
interface CameraSettingsStore {
|
||||
cameras: UiCameraConfiguration[];
|
||||
cameras: { [key: string]: UiCameraConfiguration };
|
||||
}
|
||||
|
||||
export const useCameraSettingsStore = defineStore("cameraSettings", {
|
||||
state: (): CameraSettingsStore => ({
|
||||
cameras: [PlaceholderCameraSettings]
|
||||
cameras: { [PlaceholderCameraSettings.uniqueName]: PlaceholderCameraSettings }
|
||||
}),
|
||||
getters: {
|
||||
// TODO update types to update this value being undefined. This would be a decently large change.
|
||||
currentCameraSettings(): UiCameraConfiguration {
|
||||
return this.cameras[useStateStore().currentCameraIndex];
|
||||
const currentCameraUniqueName = useStateStore().currentCameraUniqueName;
|
||||
return this.cameras[currentCameraUniqueName] || PlaceholderCameraSettings;
|
||||
},
|
||||
currentPipelineSettings(): ActivePipelineSettings {
|
||||
return this.currentCameraSettings.pipelineSettings;
|
||||
@@ -49,19 +50,19 @@ export const useCameraSettingsStore = defineStore("cameraSettings", {
|
||||
);
|
||||
},
|
||||
cameraNames(): string[] {
|
||||
return this.cameras.map((c) => c.nickname);
|
||||
return Object.values(this.cameras).map((c) => c.nickname);
|
||||
},
|
||||
cameraUniqueNames(): string[] {
|
||||
return this.cameras.map((c) => c.uniqueName);
|
||||
return Object.values(this.cameras).map((c) => c.uniqueName);
|
||||
},
|
||||
currentCameraName(): string {
|
||||
return this.cameraNames[useStateStore().currentCameraIndex];
|
||||
return this.cameras[useStateStore().currentCameraUniqueName].nickname;
|
||||
},
|
||||
pipelineNames(): string[] {
|
||||
return this.currentCameraSettings.pipelineNicknames;
|
||||
},
|
||||
currentPipelineName(): string {
|
||||
return this.pipelineNames[useStateStore().currentCameraIndex];
|
||||
return this.pipelineNames[useStateStore().currentCameraUniqueName];
|
||||
},
|
||||
isDriverMode(): boolean {
|
||||
return this.currentCameraSettings.currentPipelineIndex === WebsocketPipelineType.DriverMode;
|
||||
@@ -93,72 +94,79 @@ export const useCameraSettingsStore = defineStore("cameraSettings", {
|
||||
},
|
||||
actions: {
|
||||
updateCameraSettingsFromWebsocket(data: WebsocketCameraSettingsUpdate[]) {
|
||||
const configuredCameras = data.map<UiCameraConfiguration>((d) => ({
|
||||
cameraPath: d.cameraPath,
|
||||
const configuredCameras = data.reduce<{ [key: string]: UiCameraConfiguration }>((acc, d) => {
|
||||
acc[d.uniqueName] = {
|
||||
cameraPath: d.cameraPath,
|
||||
nickname: d.nickname,
|
||||
uniqueName: d.uniqueName,
|
||||
fov: {
|
||||
value: d.fov,
|
||||
managedByVendor: !d.isFovConfigurable
|
||||
},
|
||||
stream: {
|
||||
inputPort: d.inputStreamPort,
|
||||
outputPort: d.outputStreamPort
|
||||
},
|
||||
validVideoFormats: Object.entries(d.videoFormatList)
|
||||
.sort(([firstKey], [secondKey]) => parseInt(firstKey) - parseInt(secondKey))
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
.map<VideoFormat>(([k, v], i) => ({
|
||||
resolution: {
|
||||
width: v.width,
|
||||
height: v.height
|
||||
},
|
||||
fps: v.fps,
|
||||
pixelFormat: v.pixelFormat,
|
||||
index: v.index || i,
|
||||
diagonalFOV: v.diagonalFOV,
|
||||
horizontalFOV: v.horizontalFOV,
|
||||
verticalFOV: v.verticalFOV,
|
||||
standardDeviation: v.standardDeviation,
|
||||
mean: v.mean
|
||||
})),
|
||||
completeCalibrations: d.calibrations,
|
||||
isCSICamera: d.isCSICamera,
|
||||
minExposureRaw: d.minExposureRaw,
|
||||
maxExposureRaw: d.maxExposureRaw,
|
||||
pipelineNicknames: d.pipelineNicknames,
|
||||
currentPipelineIndex: d.currentPipelineIndex,
|
||||
pipelineSettings: d.currentPipelineSettings,
|
||||
cameraQuirks: d.cameraQuirks,
|
||||
minWhiteBalanceTemp: d.minWhiteBalanceTemp,
|
||||
maxWhiteBalanceTemp: d.maxWhiteBalanceTemp,
|
||||
matchedCameraInfo: d.matchedCameraInfo,
|
||||
isConnected: d.isConnected,
|
||||
hasConnected: d.hasConnected
|
||||
};
|
||||
return acc;
|
||||
}, {});
|
||||
this.cameras =
|
||||
Object.keys(configuredCameras).length > 0
|
||||
? configuredCameras
|
||||
: { [PlaceholderCameraSettings.uniqueName]: PlaceholderCameraSettings };
|
||||
|
||||
nickname: d.nickname,
|
||||
uniqueName: d.uniqueName,
|
||||
fov: {
|
||||
value: d.fov,
|
||||
managedByVendor: !d.isFovConfigurable
|
||||
},
|
||||
stream: {
|
||||
inputPort: d.inputStreamPort,
|
||||
outputPort: d.outputStreamPort
|
||||
},
|
||||
validVideoFormats: Object.entries(d.videoFormatList)
|
||||
.sort(([firstKey], [secondKey]) => parseInt(firstKey) - parseInt(secondKey))
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
.map<VideoFormat>(([k, v], i) => ({
|
||||
resolution: {
|
||||
width: v.width,
|
||||
height: v.height
|
||||
},
|
||||
fps: v.fps,
|
||||
pixelFormat: v.pixelFormat,
|
||||
index: v.index || i,
|
||||
diagonalFOV: v.diagonalFOV,
|
||||
horizontalFOV: v.horizontalFOV,
|
||||
verticalFOV: v.verticalFOV,
|
||||
standardDeviation: v.standardDeviation,
|
||||
mean: v.mean
|
||||
})),
|
||||
completeCalibrations: d.calibrations,
|
||||
isCSICamera: d.isCSICamera,
|
||||
minExposureRaw: d.minExposureRaw,
|
||||
maxExposureRaw: d.maxExposureRaw,
|
||||
pipelineNicknames: d.pipelineNicknames,
|
||||
currentPipelineIndex: d.currentPipelineIndex,
|
||||
pipelineSettings: d.currentPipelineSettings,
|
||||
cameraQuirks: d.cameraQuirks,
|
||||
minWhiteBalanceTemp: d.minWhiteBalanceTemp,
|
||||
maxWhiteBalanceTemp: d.maxWhiteBalanceTemp,
|
||||
matchedCameraInfo: d.matchedCameraInfo,
|
||||
isConnected: d.isConnected,
|
||||
hasConnected: d.hasConnected
|
||||
}));
|
||||
|
||||
// Clamp index to between 0 and [length - 1]
|
||||
useStateStore().currentCameraIndex = Math.max(
|
||||
0,
|
||||
Math.min(useStateStore().currentCameraIndex, configuredCameras.length - 1)
|
||||
);
|
||||
|
||||
this.cameras = configuredCameras.length > 0 ? configuredCameras : [PlaceholderCameraSettings];
|
||||
// Ensure currentCameraUniqueName is valid
|
||||
if (!this.cameras[useStateStore().currentCameraUniqueName]) {
|
||||
useStateStore().currentCameraUniqueName = Object.keys(this.cameras)[0];
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the configurable camera settings.
|
||||
*
|
||||
* @param data camera settings to save.
|
||||
* @param cameraIndex the index of the camera.
|
||||
* @param cameraUniqueNamendex the unique name of the camera.
|
||||
*/
|
||||
updateCameraSettings(data: CameraSettingsChangeRequest, cameraIndex: number = useStateStore().currentCameraIndex) {
|
||||
updateCameraSettings(
|
||||
data: CameraSettingsChangeRequest,
|
||||
cameraUniqueName: String = useStateStore().currentCameraUniqueName
|
||||
) {
|
||||
// The camera settings endpoint doesn't actually require all data, instead, it needs key data such as the FOV
|
||||
const payload = {
|
||||
settings: {
|
||||
...data
|
||||
},
|
||||
index: cameraIndex
|
||||
cameraUniqueName: cameraUniqueName
|
||||
};
|
||||
return axios.post("/settings/camera", payload);
|
||||
},
|
||||
@@ -167,16 +175,16 @@ export const useCameraSettingsStore = defineStore("cameraSettings", {
|
||||
*
|
||||
* @param newPipelineName the name of the new pipeline.
|
||||
* @param pipelineType the type of the new pipeline. Cannot be {@link WebsocketPipelineType.Calib3d} or {@link WebsocketPipelineType.DriverMode}.
|
||||
* @param cameraIndex the index of the camera
|
||||
* @param cameraUniqueNamendex the unique name of the camera.
|
||||
*/
|
||||
createNewPipeline(
|
||||
newPipelineName: string,
|
||||
pipelineType: Exclude<WebsocketPipelineType, WebsocketPipelineType.Calib3d | WebsocketPipelineType.DriverMode>,
|
||||
cameraIndex: number = useStateStore().currentCameraIndex
|
||||
cameraUniqueName: String = useStateStore().currentCameraUniqueName
|
||||
) {
|
||||
const payload = {
|
||||
addNewPipeline: [newPipelineName, pipelineType],
|
||||
cameraIndex: cameraIndex
|
||||
cameraUniqueName: cameraUniqueName
|
||||
};
|
||||
useStateStore().websocket?.send(payload, true);
|
||||
},
|
||||
@@ -185,30 +193,30 @@ export const useCameraSettingsStore = defineStore("cameraSettings", {
|
||||
*
|
||||
* @param settings settings to modify. The type of the settings should match the currently selected pipeline type.
|
||||
* @param updateStore whether or not to update the store. This is useful if the input field already models the store reference.
|
||||
* @param cameraIndex the index of the camera
|
||||
* @param cameraUniqueNamendex the unique name of the camera.
|
||||
*/
|
||||
changeCurrentPipelineSetting(
|
||||
settings: ActiveConfigurablePipelineSettings,
|
||||
updateStore = true,
|
||||
cameraIndex: number = useStateStore().currentCameraIndex
|
||||
cameraUniqueName: string = useStateStore().currentCameraUniqueName
|
||||
) {
|
||||
const payload = {
|
||||
changePipelineSetting: {
|
||||
...settings,
|
||||
cameraIndex: cameraIndex
|
||||
cameraUniqueName: cameraUniqueName
|
||||
}
|
||||
};
|
||||
if (updateStore) {
|
||||
this.changePipelineSettingsInStore(settings, cameraIndex);
|
||||
this.changePipelineSettingsInStore(settings, cameraUniqueName);
|
||||
}
|
||||
useStateStore().websocket?.send(payload, true);
|
||||
},
|
||||
changePipelineSettingsInStore(
|
||||
settings: Partial<ActivePipelineSettings>,
|
||||
cameraIndex: number = useStateStore().currentCameraIndex
|
||||
cameraUniqueName: string = useStateStore().currentCameraUniqueName
|
||||
) {
|
||||
Object.entries(settings).forEach(([k, v]) => {
|
||||
this.cameras[cameraIndex].pipelineSettings[k] = v;
|
||||
this.cameras[cameraUniqueName].pipelineSettings[k] = v;
|
||||
});
|
||||
},
|
||||
/**
|
||||
@@ -216,19 +224,19 @@ export const useCameraSettingsStore = defineStore("cameraSettings", {
|
||||
*
|
||||
* @param newName the new nickname for the camera.
|
||||
* @param updateStore whether or not to update the store. This is useful if the input field already models the store reference.
|
||||
* @param cameraIndex the index of the camera
|
||||
* @param cameraUniqueNamendex the unique name of the camera.
|
||||
*/
|
||||
changeCurrentPipelineNickname(
|
||||
newName: string,
|
||||
updateStore = true,
|
||||
cameraIndex: number = useStateStore().currentCameraIndex
|
||||
cameraUniqueName: string = useStateStore().currentCameraUniqueName
|
||||
) {
|
||||
const payload = {
|
||||
changePipelineName: newName,
|
||||
cameraIndex: cameraIndex
|
||||
cameraUniqueName: cameraUniqueName
|
||||
};
|
||||
if (updateStore) {
|
||||
this.cameras[cameraIndex].pipelineSettings.pipelineNickname = newName;
|
||||
this.cameras[cameraUniqueName].pipelineSettings.pipelineNickname = newName;
|
||||
}
|
||||
useStateStore().websocket?.send(payload, true);
|
||||
},
|
||||
@@ -236,15 +244,15 @@ export const useCameraSettingsStore = defineStore("cameraSettings", {
|
||||
* Modify the Pipeline type of the currently selected pipeline of the provided camera. This overwrites the current pipeline's settings when the backend resets the current pipeline settings.
|
||||
*
|
||||
* @param type the pipeline type to set. Cannot be {@link WebsocketPipelineType.Calib3d} or {@link WebsocketPipelineType.DriverMode}.
|
||||
* @param cameraIndex the index of the camera.
|
||||
* @param cameraUniqueNamendex the unique name of the camera.
|
||||
*/
|
||||
changeCurrentPipelineType(
|
||||
type: Exclude<WebsocketPipelineType, WebsocketPipelineType.Calib3d | WebsocketPipelineType.DriverMode>,
|
||||
cameraIndex: number = useStateStore().currentCameraIndex
|
||||
cameraUniqueName: string = useStateStore().currentCameraUniqueName
|
||||
) {
|
||||
const payload = {
|
||||
pipelineType: type,
|
||||
cameraIndex: cameraIndex
|
||||
cameraUniqueName: cameraUniqueName
|
||||
};
|
||||
useStateStore().websocket?.send(payload, true);
|
||||
},
|
||||
@@ -253,44 +261,44 @@ export const useCameraSettingsStore = defineStore("cameraSettings", {
|
||||
*
|
||||
* @param index pipeline index to set.
|
||||
* @param updateStore whether or not to update the store. This is useful if the input field already models the store reference.
|
||||
* @param cameraIndex the index of the camera.
|
||||
* @param cameraUniqueNamendex the unique name of the camera.
|
||||
*/
|
||||
changeCurrentPipelineIndex(
|
||||
index: number,
|
||||
updateStore = true,
|
||||
cameraIndex: number = useStateStore().currentCameraIndex
|
||||
cameraUniqueName: string = useStateStore().currentCameraUniqueName
|
||||
) {
|
||||
const payload = {
|
||||
currentPipeline: index,
|
||||
cameraIndex: cameraIndex
|
||||
cameraUniqueName: cameraUniqueName
|
||||
};
|
||||
if (updateStore) {
|
||||
if (
|
||||
this.cameras[cameraIndex].currentPipelineIndex !== -1 &&
|
||||
this.cameras[cameraIndex].currentPipelineIndex !== -2
|
||||
this.cameras[cameraUniqueName].currentPipelineIndex !== -1 &&
|
||||
this.cameras[cameraUniqueName].currentPipelineIndex !== -2
|
||||
) {
|
||||
this.cameras[cameraIndex].lastPipelineIndex = this.cameras[cameraIndex].currentPipelineIndex;
|
||||
this.cameras[cameraUniqueName].lastPipelineIndex = this.cameras[cameraUniqueName].currentPipelineIndex;
|
||||
}
|
||||
this.cameras[cameraIndex].currentPipelineIndex = index;
|
||||
this.cameras[cameraUniqueName].currentPipelineIndex = index;
|
||||
}
|
||||
useStateStore().websocket?.send(payload, true);
|
||||
},
|
||||
setDriverMode(isDriverMode: boolean, cameraIndex: number = useStateStore().currentCameraIndex) {
|
||||
setDriverMode(isDriverMode: boolean, cameraUniqueName: string = useStateStore().currentCameraUniqueName) {
|
||||
const payload = {
|
||||
driverMode: isDriverMode,
|
||||
cameraIndex: cameraIndex
|
||||
cameraUniqueName: cameraUniqueName
|
||||
};
|
||||
useStateStore().websocket?.send(payload, true);
|
||||
},
|
||||
/**
|
||||
* Change the currently selected pipeline of the provided camera.
|
||||
*
|
||||
* @param cameraIndex the index of the camera's pipeline to change.
|
||||
* @param cameraUniqueNamendex the unique name of the camera.
|
||||
*/
|
||||
deleteCurrentPipeline(cameraIndex: number = useStateStore().currentCameraIndex) {
|
||||
deleteCurrentPipeline(cameraUniqueName: string = useStateStore().currentCameraUniqueName) {
|
||||
const payload = {
|
||||
deleteCurrentPipeline: {},
|
||||
cameraIndex: cameraIndex
|
||||
cameraUniqueName: cameraUniqueName
|
||||
};
|
||||
useStateStore().websocket?.send(payload, true);
|
||||
},
|
||||
@@ -298,27 +306,27 @@ export const useCameraSettingsStore = defineStore("cameraSettings", {
|
||||
* Duplicate the pipeline at the provided index.
|
||||
*
|
||||
* @param pipelineIndex index of the pipeline to duplicate.
|
||||
* @param cameraIndex the index of the camera.
|
||||
* @param cameraUniqueNamendex the unique name of the camera.
|
||||
*/
|
||||
duplicatePipeline(pipelineIndex: number, cameraIndex: number = useStateStore().currentCameraIndex) {
|
||||
duplicatePipeline(pipelineIndex: number, cameraUniqueName: string = useStateStore().currentCameraUniqueName) {
|
||||
const payload = {
|
||||
duplicatePipeline: pipelineIndex,
|
||||
cameraIndex: cameraIndex
|
||||
cameraUniqueName: cameraUniqueName
|
||||
};
|
||||
useStateStore().websocket?.send(payload, true);
|
||||
},
|
||||
/**
|
||||
* Change the currently set camera
|
||||
*
|
||||
* @param cameraIndex the index of the camera to set as the current camera.
|
||||
* @param cameraUniqueName the unique name of the camera.
|
||||
* @param updateStore whether or not to update the store. This is useful if the input field already models the store reference.
|
||||
*/
|
||||
setCurrentCameraIndex(cameraIndex: number, updateStore = true) {
|
||||
setCurrentCameraUniqueName(cameraUniqueName: string, updateStore = true) {
|
||||
const payload = {
|
||||
currentCamera: cameraIndex
|
||||
cameraUniqueName: cameraUniqueName
|
||||
};
|
||||
if (updateStore) {
|
||||
useStateStore().currentCameraIndex = cameraIndex;
|
||||
useStateStore().currentCameraUniqueName = cameraUniqueName;
|
||||
}
|
||||
useStateStore().websocket?.send(payload, true);
|
||||
},
|
||||
@@ -327,17 +335,17 @@ export const useCameraSettingsStore = defineStore("cameraSettings", {
|
||||
*
|
||||
* @param newName the new nickname of the camera.
|
||||
* @param updateStore whether or not to update the store. This is useful if the input field already models the store reference.
|
||||
* @param cameraIndex the index of the camera.
|
||||
* @param cameraUniqueNamendex the unique name of the camera.
|
||||
* @return HTTP request promise to the backend
|
||||
*/
|
||||
changeCameraNickname(
|
||||
newName: string,
|
||||
updateStore = true,
|
||||
cameraIndex: number = useStateStore().currentCameraIndex
|
||||
cameraUniqueName: string = useStateStore().currentCameraUniqueName
|
||||
) {
|
||||
const payload = {
|
||||
name: newName,
|
||||
cameraIndex: cameraIndex
|
||||
cameraUniqueName: cameraUniqueName
|
||||
};
|
||||
if (updateStore) {
|
||||
this.currentCameraSettings.nickname = newName;
|
||||
@@ -348,7 +356,7 @@ export const useCameraSettingsStore = defineStore("cameraSettings", {
|
||||
* Start the 3D calibration process for the provided camera.
|
||||
*
|
||||
* @param calibrationInitData initialization calibration data.
|
||||
* @param cameraIndex the index of the camera.
|
||||
* @param cameraUniqueNamendex the unique name of the camera.
|
||||
*/
|
||||
startPnPCalibration(
|
||||
calibrationInitData: {
|
||||
@@ -360,7 +368,7 @@ export const useCameraSettingsStore = defineStore("cameraSettings", {
|
||||
useOldPattern: boolean;
|
||||
tagFamily: CalibrationTagFamilies;
|
||||
},
|
||||
cameraIndex: number = useStateStore().currentCameraIndex
|
||||
cameraUniqueName: string = useStateStore().currentCameraUniqueName
|
||||
) {
|
||||
const stateCalibData = useStateStore().calibrationData;
|
||||
const payload = {
|
||||
@@ -371,63 +379,63 @@ export const useCameraSettingsStore = defineStore("cameraSettings", {
|
||||
videoModeIndex: stateCalibData.videoFormatIndex,
|
||||
...calibrationInitData
|
||||
},
|
||||
cameraIndex: cameraIndex
|
||||
cameraUniqueName: cameraUniqueName
|
||||
};
|
||||
useStateStore().websocket?.send(payload, true);
|
||||
},
|
||||
/**
|
||||
* End the 3D calibration process for the provided camera.
|
||||
*
|
||||
* @param cameraIndex the index of the camera
|
||||
* @param cameraUniqueName the unique name of the camera.
|
||||
* @return HTTP request promise to the backend
|
||||
*/
|
||||
endPnPCalibration(cameraIndex: number = useStateStore().currentCameraIndex) {
|
||||
return axios.post("/calibration/end", { index: cameraIndex });
|
||||
endPnPCalibration(cameraUniqueName: string = useStateStore().currentCameraUniqueName) {
|
||||
return axios.post("/calibration/end", { cameraUniqueName: cameraUniqueName });
|
||||
},
|
||||
|
||||
importCalibrationFromData(
|
||||
data: { calibration: CameraCalibrationResult },
|
||||
cameraIndex: number = useStateStore().currentCameraIndex
|
||||
cameraUniqueName: string = useStateStore().currentCameraUniqueName
|
||||
) {
|
||||
const payload = {
|
||||
...data,
|
||||
cameraIndex: cameraIndex
|
||||
cameraUniqueName: cameraUniqueName
|
||||
};
|
||||
return axios.post("/calibration/importFromData", payload);
|
||||
},
|
||||
/**
|
||||
* Take a snapshot for the calibration processes
|
||||
*
|
||||
* @param cameraIndex the index of the camera that is currently in the calibration process
|
||||
* @param cameraUniqueName the unique name of the camera that is currently in the calibration process
|
||||
*/
|
||||
takeCalibrationSnapshot(cameraIndex: number = useStateStore().currentCameraIndex) {
|
||||
takeCalibrationSnapshot(cameraUniqueName: string = useStateStore().currentCameraUniqueName) {
|
||||
const payload = {
|
||||
takeCalibrationSnapshot: true,
|
||||
cameraIndex: cameraIndex
|
||||
cameraUniqueName: cameraUniqueName
|
||||
};
|
||||
useStateStore().websocket?.send(payload, true);
|
||||
},
|
||||
/**
|
||||
* Save a snapshot of the input frame of the camera.
|
||||
*
|
||||
* @param cameraIndex the index of the camera
|
||||
* @param cameraUniqueName the unique name of the camera
|
||||
*/
|
||||
saveInputSnapshot(cameraIndex: number = useStateStore().currentCameraIndex) {
|
||||
saveInputSnapshot(cameraUniqueName: string = useStateStore().currentCameraUniqueName) {
|
||||
const payload = {
|
||||
saveInputSnapshot: true,
|
||||
cameraIndex: cameraIndex
|
||||
cameraUniqueName: cameraUniqueName
|
||||
};
|
||||
useStateStore().websocket?.send(payload, true);
|
||||
},
|
||||
/**
|
||||
* Save a snapshot of the output frame of the camera.
|
||||
*
|
||||
* @param cameraIndex the index of the camera
|
||||
* @param cameraUniqueName the unique name of the camera
|
||||
*/
|
||||
saveOutputSnapshot(cameraIndex: number = useStateStore().currentCameraIndex) {
|
||||
saveOutputSnapshot(cameraUniqueName: string = useStateStore().currentCameraUniqueName) {
|
||||
const payload = {
|
||||
saveOutputSnapshot: true,
|
||||
cameraIndex: cameraIndex
|
||||
cameraUniqueName: cameraUniqueName
|
||||
};
|
||||
useStateStore().websocket?.send(payload, true);
|
||||
},
|
||||
@@ -435,35 +443,42 @@ export const useCameraSettingsStore = defineStore("cameraSettings", {
|
||||
* Set the robot offset mode type.
|
||||
*
|
||||
* @param type Offset type to take.
|
||||
* @param cameraIndex the index of the camera.
|
||||
* @param cameraUniqueName the unique name of the camera
|
||||
*/
|
||||
takeRobotOffsetPoint(type: RobotOffsetType, cameraIndex: number = useStateStore().currentCameraIndex) {
|
||||
takeRobotOffsetPoint(type: RobotOffsetType, cameraUniqueName: string = useStateStore().currentCameraUniqueName) {
|
||||
const payload = {
|
||||
robotOffsetPoint: type,
|
||||
cameraIndex: cameraIndex
|
||||
cameraUniqueName: cameraUniqueName
|
||||
};
|
||||
useStateStore().websocket?.send(payload, true);
|
||||
},
|
||||
getCalibrationCoeffs(
|
||||
resolution: Resolution,
|
||||
cameraIndex: number = useStateStore().currentCameraIndex
|
||||
cameraUniqueName: string = useStateStore().currentCameraUniqueName
|
||||
): CameraCalibrationResult | undefined {
|
||||
return this.cameras[cameraIndex].completeCalibrations.find((v) => resolutionsAreEqual(v.resolution, resolution));
|
||||
return this.cameras[cameraUniqueName].completeCalibrations.find((v) =>
|
||||
resolutionsAreEqual(v.resolution, resolution)
|
||||
);
|
||||
},
|
||||
getCalImageUrl(host: string, resolution: Resolution, idx: number, cameraIdx = useStateStore().currentCameraIndex) {
|
||||
getCalImageUrl(
|
||||
host: string,
|
||||
resolution: Resolution,
|
||||
idx: number,
|
||||
cameraUniqueName = useStateStore().currentCameraUniqueName
|
||||
) {
|
||||
const url = new URL(`http://${host}/api/utils/getCalSnapshot`);
|
||||
url.searchParams.set("width", Math.round(resolution.width).toFixed(0));
|
||||
url.searchParams.set("height", Math.round(resolution.height).toFixed(0));
|
||||
url.searchParams.set("snapshotIdx", Math.round(idx).toFixed(0));
|
||||
url.searchParams.set("cameraIdx", Math.round(cameraIdx).toFixed(0));
|
||||
url.searchParams.set("cameraUniqueName", cameraUniqueName.replace(" ", "").trim().toLowerCase());
|
||||
|
||||
return url.href;
|
||||
},
|
||||
getCalJSONUrl(host: string, resolution: Resolution, cameraIdx = useStateStore().currentCameraIndex) {
|
||||
getCalJSONUrl(host: string, resolution: Resolution, cameraUniqueName = useStateStore().currentCameraUniqueName) {
|
||||
const url = new URL(`http://${host}/api/utils/getCalibrationJSON`);
|
||||
url.searchParams.set("width", Math.round(resolution.width).toFixed(0));
|
||||
url.searchParams.set("height", Math.round(resolution.height).toFixed(0));
|
||||
url.searchParams.set("cameraIdx", Math.round(cameraIdx).toFixed(0));
|
||||
url.searchParams.set("cameraUniqueName", cameraUniqueName.replace(" ", "").trim().toLowerCase());
|
||||
|
||||
return url.href;
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ export interface IncomingWebsocketData {
|
||||
deviceIps: string[];
|
||||
};
|
||||
mutatePipelineSettings?: Partial<ActivePipelineSettings>;
|
||||
cameraIndex?: number; // Sent when mutating pipeline settings to check against currently active
|
||||
cameraUniqueName?: string; // Sent when mutating pipeline settings to check against currently active
|
||||
calibrationData?: WebsocketCalibrationData;
|
||||
visionSourceManager?: VsmState;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ const host = inject<string>("backendHost");
|
||||
|
||||
const activateModule = (moduleUniqueName: string) => {
|
||||
const url = new URL(`http://${host}/api/utils/activateMatchedCamera`);
|
||||
url.searchParams.set("uniqueName", moduleUniqueName);
|
||||
url.searchParams.set("cameraUniqueName", moduleUniqueName);
|
||||
|
||||
fetch(url.toString(), {
|
||||
method: "POST"
|
||||
@@ -34,8 +34,9 @@ const activateCamera = (cameraInfo: PVCameraInfo) => {
|
||||
});
|
||||
};
|
||||
const deactivateCamera = (cameraUniqueName: string) => {
|
||||
console.log("Deactivating " + cameraUniqueName);
|
||||
const url = new URL(`http://${host}/api/utils/unassignCamera`);
|
||||
url.searchParams.set("uniqueName", cameraUniqueName);
|
||||
url.searchParams.set("cameraUniqueName", cameraUniqueName);
|
||||
|
||||
fetch(url.toString(), {
|
||||
method: "POST"
|
||||
@@ -134,7 +135,9 @@ const getMatchedDevice = (info: PVCameraInfo | undefined): PVCameraInfo => {
|
||||
};
|
||||
|
||||
const unmatchedCameras = computed(() => {
|
||||
const activeVmPaths = useCameraSettingsStore().cameras.map((it) => uniquePathForCamera(it.matchedCameraInfo));
|
||||
const activeVmPaths = Object.values(useCameraSettingsStore().cameras).map((it) =>
|
||||
uniquePathForCamera(it.matchedCameraInfo)
|
||||
);
|
||||
const disabledVmPaths = useStateStore().vsmState.disabledConfigs.map((it) =>
|
||||
uniquePathForCamera(it.matchedCameraInfo)
|
||||
);
|
||||
@@ -145,7 +148,7 @@ const unmatchedCameras = computed(() => {
|
||||
});
|
||||
|
||||
const activeVisionModules = computed(() =>
|
||||
useCameraSettingsStore().cameras.filter(
|
||||
Object.values(useCameraSettingsStore().cameras).filter(
|
||||
(camera) => JSON.stringify(camera) !== JSON.stringify(PlaceholderCameraSettings)
|
||||
)
|
||||
);
|
||||
@@ -166,13 +169,7 @@ const setCameraView = (camera: PVCameraInfo | null, showCurrent: boolean = false
|
||||
<div class="pa-5">
|
||||
<v-row>
|
||||
<!-- Active modules -->
|
||||
<v-col
|
||||
v-for="(module, index) in activeVisionModules"
|
||||
:key="`enabled-${module.uniqueName}`"
|
||||
cols="12"
|
||||
sm="6"
|
||||
lg="4"
|
||||
>
|
||||
<v-col v-for="module in activeVisionModules" :key="`enabled-${module.uniqueName}`" cols="12" sm="6" lg="4">
|
||||
<v-card dark color="primary">
|
||||
<v-card-title>{{ module.nickname }}</v-card-title>
|
||||
<v-card-subtitle v-if="_.isEqual(getMatchedDevice(module.matchedCameraInfo), module.matchedCameraInfo)"
|
||||
@@ -211,11 +208,11 @@ const setCameraView = (camera: PVCameraInfo | null, showCurrent: boolean = false
|
||||
}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="module.isConnected && useStateStore().backendResults[index]">
|
||||
<tr v-if="module.isConnected && useStateStore().backendResults[module.uniqueName]">
|
||||
<td>Frames Processed</td>
|
||||
<td>
|
||||
{{ useStateStore().backendResults[index].sequenceID }} ({{
|
||||
useStateStore().backendResults[index].fps
|
||||
{{ useStateStore().backendResults[module.uniqueName].sequenceID }} ({{
|
||||
useStateStore().backendResults[module.uniqueName].fps
|
||||
}}
|
||||
FPS)
|
||||
</td>
|
||||
|
||||
@@ -42,12 +42,13 @@ const cameraViewType = computed<number[]>({
|
||||
// TODO - deduplicate with needsCamerasConfigured
|
||||
const warningShown = computed<boolean>(() => {
|
||||
return (
|
||||
useCameraSettingsStore().cameras.length === 0 || useCameraSettingsStore().cameras[0] === PlaceholderCameraSettings
|
||||
Object.values(useCameraSettingsStore().cameras).length === 0 ||
|
||||
useCameraSettingsStore().cameras["Placeholder Name"] === PlaceholderCameraSettings
|
||||
);
|
||||
});
|
||||
|
||||
const arducamWarningShown = computed<boolean>(() => {
|
||||
return useCameraSettingsStore().cameras.some(
|
||||
return Object.values(useCameraSettingsStore().cameras).some(
|
||||
(c) =>
|
||||
c.cameraQuirks?.quirks?.ArduCamCamera === true &&
|
||||
!(
|
||||
|
||||
Reference in New Issue
Block a user