gpx-interpolator 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,279 @@
1
+ # GPX Interpolate - TypeScript
2
+
3
+ TypeScript/Node.js implementation of GPX interpolation using piecewise cubic Hermite splines.
4
+
5
+ [中文文档](./README-zh.md) | [快速开始](./QUICKSTART-zh.md)
6
+
7
+ ## Features
8
+
9
+ - 📍 Insert intermediate points between GPX track points
10
+ - 🎯 Smooth interpolation using PCHIP (Piecewise Cubic Hermite Interpolating Polynomial)
11
+ - 📏 Distance-based interpolation resolution (specify meters between points)
12
+ - ⏱️ Preserve and interpolate timestamp information
13
+ - 📈 Optional speed calculation and saving
14
+ - 🔄 Automatically remove duplicate track points
15
+ - 🚫 Gap detection for GPS signal loss
16
+ - 📊 Track statistics (distance, duration, elevation gain, etc.)
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ npm install gpx-interpolator
22
+ ```
23
+
24
+ Or for development:
25
+
26
+ ```bash
27
+ git clone <repo>
28
+ cd gpx-interpolator
29
+ npm install
30
+ npm run build
31
+ ```
32
+
33
+ ## CLI Usage
34
+
35
+ ```bash
36
+ # Basic usage (default 1 meter resolution)
37
+ gpx-interpolator your-track.gpx
38
+
39
+ # Specify resolution in meters
40
+ gpx-interpolator -r 5 your-track.gpx
41
+
42
+ # Specify output point count
43
+ gpx-interpolator -n 1000 your-track.gpx
44
+
45
+ # Only interpolate segments > 100 meters
46
+ gpx-interpolator -r 5 -m 100 your-track.gpx
47
+
48
+ # Split track at GPS gaps > 500 meters
49
+ gpx-interpolator -r 5 -g 500 your-track.gpx
50
+
51
+ # Custom output file
52
+ gpx-interpolator -r 5 -o output.gpx your-track.gpx
53
+
54
+ # Verbose mode with statistics
55
+ gpx-interpolator -v your-track.gpx
56
+
57
+ # Show statistics only (no interpolation)
58
+ gpx-interpolator --stats-only your-track.gpx
59
+
60
+ # Dry run (preview without saving)
61
+ gpx-interpolator --dry-run -r 5 your-track.gpx
62
+
63
+ # Save speed information
64
+ gpx-interpolator -s your-track.gpx
65
+
66
+ # Process multiple files
67
+ gpx-interpolator *.gpx
68
+ ```
69
+
70
+ ### CLI Options
71
+
72
+ | Option | Description |
73
+ | ----------------------------- | ------------------------------------------------------ |
74
+ | `-r, --resolution <meters>` | Interpolation resolution in meters (default: 1.0) |
75
+ | `-n, --num <count>` | Force exact point count in output |
76
+ | `-m, --min-distance <meters>` | Only interpolate segments longer than this |
77
+ | `-g, --max-gap <meters>` | Split track at gaps larger than this (GPS signal loss) |
78
+ | `-o, --output <file>` | Output file name (single file only) |
79
+ | `-s, --speed` | Save interpolated speed in output |
80
+ | `-v, --verbose` | Verbose output with statistics |
81
+ | `--dry-run` | Preview what would be done without writing files |
82
+ | `--stats-only` | Only show track statistics, don't interpolate |
83
+
84
+ ## Module Usage
85
+
86
+ ```typescript
87
+ import {
88
+ gpxRead,
89
+ gpxWrite,
90
+ gpxInterpolate,
91
+ interpolateTrack,
92
+ gpxCalculateStatistics,
93
+ gpxDataToPoints,
94
+ pointsToGpxData,
95
+ } from "gpx-interpolator";
96
+
97
+ // Read GPX file
98
+ const gpxData = gpxRead("input.gpx");
99
+
100
+ // Basic interpolation (1 meter resolution)
101
+ const interpolated = gpxInterpolate(gpxData, 1.0);
102
+
103
+ // Advanced interpolation with options
104
+ const result = interpolateTrack(gpxData, {
105
+ resolution: 5, // 5 meters between points
106
+ minDistance: 100, // Only interpolate segments > 100m
107
+ maxGap: 500, // Split at gaps > 500m
108
+ onProgress: (percent) => console.log(`${percent}%`),
109
+ });
110
+
111
+ // Get statistics
112
+ const stats = gpxCalculateStatistics(gpxData);
113
+ console.log(`Distance: ${stats.totalDistance}m`);
114
+ console.log(`Duration: ${stats.totalDuration}s`);
115
+ console.log(`Elevation gain: ${stats.elevationGain}m`);
116
+
117
+ // Convert between formats
118
+ const points = gpxDataToPoints(gpxData); // GPXData -> GPXPoint[]
119
+ const data = pointsToGpxData(points); // GPXPoint[] -> GPXData
120
+
121
+ // Save result
122
+ gpxWrite("output.gpx", result);
123
+ ```
124
+
125
+ ## API Reference
126
+
127
+ ### Core Functions
128
+
129
+ #### `gpxInterpolate(gpxData, options)`
130
+
131
+ Interpolate GPX data using piecewise cubic Hermite splines.
132
+
133
+ ```typescript
134
+ // Simple usage (backward compatible)
135
+ gpxInterpolate(gpxData, 1.0); // 1 meter resolution
136
+ gpxInterpolate(gpxData, 5.0, 1000); // 5m resolution, force 1000 points
137
+
138
+ // With options object
139
+ gpxInterpolate(gpxData, {
140
+ resolution: 5, // meters between points (default: 1.0)
141
+ numPoints: null, // force exact point count (overrides resolution)
142
+ minDistance: 0, // only interpolate segments > this (default: 0)
143
+ maxGap: Infinity, // split at gaps > this (default: Infinity)
144
+ preserveOriginal: false, // keep original points (default: false)
145
+ onProgress: (p) => {}, // progress callback (0-100)
146
+ });
147
+ ```
148
+
149
+ #### `interpolateTrack(gpxData, options)`
150
+
151
+ Alias for `gpxInterpolate` with options object. Recommended for new code.
152
+
153
+ ### I/O Functions
154
+
155
+ #### `gpxRead(filename)`
156
+
157
+ Read GPX data from file.
158
+
159
+ #### `gpxWrite(filename, gpxData, writeSpeed?)`
160
+
161
+ Write GPX data to file.
162
+
163
+ ### Utility Functions
164
+
165
+ #### `gpxCalculateStatistics(gpxData, maxGap?)`
166
+
167
+ Calculate track statistics:
168
+
169
+ - `totalDistance` - Total distance in meters
170
+ - `totalDuration` - Duration in seconds (null if no timestamps)
171
+ - `pointCount` - Number of track points
172
+ - `avgSpeed` / `maxSpeed` - Speed in m/s
173
+ - `elevationGain` / `elevationLoss` - Elevation changes
174
+ - `minElevation` / `maxElevation` - Elevation range
175
+ - `bounds` - Bounding box (minLat, maxLat, minLon, maxLon)
176
+ - `segmentCount` - Number of segments (based on maxGap)
177
+
178
+ #### `gpxDataToPoints(gpxData)`
179
+
180
+ Convert internal GPXData format to user-friendly GPXPoint[] array.
181
+
182
+ #### `pointsToGpxData(points, tzinfo?)`
183
+
184
+ Convert GPXPoint[] array to internal GPXData format.
185
+
186
+ #### `gpxCalculateDistance(gpxData, useEle?)`
187
+
188
+ Calculate distance between consecutive points (Haversine formula).
189
+
190
+ #### `gpxCalculateSpeed(gpxData)`
191
+
192
+ Calculate speed between consecutive points.
193
+
194
+ #### `detectSegments(gpxData, maxGap)`
195
+
196
+ Detect track segments separated by gaps larger than maxGap.
197
+
198
+ #### `haversineDistance(lat1, lon1, lat2, lon2)`
199
+
200
+ Calculate distance between two coordinates in meters.
201
+
202
+ #### `formatDistance(meters)` / `formatDuration(seconds)`
203
+
204
+ Format values for display.
205
+
206
+ ### Types
207
+
208
+ ```typescript
209
+ interface GPXData {
210
+ lat: number[]; // Latitude array
211
+ lon: number[]; // Longitude array
212
+ ele: number[] | null; // Elevation array (meters)
213
+ tstamp: number[] | null; // Unix timestamps (seconds)
214
+ tzinfo: string | null; // Timezone info
215
+ }
216
+
217
+ interface GPXPoint {
218
+ lat: number;
219
+ lon: number;
220
+ ele?: number;
221
+ time?: Date;
222
+ speed?: number;
223
+ }
224
+
225
+ interface InterpolateOptions {
226
+ resolution?: number; // meters between points
227
+ numPoints?: number | null;
228
+ minDistance?: number;
229
+ maxGap?: number;
230
+ preserveOriginal?: boolean;
231
+ onProgress?: (percent: number) => void;
232
+ }
233
+
234
+ interface TrackStatistics {
235
+ totalDistance: number;
236
+ totalDuration: number | null;
237
+ pointCount: number;
238
+ avgSpeed: number | null;
239
+ maxSpeed: number | null;
240
+ elevationGain: number | null;
241
+ elevationLoss: number | null;
242
+ minElevation: number | null;
243
+ maxElevation: number | null;
244
+ bounds: { minLat; maxLat; minLon; maxLon };
245
+ segmentCount: number;
246
+ }
247
+ ```
248
+
249
+ ## How It Works
250
+
251
+ 1. **Read**: Parse GPX file and extract lat, lon, elevation, and timestamps
252
+ 2. **Clean**: Remove duplicate track points
253
+ 3. **Distance**: Calculate distances using Haversine formula (Earth curvature)
254
+ 4. **Segment**: Detect gaps (GPS signal loss) and split track if needed
255
+ 5. **Interpolate**: Use PCHIP algorithm to smoothly interpolate each dimension
256
+ 6. **Generate**: Create new points based on resolution or point count
257
+ 7. **Output**: Save to new GPX file or return data structure
258
+
259
+ ## Project Structure
260
+
261
+ ```
262
+ gpx-interpolator/
263
+ ├── src/
264
+ │ ├── types.ts # TypeScript type definitions
265
+ │ ├── pchip.ts # PCHIP interpolation algorithm
266
+ │ ├── gpx-utils.ts # GPX utility functions
267
+ │ ├── gpx-io.ts # File I/O
268
+ │ ├── interpolate.ts # Main interpolation function
269
+ │ ├── index.ts # Module exports
270
+ │ └── cli.ts # CLI tool
271
+ ├── dist/ # Compiled JavaScript
272
+ ├── package.json
273
+ ├── tsconfig.json
274
+ └── README.md
275
+ ```
276
+
277
+ ## License
278
+
279
+ MIT
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,175 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ const commander_1 = require("commander");
38
+ const path = __importStar(require("path"));
39
+ const gpx_io_1 = require("./gpx-io");
40
+ const interpolate_1 = require("./interpolate");
41
+ const gpx_utils_1 = require("./gpx-utils");
42
+ const program = new commander_1.Command();
43
+ program
44
+ .name("gpx-interpolate")
45
+ .description("Interpolate GPX files using piecewise cubic Hermite splines")
46
+ .version("1.1.0")
47
+ .argument("<files...>", "GPX file(s) to interpolate")
48
+ .option("-r, --resolution <meters>", "interpolation resolution in meters (default: 1.0)", "1.0")
49
+ .option("-n, --num <count>", "force point count in output (overrides resolution)")
50
+ .option("-m, --min-distance <meters>", "only interpolate segments longer than this (default: 0)")
51
+ .option("-g, --max-gap <meters>", "split track at gaps larger than this (GPS signal loss)")
52
+ .option("-o, --output <file>", "output file name (only for single file input)")
53
+ .option("-s, --speed", "save interpolated speed", false)
54
+ .option("-v, --verbose", "verbose output with statistics", false)
55
+ .option("--dry-run", "show what would be done without writing files", false)
56
+ .option("--stats-only", "only show track statistics, do not interpolate", false)
57
+ .action((files, options) => {
58
+ const resolution = parseFloat(options.resolution);
59
+ const numPoints = options.num ? parseInt(options.num) : null;
60
+ const minDistance = options.minDistance
61
+ ? parseFloat(options.minDistance)
62
+ : 0;
63
+ const maxGap = options.maxGap ? parseFloat(options.maxGap) : Infinity;
64
+ const writeSpeed = options.speed;
65
+ const verbose = options.verbose;
66
+ const dryRun = options.dryRun;
67
+ const statsOnly = options.statsOnly;
68
+ const outputFile = options.output;
69
+ // Validate output option
70
+ if (outputFile && files.length > 1) {
71
+ console.error("Error: --output option can only be used with a single input file");
72
+ process.exit(1);
73
+ }
74
+ let totalInputPoints = 0;
75
+ let totalOutputPoints = 0;
76
+ for (const gpxFile of files) {
77
+ // Skip already interpolated files
78
+ if (gpxFile.endsWith("_interpolated.gpx")) {
79
+ if (verbose) {
80
+ console.log(`Skipping already interpolated file: ${gpxFile}`);
81
+ }
82
+ continue;
83
+ }
84
+ try {
85
+ console.log(`\n📍 Processing ${gpxFile}...`);
86
+ console.log("─".repeat(50));
87
+ // Read GPX file
88
+ const gpxData = (0, gpx_io_1.gpxRead)(gpxFile);
89
+ totalInputPoints += gpxData.lat.length;
90
+ if (verbose || statsOnly) {
91
+ console.log(`\n📊 Track Statistics:`);
92
+ const stats = (0, gpx_utils_1.gpxCalculateStatistics)(gpxData, maxGap);
93
+ console.log(` Points: ${stats.pointCount}`);
94
+ console.log(` Distance: ${(0, gpx_utils_1.formatDistance)(stats.totalDistance)}`);
95
+ if (stats.totalDuration !== null) {
96
+ console.log(` Duration: ${(0, gpx_utils_1.formatDuration)(stats.totalDuration)}`);
97
+ console.log(` Avg Speed: ${(stats.avgSpeed * 3.6).toFixed(1)} km/h`);
98
+ console.log(` Max Speed: ${(stats.maxSpeed * 3.6).toFixed(1)} km/h`);
99
+ }
100
+ if (stats.elevationGain !== null) {
101
+ console.log(` Elevation Gain: ${stats.elevationGain.toFixed(0)} m`);
102
+ console.log(` Elevation Loss: ${stats.elevationLoss.toFixed(0)} m`);
103
+ console.log(` Min/Max Elevation: ${stats.minElevation.toFixed(0)}m / ${stats.maxElevation.toFixed(0)}m`);
104
+ }
105
+ if (maxGap !== Infinity) {
106
+ console.log(` Segments (gap > ${(0, gpx_utils_1.formatDistance)(maxGap)}): ${stats.segmentCount}`);
107
+ }
108
+ console.log(` Bounds: [${stats.bounds.minLat.toFixed(4)}, ${stats.bounds.minLon.toFixed(4)}] to [${stats.bounds.maxLat.toFixed(4)}, ${stats.bounds.maxLon.toFixed(4)}]`);
109
+ }
110
+ if (statsOnly) {
111
+ continue;
112
+ }
113
+ // Remove duplicates
114
+ const gpxDataNodup = (0, gpx_utils_1.gpxRemoveDuplicates)(gpxData);
115
+ const duplicatesRemoved = gpxData.lat.length - gpxDataNodup.lat.length;
116
+ if (duplicatesRemoved > 0 && verbose) {
117
+ console.log(`\n🔄 Removed ${duplicatesRemoved} duplicate trackpoint(s)`);
118
+ }
119
+ // Build interpolation options
120
+ const interpolateOptions = {
121
+ resolution,
122
+ numPoints,
123
+ minDistance,
124
+ maxGap,
125
+ };
126
+ if (verbose) {
127
+ console.log(`\n⚙️ Interpolation Settings:`);
128
+ console.log(` Resolution: ${resolution} m`);
129
+ if (numPoints)
130
+ console.log(` Forced point count: ${numPoints}`);
131
+ if (minDistance > 0)
132
+ console.log(` Min distance threshold: ${(0, gpx_utils_1.formatDistance)(minDistance)}`);
133
+ if (maxGap !== Infinity)
134
+ console.log(` Max gap (split at): ${(0, gpx_utils_1.formatDistance)(maxGap)}`);
135
+ }
136
+ // Interpolate
137
+ const gpxDataInterp = (0, interpolate_1.gpxInterpolate)(gpxDataNodup, interpolateOptions);
138
+ totalOutputPoints += gpxDataInterp.lat.length;
139
+ // Generate output filename
140
+ const outFile = outputFile ||
141
+ (() => {
142
+ const ext = path.extname(gpxFile);
143
+ const base = gpxFile.slice(0, -ext.length);
144
+ return `${base}_interpolated${ext}`;
145
+ })();
146
+ if (dryRun) {
147
+ console.log(`\n🔍 Dry run - would save ${gpxDataInterp.lat.length} points to ${outFile}`);
148
+ }
149
+ else {
150
+ // Write output file
151
+ (0, gpx_io_1.gpxWrite)(outFile, gpxDataInterp, writeSpeed);
152
+ console.log(`\n✅ Saved ${gpxDataInterp.lat.length} trackpoints to ${outFile}`);
153
+ }
154
+ // Show compression/expansion ratio
155
+ const ratio = gpxDataInterp.lat.length / gpxDataNodup.lat.length;
156
+ if (ratio > 1) {
157
+ console.log(` (${ratio.toFixed(1)}x more points than original)`);
158
+ }
159
+ else if (ratio < 1) {
160
+ console.log(` (${(1 / ratio).toFixed(1)}x fewer points than original)`);
161
+ }
162
+ }
163
+ catch (error) {
164
+ console.error(`\n❌ Error processing ${gpxFile}:`, error);
165
+ process.exit(1);
166
+ }
167
+ }
168
+ // Summary for multiple files
169
+ if (files.length > 1 && !statsOnly) {
170
+ console.log("\n" + "═".repeat(50));
171
+ console.log(`📈 Summary: ${totalInputPoints} → ${totalOutputPoints} points across ${files.length} files`);
172
+ }
173
+ });
174
+ program.parse();
175
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { GPXData } from './types';
2
+ /**
3
+ * Read GPX file and extract track data
4
+ */
5
+ export declare function gpxRead(gpxFile: string): GPXData;
6
+ /**
7
+ * Write GPX file from track data
8
+ */
9
+ export declare function gpxWrite(gpxFile: string, gpxData: GPXData, writeSpeed?: boolean): void;
10
+ //# sourceMappingURL=gpx-io.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gpx-io.d.ts","sourceRoot":"","sources":["../src/gpx-io.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAY,MAAM,SAAS,CAAC;AAG5C;;GAEG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAgFhD;AAED;;GAEG;AACH,wBAAgB,QAAQ,CACtB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,EAChB,UAAU,GAAE,OAAe,GAC1B,IAAI,CAiFN"}
package/dist/gpx-io.js ADDED
@@ -0,0 +1,178 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.gpxRead = gpxRead;
37
+ exports.gpxWrite = gpxWrite;
38
+ const fs = __importStar(require("fs"));
39
+ const xmldom_1 = require("@xmldom/xmldom");
40
+ const gpx_utils_1 = require("./gpx-utils");
41
+ /**
42
+ * Read GPX file and extract track data
43
+ */
44
+ function gpxRead(gpxFile) {
45
+ const gpxData = {
46
+ lat: [],
47
+ lon: [],
48
+ ele: [],
49
+ tstamp: [],
50
+ tzinfo: null,
51
+ };
52
+ const content = fs.readFileSync(gpxFile, 'utf-8');
53
+ const parser = new xmldom_1.DOMParser();
54
+ const doc = parser.parseFromString(content, 'text/xml');
55
+ const tracks = doc.getElementsByTagName('trk');
56
+ const iLatlon = [];
57
+ const iTstamp = [];
58
+ let i = 0;
59
+ for (let t = 0; t < tracks.length; t++) {
60
+ const segments = tracks[t].getElementsByTagName('trkseg');
61
+ for (let s = 0; s < segments.length; s++) {
62
+ const points = segments[s].getElementsByTagName('trkpt');
63
+ for (let p = 0; p < points.length; p++) {
64
+ const point = points[p];
65
+ const lat = parseFloat(point.getAttribute('lat') || '0');
66
+ const lon = parseFloat(point.getAttribute('lon') || '0');
67
+ gpxData.lat.push(lat);
68
+ gpxData.lon.push(lon);
69
+ iLatlon.push(i);
70
+ // Elevation
71
+ const eleNodes = point.getElementsByTagName('ele');
72
+ if (eleNodes.length > 0) {
73
+ const ele = parseFloat(eleNodes[0].textContent || '0');
74
+ gpxData.ele.push(ele);
75
+ }
76
+ // Time
77
+ const timeNodes = point.getElementsByTagName('time');
78
+ if (timeNodes.length > 0) {
79
+ const timeStr = timeNodes[0].textContent;
80
+ if (timeStr) {
81
+ const date = new Date(timeStr);
82
+ gpxData.tstamp.push(date.getTime() / 1000); // Convert to seconds
83
+ // Store timezone info from first timestamp
84
+ if (!gpxData.tzinfo) {
85
+ // Extract timezone offset
86
+ const match = timeStr.match(/([+-]\d{2}:\d{2}|Z)$/);
87
+ gpxData.tzinfo = match ? match[0] : 'Z';
88
+ }
89
+ iTstamp.push(i);
90
+ }
91
+ }
92
+ i++;
93
+ }
94
+ }
95
+ }
96
+ // Remove trackpoints without timestamp if some have timestamps
97
+ if (iTstamp.length > 0 && iLatlon.length !== iTstamp.length) {
98
+ gpxData.lat = iTstamp.map((idx) => gpxData.lat[idx]);
99
+ gpxData.lon = iTstamp.map((idx) => gpxData.lon[idx]);
100
+ gpxData.ele = gpxData.ele.length > 0
101
+ ? iTstamp.map((idx) => gpxData.ele[idx])
102
+ : null;
103
+ gpxData.tstamp = iTstamp.map((idx) => gpxData.tstamp[idx]);
104
+ }
105
+ // Convert empty arrays to null
106
+ if (gpxData.ele.length === 0)
107
+ gpxData.ele = null;
108
+ if (gpxData.tstamp.length === 0)
109
+ gpxData.tstamp = null;
110
+ return gpxData;
111
+ }
112
+ /**
113
+ * Write GPX file from track data
114
+ */
115
+ function gpxWrite(gpxFile, gpxData, writeSpeed = false) {
116
+ let gpxSpeed = null;
117
+ if (writeSpeed) {
118
+ if (!gpxData.tstamp) {
119
+ throw new Error('Timestamp data is missing from gpxData');
120
+ }
121
+ gpxSpeed = (0, gpx_utils_1.gpxCalculateSpeed)(gpxData);
122
+ }
123
+ // Create GPX XML structure
124
+ const parser = new xmldom_1.DOMParser();
125
+ const doc = parser.parseFromString('<?xml version="1.0" encoding="UTF-8"?><gpx></gpx>', 'text/xml');
126
+ const gpxElement = doc.documentElement;
127
+ gpxElement.setAttribute('version', writeSpeed ? '1.0' : '1.1');
128
+ gpxElement.setAttribute('creator', 'gpx-interpolate-ts');
129
+ gpxElement.setAttribute('xmlns', 'http://www.topografix.com/GPX/1/1');
130
+ if (!writeSpeed) {
131
+ gpxElement.setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
132
+ gpxElement.setAttribute('xsi:schemaLocation', 'http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd');
133
+ }
134
+ const track = doc.createElement('trk');
135
+ const segment = doc.createElement('trkseg');
136
+ for (let i = 0; i < gpxData.lat.length; i++) {
137
+ const trkpt = doc.createElement('trkpt');
138
+ trkpt.setAttribute('lat', gpxData.lat[i].toString());
139
+ trkpt.setAttribute('lon', gpxData.lon[i].toString());
140
+ // Elevation
141
+ if (gpxData.ele) {
142
+ const ele = doc.createElement('ele');
143
+ ele.textContent = gpxData.ele[i].toString();
144
+ trkpt.appendChild(ele);
145
+ }
146
+ // Time
147
+ if (gpxData.tstamp) {
148
+ const time = doc.createElement('time');
149
+ const date = new Date(gpxData.tstamp[i] * 1000);
150
+ // Format ISO string with timezone
151
+ let timeStr = date.toISOString();
152
+ if (gpxData.tzinfo && gpxData.tzinfo !== 'Z') {
153
+ timeStr = timeStr.replace('Z', gpxData.tzinfo);
154
+ }
155
+ time.textContent = timeStr;
156
+ trkpt.appendChild(time);
157
+ }
158
+ // Speed (for GPX 1.0)
159
+ if (writeSpeed && gpxSpeed) {
160
+ const speed = doc.createElement('speed');
161
+ speed.textContent = gpxSpeed[i].toString();
162
+ trkpt.appendChild(speed);
163
+ }
164
+ segment.appendChild(trkpt);
165
+ }
166
+ track.appendChild(segment);
167
+ gpxElement.appendChild(track);
168
+ // Serialize and write to file
169
+ const serializer = new xmldom_1.XMLSerializer();
170
+ const xmlStr = serializer.serializeToString(doc);
171
+ try {
172
+ fs.writeFileSync(gpxFile, xmlStr, 'utf-8');
173
+ }
174
+ catch (error) {
175
+ throw new Error(`Failed to save ${gpxFile}: ${error}`);
176
+ }
177
+ }
178
+ //# sourceMappingURL=gpx-io.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gpx-io.js","sourceRoot":"","sources":["../src/gpx-io.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAQA,0BAgFC;AAKD,4BAqFC;AAlLD,uCAAyB;AACzB,2CAA0D;AAE1D,2CAAgD;AAEhD;;GAEG;AACH,SAAgB,OAAO,CAAC,OAAe;IACrC,MAAM,OAAO,GAAY;QACvB,GAAG,EAAE,EAAE;QACP,GAAG,EAAE,EAAE;QACP,GAAG,EAAE,EAAE;QACP,MAAM,EAAE,EAAE;QACV,MAAM,EAAE,IAAI;KACb,CAAC;IAEF,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAClD,MAAM,MAAM,GAAG,IAAI,kBAAS,EAAE,CAAC;IAC/B,MAAM,GAAG,GAAG,MAAM,CAAC,eAAe,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IAExD,MAAM,MAAM,GAAG,GAAG,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC;IAC/C,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,IAAI,CAAC,GAAG,CAAC,CAAC;IAEV,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,oBAAoB,CAAC,QAAQ,CAAC,CAAC;QAE1D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACzC,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC;YAEzD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACvC,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;gBAExB,MAAM,GAAG,GAAG,UAAU,CAAC,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC;gBACzD,MAAM,GAAG,GAAG,UAAU,CAAC,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC;gBAEzD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBACtB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBACtB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBAEhB,YAAY;gBACZ,MAAM,QAAQ,GAAG,KAAK,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC;gBACnD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACxB,MAAM,GAAG,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,WAAW,IAAI,GAAG,CAAC,CAAC;oBACvD,OAAO,CAAC,GAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBACzB,CAAC;gBAED,OAAO;gBACP,MAAM,SAAS,GAAG,KAAK,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC;gBACrD,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACzB,MAAM,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;oBACzC,IAAI,OAAO,EAAE,CAAC;wBACZ,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC;wBAC/B,OAAO,CAAC,MAAO,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,qBAAqB;wBAElE,2CAA2C;wBAC3C,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;4BACpB,0BAA0B;4BAC1B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;4BACpD,OAAO,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;wBAC1C,CAAC;wBAED,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;oBAClB,CAAC;gBACH,CAAC;gBAED,CAAC,EAAE,CAAC;YACN,CAAC;QACH,CAAC;IACH,CAAC;IAED,+DAA+D;IAC/D,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC;QAC5D,OAAO,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QACrD,OAAO,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QACrD,OAAO,CAAC,GAAG,GAAG,OAAO,CAAC,GAAI,CAAC,MAAM,GAAG,CAAC;YACnC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,GAAI,CAAC,GAAG,CAAC,CAAC;YACzC,CAAC,CAAC,IAAI,CAAC;QACT,OAAO,CAAC,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,MAAO,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9D,CAAC;IAED,+BAA+B;IAC/B,IAAI,OAAO,CAAC,GAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;IAClD,IAAI,OAAO,CAAC,MAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAExD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,SAAgB,QAAQ,CACtB,OAAe,EACf,OAAgB,EAChB,aAAsB,KAAK;IAE3B,IAAI,QAAQ,GAAoB,IAAI,CAAC;IAErC,IAAI,UAAU,EAAE,CAAC;QACf,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;QAC5D,CAAC;QACD,QAAQ,GAAG,IAAA,6BAAiB,EAAC,OAAO,CAAC,CAAC;IACxC,CAAC;IAED,2BAA2B;IAC3B,MAAM,MAAM,GAAG,IAAI,kBAAS,EAAE,CAAC;IAC/B,MAAM,GAAG,GAAG,MAAM,CAAC,eAAe,CAChC,mDAAmD,EACnD,UAAU,CACX,CAAC;IACF,MAAM,UAAU,GAAG,GAAG,CAAC,eAAe,CAAC;IAEvC,UAAU,CAAC,YAAY,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAC/D,UAAU,CAAC,YAAY,CAAC,SAAS,EAAE,oBAAoB,CAAC,CAAC;IACzD,UAAU,CAAC,YAAY,CAAC,OAAO,EAAE,mCAAmC,CAAC,CAAC;IACtE,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,UAAU,CAAC,YAAY,CAAC,WAAW,EAAE,2CAA2C,CAAC,CAAC;QAClF,UAAU,CAAC,YAAY,CACrB,oBAAoB,EACpB,6EAA6E,CAC9E,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,GAAG,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IACvC,MAAM,OAAO,GAAG,GAAG,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;IAE5C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5C,MAAM,KAAK,GAAG,GAAG,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QACzC,KAAK,CAAC,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;QACrD,KAAK,CAAC,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;QAErD,YAAY;QACZ,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;YAChB,MAAM,GAAG,GAAG,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YACrC,GAAG,CAAC,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;YAC5C,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACzB,CAAC;QAED,OAAO;QACP,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACnB,MAAM,IAAI,GAAG,GAAG,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;YACvC,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;YAEhD,kCAAkC;YAClC,IAAI,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;YACjC,IAAI,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBAC7C,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;YACjD,CAAC;YAED,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC;YAC3B,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;QAED,sBAAsB;QACtB,IAAI,UAAU,IAAI,QAAQ,EAAE,CAAC;YAC3B,MAAM,KAAK,GAAG,GAAG,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;YACzC,KAAK,CAAC,WAAW,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;YAC3C,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QAC3B,CAAC;QAED,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IAC3B,UAAU,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IAE9B,8BAA8B;IAC9B,MAAM,UAAU,GAAG,IAAI,sBAAa,EAAE,CAAC;IACvC,MAAM,MAAM,GAAG,UAAU,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC;IAEjD,IAAI,CAAC;QACH,EAAE,CAAC,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,kBAAkB,OAAO,KAAK,KAAK,EAAE,CAAC,CAAC;IACzD,CAAC;AACH,CAAC"}