2025-10-18 00:31:14 +02:00
|
|
|
import { ListItem, ListLevel } from '$lib/components/file-list/file-list';
|
2026-01-11 19:48:48 +01:00
|
|
|
import { GPXFile, GPXStatistics, GPXStatisticsGroup, type Track } from 'gpx';
|
2026-02-01 15:57:18 +01:00
|
|
|
import maplibregl from 'maplibre-gl';
|
2025-10-18 00:31:14 +02:00
|
|
|
|
|
|
|
|
export class GPXStatisticsTree {
|
|
|
|
|
level: ListLevel;
|
|
|
|
|
statistics: {
|
|
|
|
|
[key: string]: GPXStatisticsTree | GPXStatistics;
|
|
|
|
|
} = {};
|
2026-02-01 15:57:18 +01:00
|
|
|
wptBounds: maplibregl.LngLatBounds;
|
2025-10-18 00:31:14 +02:00
|
|
|
|
|
|
|
|
constructor(element: GPXFile | Track) {
|
2026-02-01 15:57:18 +01:00
|
|
|
this.wptBounds = new maplibregl.LngLatBounds();
|
2025-10-18 00:31:14 +02:00
|
|
|
if (element instanceof GPXFile) {
|
|
|
|
|
this.level = ListLevel.FILE;
|
|
|
|
|
element.children.forEach((child, index) => {
|
|
|
|
|
this.statistics[index] = new GPXStatisticsTree(child);
|
|
|
|
|
});
|
2026-02-01 15:57:18 +01:00
|
|
|
element.wpt.forEach((wpt) => {
|
|
|
|
|
this.wptBounds.extend(wpt.getCoordinates());
|
|
|
|
|
});
|
2025-10-18 00:31:14 +02:00
|
|
|
} else {
|
|
|
|
|
this.level = ListLevel.TRACK;
|
|
|
|
|
element.children.forEach((child, index) => {
|
|
|
|
|
this.statistics[index] = child.getStatistics();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-11 19:48:48 +01:00
|
|
|
getStatisticsFor(item: ListItem): GPXStatisticsGroup {
|
|
|
|
|
let statistics = new GPXStatisticsGroup();
|
2025-10-18 00:31:14 +02:00
|
|
|
let id = item.getIdAtLevel(this.level);
|
|
|
|
|
if (id === undefined || id === 'waypoints') {
|
|
|
|
|
Object.keys(this.statistics).forEach((key) => {
|
|
|
|
|
if (this.statistics[key] instanceof GPXStatistics) {
|
2026-01-11 19:48:48 +01:00
|
|
|
statistics.add(this.statistics[key]);
|
2025-10-18 00:31:14 +02:00
|
|
|
} else {
|
2026-01-11 19:48:48 +01:00
|
|
|
statistics.add(this.statistics[key].getStatisticsFor(item));
|
2025-10-18 00:31:14 +02:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
let child = this.statistics[id];
|
|
|
|
|
if (child instanceof GPXStatistics) {
|
2026-01-11 19:48:48 +01:00
|
|
|
statistics.add(child);
|
2025-10-18 00:31:14 +02:00
|
|
|
} else if (child !== undefined) {
|
2026-01-11 19:48:48 +01:00
|
|
|
statistics.add(child.getStatisticsFor(item));
|
2025-10-18 00:31:14 +02:00
|
|
|
}
|
|
|
|
|
}
|
2026-01-11 19:48:48 +01:00
|
|
|
return statistics;
|
2025-10-18 00:31:14 +02:00
|
|
|
}
|
2026-02-01 15:57:18 +01:00
|
|
|
|
2026-02-02 21:50:01 +01:00
|
|
|
intersectsBBox(bounds: maplibregl.LngLatBounds): boolean {
|
2026-02-01 15:57:18 +01:00
|
|
|
for (let key in this.statistics) {
|
|
|
|
|
const stats = this.statistics[key];
|
|
|
|
|
if (stats instanceof GPXStatistics) {
|
|
|
|
|
const bbox = new maplibregl.LngLatBounds(
|
|
|
|
|
stats.global.bounds.southWest,
|
|
|
|
|
stats.global.bounds.northEast
|
|
|
|
|
);
|
2026-02-02 21:50:01 +01:00
|
|
|
if (!bbox.isEmpty() && bbox.intersects(bounds)) {
|
2026-02-01 15:57:18 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
2026-02-02 21:50:01 +01:00
|
|
|
} else if (stats.intersectsBBox(bounds)) {
|
2026-02-01 15:57:18 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-02 21:50:01 +01:00
|
|
|
intersectsWaypointBBox(bounds: maplibregl.LngLatBounds): boolean {
|
|
|
|
|
return !this.wptBounds.isEmpty() && this.wptBounds.intersects(bounds);
|
2026-02-01 15:57:18 +01:00
|
|
|
}
|
2025-10-18 00:31:14 +02:00
|
|
|
}
|
|
|
|
|
export type GPXFileWithStatistics = { file: GPXFile; statistics: GPXStatisticsTree };
|