2024-06-25 19:41:37 +02:00
|
|
|
import { ramerDouglasPeucker, type GPXFile, type TrackSegment } from "gpx";
|
|
|
|
|
|
|
|
const earthRadius = 6371008.8;
|
2024-04-25 16:41:06 +02:00
|
|
|
|
|
|
|
export function getZoomLevelForDistance(latitude: number, distance?: number): number {
|
|
|
|
if (distance === undefined) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
const rad = Math.PI / 180;
|
|
|
|
const lat = latitude * rad;
|
|
|
|
|
2024-07-23 15:55:16 +02:00
|
|
|
return Math.min(22, Math.max(0, Math.log2((earthRadius * Math.cos(lat)) / distance)));
|
2024-04-25 16:41:06 +02:00
|
|
|
}
|
|
|
|
|
2024-05-23 12:57:24 +02:00
|
|
|
export function updateAnchorPoints(file: GPXFile) {
|
|
|
|
let segments = file.getSegments();
|
|
|
|
|
2024-05-24 16:37:26 +02:00
|
|
|
for (let segment of segments) {
|
2024-05-23 12:57:24 +02:00
|
|
|
if (!segment._data.anchors) { // New segment, compute anchor points for it
|
|
|
|
computeAnchorPoints(segment);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (segment.trkpt.length > 0) {
|
2024-07-04 02:17:50 +02:00
|
|
|
// Ensure first and last points are anchors and always visible
|
|
|
|
segment.trkpt[0]._data.anchor = true;
|
|
|
|
segment.trkpt[0]._data.zoom = 0;
|
|
|
|
segment.trkpt[segment.trkpt.length - 1]._data.anchor = true;
|
|
|
|
segment.trkpt[segment.trkpt.length - 1]._data.zoom = 0;
|
2024-05-23 12:57:24 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function computeAnchorPoints(segment: TrackSegment) {
|
2024-04-25 19:02:34 +02:00
|
|
|
let points = segment.trkpt;
|
2024-07-23 15:55:16 +02:00
|
|
|
let anchors = ramerDouglasPeucker(points, 1);
|
2024-04-30 15:19:50 +02:00
|
|
|
anchors.forEach((anchor) => {
|
|
|
|
let point = anchor.point;
|
|
|
|
point._data.anchor = true;
|
|
|
|
point._data.zoom = getZoomLevelForDistance(point.getLatitude(), anchor.distance);
|
2024-04-25 19:02:34 +02:00
|
|
|
});
|
2024-04-30 15:19:50 +02:00
|
|
|
segment._data.anchors = true;
|
2024-04-25 16:41:06 +02:00
|
|
|
}
|
|
|
|
|