mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2025-08-31 23:53:25 +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) {
|
||||
this.trk.forEach((track) => {
|
||||
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) {
|
||||
if (!this.extensions) {
|
||||
this.extensions = {};
|
||||
@@ -944,6 +964,14 @@ export class TrackSegment extends GPXTreeLeaf {
|
||||
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) {
|
||||
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 {
|
||||
let dist = distance(a.getCoordinates(), b.getCoordinates()) / 1000;
|
||||
return new Date(a.time.getTime() + 1000 * 3600 * dist / speed);
|
||||
|
@@ -33,6 +33,7 @@
|
||||
let endTime: string | undefined = undefined;
|
||||
let movingTime: number | undefined = undefined;
|
||||
let speed: number | undefined = undefined;
|
||||
let artificial = false;
|
||||
|
||||
function toCalendarDate(date: Date): CalendarDate {
|
||||
return new CalendarDate(date.getFullYear(), date.getMonth() + 1, date.getDate());
|
||||
@@ -281,8 +282,8 @@
|
||||
/>
|
||||
</div>
|
||||
{#if $gpxStatistics.global.time.moving === 0 || $gpxStatistics.global.time.moving === undefined}
|
||||
<div class="mt-0.5 flex flex-row gap-1 items-center hidden">
|
||||
<Checkbox id="artificial-time" disabled={!canUpdate} />
|
||||
<div class="mt-0.5 flex flex-row gap-1 items-center">
|
||||
<Checkbox id="artificial-time" bind:checked={artificial} disabled={!canUpdate} />
|
||||
<Label for="artificial-time">
|
||||
{$_('toolbar.time.artificial')}
|
||||
</Label>
|
||||
@@ -296,7 +297,11 @@
|
||||
class="grow"
|
||||
on:click={() => {
|
||||
let effectiveSpeed = getSpeed();
|
||||
if (startDate === undefined || startTime === undefined || effectiveSpeed === undefined) {
|
||||
if (
|
||||
startDate === undefined ||
|
||||
startTime === undefined ||
|
||||
effectiveSpeed === undefined
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -316,15 +321,42 @@
|
||||
let fileId = item.getFileId();
|
||||
dbUtils.applyToFile(fileId, (file) => {
|
||||
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) {
|
||||
if (artificial) {
|
||||
file.createArtificialTimestamps(
|
||||
getDate(startDate, startTime),
|
||||
movingTime,
|
||||
item.getTrackIndex()
|
||||
);
|
||||
} else {
|
||||
file.changeTimestamps(
|
||||
getDate(startDate, startTime),
|
||||
effectiveSpeed,
|
||||
ratio,
|
||||
item.getTrackIndex()
|
||||
);
|
||||
}
|
||||
} else if (item instanceof ListTrackSegmentItem) {
|
||||
if (artificial) {
|
||||
file.createArtificialTimestamps(
|
||||
getDate(startDate, startTime),
|
||||
movingTime,
|
||||
item.getTrackIndex(),
|
||||
item.getSegmentIndex()
|
||||
);
|
||||
} else {
|
||||
file.changeTimestamps(
|
||||
getDate(startDate, startTime),
|
||||
effectiveSpeed,
|
||||
@@ -333,6 +365,7 @@
|
||||
item.getSegmentIndex()
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}}
|
||||
>
|
||||
|
Reference in New Issue
Block a user