Improve UI stability, reliability, and readability (#1104)

closes #1090
closes #1030

Also fixes various styling issues and overflow issues for mobile support
This commit is contained in:
Sriman Achanta
2024-01-02 11:03:16 -05:00
committed by GitHub
parent 2a1792e71a
commit e4f475a253
24 changed files with 1436 additions and 5260 deletions

View File

@@ -29,61 +29,83 @@ const fpsTooLow = computed<boolean>(() => {
return currFPS - targetFPS < -5 && currFPS !== 0 && !driverMode && gpuAccel && isReflective;
});
const performanceRecommendation = computed<string>(() => {
if (
fpsTooLow.value &&
!useCameraSettingsStore().currentPipelineSettings.inputShouldShow &&
useCameraSettingsStore().currentPipelineSettings.pipelineType === PipelineType.Reflective
) {
return "HSV thresholds are too broad; narrow them for better performance";
} else if (fpsTooLow.value && useCameraSettingsStore().currentPipelineSettings.inputShouldShow) {
return "Stop viewing the raw stream for better performance";
} else {
return `${Math.min(Math.round(useStateStore().currentPipelineResults?.latency || 0), 9999)} ms latency`;
}
});
</script>
<template>
<v-card color="primary" height="100%" style="display: flex; flex-direction: column" dark>
<v-card-title
class="pb-0 mb-0 pl-4 pt-1"
style="min-height: 50px; justify-content: space-between; align-content: center"
>
<div class="pt-2">
<span class="mr-4">Cameras</span>
<v-row>
<v-col class="align-self-center text-no-wrap">
<v-card-title>Cameras</v-card-title>
</v-col>
<v-col class="align-self-center" style="text-align: right; margin-right: 12px; padding-left: 24px">
<v-chip
label
:color="fpsTooLow ? 'error' : 'transparent'"
:text-color="fpsTooLow ? '#C7EA46' : '#ff4d00'"
style="font-size: 1rem; padding: 0; margin: 0"
>
<span class="pr-1">
Processing @ {{ Math.round(useStateStore().currentPipelineResults?.fps || 0) }}&nbsp;FPS &ndash;
</span>
<span
v-if="
fpsTooLow &&
!useCameraSettingsStore().currentPipelineSettings.inputShouldShow &&
useCameraSettingsStore().currentPipelineSettings.pipelineType === PipelineType.Reflective
"
>
HSV thresholds are too broad; narrow them for better performance
</span>
<span v-else-if="fpsTooLow && useCameraSettingsStore().currentPipelineSettings.inputShouldShow">
stop viewing the raw stream for better performance
</span>
<span v-else>
{{ Math.min(Math.round(useStateStore().currentPipelineResults?.latency || 0), 9999) }} ms latency
</span>
<span class="pr-1"
>Processing @ {{ Math.round(useStateStore().currentPipelineResults?.fps || 0) }}&nbsp;FPS &ndash;</span
><span>{{ performanceRecommendation }}</span>
</v-chip>
</div>
<div>
</v-col>
<v-col
class="align-self-center"
style="
width: min-content;
flex-grow: 0;
display: flex;
justify-content: flex-end;
margin-right: 24px;
padding: 0;
"
>
<v-switch
v-model="driverMode"
:disabled="useCameraSettingsStore().isCalibrationMode || useCameraSettingsStore().pipelineNames.length === 0"
label="Driver Mode"
style="margin-left: auto"
style="margin: 0; padding: 0; padding-left: 18px; margin-top: 14px"
color="accent"
class="pt-2"
/>
</div>
</v-card-title>
</v-col>
</v-row>
<v-divider style="border-color: white" />
<v-row class="pl-3 pr-3 pt-3 pb-3" style="flex-wrap: nowrap; justify-content: center">
<v-col v-show="value.includes(0)" style="max-width: 500px; display: flex; align-items: center">
<v-row class="stream-viewer-container pa-3">
<v-col v-show="value.includes(0)" class="stream-view">
<photon-camera-stream id="input-camera-stream" stream-type="Raw" style="width: 100%; height: auto" />
</v-col>
<v-col v-show="value.includes(1)" style="max-width: 500px; display: flex; align-items: center">
<v-col v-show="value.includes(1)" class="stream-view">
<photon-camera-stream id="output-camera-stream" stream-type="Processed" style="width: 100%; height: auto" />
</v-col>
</v-row>
</v-card>
</template>
<style scoped>
.stream-viewer-container {
display: flex;
justify-content: center;
}
.stream-view {
max-width: 500px;
}
@media only screen and (max-width: 512px) {
.stream-view {
min-width: 80%;
}
}
</style>

View File

@@ -39,11 +39,11 @@ const processingMode = computed<number>({
<p style="color: white">Processing Mode</p>
<v-btn-toggle v-model="processingMode" mandatory dark class="fill">
<v-btn color="secondary">
<v-icon>mdi-square-outline</v-icon>
<v-icon left>mdi-square-outline</v-icon>
<span>2D</span>
</v-btn>
<v-btn color="secondary" :disabled="!useCameraSettingsStore().isCurrentVideoFormatCalibrated">
<v-icon>mdi-cube-outline</v-icon>
<v-icon left>mdi-cube-outline</v-icon>
<span>3D</span>
</v-btn>
</v-btn-toggle>
@@ -54,12 +54,12 @@ const processingMode = computed<number>({
<p style="color: white">Stream Display</p>
<v-btn-toggle v-model="localValue" :multiple="true" mandatory dark class="fill">
<v-btn color="secondary" class="fill">
<v-icon>mdi-import</v-icon>
<span>Raw</span>
<v-icon left class="mode-btn-icon">mdi-import</v-icon>
<span class="mode-btn-label">Raw</span>
</v-btn>
<v-btn color="secondary" class="fill">
<v-icon>mdi-export</v-icon>
<span>Processed</span>
<v-icon left class="mode-btn-icon">mdi-export</v-icon>
<span class="mode-btn-label">Processed</span>
</v-btn>
</v-btn-toggle>
</v-col>
@@ -82,4 +82,13 @@ th {
width: 80px;
text-align: center;
}
@media only screen and (max-width: 351px) {
.mode-btn-icon {
margin: 0 !important;
}
.mode-btn-label {
display: none;
}
}
</style>

View File

@@ -1,15 +1,18 @@
<script setup lang="ts">
import { useCameraSettingsStore } from "@/stores/settings/CameraSettingsStore";
import { PipelineType } from "@/types/PipelineTypes";
import PvSelect from "@/components/common/pv-select.vue";
import PvSlider from "@/components/common/pv-slider.vue";
import PvSwitch from "@/components/common/pv-switch.vue";
import { computed, getCurrentInstance } from "vue";
import { useStateStore } from "@/stores/StateStore";
import type { ActivePipelineSettings } from "@/types/PipelineTypes";
import { useCameraSettingsStore } from "@/stores/settings/CameraSettingsStore";
// 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 = useCameraSettingsStore().currentPipelineSettings;
const currentPipelineSettings = computed<ActivePipelineSettings>(
() => useCameraSettingsStore().currentPipelineSettings
);
const interactiveCols = computed(
() =>

View File

@@ -1,6 +1,6 @@
<script setup lang="ts">
import { useCameraSettingsStore } from "@/stores/settings/CameraSettingsStore";
import { PipelineType } from "@/types/PipelineTypes";
import { PipelineType, type ActivePipelineSettings } from "@/types/PipelineTypes";
import PvSlider from "@/components/common/pv-slider.vue";
import PvSwitch from "@/components/common/pv-switch.vue";
import PvRangeSlider from "@/components/common/pv-range-slider.vue";
@@ -10,7 +10,9 @@ import { useStateStore } from "@/stores/StateStore";
// 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 = useCameraSettingsStore().currentPipelineSettings;
const currentPipelineSettings = computed<ActivePipelineSettings>(
() => useCameraSettingsStore().currentPipelineSettings
);
const interactiveCols = computed(
() =>

View File

@@ -1,6 +1,6 @@
<script setup lang="ts">
import { useCameraSettingsStore } from "@/stores/settings/CameraSettingsStore";
import { PipelineType } from "@/types/PipelineTypes";
import { type ActivePipelineSettings, PipelineType } from "@/types/PipelineTypes";
import PvRangeSlider from "@/components/common/pv-range-slider.vue";
import PvSelect from "@/components/common/pv-select.vue";
import PvSlider from "@/components/common/pv-slider.vue";
@@ -9,7 +9,9 @@ import { useStateStore } from "@/stores/StateStore";
// 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 = useCameraSettingsStore().currentPipelineSettings;
const currentPipelineSettings = computed<ActivePipelineSettings>(
() => useCameraSettingsStore().currentPipelineSettings
);
// TODO fix pv-range-slider so that store access doesn't need to be deferred
const contourArea = computed<[number, number]>({
@@ -26,23 +28,23 @@ const contourFullness = computed<[number, number]>({
});
const contourPerimeter = computed<[number, number]>({
get: () =>
currentPipelineSettings.pipelineType === PipelineType.ColoredShape
? (Object.values(currentPipelineSettings.contourPerimeter) as [number, number])
currentPipelineSettings.value.pipelineType === PipelineType.ColoredShape
? (Object.values(currentPipelineSettings.value.contourPerimeter) as [number, number])
: ([0, 0] as [number, number]),
set: (v) => {
if (currentPipelineSettings.pipelineType === PipelineType.ColoredShape) {
currentPipelineSettings.contourPerimeter = v;
if (currentPipelineSettings.value.pipelineType === PipelineType.ColoredShape) {
currentPipelineSettings.value.contourPerimeter = v;
}
}
});
const contourRadius = computed<[number, number]>({
get: () =>
currentPipelineSettings.pipelineType === PipelineType.ColoredShape
? (Object.values(currentPipelineSettings.contourRadius) as [number, number])
currentPipelineSettings.value.pipelineType === PipelineType.ColoredShape
? (Object.values(currentPipelineSettings.value.contourRadius) as [number, number])
: ([0, 0] as [number, number]),
set: (v) => {
if (currentPipelineSettings.pipelineType === PipelineType.ColoredShape) {
currentPipelineSettings.contourRadius = v;
if (currentPipelineSettings.value.pipelineType === PipelineType.ColoredShape) {
currentPipelineSettings.value.contourRadius = v;
}
}
});
@@ -103,8 +105,8 @@ const interactiveCols = computed(
v-model="contourPerimeter"
label="Perimeter"
tooltip="Min and max perimeter of the shape, in pixels"
min="0"
max="4000"
:min="0"
:max="4000"
:slider-cols="interactiveCols"
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourPerimeter: value }, false)"
/>

View File

@@ -6,6 +6,7 @@ import PvSelect from "@/components/common/pv-select.vue";
import { computed, getCurrentInstance } from "vue";
import { useSettingsStore } from "@/stores/settings/GeneralSettingsStore";
import { useStateStore } from "@/stores/StateStore";
import { getResolutionString } from "@/lib/PhotonUtils";
// Due to something with libcamera or something else IDK much about, the 90° rotations need to be disabled if the libcamera drivers are being used.
const cameraRotations = computed(() =>
@@ -30,7 +31,7 @@ const getNumberOfSkippedDivisors = () => streamDivisors.length - getFilteredStre
const cameraResolutions = computed(() =>
useCameraSettingsStore().currentCameraSettings.validVideoFormats.map(
(f) => `${f.resolution.width} X ${f.resolution.height} at ${f.fps} FPS, ${f.pixelFormat}`
(f) => `${getResolutionString(f.resolution)} at ${f.fps} FPS, ${f.pixelFormat}`
)
);
const handleResolutionChange = (value: number) => {
@@ -48,7 +49,11 @@ const streamResolutions = computed(() => {
const streamDivisors = getFilteredStreamDivisors();
const currentResolution = useCameraSettingsStore().currentVideoFormat.resolution;
return streamDivisors.map(
(x) => `${Math.floor(currentResolution.width / x)} X ${Math.floor(currentResolution.height / x)}`
(x) =>
`${getResolutionString({
width: Math.floor(currentResolution.width / x),
height: Math.floor(currentResolution.height / x)
})}`
);
});
const handleStreamResolutionChange = (value: number) => {

View File

@@ -1,7 +1,7 @@
<script setup lang="ts">
import PvSelect from "@/components/common/pv-select.vue";
import { useCameraSettingsStore } from "@/stores/settings/CameraSettingsStore";
import { PipelineType, RobotOffsetPointMode } from "@/types/PipelineTypes";
import { type ActivePipelineSettings, PipelineType, RobotOffsetPointMode } from "@/types/PipelineTypes";
import PvSwitch from "@/components/common/pv-switch.vue";
import { computed, getCurrentInstance } from "vue";
import { RobotOffsetType } from "@/types/SettingTypes";
@@ -40,7 +40,11 @@ const offsetPoints = computed<MetricItem[]>(() => {
}
});
const currentPipelineSettings = useCameraSettingsStore().currentPipelineSettings;
// 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 interactiveCols = computed(
() =>

View File

@@ -1,14 +1,15 @@
<script setup lang="ts">
import { useCameraSettingsStore } from "@/stores/settings/CameraSettingsStore";
import { PipelineType } from "@/types/PipelineTypes";
import { type ActivePipelineSettings, PipelineType } from "@/types/PipelineTypes";
import { useStateStore } from "@/stores/StateStore";
import { angleModulus, toDeg } from "@/lib/MathUtils";
import { computed } from "vue";
const wrapToPi = (delta: number): number => {
let ret = delta;
while (ret < -Math.PI) ret += Math.PI * 2;
while (ret > Math.PI) ret -= Math.PI * 2;
return ret;
};
// 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 calculateStdDev = (values: number[]): number => {
if (values.length < 2) return 0;
@@ -21,14 +22,9 @@ const calculateStdDev = (values: number[]): number => {
// Borrowed from WPILib's Rotation2d
const hypot = Math.hypot(cosmean, sinmean);
let mean;
if (hypot > 1e-6) {
mean = Math.atan2(sinmean / hypot, cosmean / hypot);
} else {
mean = 0;
}
const mean = hypot > 1e-6 ? Math.atan2(sinmean / hypot, cosmean / hypot) : 0;
return Math.sqrt(values.map((x) => Math.pow(wrapToPi(x - mean), 2)).reduce((a, b) => a + b) / values.length);
return Math.sqrt(values.map((x) => Math.pow(angleModulus(x - mean), 2)).reduce((a, b) => a + b) / values.length);
};
const resetCurrentBuffer = () => {
// Need to clear the array in place
@@ -38,71 +34,78 @@ const resetCurrentBuffer = () => {
<template>
<div>
<v-row align="start" class="pb-4" style="height: 300px">
<v-simple-table fixed-header dense dark>
<v-row align="start" class="pb-4">
<v-simple-table dense class="pt-2 pb-12">
<template #default>
<thead style="font-size: 1.25rem">
<thead>
<tr>
<th
v-if="
useCameraSettingsStore().currentPipelineType === PipelineType.AprilTag ||
useCameraSettingsStore().currentPipelineType === PipelineType.Aruco
currentPipelineSettings.pipelineType === PipelineType.AprilTag ||
currentPipelineSettings.pipelineType === PipelineType.Aruco
"
class="text-center"
class="text-center white--text"
>
Fiducial ID
</th>
<template v-if="!useCameraSettingsStore().currentPipelineSettings.solvePNPEnabled">
<th class="text-center">Pitch &theta;&deg;</th>
<th class="text-center">Yaw &theta;&deg;</th>
<th class="text-center">Skew &theta;&deg;</th>
<th class="text-center">Area %</th>
<th class="text-center white--text">Pitch &theta;&deg;</th>
<th class="text-center white--text">Yaw &theta;&deg;</th>
<th class="text-center white--text">Skew &theta;&deg;</th>
<th class="text-center white--text">Area %</th>
</template>
<template v-else>
<th class="text-center">X meters</th>
<th class="text-center">Y meters</th>
<th class="text-center">Z Angle &theta;&deg;</th>
<th class="text-center white--text">X meters</th>
<th class="text-center white--text">Y meters</th>
<th class="text-center white--text">Z Angle &theta;&deg;</th>
</template>
<template
v-if="
(useCameraSettingsStore().currentPipelineType === PipelineType.AprilTag ||
useCameraSettingsStore().currentPipelineType === PipelineType.Aruco) &&
(currentPipelineSettings.pipelineType === PipelineType.AprilTag ||
currentPipelineSettings.pipelineType === PipelineType.Aruco) &&
useCameraSettingsStore().currentPipelineSettings.solvePNPEnabled
"
>
<th class="text-center">Ambiguity Ratio</th>
<th class="text-center white--text">Ambiguity Ratio</th>
</template>
</tr>
</thead>
<tbody>
<tr v-for="(target, index) in useStateStore().currentPipelineResults?.targets" :key="index">
<tr
v-for="(target, index) in useStateStore().currentPipelineResults?.targets"
:key="index"
class="white--text"
>
<td
v-if="
useCameraSettingsStore().currentPipelineType === PipelineType.AprilTag ||
useCameraSettingsStore().currentPipelineType === PipelineType.Aruco
currentPipelineSettings.pipelineType === PipelineType.AprilTag ||
currentPipelineSettings.pipelineType === PipelineType.Aruco
"
class="text-center"
>
{{ target.fiducialId }}
</td>
<template v-if="!useCameraSettingsStore().currentPipelineSettings.solvePNPEnabled">
<td>{{ target.pitch.toFixed(2) }}&deg;</td>
<td>{{ target.yaw.toFixed(2) }}&deg;</td>
<td>{{ target.skew.toFixed(2) }}&deg;</td>
<td>{{ target.area.toFixed(2) }}&deg;</td>
<td class="text-center">{{ target.pitch.toFixed(2) }}&deg;</td>
<td class="text-center">{{ target.yaw.toFixed(2) }}&deg;</td>
<td class="text-center">{{ target.skew.toFixed(2) }}&deg;</td>
<td class="text-center">{{ target.area.toFixed(2) }}&deg;</td>
</template>
<template v-else>
<td>{{ target.pose?.x.toFixed(2) }}&nbsp;m</td>
<td>{{ target.pose?.y.toFixed(2) }}&nbsp;m</td>
<td>{{ (((target.pose?.angle_z || 0) * 180.0) / Math.PI).toFixed(2) }}&deg;</td>
<td class="text-center">{{ target.pose?.x.toFixed(2) }}&nbsp;m</td>
<td class="text-center">{{ target.pose?.y.toFixed(2) }}&nbsp;m</td>
<td class="text-center">{{ toDeg(target.pose?.angle_z || 0).toFixed(2) }}&deg;</td>
</template>
<template
v-if="
(useCameraSettingsStore().currentPipelineType === PipelineType.AprilTag ||
useCameraSettingsStore().currentPipelineType === PipelineType.Aruco) &&
(currentPipelineSettings.pipelineType === PipelineType.AprilTag ||
currentPipelineSettings.pipelineType === PipelineType.Aruco) &&
useCameraSettingsStore().currentPipelineSettings.solvePNPEnabled
"
>
<td>{{ target.ambiguity >= 0 ? target.ambiguity.toFixed(2) : "(In Multi-Target)" }}</td>
<td class="text-center">
{{ target.ambiguity >= 0 ? target.ambiguity.toFixed(2) : "(In Multi-Target)" }}
</td>
</template>
</tr>
</tbody>
@@ -111,9 +114,9 @@ const resetCurrentBuffer = () => {
</v-row>
<v-container
v-if="
(useCameraSettingsStore().currentPipelineType === PipelineType.AprilTag ||
useCameraSettingsStore().currentPipelineType === PipelineType.Aruco) &&
useCameraSettingsStore().currentPipelineSettings.doMultiTarget &&
(currentPipelineSettings.pipelineType === PipelineType.AprilTag ||
currentPipelineSettings.pipelineType === PipelineType.Aruco) &&
currentPipelineSettings.doMultiTarget &&
useCameraSettingsStore().isCurrentVideoFormatCalibrated &&
useCameraSettingsStore().currentPipelineSettings.solvePNPEnabled
"
@@ -122,46 +125,57 @@ const resetCurrentBuffer = () => {
<v-card-subtitle class="ma-0 pa-0 pb-4" style="font-size: 16px"
>Multi-tag pose, field-to-camera</v-card-subtitle
>
<v-simple-table fixed-header height="100%" dense dark>
<thead style="font-size: 1.25rem">
<th class="text-center">X meters</th>
<th class="text-center">Y meters</th>
<th class="text-center">Z meters</th>
<th class="text-center">X Angle &theta;&deg;</th>
<th class="text-center">Y Angle &theta;&deg;</th>
<th class="text-center">Z Angle &theta;&deg;</th>
<th class="text-center">Tags</th>
</thead>
<tbody v-show="useStateStore().currentPipelineResults?.multitagResult">
<td>{{ useStateStore().currentPipelineResults?.multitagResult?.bestTransform.x.toFixed(2) }}&nbsp;m</td>
<td>{{ useStateStore().currentPipelineResults?.multitagResult?.bestTransform.y.toFixed(2) }}&nbsp;m</td>
<td>{{ useStateStore().currentPipelineResults?.multitagResult?.bestTransform.z.toFixed(2) }}&nbsp;m</td>
<td>
{{
(
(useStateStore().currentPipelineResults?.multitagResult?.bestTransform.angle_x || 0) *
(180.0 / Math.PI)
).toFixed(2)
}}&deg;
</td>
<td>
{{
(
(useStateStore().currentPipelineResults?.multitagResult?.bestTransform.angle_y || 0) *
(180.0 / Math.PI)
).toFixed(2)
}}&deg;
</td>
<td>
{{
(
(useStateStore().currentPipelineResults?.multitagResult?.bestTransform.angle_z || 0) *
(180.0 / Math.PI)
).toFixed(2)
}}&deg;
</td>
<td>{{ useStateStore().currentPipelineResults?.multitagResult?.fiducialIDsUsed }}</td>
</tbody>
<v-simple-table dense>
<template #default>
<thead>
<tr class="white--text">
<th class="text-center white--text">X meters</th>
<th class="text-center white--text">Y meters</th>
<th class="text-center white--text">Z meters</th>
<th class="text-center white--text">X Angle &theta;&deg;</th>
<th class="text-center white--text">Y Angle &theta;&deg;</th>
<th class="text-center white--text">Z Angle &theta;&deg;</th>
<th class="text-center white--text">Tags</th>
</tr>
</thead>
<tbody v-show="useStateStore().currentPipelineResults?.multitagResult">
<tr>
<td class="text-center white--text">
{{ useStateStore().currentPipelineResults?.multitagResult?.bestTransform.x.toFixed(2) }}&nbsp;m
</td>
<td class="text-center white--text">
{{ useStateStore().currentPipelineResults?.multitagResult?.bestTransform.y.toFixed(2) }}&nbsp;m
</td>
<td class="text-center white--text">
{{ useStateStore().currentPipelineResults?.multitagResult?.bestTransform.z.toFixed(2) }}&nbsp;m
</td>
<td class="text-center white--text">
{{
toDeg(useStateStore().currentPipelineResults?.multitagResult?.bestTransform.angle_x || 0).toFixed(
2
)
}}&deg;
</td>
<td class="text-center white--text">
{{
toDeg(useStateStore().currentPipelineResults?.multitagResult?.bestTransform.angle_y || 0).toFixed(
2
)
}}&deg;
</td>
<td class="text-center white--text">
{{
toDeg(useStateStore().currentPipelineResults?.multitagResult?.bestTransform.angle_z || 0).toFixed(
2
)
}}&deg;
</td>
<td class="text-center white--text">
{{ useStateStore().currentPipelineResults?.multitagResult?.fiducialIDsUsed }}
</td>
</tr>
</tbody>
</template>
</v-simple-table>
</v-row>
<v-row class="pb-4 white--text" style="display: flex; flex-direction: column">
@@ -172,53 +186,65 @@ const resetCurrentBuffer = () => {
<v-btn color="secondary" class="mb-4 mt-1" style="width: min-content" depressed @click="resetCurrentBuffer"
>Reset Samples</v-btn
>
<v-simple-table fixed-header height="100%" dense dark>
<thead style="font-size: 1.25rem">
<th class="text-center">X meters</th>
<th class="text-center">Y meters</th>
<th class="text-center">Z meters</th>
<th class="text-center">X Angle &theta;&deg;</th>
<th class="text-center">Y Angle &theta;&deg;</th>
<th class="text-center">Z Angle &theta;&deg;</th>
</thead>
<tbody v-show="useStateStore().currentPipelineResults?.multitagResult">
<td>
{{
calculateStdDev(useStateStore().currentMultitagBuffer?.map((v) => v.bestTransform.x) || []).toFixed(5)
}}&nbsp;m
</td>
<td>
{{
calculateStdDev(useStateStore().currentMultitagBuffer?.map((v) => v.bestTransform.y) || []).toFixed(5)
}}&nbsp;m
</td>
<td>
{{
calculateStdDev(useStateStore().currentMultitagBuffer?.map((v) => v.bestTransform.z) || []).toFixed(5)
}}&nbsp;m
</td>
<td>
{{
calculateStdDev(
useStateStore().currentMultitagBuffer?.map((v) => v.bestTransform.angle_x * (180.0 / Math.PI)) || []
).toFixed(5)
}}&deg;
</td>
<td>
{{
calculateStdDev(
useStateStore().currentMultitagBuffer?.map((v) => v.bestTransform.angle_y * (180.0 / Math.PI)) || []
).toFixed(5)
}}&deg;
</td>
<td>
{{
calculateStdDev(
useStateStore().currentMultitagBuffer?.map((v) => v.bestTransform.angle_z * (180.0 / Math.PI)) || []
).toFixed(5)
}}&deg;
</td>
</tbody>
<v-simple-table dense>
<template #default>
<thead>
<tr>
<th class="text-center white--text">X meters</th>
<th class="text-center white--text">Y meters</th>
<th class="text-center white--text">Z meters</th>
<th class="text-center white--text">X Angle &theta;&deg;</th>
<th class="text-center white--text">Y Angle &theta;&deg;</th>
<th class="text-center white--text">Z Angle &theta;&deg;</th>
</tr>
</thead>
<tbody v-show="useStateStore().currentPipelineResults?.multitagResult">
<tr>
<td class="text-center white--text">
{{
calculateStdDev(useStateStore().currentMultitagBuffer?.map((v) => v.bestTransform.x) || []).toFixed(
5
)
}}&nbsp;m
</td>
<td class="text-center white--text">
{{
calculateStdDev(useStateStore().currentMultitagBuffer?.map((v) => v.bestTransform.y) || []).toFixed(
5
)
}}&nbsp;m
</td>
<td class="text-center white--text">
{{
calculateStdDev(useStateStore().currentMultitagBuffer?.map((v) => v.bestTransform.z) || []).toFixed(
5
)
}}&nbsp;m
</td>
<td class="text-center white--text">
{{
calculateStdDev(
useStateStore().currentMultitagBuffer?.map((v) => toDeg(v.bestTransform.angle_x)) || []
).toFixed(5)
}}&deg;
</td>
<td class="text-center white--text">
{{
calculateStdDev(
useStateStore().currentMultitagBuffer?.map((v) => toDeg(v.bestTransform.angle_y)) || []
).toFixed(5)
}}&deg;
</td>
<td class="text-center white--text">
{{
calculateStdDev(
useStateStore().currentMultitagBuffer?.map((v) => toDeg(v.bestTransform.angle_z)) || []
).toFixed(5)
}}&deg;
</td>
</tr>
</tbody>
</template>
</v-simple-table>
</v-row>
</v-container>
@@ -227,23 +253,30 @@ const resetCurrentBuffer = () => {
<style scoped lang="scss">
.v-data-table {
width: 100%;
height: 100%;
text-align: center;
background-color: #006492 !important;
width: 100%;
font-size: 1rem !important;
th,
td {
background-color: #006492 !important;
font-size: 1rem !important;
thead {
tr {
th {
font-size: 1rem !important;
color: white !important;
}
}
}
td {
font-family: monospace !important;
}
tbody :hover td {
background-color: #005281 !important;
tbody {
:hover {
td {
background-color: #005281 !important;
}
}
tr {
td {
font-size: 1rem !important;
color: white !important;
}
}
}
::-webkit-scrollbar {