mirror of
https://github.com/PhotonVision/photonvision
synced 2026-07-01 02:41:42 +00:00
## Description Upgrades to Vue 3 and necessary associated dependencies. Also fixes some issues with the layout and adds validation for object detection models. Closes #885, closes #1943, closes #1449. ## Meta Merge checklist: - [x] Pull Request title is [short, imperative summary](https://cbea.ms/git-commit/) of proposed changes - [x] The description documents the _what_ and _why_ - [ ] If this PR changes behavior or adds a feature, user documentation is updated - [ ] If this PR touches photon-serde, all messages have been regenerated and hashes have not changed unexpectedly - [ ] If this PR touches configuration, this is backwards compatible with settings back to v2024.3.1 - [ ] If this PR touches pipeline settings or anything related to data exchange, the frontend typing is updated - [ ] If this PR addresses a bug, a regression test for it is added --------- Co-authored-by: Matt M <matthew.morley.ca@gmail.com> Co-authored-by: Gold856 <117957790+Gold856@users.noreply.github.com> Co-authored-by: samfreund <techguy763@gmail.com>
240 lines
9.2 KiB
Vue
240 lines
9.2 KiB
Vue
<script setup lang="ts">
|
|
import PvSelect from "@/components/common/pv-select.vue";
|
|
import { useCameraSettingsStore } from "@/stores/settings/CameraSettingsStore";
|
|
import { type ActivePipelineSettings, PipelineType, RobotOffsetPointMode } from "@/types/PipelineTypes";
|
|
import PvSwitch from "@/components/common/pv-switch.vue";
|
|
import { computed } from "vue";
|
|
import { RobotOffsetType } from "@/types/SettingTypes";
|
|
import { useStateStore } from "@/stores/StateStore";
|
|
import { useDisplay } from "vuetify";
|
|
|
|
const isTagPipeline = computed(
|
|
() =>
|
|
useCameraSettingsStore().currentPipelineType === PipelineType.AprilTag ||
|
|
useCameraSettingsStore().currentPipelineType === PipelineType.Aruco
|
|
);
|
|
|
|
interface MetricItem {
|
|
header: string;
|
|
value?: string;
|
|
}
|
|
|
|
const offsetPoints = computed<MetricItem[]>(() => {
|
|
switch (useCameraSettingsStore().currentPipelineSettings.offsetRobotOffsetMode) {
|
|
case RobotOffsetPointMode.Single:
|
|
const value = Object.values(useCameraSettingsStore().currentPipelineSettings.offsetSinglePoint);
|
|
return [{ header: "Offset Point", value: `(${value[0].toFixed(2)}°, ${value[1].toFixed(2)}°)` }];
|
|
case RobotOffsetPointMode.Dual:
|
|
const firstPoint = Object.values(useCameraSettingsStore().currentPipelineSettings.offsetDualPointA);
|
|
const firstPointArea = useCameraSettingsStore().currentPipelineSettings.offsetDualPointAArea;
|
|
const secondPoint = Object.values(useCameraSettingsStore().currentPipelineSettings.offsetDualPointB);
|
|
const secondPointArea = useCameraSettingsStore().currentPipelineSettings.offsetDualPointBArea;
|
|
return [
|
|
{ header: "First Offset Point", value: `(${firstPoint[0].toFixed(2)}°, ${firstPoint[1].toFixed(2)}°)` },
|
|
{ header: "First Offset Point Area", value: `${firstPointArea.toFixed(2)}%` },
|
|
{ header: "Second Offset Point", value: `(${secondPoint[0].toFixed(2)}°, ${secondPoint[1].toFixed(2)}°)` },
|
|
{ header: "Second Offset Point Area", value: `${secondPointArea.toFixed(2)}%` }
|
|
];
|
|
default:
|
|
case RobotOffsetPointMode.None:
|
|
return [];
|
|
}
|
|
});
|
|
|
|
// TODO fix pipeline typing in order to fix this, the store settings call should be able to infer that only valid pipeline type settings are exposed based on pre-checks for the entire config section
|
|
// Defer reference to store access method
|
|
const currentPipelineSettings = computed<ActivePipelineSettings>(
|
|
() => useCameraSettingsStore().currentPipelineSettings
|
|
);
|
|
const { mdAndDown } = useDisplay();
|
|
|
|
const interactiveCols = computed(() =>
|
|
mdAndDown.value && (!useStateStore().sidebarFolded || useCameraSettingsStore().isDriverMode) ? 8 : 7
|
|
);
|
|
</script>
|
|
|
|
<template>
|
|
<div>
|
|
<pv-switch
|
|
v-model="useCameraSettingsStore().currentPipelineSettings.outputShowMultipleTargets"
|
|
label="Show Multiple Targets"
|
|
tooltip="If enabled, up to five targets will be displayed and sent via PhotonLib, instead of just one"
|
|
:disabled="isTagPipeline"
|
|
:switch-cols="interactiveCols"
|
|
@update:modelValue="
|
|
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ outputShowMultipleTargets: value }, false)
|
|
"
|
|
/>
|
|
<pv-switch
|
|
v-if="
|
|
(currentPipelineSettings.pipelineType === PipelineType.AprilTag ||
|
|
currentPipelineSettings.pipelineType === PipelineType.Aruco) &&
|
|
useCameraSettingsStore().isCurrentVideoFormatCalibrated &&
|
|
useCameraSettingsStore().currentPipelineSettings.solvePNPEnabled
|
|
"
|
|
v-model="currentPipelineSettings.doMultiTarget"
|
|
label="Do Multi-Target Estimation"
|
|
tooltip="If enabled, all visible fiducial targets will be used to provide a single pose estimate from their combined model."
|
|
:switch-cols="interactiveCols"
|
|
:disabled="!isTagPipeline"
|
|
@update:modelValue="
|
|
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ doMultiTarget: value }, false)
|
|
"
|
|
/>
|
|
<pv-switch
|
|
v-if="
|
|
(currentPipelineSettings.pipelineType === PipelineType.AprilTag ||
|
|
currentPipelineSettings.pipelineType === PipelineType.Aruco) &&
|
|
useCameraSettingsStore().isCurrentVideoFormatCalibrated &&
|
|
useCameraSettingsStore().currentPipelineSettings.solvePNPEnabled
|
|
"
|
|
v-model="currentPipelineSettings.doSingleTargetAlways"
|
|
label="Always Do Single-Target Estimation"
|
|
tooltip="If disabled, visible fiducial targets used for multi-target estimation will not also be used for single-target estimation."
|
|
:switch-cols="interactiveCols"
|
|
:disabled="!isTagPipeline || !currentPipelineSettings.doMultiTarget"
|
|
@update:modelValue="
|
|
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ doSingleTargetAlways: value }, false)
|
|
"
|
|
/>
|
|
<pv-select
|
|
v-model="useCameraSettingsStore().currentPipelineSettings.contourTargetOffsetPointEdge"
|
|
label="Target Offset Point"
|
|
tooltip="Changes where the 'center' of the target is (used for calculating e.g. pitch and yaw)"
|
|
:items="['Center', 'Top', 'Bottom', 'Left', 'Right']"
|
|
:select-cols="interactiveCols"
|
|
@update:modelValue="
|
|
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourTargetOffsetPointEdge: value }, false)
|
|
"
|
|
/>
|
|
<pv-select
|
|
v-if="!isTagPipeline"
|
|
v-model="useCameraSettingsStore().currentPipelineSettings.contourTargetOrientation"
|
|
label="Target Orientation"
|
|
tooltip="Used to determine how to calculate target landmarks (e.g. the top, left, or bottom of the target)"
|
|
:items="['Portrait', 'Landscape']"
|
|
:select-cols="interactiveCols"
|
|
@update:modelValue="
|
|
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourTargetOrientation: value }, false)
|
|
"
|
|
/>
|
|
<pv-select
|
|
v-model="useCameraSettingsStore().currentPipelineSettings.offsetRobotOffsetMode"
|
|
label="Robot Offset Mode"
|
|
tooltip="Used to add an arbitrary offset to the location of the targeting crosshair"
|
|
:items="['None', 'Single Point', 'Dual Point']"
|
|
:select-cols="interactiveCols"
|
|
@update:modelValue="
|
|
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ offsetRobotOffsetMode: value }, false)
|
|
"
|
|
/>
|
|
<table
|
|
v-if="useCameraSettingsStore().currentPipelineSettings.offsetRobotOffsetMode !== RobotOffsetPointMode.None"
|
|
class="metrics-table mt-3 mb-3"
|
|
>
|
|
<tr>
|
|
<th v-for="(item, itemIndex) in offsetPoints" :key="itemIndex" class="metric-item metric-item-title">
|
|
{{ item.header }}
|
|
</th>
|
|
</tr>
|
|
<tr>
|
|
<td v-for="(item, itemIndex) in offsetPoints" :key="itemIndex" class="metric-item">
|
|
{{ item.value }}
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
<div
|
|
v-if="useCameraSettingsStore().currentPipelineSettings.offsetRobotOffsetMode !== RobotOffsetPointMode.None"
|
|
class="d-flex align-center"
|
|
>
|
|
<v-card-text
|
|
v-if="useCameraSettingsStore().currentPipelineSettings.offsetRobotOffsetMode === RobotOffsetPointMode.Single"
|
|
class="d-flex pa-0 flex-wrap"
|
|
>
|
|
<v-col cols="6" class="pl-0">
|
|
<v-btn
|
|
size="small"
|
|
block
|
|
color="accent"
|
|
class="text-black"
|
|
@click="useCameraSettingsStore().takeRobotOffsetPoint(RobotOffsetType.Single)"
|
|
>
|
|
Take Point
|
|
</v-btn>
|
|
</v-col>
|
|
<v-col cols="6" class="pr-0">
|
|
<v-btn
|
|
size="small"
|
|
block
|
|
color="yellow-darken-3"
|
|
@click="useCameraSettingsStore().takeRobotOffsetPoint(RobotOffsetType.Clear)"
|
|
>
|
|
Clear All Points
|
|
</v-btn>
|
|
</v-col>
|
|
</v-card-text>
|
|
<v-card-text
|
|
v-else-if="useCameraSettingsStore().currentPipelineSettings.offsetRobotOffsetMode === RobotOffsetPointMode.Dual"
|
|
class="d-flex pa-0 flex-wrap"
|
|
>
|
|
<v-col cols="6" lg="4" class="pl-0 pr-2">
|
|
<v-btn
|
|
size="small"
|
|
block
|
|
color="accent"
|
|
class="text-black"
|
|
@click="useCameraSettingsStore().takeRobotOffsetPoint(RobotOffsetType.DualFirst)"
|
|
>
|
|
Take First Point
|
|
</v-btn>
|
|
</v-col>
|
|
<v-col cols="6" lg="4" class="pl-2 pr-0 pr-lg-2">
|
|
<v-btn
|
|
size="small"
|
|
block
|
|
color="accent"
|
|
class="text-black"
|
|
@click="useCameraSettingsStore().takeRobotOffsetPoint(RobotOffsetType.DualSecond)"
|
|
>
|
|
Take Second Point
|
|
</v-btn>
|
|
</v-col>
|
|
<v-col cols="12" lg="4" class="pl-0 pl-lg-2 pr-0">
|
|
<v-btn
|
|
size="small"
|
|
block
|
|
color="yellow-darken-3"
|
|
@click="useCameraSettingsStore().takeRobotOffsetPoint(RobotOffsetType.Clear)"
|
|
>
|
|
Clear All Points
|
|
</v-btn>
|
|
</v-col>
|
|
</v-card-text>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.metrics-table {
|
|
border-collapse: separate;
|
|
border-spacing: 0;
|
|
border-radius: 5px;
|
|
border: 1px solid white;
|
|
width: 100%;
|
|
text-align: center;
|
|
}
|
|
|
|
.metric-item {
|
|
padding: 1px 15px 1px 10px;
|
|
border-right: 1px solid;
|
|
font-weight: normal;
|
|
color: white;
|
|
}
|
|
|
|
.metric-item-title {
|
|
font-size: 18px;
|
|
text-decoration: underline;
|
|
text-decoration-color: #ffd843;
|
|
}
|
|
</style>
|