UNPKG

@sports-alliance/sports-lib

Version:

A Library to for importing / exporting and processing GPX, TCX, FIT and JSON files from services such as Strava, Movescount, Garmin, Polar etc

133 lines (132 loc) 7.52 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.RouteImporterJSON = void 0; const activity_types_1 = require("../../../../activities/activity.types"); const creator_1 = require("../../../../creators/creator"); const data_altitude_1 = require("../../../../data/data.altitude"); const data_latitude_degrees_1 = require("../../../../data/data.latitude-degrees"); const data_longitude_degrees_1 = require("../../../../data/data.longitude-degrees"); const data_store_1 = require("../../../../data/data.store"); const importer_json_1 = require("../../../../events/adapters/importers/json/importer.json"); const parsing_event_lib_error_1 = require("../../../../errors/parsing-event-lib.error"); const route_1 = require("../../../route"); const route_file_1 = require("../../../route-file"); const route_file_utilities_1 = require("../../../route-file.utilities"); const route_stream_1 = require("../../../route-stream"); class RouteImporterJSON { static getRouteFileFromJSON(json) { const creator = json.creator ? importer_json_1.EventImporterJSON.getCreatorFromJSON(json.creator) : new creator_1.Creator('Unknown Device'); const routeFile = new route_file_1.RouteFile(json.name, json.srcFileType, creator, [], json.waypoints || [], json.createdAt !== null && json.createdAt !== undefined ? new Date(json.createdAt) : null); if (json.id) { routeFile.setID(json.id); } (json.routes || []).forEach(routeJSON => { routeFile.addRoute(this.getRouteFromJSON(routeJSON, creator)); }); if (this.hasStats(json.stats)) { this.addStatsFromJSON(json.stats, routeFile); } else { route_file_utilities_1.RouteFileUtilities.reGenerateStatsForRouteFile(routeFile); } return routeFile; } static getRouteFromJSON(json, routeFileCreator) { var _a; const creator = json.creator ? importer_json_1.EventImporterJSON.getCreatorFromJSON(json.creator) : routeFileCreator || new creator_1.Creator('Unknown Device'); const streams = this.getStreamsFromJSON(json.streams || []); const points = this.getValidatedPoints(json.points || [], streams); this.addMissingGeometryStreamsFromPoints(points, streams); const route = new route_1.Route(creator, undefined, json.name || null, activity_types_1.ActivityTypesHelper.resolveActivityType(json.activityType) || null, points, { comment: json.comment || null, description: json.description || null, number: (_a = json.number) !== null && _a !== void 0 ? _a : null, links: json.links || [], extensions: json.extensions }); if (json.id) { route.setID(json.id); } this.addStatsFromJSON(json.stats, route); streams.forEach(stream => route.addStream(stream)); return route; } static addStatsFromJSON(jsonStats, target) { Object.keys(jsonStats || {}).forEach(statName => { target.addStat(data_store_1.DynamicDataLoader.getDataInstanceFromDataType(statName, (jsonStats || {})[statName])); }); } static hasStats(jsonStats) { return !!jsonStats && Object.keys(jsonStats).length > 0; } static getStreamsFromJSON(streamsJSON) { if (Array.isArray(streamsJSON)) { return streamsJSON.map(streamJson => new route_stream_1.RouteStream(streamJson.type, streamJson.data)); } return Object.keys(streamsJSON || {}).map(streamKey => new route_stream_1.RouteStream(streamKey, streamsJSON[streamKey])); } static getValidatedPoints(points, streams) { if (!points.length) { return points; } const streamsByType = new Map(streams.map(stream => [stream.type, stream])); const latitudeStream = streamsByType.get(data_latitude_degrees_1.DataLatitudeDegrees.type); const longitudeStream = streamsByType.get(data_longitude_degrees_1.DataLongitudeDegrees.type); const altitudeStream = streamsByType.get(data_altitude_1.DataAltitude.type); this.validateGeometryStream(points, latitudeStream, point => point.latitudeDegrees, data_latitude_degrees_1.DataLatitudeDegrees.type, true); this.validateGeometryStream(points, longitudeStream, point => point.longitudeDegrees, data_longitude_degrees_1.DataLongitudeDegrees.type, true); this.validateGeometryStream(points, altitudeStream, point => point.altitude, data_altitude_1.DataAltitude.type, false); return points.map((point, index) => (Object.assign(Object.assign({}, point), { altitude: point.altitude !== undefined ? point.altitude : Number.isFinite(altitudeStream === null || altitudeStream === void 0 ? void 0 : altitudeStream.getData()[index]) ? altitudeStream.getData()[index] : null }))); } static validateGeometryStream(points, stream, getPointValue, streamType, requiredPointValue) { points.forEach((point, index) => { const pointValue = getPointValue(point); if (requiredPointValue && !Number.isFinite(pointValue)) { throw new parsing_event_lib_error_1.ParsingEventLibError(`Invalid route point ${streamType} at index ${index}`); } }); if (!stream) { return; } const streamData = stream.getData(); if (streamData.length !== points.length) { throw new parsing_event_lib_error_1.ParsingEventLibError(`Route JSON geometry conflict: ${streamType} stream length ${streamData.length} does not match points length ${points.length}`); } streamData.forEach((streamValue, index) => { const pointValue = getPointValue(points[index]); if (!Number.isFinite(pointValue) && !Number.isFinite(streamValue)) { return; } if (!Number.isFinite(pointValue) && Number.isFinite(streamValue)) { return; } if (!Number.isFinite(pointValue) || !Number.isFinite(streamValue) || Math.abs(pointValue - streamValue) > 1e-9) { throw new parsing_event_lib_error_1.ParsingEventLibError(`Route JSON geometry conflict: ${streamType} mismatch at index ${index}`); } }); } static addMissingGeometryStreamsFromPoints(points, streams) { if (!points.length) { return; } const existingStreamTypes = new Set(streams.map(stream => stream.type)); if (!existingStreamTypes.has(data_latitude_degrees_1.DataLatitudeDegrees.type)) { streams.push(new route_stream_1.RouteStream(data_latitude_degrees_1.DataLatitudeDegrees.type, points.map(point => point.latitudeDegrees))); } if (!existingStreamTypes.has(data_longitude_degrees_1.DataLongitudeDegrees.type)) { streams.push(new route_stream_1.RouteStream(data_longitude_degrees_1.DataLongitudeDegrees.type, points.map(point => point.longitudeDegrees))); } if (!existingStreamTypes.has(data_altitude_1.DataAltitude.type) && points.some(point => Number.isFinite(point.altitude))) { streams.push(new route_stream_1.RouteStream(data_altitude_1.DataAltitude.type, points.map(point => (Number.isFinite(point.altitude) ? point.altitude : null)))); } } } exports.RouteImporterJSON = RouteImporterJSON;