From 1766cf2062b17467d8060d4015256af76dce5e90 Mon Sep 17 00:00:00 2001 From: "Patrik J. Braun" Date: Sat, 18 Mar 2023 22:10:59 +0100 Subject: [PATCH] Adding middle point removal for gpx compression and enabling polyline smoothing #504 --- .../model/fileprocessing/GPXProcessing.ts | 33 +++++++++++++++++-- src/common/config/private/PrivateConfig.ts | 14 +++++++- .../lightbox.map.gallery.component.ts | 2 +- 3 files changed, 44 insertions(+), 5 deletions(-) diff --git a/src/backend/model/fileprocessing/GPXProcessing.ts b/src/backend/model/fileprocessing/GPXProcessing.ts index 49b71179..cc46d118 100644 --- a/src/backend/model/fileprocessing/GPXProcessing.ts +++ b/src/backend/model/fileprocessing/GPXProcessing.ts @@ -5,9 +5,10 @@ import {ProjectPath} from '../../ProjectPath'; import {Config} from '../../../common/config/private/Config'; import {SupportedFormats} from '../../../common/SupportedFormats'; -type gpxEntry = { '$': { lat: string, lon: string }, ele: string[], time: string[], extensions: unknown }; +type gpxEntry = { '$': { lat: string, lon: string }, ele?: string[], time: string[], extensions?: unknown }; export class GPXProcessing { + private static readonly GPX_FLOAT_ACCURACY = 6; public static isMetaFile(fullPath: string): boolean { const extension = path.extname(fullPath).toLowerCase(); @@ -21,6 +22,7 @@ export class GPXProcessing { path.basename(filePath) + '_' + Config.MetaFile.GPXCompressing.minDistance + 'm' + Config.MetaFile.GPXCompressing.minTimeDistance + 'ms' + + Config.MetaFile.GPXCompressing.maxMiddleDeviance + 'm' + path.extname(filePath)); } @@ -117,13 +119,38 @@ export class GPXProcessing { dist < Config.MetaFile.GPXCompressing.minDistance); }; + const postFilter = (i: number, list: gpxEntry[]) => { + if (i === 0 || i >= list.length - 1) { // always keep the first and last items + return true; + } + /* if point on the same line that the next and prev point would draw, lets skip it*/ + const avg = (a: string, b: string) => ((parseFloat(a) + parseFloat(b)) / 2).toFixed(this.GPX_FLOAT_ACCURACY); + const modPoint: gpxEntry = { + $: { + lat: avg(list[i - 1].$.lat, list[i + 1].$.lat), + lon: avg(list[i - 1].$.lon, list[i + 1].$.lon) + }, + time: list[i].time + }; + + const deviation = distance(modPoint, list[i]); // meters + return !(deviation < Config.MetaFile.GPXCompressing.maxMiddleDeviance); // keep if deviation is too big + }; + gpxObj.gpx.trk[0].trkseg[0].trkpt = items.filter(gpxEntryFilter).map((v) => { - v.$.lon = parseFloat(v.$.lon).toFixed(6); - v.$.lat = parseFloat(v.$.lat).toFixed(6); + v.$.lon = parseFloat(v.$.lon).toFixed(this.GPX_FLOAT_ACCURACY); + v.$.lat = parseFloat(v.$.lat).toFixed(this.GPX_FLOAT_ACCURACY); delete v.ele; delete v.extensions; return v; }); + + for (let i = 0; i < gpxObj.gpx.trk[0].trkseg[0].trkpt.length; ++i) { + if (!postFilter(i, gpxObj.gpx.trk[0].trkseg[0].trkpt)) { + gpxObj.gpx.trk[0].trkseg[0].trkpt.splice(i, 1); + --i; + } + } } await fsp.writeFile(outPath, (new xml2js.Builder({renderOpts: {pretty: false}})).buildObject(gpxObj)); diff --git a/src/common/config/private/PrivateConfig.ts b/src/common/config/private/PrivateConfig.ts index 575c87d6..b179471b 100644 --- a/src/common/config/private/PrivateConfig.ts +++ b/src/common/config/private/PrivateConfig.ts @@ -346,9 +346,21 @@ export class ServerGPXCompressingConfig extends ClientGPXCompressingConfig { unit: 'm', uiDisabled: (sc: ServerGPXCompressingConfig, c: ServerConfig) => !c.Map.enabled || !sc.enabled || !c.MetaFile.gpx } as TAGS, - description: $localize`Filters out entry that are closer than this in meters.` + description: $localize`Filters out entry that are closer than this to each other in meters.` }) minDistance: number = 5; + @ConfigProperty({ + type: 'unsignedInt', + tags: + { + name: $localize`Max middle point deviance`, + priority: ConfigPriority.underTheHood, + unit: 'm', + uiDisabled: (sc: ServerGPXCompressingConfig, c: ServerConfig) => !c.Map.enabled || !sc.enabled || !c.MetaFile.gpx + } as TAGS, + description: $localize`Filters out entry that would fall on the line if we would just connect the previous and the next points. This setting sets the sensitivity for that (higher number, more points are filtered).` + }) + maxMiddleDeviance: number = 5; @ConfigProperty({ type: 'unsignedInt', tags: diff --git a/src/frontend/app/ui/gallery/map/lightbox/lightbox.map.gallery.component.ts b/src/frontend/app/ui/gallery/map/lightbox/lightbox.map.gallery.component.ts index 6bd6f359..6644916d 100644 --- a/src/frontend/app/ui/gallery/map/lightbox/lightbox.map.gallery.component.ts +++ b/src/frontend/app/ui/gallery/map/lightbox/lightbox.map.gallery.component.ts @@ -487,7 +487,7 @@ export class GalleryMapLightboxComponent implements OnChanges, OnDestroy { marker(parsedGPX.path[0]) ); this.mapLayersControlOption.overlays.Paths.addLayer( - polyline(parsedGPX.path) + polyline(parsedGPX.path, {smoothFactor: 3}) ); } parsedGPX.markers.forEach((mc) => {