mirror of
https://github.com/PhotonVision/photonvision
synced 2026-06-25 01:41:40 +00:00
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:
@@ -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(
|
||||
() =>
|
||||
|
||||
@@ -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(
|
||||
() =>
|
||||
|
||||
@@ -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)"
|
||||
/>
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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(
|
||||
() =>
|
||||
|
||||
@@ -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 θ°</th>
|
||||
<th class="text-center">Yaw θ°</th>
|
||||
<th class="text-center">Skew θ°</th>
|
||||
<th class="text-center">Area %</th>
|
||||
<th class="text-center white--text">Pitch θ°</th>
|
||||
<th class="text-center white--text">Yaw θ°</th>
|
||||
<th class="text-center white--text">Skew θ°</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 θ°</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 θ°</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) }}°</td>
|
||||
<td>{{ target.yaw.toFixed(2) }}°</td>
|
||||
<td>{{ target.skew.toFixed(2) }}°</td>
|
||||
<td>{{ target.area.toFixed(2) }}°</td>
|
||||
<td class="text-center">{{ target.pitch.toFixed(2) }}°</td>
|
||||
<td class="text-center">{{ target.yaw.toFixed(2) }}°</td>
|
||||
<td class="text-center">{{ target.skew.toFixed(2) }}°</td>
|
||||
<td class="text-center">{{ target.area.toFixed(2) }}°</td>
|
||||
</template>
|
||||
<template v-else>
|
||||
<td>{{ target.pose?.x.toFixed(2) }} m</td>
|
||||
<td>{{ target.pose?.y.toFixed(2) }} m</td>
|
||||
<td>{{ (((target.pose?.angle_z || 0) * 180.0) / Math.PI).toFixed(2) }}°</td>
|
||||
<td class="text-center">{{ target.pose?.x.toFixed(2) }} m</td>
|
||||
<td class="text-center">{{ target.pose?.y.toFixed(2) }} m</td>
|
||||
<td class="text-center">{{ toDeg(target.pose?.angle_z || 0).toFixed(2) }}°</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 θ°</th>
|
||||
<th class="text-center">Y Angle θ°</th>
|
||||
<th class="text-center">Z Angle θ°</th>
|
||||
<th class="text-center">Tags</th>
|
||||
</thead>
|
||||
<tbody v-show="useStateStore().currentPipelineResults?.multitagResult">
|
||||
<td>{{ useStateStore().currentPipelineResults?.multitagResult?.bestTransform.x.toFixed(2) }} m</td>
|
||||
<td>{{ useStateStore().currentPipelineResults?.multitagResult?.bestTransform.y.toFixed(2) }} m</td>
|
||||
<td>{{ useStateStore().currentPipelineResults?.multitagResult?.bestTransform.z.toFixed(2) }} m</td>
|
||||
<td>
|
||||
{{
|
||||
(
|
||||
(useStateStore().currentPipelineResults?.multitagResult?.bestTransform.angle_x || 0) *
|
||||
(180.0 / Math.PI)
|
||||
).toFixed(2)
|
||||
}}°
|
||||
</td>
|
||||
<td>
|
||||
{{
|
||||
(
|
||||
(useStateStore().currentPipelineResults?.multitagResult?.bestTransform.angle_y || 0) *
|
||||
(180.0 / Math.PI)
|
||||
).toFixed(2)
|
||||
}}°
|
||||
</td>
|
||||
<td>
|
||||
{{
|
||||
(
|
||||
(useStateStore().currentPipelineResults?.multitagResult?.bestTransform.angle_z || 0) *
|
||||
(180.0 / Math.PI)
|
||||
).toFixed(2)
|
||||
}}°
|
||||
</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 θ°</th>
|
||||
<th class="text-center white--text">Y Angle θ°</th>
|
||||
<th class="text-center white--text">Z Angle θ°</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) }} m
|
||||
</td>
|
||||
<td class="text-center white--text">
|
||||
{{ useStateStore().currentPipelineResults?.multitagResult?.bestTransform.y.toFixed(2) }} m
|
||||
</td>
|
||||
<td class="text-center white--text">
|
||||
{{ useStateStore().currentPipelineResults?.multitagResult?.bestTransform.z.toFixed(2) }} m
|
||||
</td>
|
||||
<td class="text-center white--text">
|
||||
{{
|
||||
toDeg(useStateStore().currentPipelineResults?.multitagResult?.bestTransform.angle_x || 0).toFixed(
|
||||
2
|
||||
)
|
||||
}}°
|
||||
</td>
|
||||
<td class="text-center white--text">
|
||||
{{
|
||||
toDeg(useStateStore().currentPipelineResults?.multitagResult?.bestTransform.angle_y || 0).toFixed(
|
||||
2
|
||||
)
|
||||
}}°
|
||||
</td>
|
||||
<td class="text-center white--text">
|
||||
{{
|
||||
toDeg(useStateStore().currentPipelineResults?.multitagResult?.bestTransform.angle_z || 0).toFixed(
|
||||
2
|
||||
)
|
||||
}}°
|
||||
</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 θ°</th>
|
||||
<th class="text-center">Y Angle θ°</th>
|
||||
<th class="text-center">Z Angle θ°</th>
|
||||
</thead>
|
||||
<tbody v-show="useStateStore().currentPipelineResults?.multitagResult">
|
||||
<td>
|
||||
{{
|
||||
calculateStdDev(useStateStore().currentMultitagBuffer?.map((v) => v.bestTransform.x) || []).toFixed(5)
|
||||
}} m
|
||||
</td>
|
||||
<td>
|
||||
{{
|
||||
calculateStdDev(useStateStore().currentMultitagBuffer?.map((v) => v.bestTransform.y) || []).toFixed(5)
|
||||
}} m
|
||||
</td>
|
||||
<td>
|
||||
{{
|
||||
calculateStdDev(useStateStore().currentMultitagBuffer?.map((v) => v.bestTransform.z) || []).toFixed(5)
|
||||
}} m
|
||||
</td>
|
||||
<td>
|
||||
{{
|
||||
calculateStdDev(
|
||||
useStateStore().currentMultitagBuffer?.map((v) => v.bestTransform.angle_x * (180.0 / Math.PI)) || []
|
||||
).toFixed(5)
|
||||
}}°
|
||||
</td>
|
||||
<td>
|
||||
{{
|
||||
calculateStdDev(
|
||||
useStateStore().currentMultitagBuffer?.map((v) => v.bestTransform.angle_y * (180.0 / Math.PI)) || []
|
||||
).toFixed(5)
|
||||
}}°
|
||||
</td>
|
||||
<td>
|
||||
{{
|
||||
calculateStdDev(
|
||||
useStateStore().currentMultitagBuffer?.map((v) => v.bestTransform.angle_z * (180.0 / Math.PI)) || []
|
||||
).toFixed(5)
|
||||
}}°
|
||||
</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 θ°</th>
|
||||
<th class="text-center white--text">Y Angle θ°</th>
|
||||
<th class="text-center white--text">Z Angle θ°</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
|
||||
)
|
||||
}} m
|
||||
</td>
|
||||
<td class="text-center white--text">
|
||||
{{
|
||||
calculateStdDev(useStateStore().currentMultitagBuffer?.map((v) => v.bestTransform.y) || []).toFixed(
|
||||
5
|
||||
)
|
||||
}} m
|
||||
</td>
|
||||
<td class="text-center white--text">
|
||||
{{
|
||||
calculateStdDev(useStateStore().currentMultitagBuffer?.map((v) => v.bestTransform.z) || []).toFixed(
|
||||
5
|
||||
)
|
||||
}} m
|
||||
</td>
|
||||
<td class="text-center white--text">
|
||||
{{
|
||||
calculateStdDev(
|
||||
useStateStore().currentMultitagBuffer?.map((v) => toDeg(v.bestTransform.angle_x)) || []
|
||||
).toFixed(5)
|
||||
}}°
|
||||
</td>
|
||||
<td class="text-center white--text">
|
||||
{{
|
||||
calculateStdDev(
|
||||
useStateStore().currentMultitagBuffer?.map((v) => toDeg(v.bestTransform.angle_y)) || []
|
||||
).toFixed(5)
|
||||
}}°
|
||||
</td>
|
||||
<td class="text-center white--text">
|
||||
{{
|
||||
calculateStdDev(
|
||||
useStateStore().currentMultitagBuffer?.map((v) => toDeg(v.bestTransform.angle_z)) || []
|
||||
).toFixed(5)
|
||||
}}°
|
||||
</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 {
|
||||
|
||||
Reference in New Issue
Block a user