-
Notifications
You must be signed in to change notification settings - Fork 24
Pause/resume for lawnmower #1491
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
yannik131
wants to merge
35
commits into
master
Choose a base branch
from
547-pause-resume-for-lawnmower
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
35 commits
Select commit
Hold shift + click to select a range
8abe79b
Fixed lawnmower center section first bug
yannik131 319d081
Added playPause widget
yannik131 f2ddc1f
Wiring of lawnmower states
yannik131 e179513
play/pause for lawnmower works
yannik131 5f732cb
Renamed play/pause states
yannik131 3bae58f
More concise naming
yannik131 7e8a51d
Fixed some naming issues
yannik131 e2a6fdc
Fixed renaming issues
yannik131 f67e736
Unified annotation mode buttons
yannik131 c9425ba
Wait for next tick to resume lawnmower
yannik131 7808884
Prefer @ over relative paths
yannik131 cfd6e25
Fixed wrong lawnmower position after resume
yannik131 c45cec0
Function name reflects signal emitted
yannik131 d85ca64
Restore last lawnmower section, remove unused code
yannik131 755071f
Removed unused code
yannik131 5e3d249
Refactored volare into composable
yannik131 1f6e235
Moved more code to volare component
yannik131 f866ab5
Implemented load/save for volare
yannik131 b27e065
TODO for removing watchers maybe
yannik131 befcb4b
Fixing volare pause/resume bugs
yannik131 dfc92ad
Use ID instead of index for resuming volare
yannik131 4dba4c3
Fixed linter errors
yannik131 628b63f
Merge branch 'master' into 547-pause-resume-for-lawnmower
yannik131 64f02e5
trying to pause lawnmower with viewport change
yannik131 95969d6
Use only a single mode state for paused
yannik131 4c45aa8
lawnmower pause/resume
yannik131 bf5985e
Pause/resume for lawnmower is now working
yannik131 6a4dac9
Muted text for lawnmower, playPause works for lawnmower
yannik131 1a001dc
Volare pause stated muted text
yannik131 424ce7d
linter fixes, don't overwrite saved state
yannik131 a12106b
Undid auto formatting
yannik131 1d65214
kebab-case for vue signals
yannik131 a95884a
fixed volare mode check
yannik131 f4cad92
Removed todo comment
yannik131 3bba13c
fixed timestamp typo
yannik131 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -23,6 +23,8 @@ import {CrossOriginTiffError} from './stores/images.js'; | |||||
| import {debounce} from '@/core/utils.js'; | ||||||
| import {handleErrorResponse} from '@/core/messages/store.js'; | ||||||
| import {urlParams as UrlParams} from '@/core/utils.js'; | ||||||
| import {LawnmowerSaveState} from './components/annotationCanvas/lawnmower.vue'; | ||||||
| import {useVolareMode} from './components/annotationCanvas/volare.js'; | ||||||
|
|
||||||
| const asyncAnnotationCanvas = defineAsyncComponent({ | ||||||
| loader: function () { | ||||||
|
|
@@ -73,7 +75,6 @@ export default { | |||||
| mapResolution: undefined, | ||||||
| selectedLabel: null, | ||||||
| annotationMode: 'default', | ||||||
| focussedAnnotationIndex: null, | ||||||
| // For lawnmower and sampling modes: When switching images, this determines | ||||||
| // if the first (0) or the last (Infinity) image section/sampling location | ||||||
| // should be shown. | ||||||
|
|
@@ -89,13 +90,15 @@ export default { | |||||
| preferredUnit: 'auto', | ||||||
| imagesArea: null, | ||||||
| openTab: null, | ||||||
| userUpdatedVolareResolution: false, | ||||||
| userId: null, | ||||||
| crossOriginError: false, | ||||||
| maybeCorsTiffError: false, | ||||||
| imageFilenames: {}, | ||||||
| labelTrees: [], | ||||||
| projectIds: [], | ||||||
| lawnmowerSaveState: "", | ||||||
| volare: null, | ||||||
| pauseLawnmowerAutomatically: false, | ||||||
| }; | ||||||
| }, | ||||||
| provide() { | ||||||
|
|
@@ -131,14 +134,8 @@ export default { | |||||
| selectedAnnotations() { | ||||||
| return this.filteredAnnotations.filter((a) => a.selected); | ||||||
| }, | ||||||
| focussedAnnotation() { | ||||||
| return this.filteredAnnotations[this.focussedAnnotationIndex]; | ||||||
| }, | ||||||
| isDefaultAnnotationMode() { | ||||||
| return this.annotationMode === 'default'; | ||||||
| }, | ||||||
| isVolareAnnotationMode() { | ||||||
| return this.annotationMode === 'volare'; | ||||||
| return this.annotationMode === 'default' || this.annotationMode === 'volarePaused' || this.annotationMode === 'lawnmowerPaused'; | ||||||
| }, | ||||||
| isLawnmowerAnnotationMode() { | ||||||
| return this.annotationMode === 'lawnmower'; | ||||||
|
|
@@ -206,20 +203,8 @@ export default { | |||||
| return; | ||||||
| } | ||||||
|
|
||||||
| if (this.isVolareAnnotationMode) { | ||||||
| if (this.focussedAnnotationIndex < (this.filteredAnnotations.length - 1)) { | ||||||
| this.focussedAnnotationIndex++; | ||||||
| return; | ||||||
| } else if (this.focussedAnnotationIndex === Infinity) { | ||||||
| // This may happen if the volume has only one image and we can't | ||||||
| // switch to the next image. Here, we want to go to the second | ||||||
| // annotation of the image. | ||||||
| this.focussedAnnotationIndex = Math.min(1, this.filteredAnnotations.length - 1); | ||||||
| } else { | ||||||
| // Show the first annotation of the next image in this case, so | ||||||
| // don't return. | ||||||
| this.focussedAnnotationIndex = -Infinity; | ||||||
| } | ||||||
| if (this.volare.handleNextAnnotation()) { | ||||||
| return; | ||||||
| } else if (this.isLawnmowerAnnotationMode) { | ||||||
| // This returns false if the image section can't be advanced (i.e. | ||||||
| // the last section is shown). | ||||||
|
|
@@ -246,20 +231,8 @@ export default { | |||||
| return; | ||||||
| } | ||||||
|
|
||||||
| if (this.isVolareAnnotationMode) { | ||||||
| if (this.focussedAnnotationIndex > 0) { | ||||||
| this.focussedAnnotationIndex--; | ||||||
| return; | ||||||
| } else if (this.focussedAnnotationIndex === -Infinity) { | ||||||
| // This may happen if the volume has only one image and we can't | ||||||
| // switch to the next image. Here, we want to go to the second to | ||||||
| // last annotation of the image. | ||||||
| this.focussedAnnotationIndex = Math.max(this.filteredAnnotations.length - 2, 0); | ||||||
| } else { | ||||||
| // Show the last annotation of the previous image in this case, | ||||||
| // so don't return. | ||||||
| this.focussedAnnotationIndex = Infinity; | ||||||
| } | ||||||
| if (this.volare.handlePreviousAnnotation()) { | ||||||
| return; | ||||||
| } else if (this.isLawnmowerAnnotationMode) { | ||||||
| // This returns false if the image section can't be reversed (i.e. | ||||||
| // the first section is shown). | ||||||
|
|
@@ -282,26 +255,6 @@ export default { | |||||
| // Show previous image. | ||||||
| this.imageIndex = this.getPreviousIndex(this.imageIndex); | ||||||
| }, | ||||||
| maybeUpdateFocussedAnnotation() { | ||||||
| if (this.isVolareAnnotationMode) { | ||||||
| if (this.filteredAnnotations.length > 0) { | ||||||
| if (this.focussedAnnotationIndex === Infinity) { | ||||||
| // Show the last annotation if the previous image is shown. | ||||||
| this.focussedAnnotationIndex = this.filteredAnnotations.length - 1; | ||||||
| } else { | ||||||
| // Show the first annotation if the next image is shown or | ||||||
| // the annotation filter changed. | ||||||
| this.focussedAnnotationIndex = 0; | ||||||
| } | ||||||
| } else { | ||||||
| // Show the whole image if there are no annotations. | ||||||
| this.focussedAnnotationIndex = null; | ||||||
| this.$refs.canvas.fitImage(); | ||||||
| } | ||||||
| } else { | ||||||
| this.focussedAnnotationIndex = null; | ||||||
| } | ||||||
| }, | ||||||
| maybeUpdateShownImageSection() { | ||||||
| if (this.isLawnmowerAnnotationMode) { | ||||||
| if (this.annotationModeCarry === Infinity) { | ||||||
|
|
@@ -325,7 +278,6 @@ export default { | |||||
| } | ||||||
| }, | ||||||
| maybeUpdateAnnotationMode(data) { | ||||||
| this.maybeUpdateFocussedAnnotation(); | ||||||
| this.maybeUpdateShownImageSection(); | ||||||
| this.maybeUpdateShownSampling(data); | ||||||
| }, | ||||||
|
|
@@ -338,6 +290,9 @@ export default { | |||||
| y: Math.round(viewport.center[1]), | ||||||
| }); | ||||||
| }, | ||||||
| handleMapMovestart() { | ||||||
| this.pauseLawnmowerAfterViewportChanged(); | ||||||
| }, | ||||||
| // Handler for the select event fired by the global event bus. | ||||||
| handleSelectAnnotation(annotation, shift) { | ||||||
| // Handle the case where the second argument is an event object for | ||||||
|
|
@@ -370,9 +325,6 @@ export default { | |||||
| }); | ||||||
| } | ||||||
| }, | ||||||
| focusAnnotation(annotation, fast, keepResolution) { | ||||||
| this.$refs.canvas.focusAnnotation(annotation, fast, keepResolution); | ||||||
| }, | ||||||
| handleDetachAnnotationLabel(annotation, annotationLabel) { | ||||||
| if (this.isEditor) { | ||||||
| if (annotation.labels.length > 1) { | ||||||
|
|
@@ -411,13 +363,6 @@ export default { | |||||
| .catch(handleErrorResponse); | ||||||
| } | ||||||
| }, | ||||||
| selectAndFocusAnnotation(annotation, keepResolution) { | ||||||
| this.selectedAnnotations.forEach(function (a) { | ||||||
| a.selected = false; | ||||||
| }); | ||||||
| annotation.selected = true; | ||||||
| this.focusAnnotation(annotation, true, keepResolution); | ||||||
| }, | ||||||
| handleFilter(filter) { | ||||||
| this.annotationFilter = filter; | ||||||
| }, | ||||||
|
|
@@ -471,7 +416,7 @@ export default { | |||||
| confidence: 1, | ||||||
| }; | ||||||
|
|
||||||
| if (this.isVolareAnnotationMode) { | ||||||
| if (this.annotationMode === 'volare') { | ||||||
| this.$refs.canvas.blinkAnnotation(annotation); | ||||||
| } | ||||||
|
|
||||||
|
|
@@ -596,6 +541,31 @@ export default { | |||||
| break; | ||||||
| } | ||||||
| }, | ||||||
| enableAutomaticLawnmowerPausing() { | ||||||
| this.pauseLawnmowerAutomatically = true; | ||||||
| }, | ||||||
| disableAutomaticLawnmowerPausing() { | ||||||
| this.pauseLawnmowerAutomatically = false; | ||||||
| }, | ||||||
| pauseLawnmowerAfterViewportChanged() { | ||||||
| if (!this.isLawnmowerAnnotationMode || !this.pauseLawnmowerAutomatically) { | ||||||
| return; | ||||||
| } | ||||||
|
|
||||||
| this.$refs.annotationModesTab.pauseLawnmower(); | ||||||
| }, | ||||||
| pauseLawnmower(timestamp) { | ||||||
| this.$refs.annotationModesTab.pauseLawnmower(timestamp); | ||||||
| }, | ||||||
| pauseVolare(timestamp) { | ||||||
| this.$refs.annotationModesTab.pauseVolare(timestamp); | ||||||
| }, | ||||||
| showImageWithId(imageId) { | ||||||
| const index = this.imagesIds.indexOf(imageId); | ||||||
| if (index !== -1) { | ||||||
| this.imageIndex = index; | ||||||
| } | ||||||
| }, | ||||||
| handleAnnotationModeChange(mode, data) { | ||||||
| this.annotationMode = mode; | ||||||
| this.annotationModeCarry = null; | ||||||
|
|
@@ -663,6 +633,9 @@ export default { | |||||
| openSidebarLabels() { | ||||||
| this.openTab = 'labels'; | ||||||
| }, | ||||||
| focusAnnotation(annotation, fast, keepResolution) { | ||||||
| this.$refs.canvas.focusAnnotation(annotation, fast, keepResolution); | ||||||
| } | ||||||
| }, | ||||||
| watch: { | ||||||
| async imageId(id) { | ||||||
|
|
@@ -677,6 +650,11 @@ export default { | |||||
| let [image, annotations] = await Promise.all(this.getImageAndAnnotationsPromises(id)); | ||||||
| this.image = image; | ||||||
| this.annotations = annotations; | ||||||
|
|
||||||
| // Wait for the canvas to be updated, otherwise lawnmower mode | ||||||
| // may compute the current section using the old viewport | ||||||
| await this.$nextTick(); | ||||||
|
|
||||||
| this.maybeUpdateAnnotationMode(); | ||||||
| this.maybeShowTilingInProgressMessage(); | ||||||
| } catch (e) { | ||||||
|
|
@@ -702,14 +680,6 @@ export default { | |||||
| // Twice the count because the next and previous images are cached. | ||||||
| ImagesStore.setMaxCacheSize(count * 2); | ||||||
| }, | ||||||
| focussedAnnotation(annotation) { | ||||||
| if (annotation) { | ||||||
| this.selectAndFocusAnnotation(annotation, this.userUpdatedVolareResolution); | ||||||
| } | ||||||
| }, | ||||||
| annotationFilter() { | ||||||
| this.maybeUpdateFocussedAnnotation(); | ||||||
| }, | ||||||
| showScaleLine(show) { | ||||||
| if (show) { | ||||||
| this.fetchImagesArea(); | ||||||
|
|
@@ -720,16 +690,6 @@ export default { | |||||
| this.fetchImagesArea(); | ||||||
| } | ||||||
| }, | ||||||
| isVolareAnnotationMode(enabled) { | ||||||
| if (!enabled) { | ||||||
| this.userUpdatedVolareResolution = false; | ||||||
| } | ||||||
| }, | ||||||
| mapResolution() { | ||||||
| if (this.isVolareAnnotationMode) { | ||||||
| this.userUpdatedVolareResolution = true; | ||||||
| } | ||||||
| }, | ||||||
| image(image) { | ||||||
| this.crossOriginError = image?.crossOrigin; | ||||||
| }, | ||||||
|
|
@@ -738,6 +698,15 @@ export default { | |||||
| this.openTab = ''; | ||||||
| } | ||||||
| }, | ||||||
| annotationMode(newMode, oldMode) { | ||||||
| if (newMode === 'lawnmowerPaused') { | ||||||
| this.lawnmowerSaveState = LawnmowerSaveState.SAVE; | ||||||
| } else if (oldMode === 'lawnmowerPaused' && newMode === 'lawnmower') { | ||||||
| this.lawnmowerSaveState = LawnmowerSaveState.LOAD; | ||||||
| } else { | ||||||
| this.lawnmowerSaveState = LawnmowerSaveState.DISCARD; | ||||||
| } | ||||||
| } | ||||||
| }, | ||||||
| created() { | ||||||
| this.allImagesIds = biigle.$require('annotations.imagesIds'); | ||||||
|
|
@@ -789,7 +758,7 @@ export default { | |||||
| // Use $nextTick so the annotationCanvas component has time to | ||||||
| // render the image. | ||||||
| this.$nextTick( | ||||||
| () => this.selectAndFocusAnnotation(annotations[i]) | ||||||
| () => this.volare.selectAndFocusAnnotation(annotations[i]) | ||||||
| ); | ||||||
| return; | ||||||
| } | ||||||
|
|
@@ -813,6 +782,19 @@ export default { | |||||
| Keyboard.on('C', this.selectLastAnnotation, 0, this.listenerSet); | ||||||
|
|
||||||
| this.initLabelBot(); | ||||||
|
|
||||||
| this.volare = useVolareMode({ | ||||||
| filteredAnnotations: computed(() => this.filteredAnnotations), | ||||||
| selectedAnnotations: computed(() => this.selectedAnnotations), | ||||||
| focusAnnotationInCanvas: this.focusAnnotation, | ||||||
| fitImageInCanvas: (...args) => this.$refs.canvas.fitImage(...args), | ||||||
| annotationFilter: this.annotationFilter, | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is usually
Suggested change
|
||||||
| image: computed(() => this.image), | ||||||
| mapResolution: computed(() => this.mapResolution), | ||||||
| showImageWithId: this.showImageWithId, | ||||||
| annotationMode: computed(() => this.annotationMode), | ||||||
| restoreVolarePauseState: (timestamp) => this.$refs.annotationModesTab.pauseVolare(timestamp) | ||||||
| }); | ||||||
| }, | ||||||
| }; | ||||||
| </script> | ||||||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This name is now misleading. Since it's only used for the highlight, maybe negate it and call it "should HighlightAnnotationMode", then update the use in the template.