Onsdag 17 Aug 2022
22.8.17 2:07
Utvecklar tränings-segment
Hujedamig vilket projekt, detta var ett sånt där typiskt projekt där man tror att det skall ta några timmar & tillslut visar det sig att det tar 10ggr längre tid än vad man tänkt
Jag utvecklade en GPX parser 2019 & har sedan dess laddat upp alla(?) tränings-loggar men ända sedan jag har jag viljat lägga till segment också, det har alltså dröjt 3 år tills jag fick tummen ur 😂
Inför utvecklingen hade jag funderat på hur jag skulle gå tillväga, finns alltid 100 olika sätt att göra samma sak på så jag fastnade inte på bara en lösning, så bara att köra igång & testa, jag testade massa olika tillvägagångssätt & till slut landade jag på nedanstående, tror det är hyffsat optimerat, mitt första försök tog 500 databasanrop & 20s att parsa för en 1 timmes cykeltur, nuvarande implementering tar 2s & ~50st databasanrop, antalet databasanrop låter högt men jag gör 1 var 500:e meter; detta kan ökas rejält men just nu finns det ingen anledning när detta är något som görs 3-4 gånger i veckan på sin höjd, hade detta varit en kommersiell sida där detta körs flera gånger i sekunden så hade det varit en annan femma
Att skapa själva segmenten var ju inget större problem; alla GPX filer är ju sparade efter att dom parsats så jag gjorde bara en tabell med alla träningstillfällen & använde dom för att skapa segment:
Så; fyll i namn, klicka i "histogramet" för att välja start & slut long/lat & sen klicka på spara, efter det så går parsern igenom GPX filen & räknar ut segmentets distans, höjdmeter (upp & ner), genomsnittlig lutning osv osv (visar inte all information i segment tabellen, bara dom viktigaste), jag sparar resultatet i databasen + start long/lat & slut long/lat för att lättare kunna söka efter segment baserad på geografisk data. När jag laddar upp en träningsrunda så sparar jag inte några av datapunkterna i en databas, det är ju 1 datapunkt per sekund så det skulle bli några miljoner rader i databasen till ingen egentlig nytta, hade ju kunnat spara % 10 av punkterna kanske men äh 🤷♂️
Däremot sparar jag varje punkt för segmentet i en separat databas, vill kunna matcha flera punkter mellan segment punkterna & träningsrundans punkter, det räcker ju inte att bara spara ett segments start & slutposition för det går ju cykla 100 olika vägar emellan start & mål, så jag behöver så många punkter därimellan som möjligt för att kunna vara säker på att segmentets sträcka verkligen är den som har cyklats på
Sen efter det dök första problemet upp; hur matchar jag segmenten med en träningsrunda? Att matcha ett segment när jag laddar upp en tränings-runda var inte så svårt, redan första iterationen av GPX filen så får jag ju fram en long/lat som jag kan använda för att kolla om det finns ett segment i närheten av tränings-starten, det vore ju osmart att kolla upp detta varje tränings-punkt för det är ju 3'600st per timma så att kanske göra 10'000 databasanrop är ju inte...ja, det gör man ju helt enkel inte, så vi tränings-starten kollar jag om det finns ett segment inom 500m, finns det några segment så sparar jag deras data i en array (id, long, lat), så då räcker det att göra 1 databasanrop per 500m, går göra dom i ännu glesare intervaller men detta duger. Så hittas segment så kollar jag exakt hur långt det är mellan nuvarande tränings punkt & segmentets startpunkt, är det 348m fågelvägen så behöver jag ju inte mäta distansen igen förrän om 348m (börjar mäta igen strax innan dess för att vara på den säkra sidan), när träningsmätpunkten är inom 30m från segmentets start så börjar jag matcha varje sekund/mätpunkt, jag kollar om startpunken är inom X antal meter (ibland kan man köra nära ett segments start men inte faktiskt köra på segmentet, tex om ett segment börjar i en korsning & man kör åt något annan riktning), så först "mjuk-startas" ett segment, sätts som potentiell startad, i början måste X antal mätpunkter matcha med varandra inom X antal meter (just nu 30m, men skulle kunna gå lägre än så gör GPS:er är ganska exakta, men jag vill dels fånga upp mätpunkter där GPS:en kanske har dålig mottagning + distansen måste vara ganska väl tilltagen då mätpunkterna är 1ggr/s, så matchingen beror ju på hur snabbt jag cyklar, 30m motsvarar 108km/h så ja, det är väl tilltaget för riktigt så snabb är jag inte 😂, dom flesta mätpunkter matchas inom +-2m) för att segmentet skall bli satt som "start-validerat", matchas bara X antal mätpunkter med varandra, alltså under ett visst värde, tex om bara 50% matchar så slängs det segmentet bort för då är det inte troligen att jag cyklar på det segmentet; jag var i närheten av starten av ett segment men cyklade åt ett annat håll
Problemet dök upp när jag skulle matcha nyskapade segment med gamla tränings-tillfällen, jag vill ju inte parsa alla träningar igen, det tar ju en evighet, först tänkte jag att jag vet ju startpositionen long/lat på alla träningar & jag vet även distansen, så då är det ju bara att fråga databasen ifall det finns några segment inom träningsdistansens radie från startpositionen, problemet är att då kommer troligen ALLA segment att matchas, för cyklar jag 10 mil rakt söderut så kommer även alla segment 10 mil norrut också att hittas, det är ju sjukt onödigt. Så den bästa lösningen jag kunde komma på var att skapa en till tabell i databasen som jag kallar "SegmentBeacons", den består bara av "WorkoutID" & "BeaconPoint" (long/lat), så då kunde jag ladda in alla GPX filer igen, behövde inte parsa hela, bara var 2'000m & skapa en punkt med tränings id & position. Så då kan jag använda den tabellen till att göra en "baklänges" sökning, isället för att fråga databasen om det finns några segment inom startpunken på en träning så kan jag nu istället när ett nytt segment skapas kolla om det finns några "BeaconPoints" i närheten av segmentets "StartPoint" & på så sätt få reda på vilka cykelturer som potentiellt har passerat segmentet & då behövs ju bara ett fåtal träningar parsas igen istället för nästan alla
Det dök upp flera andra problem men det får kanske bli ett separat inlägg om det
1'672 visningar #Programmering