option to remove time gaps when merging

This commit is contained in:
vcoppe
2024-10-01 13:17:39 +02:00
parent 5cca106d18
commit 11934e5825
4 changed files with 35 additions and 7 deletions

View File

@@ -890,7 +890,7 @@ export class TrackSegment extends GPXTreeLeaf {
} }
// Producers // Producers
replaceTrackPoints(start: number, end: number, points: TrackPoint[], speed?: number, startTime?: Date) { replaceTrackPoints(start: number, end: number, points: TrackPoint[], speed?: number, startTime?: Date, removeGaps?: boolean) {
let og = getOriginal(this); // Read as much as possible from the original object because it is faster let og = getOriginal(this); // Read as much as possible from the original object because it is faster
let trkpt = og.trkpt.slice(); let trkpt = og.trkpt.slice();
@@ -909,6 +909,21 @@ export class TrackSegment extends GPXTreeLeaf {
} else if (last !== undefined && points[0].time < last.time) { } else if (last !== undefined && points[0].time < last.time) {
// Adapt timestamps of the new points because they are too early // Adapt timestamps of the new points because they are too early
points = withShiftedAndCompressedTimestamps(points, speed, 1, last); points = withShiftedAndCompressedTimestamps(points, speed, 1, last);
} else if (last !== undefined && removeGaps) {
// Remove gaps between the new points and the previous point
if (last.getLatitude() === points[0].getLatitude() && last.getLongitude() === points[0].getLongitude()) {
// Same point, make the new points start at its timestamp and remove the first point
if (points[0].time > last.time) {
points = withShiftedAndCompressedTimestamps(points, speed, 1, last).slice(1);
}
} else {
// Different points, make the new points start one second after the previous point
if (points[0].time.getTime() - last.time.getTime() > 1000) {
let artificialLast = points[0].clone();
artificialLast.time = new Date(last.time.getTime() + 1000);
points = withShiftedAndCompressedTimestamps(points, speed, 1, artificialLast);
}
}
} }
} }
if (end < trkpt.length - 1) { if (end < trkpt.length - 1) {

View File

@@ -11,15 +11,18 @@
import { selection } from '$lib/components/file-list/Selection'; import { selection } from '$lib/components/file-list/Selection';
import { Button } from '$lib/components/ui/button'; import { Button } from '$lib/components/ui/button';
import { Label } from '$lib/components/ui/label/index.js'; import { Label } from '$lib/components/ui/label/index.js';
import { Checkbox } from '$lib/components/ui/checkbox';
import * as RadioGroup from '$lib/components/ui/radio-group'; import * as RadioGroup from '$lib/components/ui/radio-group';
import { _, locale } from 'svelte-i18n'; import { _, locale } from 'svelte-i18n';
import { dbUtils, getFile } from '$lib/db'; import { dbUtils, getFile } from '$lib/db';
import { Group } from 'lucide-svelte'; import { Group } from 'lucide-svelte';
import { getURLForLanguage } from '$lib/utils'; import { getURLForLanguage } from '$lib/utils';
import Shortcut from '$lib/components/Shortcut.svelte'; import Shortcut from '$lib/components/Shortcut.svelte';
import { gpxStatistics } from '$lib/stores';
let canMergeTraces = false; let canMergeTraces = false;
let canMergeContents = false; let canMergeContents = false;
let removeGaps = false;
$: if ($selection.size > 1) { $: if ($selection.size > 1) {
canMergeTraces = true; canMergeTraces = true;
@@ -56,22 +59,31 @@
<div class="flex flex-col gap-3 w-full max-w-80 {$$props.class ?? ''}"> <div class="flex flex-col gap-3 w-full max-w-80 {$$props.class ?? ''}">
<RadioGroup.Root bind:value={mergeType}> <RadioGroup.Root bind:value={mergeType}>
<Label class="flex flex-row items-center gap-2 leading-5"> <Label class="flex flex-row items-center gap-1.5 leading-5">
<RadioGroup.Item value={MergeType.TRACES} /> <RadioGroup.Item value={MergeType.TRACES} />
{$_('toolbar.merge.merge_traces')} {$_('toolbar.merge.merge_traces')}
</Label> </Label>
<Label class="flex flex-row items-center gap-2 leading-5"> <Label class="flex flex-row items-center gap-1.5 leading-5">
<RadioGroup.Item value={MergeType.CONTENTS} /> <RadioGroup.Item value={MergeType.CONTENTS} />
{$_('toolbar.merge.merge_contents')} {$_('toolbar.merge.merge_contents')}
</Label> </Label>
</RadioGroup.Root> </RadioGroup.Root>
{#if mergeType === MergeType.TRACES && $gpxStatistics.global.time.total > 0}
<div class="flex flex-row items-center gap-1.5">
<Checkbox id="remove-gaps" bind:checked={removeGaps} />
<Label for="remove-gaps">{$_('toolbar.merge.remove_gaps')}</Label>
</div>
{/if}
<Button <Button
variant="outline" variant="outline"
class="whitespace-normal h-fit" class="whitespace-normal h-fit"
disabled={(mergeType === MergeType.TRACES && !canMergeTraces) || disabled={(mergeType === MergeType.TRACES && !canMergeTraces) ||
(mergeType === MergeType.CONTENTS && !canMergeContents)} (mergeType === MergeType.CONTENTS && !canMergeContents)}
on:click={() => { on:click={() => {
dbUtils.mergeSelection(mergeType === MergeType.TRACES); dbUtils.mergeSelection(
mergeType === MergeType.TRACES,
mergeType === MergeType.TRACES && $gpxStatistics.global.time.total > 0 && removeGaps
);
}} }}
> >
<Group size="16" class="mr-1 shrink-0" /> <Group size="16" class="mr-1 shrink-0" />

View File

@@ -574,7 +574,7 @@ export const dbUtils = {
}); });
}); });
}, },
mergeSelection: (mergeTraces: boolean) => { mergeSelection: (mergeTraces: boolean, removeGaps: boolean) => {
applyGlobal((draft) => { applyGlobal((draft) => {
let first = true; let first = true;
let target: ListItem = new ListRootItem(); let target: ListItem = new ListRootItem();
@@ -649,7 +649,7 @@ export const dbUtils = {
let s = new TrackSegment(); let s = new TrackSegment();
toMerge.trk.map((track) => { toMerge.trk.map((track) => {
track.trkseg.forEach((segment) => { track.trkseg.forEach((segment) => {
s.replaceTrackPoints(s.trkpt.length, s.trkpt.length, segment.trkpt.slice(), speed, startTime); s.replaceTrackPoints(s.trkpt.length, s.trkpt.length, segment.trkpt.slice(), speed, startTime, removeGaps);
}); });
}); });
toMerge.trk = [toMerge.trk[0]]; toMerge.trk = [toMerge.trk[0]];
@@ -658,7 +658,7 @@ export const dbUtils = {
if (toMerge.trkseg.length > 0) { if (toMerge.trkseg.length > 0) {
let s = new TrackSegment(); let s = new TrackSegment();
toMerge.trkseg.forEach((segment) => { toMerge.trkseg.forEach((segment) => {
s.replaceTrackPoints(s.trkpt.length, s.trkpt.length, segment.trkpt.slice(), speed, startTime); s.replaceTrackPoints(s.trkpt.length, s.trkpt.length, segment.trkpt.slice(), speed, startTime, removeGaps);
}); });
toMerge.trkseg = [s]; toMerge.trkseg = [s];
} }

View File

@@ -173,6 +173,7 @@
"merge_traces": "Connect the traces", "merge_traces": "Connect the traces",
"merge_contents": "Merge the contents and keep the traces disconnected", "merge_contents": "Merge the contents and keep the traces disconnected",
"merge_selection": "Merge selection", "merge_selection": "Merge selection",
"remove_gaps": "Remove time gaps between traces",
"tooltip": "Merge items together", "tooltip": "Merge items together",
"help_merge_traces": "Connecting the selected traces will create a single continuous trace.", "help_merge_traces": "Connecting the selected traces will create a single continuous trace.",
"help_cannot_merge_traces": "Your selection must contain several traces to connect them.", "help_cannot_merge_traces": "Your selection must contain several traces to connect them.",