prettier config + format all, closes #175

This commit is contained in:
vcoppe
2025-02-02 11:17:22 +01:00
parent 01cfd448f0
commit 0b457f9a1e
157 changed files with 17194 additions and 29365 deletions

1
gpx/.prettierignore Normal file
View File

@@ -0,0 +1 @@
package-lock.json

1573
gpx/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -18,10 +18,14 @@
"devDependencies": {
"@types/geojson": "^7946.0.14",
"@types/node": "^20.16.10",
"@typescript-eslint/parser": "^8.22.0",
"prettier": "^3.4.2",
"typescript": "^5.6.2"
},
"scripts": {
"build": "tsc",
"postinstall": "npm run build"
"postinstall": "npm run build",
"lint": "prettier --check . && eslint .",
"format": "prettier --write ."
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -2,4 +2,3 @@ export * from './gpx';
export { Coordinates, LineStyleExtension, WaypointType } from './types';
export { parseGPX, buildGPX } from './io';
export * from './simplify';

View File

@@ -1,32 +1,40 @@
import { XMLParser, XMLBuilder } from "fast-xml-parser";
import { GPXFileType } from "./types";
import { GPXFile } from "./gpx";
import { XMLParser, XMLBuilder } from 'fast-xml-parser';
import { GPXFileType } from './types';
import { GPXFile } from './gpx';
const attributesWithNamespace = {
'RoutePointExtension': 'gpxx:RoutePointExtension',
'rpt': 'gpxx:rpt',
'TrackPointExtension': 'gpxtpx:TrackPointExtension',
'PowerExtension': 'gpxpx:PowerExtension',
'atemp': 'gpxtpx:atemp',
'hr': 'gpxtpx:hr',
'cad': 'gpxtpx:cad',
'Extensions': 'gpxtpx:Extensions',
'PowerInWatts': 'gpxpx:PowerInWatts',
'power': 'gpxpx:PowerExtension',
'line': 'gpx_style:line',
'color': 'gpx_style:color',
'opacity': 'gpx_style:opacity',
'width': 'gpx_style:width',
RoutePointExtension: 'gpxx:RoutePointExtension',
rpt: 'gpxx:rpt',
TrackPointExtension: 'gpxtpx:TrackPointExtension',
PowerExtension: 'gpxpx:PowerExtension',
atemp: 'gpxtpx:atemp',
hr: 'gpxtpx:hr',
cad: 'gpxtpx:cad',
Extensions: 'gpxtpx:Extensions',
PowerInWatts: 'gpxpx:PowerInWatts',
power: 'gpxpx:PowerExtension',
line: 'gpx_style:line',
color: 'gpx_style:color',
opacity: 'gpx_style:opacity',
width: 'gpx_style:width',
};
export function parseGPX(gpxData: string): GPXFile {
const parser = new XMLParser({
ignoreAttributes: false,
attributeNamePrefix: "",
attributeNamePrefix: '',
attributesGroupName: 'attributes',
removeNSPrefix: true,
isArray(name: string) {
return name === 'trk' || name === 'trkseg' || name === 'trkpt' || name === 'wpt' || name === 'rte' || name === 'rtept' || name === 'gpxx:rpt';
return (
name === 'trk' ||
name === 'trkseg' ||
name === 'trkpt' ||
name === 'wpt' ||
name === 'rte' ||
name === 'rtept' ||
name === 'gpxx:rpt'
);
},
attributeValueProcessor(attrName, attrValue, jPath) {
if (attrName === 'lat' || attrName === 'lon') {
@@ -51,8 +59,14 @@ export function parseGPX(gpxData: string): GPXFile {
return new Date(tagValue);
}
if (tagName === 'gpxtpx:atemp' || tagName === 'gpxtpx:hr' || tagName === 'gpxtpx:cad' || tagName === 'gpxpx:PowerInWatts' ||
tagName === 'gpx_style:opacity' || tagName === 'gpx_style:width') {
if (
tagName === 'gpxtpx:atemp' ||
tagName === 'gpxtpx:hr' ||
tagName === 'gpxtpx:cad' ||
tagName === 'gpxpx:PowerInWatts' ||
tagName === 'gpx_style:opacity' ||
tagName === 'gpx_style:width'
) {
return parseFloat(tagValue);
}
@@ -60,7 +74,7 @@ export function parseGPX(gpxData: string): GPXFile {
// Finish the transformation of the simple <power> tag to the more complex <gpxpx:PowerExtension> tag
// Note that this only targets the transformed <power> tag, since it must be a leaf node
return {
'gpxpx:PowerInWatts': parseFloat(tagValue)
'gpxpx:PowerInWatts': parseFloat(tagValue),
};
}
}
@@ -72,7 +86,7 @@ export function parseGPX(gpxData: string): GPXFile {
const parsed: GPXFileType = parser.parse(gpxData).gpx;
// @ts-ignore
if (parsed.metadata === "") {
if (parsed.metadata === '') {
parsed.metadata = {};
}
@@ -85,7 +99,7 @@ export function buildGPX(file: GPXFile, exclude: string[]): string {
const builder = new XMLBuilder({
format: true,
ignoreAttributes: false,
attributeNamePrefix: "",
attributeNamePrefix: '',
attributesGroupName: 'attributes',
suppressEmptyNode: true,
tagValueProcessor: (tagName: string, tagValue: unknown): string => {
@@ -96,13 +110,13 @@ export function buildGPX(file: GPXFile, exclude: string[]): string {
},
});
if (!gpx.attributes)
gpx.attributes = {};
if (!gpx.attributes) gpx.attributes = {};
gpx.attributes['creator'] = gpx.attributes['creator'] ?? 'https://gpx.studio';
gpx.attributes['version'] = '1.1';
gpx.attributes['xmlns'] = 'http://www.topografix.com/GPX/1/1';
gpx.attributes['xmlns:xsi'] = 'http://www.w3.org/2001/XMLSchema-instance';
gpx.attributes['xsi:schemaLocation'] = 'http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd http://www.garmin.com/xmlschemas/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd http://www.garmin.com/xmlschemas/PowerExtension/v1 http://www.garmin.com/xmlschemas/PowerExtensionv1.xsd http://www.topografix.com/GPX/gpx_style/0/2 http://www.topografix.com/GPX/gpx_style/0/2/gpx_style.xsd';
gpx.attributes['xsi:schemaLocation'] =
'http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd http://www.garmin.com/xmlschemas/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd http://www.garmin.com/xmlschemas/PowerExtension/v1 http://www.garmin.com/xmlschemas/PowerExtensionv1.xsd http://www.topografix.com/GPX/gpx_style/0/2 http://www.topografix.com/GPX/gpx_style/0/2/gpx_style.xsd';
gpx.attributes['xmlns:gpxtpx'] = 'http://www.garmin.com/xmlschemas/TrackPointExtension/v1';
gpx.attributes['xmlns:gpxx'] = 'http://www.garmin.com/xmlschemas/GpxExtensions/v3';
gpx.attributes['xmlns:gpxpx'] = 'http://www.garmin.com/xmlschemas/PowerExtension/v1';
@@ -113,19 +127,24 @@ export function buildGPX(file: GPXFile, exclude: string[]): string {
}
return builder.build({
"?xml": {
'?xml': {
attributes: {
version: "1.0",
encoding: "UTF-8",
}
version: '1.0',
encoding: 'UTF-8',
},
},
gpx: removeEmptyElements(gpx)
gpx: removeEmptyElements(gpx),
});
}
function removeEmptyElements(obj: GPXFileType): GPXFileType {
for (const key in obj) {
if (obj[key] === null || obj[key] === undefined || obj[key] === '' || (Array.isArray(obj[key]) && obj[key].length === 0)) {
if (
obj[key] === null ||
obj[key] === undefined ||
obj[key] === '' ||
(Array.isArray(obj[key]) && obj[key].length === 0)
) {
delete obj[key];
} else if (typeof obj[key] === 'object' && !(obj[key] instanceof Date)) {
removeEmptyElements(obj[key]);
@@ -135,4 +154,4 @@ function removeEmptyElements(obj: GPXFileType): GPXFileType {
}
}
return obj;
}
}

View File

@@ -1,33 +1,48 @@
import { TrackPoint } from "./gpx";
import { Coordinates } from "./types";
import { TrackPoint } from './gpx';
import { Coordinates } from './types';
export type SimplifiedTrackPoint = { point: TrackPoint, distance?: number };
export type SimplifiedTrackPoint = { point: TrackPoint; distance?: number };
const earthRadius = 6371008.8;
export function ramerDouglasPeucker(points: TrackPoint[], epsilon: number = 50, measure: (a: TrackPoint, b: TrackPoint, c: TrackPoint) => number = crossarcDistance): SimplifiedTrackPoint[] {
export function ramerDouglasPeucker(
points: TrackPoint[],
epsilon: number = 50,
measure: (a: TrackPoint, b: TrackPoint, c: TrackPoint) => number = crossarcDistance
): SimplifiedTrackPoint[] {
if (points.length == 0) {
return [];
} else if (points.length == 1) {
return [{
point: points[0]
}];
return [
{
point: points[0],
},
];
}
let simplified = [{
point: points[0]
}];
let simplified = [
{
point: points[0],
},
];
ramerDouglasPeuckerRecursive(points, epsilon, measure, 0, points.length - 1, simplified);
simplified.push({
point: points[points.length - 1]
point: points[points.length - 1],
});
return simplified;
}
function ramerDouglasPeuckerRecursive(points: TrackPoint[], epsilon: number, measure: (a: TrackPoint, b: TrackPoint, c: TrackPoint) => number, start: number, end: number, simplified: SimplifiedTrackPoint[]) {
function ramerDouglasPeuckerRecursive(
points: TrackPoint[],
epsilon: number,
measure: (a: TrackPoint, b: TrackPoint, c: TrackPoint) => number,
start: number,
end: number,
simplified: SimplifiedTrackPoint[]
) {
let largest = {
index: 0,
distance: 0
distance: 0,
};
for (let i = start + 1; i < end; i++) {
@@ -45,12 +60,20 @@ function ramerDouglasPeuckerRecursive(points: TrackPoint[], epsilon: number, mea
}
}
export function crossarcDistance(point1: TrackPoint, point2: TrackPoint, point3: TrackPoint | Coordinates): number {
return crossarc(point1.getCoordinates(), point2.getCoordinates(), point3 instanceof TrackPoint ? point3.getCoordinates() : point3);
export function crossarcDistance(
point1: TrackPoint,
point2: TrackPoint,
point3: TrackPoint | Coordinates
): number {
return crossarc(
point1.getCoordinates(),
point2.getCoordinates(),
point3 instanceof TrackPoint ? point3.getCoordinates() : point3
);
}
function crossarc(coord1: Coordinates, coord2: Coordinates, coord3: Coordinates): number {
// Calculates the shortest distance in meters
// Calculates the shortest distance in meters
// between an arc (defined by p1 and p2) and a third point, p3.
// Input lat1,lon1,lat2,lon2,lat3,lon3 in degrees.
@@ -74,7 +97,7 @@ function crossarc(coord1: Coordinates, coord2: Coordinates, coord3: Coordinates)
}
// Is relative bearing obtuse?
if (diff > (Math.PI / 2)) {
if (diff > Math.PI / 2) {
return dis13;
}
@@ -83,7 +106,8 @@ function crossarc(coord1: Coordinates, coord2: Coordinates, coord3: Coordinates)
// Is p4 beyond the arc?
let dis12 = distance(lat1, lon1, lat2, lon2);
let dis14 = Math.acos(Math.cos(dis13 / earthRadius) / Math.cos(dxt / earthRadius)) * earthRadius;
let dis14 =
Math.acos(Math.cos(dis13 / earthRadius) / Math.cos(dxt / earthRadius)) * earthRadius;
if (dis14 > dis12) {
return distance(lat2, lon2, lat3, lon3);
} else {
@@ -93,18 +117,32 @@ function crossarc(coord1: Coordinates, coord2: Coordinates, coord3: Coordinates)
function distance(latA: number, lonA: number, latB: number, lonB: number): number {
// Finds the distance between two lat / lon points.
return Math.acos(Math.sin(latA) * Math.sin(latB) + Math.cos(latA) * Math.cos(latB) * Math.cos(lonB - lonA)) * earthRadius;
return (
Math.acos(
Math.sin(latA) * Math.sin(latB) +
Math.cos(latA) * Math.cos(latB) * Math.cos(lonB - lonA)
) * earthRadius
);
}
function bearing(latA: number, lonA: number, latB: number, lonB: number): number {
// Finds the bearing from one lat / lon point to another.
return Math.atan2(Math.sin(lonB - lonA) * Math.cos(latB),
Math.cos(latA) * Math.sin(latB) - Math.sin(latA) * Math.cos(latB) * Math.cos(lonB - lonA));
return Math.atan2(
Math.sin(lonB - lonA) * Math.cos(latB),
Math.cos(latA) * Math.sin(latB) - Math.sin(latA) * Math.cos(latB) * Math.cos(lonB - lonA)
);
}
export function projectedPoint(point1: TrackPoint, point2: TrackPoint, point3: TrackPoint | Coordinates): Coordinates {
return projected(point1.getCoordinates(), point2.getCoordinates(), point3 instanceof TrackPoint ? point3.getCoordinates() : point3);
export function projectedPoint(
point1: TrackPoint,
point2: TrackPoint,
point3: TrackPoint | Coordinates
): Coordinates {
return projected(
point1.getCoordinates(),
point2.getCoordinates(),
point3 instanceof TrackPoint ? point3.getCoordinates() : point3
);
}
function projected(coord1: Coordinates, coord2: Coordinates, coord3: Coordinates): Coordinates {
@@ -132,7 +170,7 @@ function projected(coord1: Coordinates, coord2: Coordinates, coord3: Coordinates
}
// Is relative bearing obtuse?
if (diff > (Math.PI / 2)) {
if (diff > Math.PI / 2) {
return coord1;
}
@@ -141,15 +179,23 @@ function projected(coord1: Coordinates, coord2: Coordinates, coord3: Coordinates
// Is p4 beyond the arc?
let dis12 = distance(lat1, lon1, lat2, lon2);
let dis14 = Math.acos(Math.cos(dis13 / earthRadius) / Math.cos(dxt / earthRadius)) * earthRadius;
let dis14 =
Math.acos(Math.cos(dis13 / earthRadius) / Math.cos(dxt / earthRadius)) * earthRadius;
if (dis14 > dis12) {
return coord2;
} else {
// Determine the closest point (p4) on the great circle
const f = dis14 / earthRadius;
const lat4 = Math.asin(Math.sin(lat1) * Math.cos(f) + Math.cos(lat1) * Math.sin(f) * Math.cos(bear12));
const lon4 = lon1 + Math.atan2(Math.sin(bear12) * Math.sin(f) * Math.cos(lat1), Math.cos(f) - Math.sin(lat1) * Math.sin(lat4));
const lat4 = Math.asin(
Math.sin(lat1) * Math.cos(f) + Math.cos(lat1) * Math.sin(f) * Math.cos(bear12)
);
const lon4 =
lon1 +
Math.atan2(
Math.sin(bear12) * Math.sin(f) * Math.cos(lat1),
Math.cos(f) - Math.sin(lat1) * Math.sin(lat4)
);
return { lat: lat4 / rad, lon: lon4 / rad };
}
}
}

View File

@@ -93,11 +93,11 @@ export type TrackPointExtension = {
'gpxtpx:hr'?: number;
'gpxtpx:cad'?: number;
'gpxtpx:Extensions'?: Record<string, string>;
}
};
export type PowerExtension = {
'gpxpx:PowerInWatts'?: number;
}
};
export type Author = {
name?: string;
@@ -114,12 +114,12 @@ export type RouteType = {
type?: string;
extensions?: TrackExtensions;
rtept: WaypointType[];
}
};
export type RoutePointExtension = {
'gpxx:rpt'?: GPXXRoutePoint[];
}
};
export type GPXXRoutePoint = {
attributes: Coordinates;
}
};

View File

@@ -4,9 +4,7 @@
"target": "ES2015",
"declaration": true,
"outDir": "./dist",
"moduleResolution": "node",
"moduleResolution": "node"
},
"include": [
"src"
],
}
"include": ["src"]
}