Skip to content

Commit

Permalink
Mission-planning: Implement undo for last generated survey
Browse files Browse the repository at this point in the history
Signed-off-by: Arturo Manzoli <[email protected]>
  • Loading branch information
ArturoManzoli committed Jan 16, 2025
1 parent 41f5ceb commit db453fa
Show file tree
Hide file tree
Showing 2 changed files with 161 additions and 1 deletion.
25 changes: 25 additions & 0 deletions src/components/mission-planning/ContextMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,24 @@
</template>
</v-tooltip>
</div>
<div v-if="enableUndo" id="button-3" class="orbit-button orbit-button-3">
<v-tooltip text="Edit survey's polygon">
<template #activator="{ props: tooltipProps2 }">
<v-btn
v-bind="tooltipProps2"
variant="elevated"
icon="mdi-pencil"
:style="{ backgroundColor: '#333333EE' }"
rounded="full"
:disabled="undoIsInProgress"
size="x-small"
color="#FFFFFF22"
class="text-[13px] rotate-[220deg]"
@click="handleUndoGenerateWaypoints"
></v-btn>
</template>
</v-tooltip>
</div>
<v-tooltip text="Delete survey">
<template #activator="{ props: tooltipProps3 }">
<div
Expand Down Expand Up @@ -118,6 +136,8 @@ const props = defineProps<{
selectedSurveyId: string | null
isCreatingSurvey: boolean
isCreatingSimpleMission: boolean
undoIsInProgress: boolean
enableUndo: boolean
}>()
/* eslint-enable jsdoc/require-jsdoc */
Expand All @@ -126,6 +146,7 @@ const emit = defineEmits<{
(event: 'toggleSurvey'): void
(event: 'toggleSimpleMission'): void
(event: 'deleteSelectedSurvey'): void
(event: 'undoGeneratedWaypoints'): void
(event: 'surveyLinesAngle', angle: number): void
(event: 'regenerateSurveyWaypoints', angle: number): void
}>()
Expand Down Expand Up @@ -168,6 +189,10 @@ const handleToggleSimpleMission = (): void => {
emit('close')
}
const handleUndoGenerateWaypoints = (): void => {
emit('undoGeneratedWaypoints')
}
const handleDeleteSelectedSurvey = (): void => {
emit('deleteSelectedSurvey')
}
Expand Down
137 changes: 136 additions & 1 deletion src/views/MissionPlanningView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -303,10 +303,13 @@
:is-creating-simple-mission="isCreatingSimpleMission"
:surveys="surveys"
:selected-survey-id="selectedSurveyId"
:undo-is-in-progress="undoIsInProgress"
:enable-undo="enableUndoForCurrentSurvey"
@close="hideContextMenu"
@delete-selected-survey="deleteSelectedSurvey"
@toggle-survey="toggleSurvey"
@toggle-simple-mission="toggleSimpleMission"
@undo-generated-waypoints="undoGenerateWaypoints"
@regenerate-survey-waypoints="regenerateSurveyWaypoints"
@survey-lines-angle="onSurveyLinesAngleChange"
/>
Expand Down Expand Up @@ -402,11 +405,22 @@ const selectedSurveyId = ref<string>('')
const surveyPolygonLayers = ref<{ [key: string]: Polygon }>({})
const lastSelectedSurveyId = ref('')
const surveys = ref<Survey[]>([])
const canUndo = ref<Record<string, boolean>>({})
const undoIsInProgress = ref(false)
const lastSurveyState = ref<Record<string, SurveyPolygon>>({})
const isDragging = ref(false)
let dragStartLatLng: L.LatLng | null = null
let polygonLatLngsAtDragStart: L.LatLng[] = []
let ignoreNextClick = false
const enableUndoForCurrentSurvey = computed(() => {
return (
surveys.value.length > 0 &&
selectedSurveyId.value === surveys.value[surveys.value.length - 1].id &&
canUndo.value[selectedSurveyId.value]
)
})
const selectedSurvey = computed(() => {
return surveys.value.find((survey) => survey.id === selectedSurveyId.value)
})
Expand Down Expand Up @@ -547,6 +561,8 @@ const toggleSurvey = (): void => {
}
if (isCreatingSurvey.value) {
isCreatingSurvey.value = false
lastSurveyState.value = {}
canUndo.value = {}
return
}
isCreatingSurvey.value = true
Expand Down Expand Up @@ -650,11 +666,18 @@ const handleKeyDown = (event: KeyboardEvent): void => {
if (event.key === 'Delete' && selectedSurveyId.value) {
deleteSelectedSurvey()
}
if (event.ctrlKey && event.key.toLowerCase() === 'z' && enableUndoForCurrentSurvey.value && !undoIsInProgress.value) {
console.log('Undo In Progress')
undoGenerateWaypoints()
event.preventDefault()
}
}
const clearSurveyCreation = (): void => {
clearSurveyPath()
isCreatingSurvey.value = false
lastSurveyState.value = {}
canUndo.value = {}
}
const deleteSelectedSurvey = (): void => {
Expand Down Expand Up @@ -699,6 +722,12 @@ const deleteSelectedSurvey = (): void => {
if (selectedSurveyId.value === surveyId) {
selectedSurveyId.value = surveys.value.length > 0 ? surveys.value[0].id : ''
}
if (lastSurveyState.value[surveyId]) {
delete lastSurveyState.value[surveyId]
}
if (canUndo.value[surveyId]) {
delete canUndo.value[surveyId]
}
showSnackbar({ variant: 'success', message: 'Survey deleted.', duration: 2000 })
hideContextMenu()
Expand Down Expand Up @@ -1089,12 +1118,17 @@ const generateWaypointsFromSurvey = (): void => {
}
const newSurveyId = uuid()
canUndo.value[newSurveyId] = true
const polygonCoordinates: WaypointCoordinates[] = surveyPolygonVertexesPositions.value.map((latLng) => [
latLng.lat,
latLng.lng,
])
lastSurveyState.value[newSurveyId] = {
polygonPositions: polygonCoordinates,
}
const adjustedAngle = 90 - surveyLinesAngle.value
const continuousPath = generateSurveyPath(
surveyPolygonVertexesPositions.value,
Expand Down Expand Up @@ -1269,6 +1303,108 @@ const createSurveyVertexMarker = (
})
}
const undoGenerateWaypoints = (): void => {
if (undoIsInProgress.value) return
contextMenuVisible.value = false
undoIsInProgress.value = true
const surveyId = selectedSurveyId.value
if (!surveyId || !canUndo.value[surveyId] || !lastSurveyState.value[surveyId]) {
showSnackbar({ variant: 'error', message: 'Nothing to undo.', duration: 2000 })
undoIsInProgress.value = false
return
}
if (selectedSurvey.value) {
selectedSurvey.value.waypoints.forEach((waypoint) => {
const index = missionStore.currentPlanningWaypoints.findIndex((wp) => wp.id === waypoint.id)
if (index !== -1) {
missionStore.currentPlanningWaypoints.splice(index, 1)
}
const marker = waypointMarkers.value[waypoint.id]
if (marker) {
planningMap.value?.removeLayer(marker)
delete waypointMarkers.value[waypoint.id]
}
})
}
planningMap.value?.eachLayer((layer) => {
if (layer instanceof L.Polyline && layer.options.className === 'waypoint-connection') {
planningMap.value?.removeLayer(layer)
}
})
const index = surveys.value.findIndex((survey) => survey.id === surveyId)
if (index !== -1) {
surveys.value.splice(index, 1)
}
selectedSurveyId.value = ''
const surveyState = lastSurveyState.value[surveyId]
surveyPolygonVertexesPositions.value = surveyState.polygonPositions.map(([lat, lng]) => L.latLng(lat, lng))
surveyPolygonVertexesMarkers.value.forEach((marker) => marker.remove())
surveyPolygonVertexesMarkers.value = []
surveyEdgeAddMarkers.forEach((marker) => marker.remove())
surveyEdgeAddMarkers.length = 0
if (surveyPolygonLayer.value) {
planningMap.value?.removeLayer(surveyPolygonLayer.value as unknown as L.Layer)
surveyPolygonLayer.value = null
}
if (surveyPathLayer.value) {
planningMap.value?.removeLayer(surveyPathLayer.value as unknown as L.Layer)
surveyPathLayer.value = null
}
surveyPolygonVertexesPositions.value.forEach((latLng) => {
const newMarker = createSurveyVertexMarker(
latLng,
// onClick callback
(marker) => {
const targetIndex = surveyPolygonVertexesMarkers.value.indexOf(marker)
if (targetIndex !== -1) {
surveyPolygonVertexesPositions.value.splice(targetIndex, 1)
surveyPolygonVertexesMarkers.value.splice(targetIndex, 1)
marker.remove()
updatePolygon()
updateSurveyEdgeAddMarkers()
createSurveyPath()
}
},
// onDrag callback
() => {
updatePolygon()
createSurveyPath()
}
).addTo(planningMap.value!)
surveyPolygonVertexesMarkers.value.push(newMarker)
})
updateSurveyEdgeAddMarkers()
surveyPolygonLayer.value = L.polygon(surveyPolygonVertexesPositions.value, {
color: '#3B82F6',
fillColor: '#60A5FA',
fillOpacity: 0.2,
weight: 3,
className: 'survey-polygon',
}).addTo(planningMap.value!)
enablePolygonDragging()
delete lastSurveyState.value[surveyId]
delete canUndo.value[surveyId]
isCreatingSurvey.value = true
createSurveyPath()
showSnackbar({ variant: 'success', message: 'Undo successful.', duration: 1000 })
undoIsInProgress.value = false
}
const addWaypointMarker = (waypoint: Waypoint): void => {
if (!planningMap.value) return
Expand Down Expand Up @@ -1377,7 +1513,6 @@ onMounted(async () => {
})
await goHome()
await nextTick()
if (planningMap.value) {
planningMap.value.on('contextmenu', showContextMenu)
Expand Down

0 comments on commit db453fa

Please sign in to comment.