mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2025-09-03 17:12:31 +00:00
realistic timestamps option
This commit is contained in:
@@ -350,6 +350,15 @@ export class GPXFile extends GPXTreeNode<Track>{
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createArtificialTimestamps(startTime: Date, totalTime: number, trackIndex?: number, segmentIndex?: number) {
|
||||||
|
let lastPoint = undefined;
|
||||||
|
this.trk.forEach((track, index) => {
|
||||||
|
if (trackIndex === undefined || trackIndex === index) {
|
||||||
|
track.createArtificialTimestamps(startTime, totalTime, lastPoint, segmentIndex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
setStyle(style: LineStyleExtension) {
|
setStyle(style: LineStyleExtension) {
|
||||||
this.trk.forEach((track) => {
|
this.trk.forEach((track) => {
|
||||||
track.setStyle(style);
|
track.setStyle(style);
|
||||||
@@ -581,6 +590,17 @@ export class Track extends GPXTreeNode<TrackSegment> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createArtificialTimestamps(startTime: Date, totalTime: number, lastPoint: TrackPoint | undefined, segmentIndex?: number) {
|
||||||
|
this.trkseg.forEach((segment, index) => {
|
||||||
|
if (segmentIndex === undefined || segmentIndex === index) {
|
||||||
|
segment.createArtificialTimestamps(startTime, totalTime, lastPoint);
|
||||||
|
if (segment.trkpt.length > 0) {
|
||||||
|
lastPoint = segment.trkpt[segment.trkpt.length - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
setStyle(style: LineStyleExtension, force: boolean = true) {
|
setStyle(style: LineStyleExtension, force: boolean = true) {
|
||||||
if (!this.extensions) {
|
if (!this.extensions) {
|
||||||
this.extensions = {};
|
this.extensions = {};
|
||||||
@@ -944,6 +964,14 @@ export class TrackSegment extends GPXTreeLeaf {
|
|||||||
this.trkpt = freeze(trkpt); // Pre-freeze the array, faster as well
|
this.trkpt = freeze(trkpt); // Pre-freeze the array, faster as well
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createArtificialTimestamps(startTime: Date, totalTime: number, lastPoint: TrackPoint | undefined) {
|
||||||
|
let og = getOriginal(this); // Read as much as possible from the original object because it is faster
|
||||||
|
let slope = og._computeSlope();
|
||||||
|
let trkpt = withArtificialTimestamps(og.trkpt, totalTime, lastPoint, startTime, slope);
|
||||||
|
this.trkpt = freeze(trkpt); // Pre-freeze the array, faster as well
|
||||||
|
}
|
||||||
|
|
||||||
setHidden(hidden: boolean) {
|
setHidden(hidden: boolean) {
|
||||||
this._data.hidden = hidden;
|
this._data.hidden = hidden;
|
||||||
}
|
}
|
||||||
@@ -1442,6 +1470,30 @@ function withShiftedAndCompressedTimestamps(points: TrackPoint[], speed: number,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function withArtificialTimestamps(points: TrackPoint[], totalTime: number, lastPoint: TrackPoint | undefined, startTime: Date, slope: number[]): TrackPoint[] {
|
||||||
|
let weight = [];
|
||||||
|
let totalWeight = 0;
|
||||||
|
|
||||||
|
for (let i = 0; i < points.length - 1; i++) {
|
||||||
|
let dist = distance(points[i].getCoordinates(), points[i + 1].getCoordinates());
|
||||||
|
let w = dist * (0.5 + 1 / (1 + Math.exp(- 0.2 * slope[i])));
|
||||||
|
weight.push(w);
|
||||||
|
totalWeight += w;
|
||||||
|
}
|
||||||
|
|
||||||
|
let last = lastPoint;
|
||||||
|
return points.map((point, i) => {
|
||||||
|
let pt = point.clone();
|
||||||
|
if (i === 0) {
|
||||||
|
pt.time = lastPoint?.time ?? startTime;
|
||||||
|
} else {
|
||||||
|
pt.time = new Date(last.time.getTime() + totalTime * 1000 * weight[i - 1] / totalWeight);
|
||||||
|
}
|
||||||
|
last = pt;
|
||||||
|
return pt;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function getTimestamp(a: TrackPoint, b: TrackPoint, speed: number): Date {
|
function getTimestamp(a: TrackPoint, b: TrackPoint, speed: number): Date {
|
||||||
let dist = distance(a.getCoordinates(), b.getCoordinates()) / 1000;
|
let dist = distance(a.getCoordinates(), b.getCoordinates()) / 1000;
|
||||||
return new Date(a.time.getTime() + 1000 * 3600 * dist / speed);
|
return new Date(a.time.getTime() + 1000 * 3600 * dist / speed);
|
||||||
|
@@ -33,6 +33,7 @@
|
|||||||
let endTime: string | undefined = undefined;
|
let endTime: string | undefined = undefined;
|
||||||
let movingTime: number | undefined = undefined;
|
let movingTime: number | undefined = undefined;
|
||||||
let speed: number | undefined = undefined;
|
let speed: number | undefined = undefined;
|
||||||
|
let artificial = false;
|
||||||
|
|
||||||
function toCalendarDate(date: Date): CalendarDate {
|
function toCalendarDate(date: Date): CalendarDate {
|
||||||
return new CalendarDate(date.getFullYear(), date.getMonth() + 1, date.getDate());
|
return new CalendarDate(date.getFullYear(), date.getMonth() + 1, date.getDate());
|
||||||
@@ -281,8 +282,8 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{#if $gpxStatistics.global.time.moving === 0 || $gpxStatistics.global.time.moving === undefined}
|
{#if $gpxStatistics.global.time.moving === 0 || $gpxStatistics.global.time.moving === undefined}
|
||||||
<div class="mt-0.5 flex flex-row gap-1 items-center hidden">
|
<div class="mt-0.5 flex flex-row gap-1 items-center">
|
||||||
<Checkbox id="artificial-time" disabled={!canUpdate} />
|
<Checkbox id="artificial-time" bind:checked={artificial} disabled={!canUpdate} />
|
||||||
<Label for="artificial-time">
|
<Label for="artificial-time">
|
||||||
{$_('toolbar.time.artificial')}
|
{$_('toolbar.time.artificial')}
|
||||||
</Label>
|
</Label>
|
||||||
@@ -296,7 +297,11 @@
|
|||||||
class="grow"
|
class="grow"
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
let effectiveSpeed = getSpeed();
|
let effectiveSpeed = getSpeed();
|
||||||
if (startDate === undefined || startTime === undefined || effectiveSpeed === undefined) {
|
if (
|
||||||
|
startDate === undefined ||
|
||||||
|
startTime === undefined ||
|
||||||
|
effectiveSpeed === undefined
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,15 +321,42 @@
|
|||||||
let fileId = item.getFileId();
|
let fileId = item.getFileId();
|
||||||
dbUtils.applyToFile(fileId, (file) => {
|
dbUtils.applyToFile(fileId, (file) => {
|
||||||
if (item instanceof ListFileItem) {
|
if (item instanceof ListFileItem) {
|
||||||
file.changeTimestamps(getDate(startDate, startTime), effectiveSpeed, ratio);
|
if (artificial) {
|
||||||
|
file.createArtificialTimestamps(
|
||||||
|
getDate(startDate, startTime),
|
||||||
|
movingTime
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
file.changeTimestamps(
|
||||||
|
getDate(startDate, startTime),
|
||||||
|
effectiveSpeed,
|
||||||
|
ratio
|
||||||
|
);
|
||||||
|
}
|
||||||
} else if (item instanceof ListTrackItem) {
|
} else if (item instanceof ListTrackItem) {
|
||||||
|
if (artificial) {
|
||||||
|
file.createArtificialTimestamps(
|
||||||
|
getDate(startDate, startTime),
|
||||||
|
movingTime,
|
||||||
|
item.getTrackIndex()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
file.changeTimestamps(
|
file.changeTimestamps(
|
||||||
getDate(startDate, startTime),
|
getDate(startDate, startTime),
|
||||||
effectiveSpeed,
|
effectiveSpeed,
|
||||||
ratio,
|
ratio,
|
||||||
item.getTrackIndex()
|
item.getTrackIndex()
|
||||||
);
|
);
|
||||||
|
}
|
||||||
} else if (item instanceof ListTrackSegmentItem) {
|
} else if (item instanceof ListTrackSegmentItem) {
|
||||||
|
if (artificial) {
|
||||||
|
file.createArtificialTimestamps(
|
||||||
|
getDate(startDate, startTime),
|
||||||
|
movingTime,
|
||||||
|
item.getTrackIndex(),
|
||||||
|
item.getSegmentIndex()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
file.changeTimestamps(
|
file.changeTimestamps(
|
||||||
getDate(startDate, startTime),
|
getDate(startDate, startTime),
|
||||||
effectiveSpeed,
|
effectiveSpeed,
|
||||||
@@ -333,6 +365,7 @@
|
|||||||
item.getSegmentIndex()
|
item.getSegmentIndex()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
Reference in New Issue
Block a user