mirror of
				https://github.com/gpxstudio/gpx.studio.git
				synced 2025-11-04 05:21:09 +00:00 
			
		
		
		
	option to remove time gaps when merging
This commit is contained in:
		@@ -890,7 +890,7 @@ export class TrackSegment extends GPXTreeLeaf {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 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 trkpt = og.trkpt.slice();
 | 
			
		||||
 | 
			
		||||
@@ -909,6 +909,21 @@ export class TrackSegment extends GPXTreeLeaf {
 | 
			
		||||
                } else if (last !== undefined && points[0].time < last.time) {
 | 
			
		||||
                    // Adapt timestamps of the new points because they are too early
 | 
			
		||||
                    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) {
 | 
			
		||||
 
 | 
			
		||||
@@ -11,15 +11,18 @@
 | 
			
		||||
	import { selection } from '$lib/components/file-list/Selection';
 | 
			
		||||
	import { Button } from '$lib/components/ui/button';
 | 
			
		||||
	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 { _, locale } from 'svelte-i18n';
 | 
			
		||||
	import { dbUtils, getFile } from '$lib/db';
 | 
			
		||||
	import { Group } from 'lucide-svelte';
 | 
			
		||||
	import { getURLForLanguage } from '$lib/utils';
 | 
			
		||||
	import Shortcut from '$lib/components/Shortcut.svelte';
 | 
			
		||||
	import { gpxStatistics } from '$lib/stores';
 | 
			
		||||
 | 
			
		||||
	let canMergeTraces = false;
 | 
			
		||||
	let canMergeContents = false;
 | 
			
		||||
	let removeGaps = false;
 | 
			
		||||
 | 
			
		||||
	$: if ($selection.size > 1) {
 | 
			
		||||
		canMergeTraces = true;
 | 
			
		||||
@@ -56,22 +59,31 @@
 | 
			
		||||
 | 
			
		||||
<div class="flex flex-col gap-3 w-full max-w-80 {$$props.class ?? ''}">
 | 
			
		||||
	<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} />
 | 
			
		||||
			{$_('toolbar.merge.merge_traces')}
 | 
			
		||||
		</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} />
 | 
			
		||||
			{$_('toolbar.merge.merge_contents')}
 | 
			
		||||
		</Label>
 | 
			
		||||
	</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
 | 
			
		||||
		variant="outline"
 | 
			
		||||
		class="whitespace-normal h-fit"
 | 
			
		||||
		disabled={(mergeType === MergeType.TRACES && !canMergeTraces) ||
 | 
			
		||||
			(mergeType === MergeType.CONTENTS && !canMergeContents)}
 | 
			
		||||
		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" />
 | 
			
		||||
 
 | 
			
		||||
@@ -574,7 +574,7 @@ export const dbUtils = {
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    },
 | 
			
		||||
    mergeSelection: (mergeTraces: boolean) => {
 | 
			
		||||
    mergeSelection: (mergeTraces: boolean, removeGaps: boolean) => {
 | 
			
		||||
        applyGlobal((draft) => {
 | 
			
		||||
            let first = true;
 | 
			
		||||
            let target: ListItem = new ListRootItem();
 | 
			
		||||
@@ -649,7 +649,7 @@ export const dbUtils = {
 | 
			
		||||
                    let s = new TrackSegment();
 | 
			
		||||
                    toMerge.trk.map((track) => {
 | 
			
		||||
                        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]];
 | 
			
		||||
@@ -658,7 +658,7 @@ export const dbUtils = {
 | 
			
		||||
                if (toMerge.trkseg.length > 0) {
 | 
			
		||||
                    let s = new TrackSegment();
 | 
			
		||||
                    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];
 | 
			
		||||
                }
 | 
			
		||||
 
 | 
			
		||||
@@ -173,6 +173,7 @@
 | 
			
		||||
            "merge_traces": "Connect the traces",
 | 
			
		||||
            "merge_contents": "Merge the contents and keep the traces disconnected",
 | 
			
		||||
            "merge_selection": "Merge selection",
 | 
			
		||||
            "remove_gaps": "Remove time gaps between traces",
 | 
			
		||||
            "tooltip": "Merge items together",
 | 
			
		||||
            "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.",
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user