User:Melnibon/FR:SplitTracks

From OpenStreetMap Wiki
Jump to: navigation, search

Séparation d'une trace en plusieurs segments

Mon GPS enregistre tous mes trajets dans un seul fichier appelé Current.gpx. Le problème est qu'il contient différents segments, certains sont à garder, d'autres sont à jeter. Évidemment, je pourrais utiliser le menu de gestion des traces de mon GPS pour enregistrer la trace courante dans un nouveau fichier, mais ce n'est pas pratique et il faut y penser à chaque fois. Le but de ce script python est séparer tous les segments du fichier Current.gpx en différents fichiers gpx, ne contenant chacun qu'un seul segment. Chaque fichier résultant est nommé d'après le timestamp de son premier point et le nombre de points qu'ils contient. Ça permet en un seul coup d'œil de supprimer les traces trop courtes.

Comme mon GPS enregistre aussi le rythme cardiaque à chaque point (sous forme d'une extension sous chaque trkpt), le script fait deux versions de chaque trace : complète et sans les extensions. Je ne publie que le fichier sans extension sous OpenStreetMap.

#!/usr/bin/python
# -*- coding: utf-8 -*-

# usage : lancer le script dans un dossier contenant les .gpx à traiter

# (c) Pierre Nerzic 02/2010, pierre.nerzic@free.fr

# Ce script sépare les segments de tous les fichiers GPX du répertoire courant.
# Il les nomme en fonction de la date de leur premier point.
# Il ne traite pas les fichiers qui ne contiennent qu'un seul segment
#
# Explications: structure d'un fichier gpx :
#
# <?xml...>
# <gpx>
#     <metadata>
#         infos à préserver
#     </metadata>
#     <trk>
#         <name>
#             nom à préserver
#         </name>
#         <trkseg>
#             <trkpt>
#                 données à préserver
#             </trkpt>
#             ...
#         </trkseg>
#         ...
#     </trk>
#     ...
# </gpx>
#
# Le script sépare en autant de fichiers que nécessaire toutes les trk et trkseg.
# On ne retrouve plus qu'un seul trk et trkseg par fichier produit. Le trkseg contenant
# tous les points du fichier d'origine liés à ce trkseg.
# Il préserve toutes les autres informations. Le fichier d'origine reste inchangé.
# Il fait aussi une copie ne contenant aucune extension spécifique Garmin.

## ne pas modifier au delà

import xml.dom.minidom
from datetime import datetime
import calendar
import time
import os
import os.path
import codecs


def SplitTracks(filename):
    # ouvrir le fichier gpx à traiter
    doc = xml.dom.minidom.parse(filename)

    # séparer ce document en toutes ses pistes
    for trkseg in doc.getElementsByTagName('trkseg'):

        # obtenir la date du premier point de ce segment
        date = trkseg.getElementsByTagName('trkpt')[0].getElementsByTagName('time')[0].firstChild.data

        # mettre la date au format YYYY-MM-DD--HH-MM-SS heure locale
        date = datetime.strptime(date,"%Y-%m-%dT%H:%M:%SZ").timetuple()
        secs = calendar.timegm(date)
        date = time.localtime(secs)
        date = time.strftime("%Y-%m-%d--%H-%M-%S",date)
        nbpoints = len(trkseg.getElementsByTagName('trkpt'))

        # si le fichier porte déjà le nom de ce segment, arrêter là
        if os.path.isfile("%s--%dpts.gpx"%(date,nbpoints)): continue
        if os.path.isfile("%s--%dpts-hr.gpx"%(date,nbpoints)): continue

        # faire une copie de doc ne contenant que ce trkseg
        trkseg2 = trkseg.cloneNode(True)

        # créer un node trk contenant les mêmes informations name
        trk = trkseg.parentNode
        trk2 = trk.cloneNode(False)
        # lui rajouter tous ses fils qui ne sont pas des trkseg
        for child in trk.childNodes:
            if child.nodeType != child.ELEMENT_NODE or child.nodeName != 'trkseg':
                trk2.appendChild(child.cloneNode(True))
        # lui ajouter le trkseg à garder
        trk2.appendChild(trkseg2)

        # créer un node gpx contenant les mêmes informations metadata
        gpx = trk.parentNode
        gpx2 = gpx.cloneNode(False)
        # lui rajouter tous ses fils qui ne sont pas des trk
        for child in gpx.childNodes:
            if child.nodeType != child.ELEMENT_NODE or child.nodeName != 'trk':
                gpx2.appendChild(child.cloneNode(True))
        # lui ajouter le trk filtré
        gpx2.appendChild(trk2)

        # créer un document xml
        doc2 = xml.dom.minidom.Document()
        doc2.appendChild(gpx2)

        # écrire le document xml dans le fichier gpx de sortie
        print('\tEcriture du fichier %s--%dpts.gpx'%(date,nbpoints))
        #print(doc2.toprettyxml())
        codecs.open("%s--%dpts.gpx"%(date,nbpoints),'w','utf-8').write(doc2.toxml())

        # supprimer les extensions des trkpt
        changement = False
        for trkpt in doc2.getElementsByTagName('trkpt'):

            # passer au suivant s'il n'y a rien à enlever
            extensions = trkpt.getElementsByTagName('extensions')
            if len(extensions) == 0: continue

            # retirer ces informations du trkpt
            for extension in extensions:
                trkpt.removeChild(extension)
            changement = True

        # après avoir traité tous les points, écrire le nouveau contenu
        if changement:
            # écrire le nouveau contenu dans un autre fichier
            print('\tEcriture du fichier %s--%dpts-ext.gpx'%(date,nbpoints))
            codecs.open("%s--%dpts-hr.gpx"%(date,nbpoints),'w','utf-8').write(doc2.toxml())


        # libérer la mémoire occupée par la copie du fichier gpx
        doc2.unlink()

    # libérer la mémoire occupée par le fichier gpx
    doc.unlink()


# traiter tous les fichiers gpx du répertoire courant
for fich in os.listdir('.'):
    nom,ext = os.path.splitext(fich)
    if ext == '.gpx':
        print('Traitement de '+fich)
        SplitTracks(fich)

Ce script tourne avec python2 et python3. Il n'emploie que des librairies standard de python.

Par défaut, ce script traite tous les fichiers du répertoire courant, mais on peut le modifier pour qu'il ne traite que Current.gpx.