mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2025-08-31 23:53:25 +00:00
option to remove time gaps when merging
This commit is contained in:
@@ -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) {
|
||||||
|
@@ -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" />
|
||||||
|
@@ -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];
|
||||||
}
|
}
|
||||||
|
@@ -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.",
|
||||||
|
Reference in New Issue
Block a user