Le blog tech de Nicolas Steinmetz (Time Series, IoT, Web, Ops, Data)
La société SenX a proposé un code contest suite à la publication de son article sur les formes géospatiales. L’objet du concours porte sur le trajet d’un véhicule aux USA et il consiste à déterminer :
Maintenant que le gagnant a été annoncé (TL;DR: moi 😎🎉) et en attendant le corrigé officiel, voici ma proposition de solution.
Les données de départ sont :
@senx/dataset/route66_vehicle_gts
: le trajet réalisé par le véhicule@senx/dataset/route66_geoshape
: la route 66// Define points from the car journey on the US66 road
[
// Here is the gts of the car datalogger
@senx/dataset/route66_vehicle_gts
// Here is the route 66 geoshape (+/- 20meters)
@senx/dataset/route66_geoshape
mapper.geo.within 0 0 0
] MAP
"onTheRoad" STORE
$onTheRoad
{
'timesplit' 60 s
}
MOTIONSPLIT
0 GET
'sectionOnTheRoad' STORE
// Compute distance for each GTS and output it as a single point
[ $sectionOnTheRoad mapper.hdist MAXLONG MAXLONG 1 ] MAP
// Sum all GTS
0 SWAP <% VALUES 0 GET + %> FOREACH
// Convert to km
1000 /
// Enjoy !
Explications :
mapper.geo.within
(doc). Ce mapper compare deux zones géographiques et ne retient que les poits qui sont dans la zone voulue. Ici, je prends donc tous les points du trajet et les compare avec ceux de la route 66. Seuls les points sur la route 66 sont conservés. Le résultat est une aggrégation de points que l’on stocke dans la variable onTheRoad
.MOTIONSPLIT
(doc) pour calculer la distance entre deux points. Obtenant une liste de 1 élément contenant une liste, j’ai rajouté le 0 GET
pour supprimer la liste parente. On obtient alors une liste de 8 séries temporelles (GTS) correspondant à chaque tronçon sur la route. On stocke cela dans la variable sectionOnTheRoad
.mapper.hdist
(doc) permet de calculer la distance totale sur une fenêtre glissante de points. L’utilisation de MAXLONG
permet d’avoir une valeur suffisamment grande pour notre cas d’espèce pour prendre l’ensemble des données de chacune des 8 listes - il n’est pas nécessaire de connaitre la taille exacte de la liste pour travailler dessus et cela ne crée pas d’erreur non plus ; ça peut déstabiliser !. Le 1
permet de n’avoir qu’une valeur en sortie. On a donc en sortie la distance de chacune des 8 sections.0
(pour initialiser l’opération d’addition) et ajouter la première valeur de la liste et ainsi de suite. Une fois qu’on a la somme, on divise par 1000 pour avoir des kilomètres79.82147744769853
Pour comprendre la partie 2, on peut réécrire la chose de la façon suivante :
[ $sectionOnTheRoad mapper.hdist MAXLONG MAXLONG 1 ] MAP
'totalDistancePerSection' STORE
0 $totalDistancePerSection <% VALUES 0 GET + %> FOREACH
Non, toujours pas ? Vous me rassurez, j’ai du creuser plus loin aussi.
Commençons par :
$totalDistancePerSection <% VALUES 0 GET %> FOREACH
VALUES
(doc) consomme une série temporelle et en sort les valeurs sous la forme d’une liste. Nous avons une liste initiale de 8 séries que nous avons ramené à 8 points. Avec FOREACH
(doc), on applique donc la fonction VALUES
sur chaque série contenant un seul point. Plutôt que d’avoir en sortie des listes à un seul point, le 0 GET
permet d’avoir directement la valeur.
Pour faire une addition, en WarpScript, c’est :
1 1 +
ou :
1
1
+
Par celà, j’entends que pour appliquer +
, il faut que les deux éléments soient définis dans la pile.
Notre boucle FOREACH
emet dans la pile chaque valeur qu’il faut ajouter à la précédente. On peut donc rajouter le +
dans la boucle FOREACH
:
$totalDistancePerSection <% VALUES 0 GET + %> FOREACH
Mais si je cherche à exécuter cela, cela ne fonctionne pas - cela reviendrait à faire:
valeur1IssueDuForeach +
valeur2IssueDuForeach +
valeur3IssueDuForeach +
valeur4IssueDuForeach +
...
Si on part de la fin, la valeur 4 va pouvoir être additionnée à la valeur 3 car celle-ci existe dans la pile. MAIS la valeur 1 n’est additionnée à rien à ce stade et l’opération est invalide. D’où la nécessité de rajouter le 0
pour pouvoir avoir deux éléments pour notre première addition.
Ce qui nous donne bien :
0 $totalDistancePerSection <% VALUES 0 GET + %> FOREACH
Maintenant que la brume s’est éclaircie et que le 🤯 est passé à 😎 pour cette syntaxe de fin, je vous propose de nous retrouver dans un prochain billet pour la suite de ma solution au concours.