// License: GPL. For details, see LICENSE file.
package org.openstreetmap.josm.plugins.dataimport.io;
import static org.openstreetmap.josm.tools.I18n.tr;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.datatype.XMLGregorianCalendar;
import org.openstreetmap.josm.Main;
import org.openstreetmap.josm.actions.ExtensionFileFilter;
import org.openstreetmap.josm.data.coor.LatLon;
import org.openstreetmap.josm.data.gpx.GpxData;
import org.openstreetmap.josm.data.gpx.ImmutableGpxTrack;
import org.openstreetmap.josm.data.gpx.WayPoint;
import org.openstreetmap.josm.gui.layer.GpxLayer;
import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer;
import org.openstreetmap.josm.gui.progress.ProgressMonitor;
import org.openstreetmap.josm.io.FileImporter;
import org.openstreetmap.josm.plugins.dataimport.io.tcx.ActivityLapT;
import org.openstreetmap.josm.plugins.dataimport.io.tcx.ActivityT;
import org.openstreetmap.josm.plugins.dataimport.io.tcx.CourseT;
import org.openstreetmap.josm.plugins.dataimport.io.tcx.PositionT;
import org.openstreetmap.josm.plugins.dataimport.io.tcx.TrackT;
import org.openstreetmap.josm.plugins.dataimport.io.tcx.TrackpointT;
import org.openstreetmap.josm.plugins.dataimport.io.tcx.TrainingCenterDatabaseT;
/**
* TCX Reader. This class is based on code genarated by the Java Architecture
* for XML Binding (JAXB). For this class to work you will need the API und IMPL
* Jars from the RI. JAXB can be downloaded at <a
* href="https://jaxb.dev.java.net/">https://jaxb.dev.java.net/</a>. This class
* has been developed using JAXB version 2.1.7.
* <p>
* Additional information and tutorial are available at: <a
* href="http://java.sun.com/developer/technicalArticles/WebServices/jaxb/">http://java.sun.com/developer/technicalArticles/WebServices/jaxb/</a>
* <p>
* The Garmin TCX Schema file can be downloaded from: <a
* href="http://www.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd">http://www.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd</a>
* The command used to generate the code is:
* {@code xjc.bat -p org.openstreetmap.josm.io.tcx TrainingCenterDatabasev2.xsd -d <path to the src folder of JOSM>}
* <p>
* Note: if you get an exception that JAXB 2.1 is not supported on your system, you will have to add the jaxb-api.jar
* to the endorsed directory (create it if necessary) of your JRE. Usually it is something like this:
* {@code \<program files>\Java\jre<java version>\lib\endorsed}
*
* @author adrian <as@nitegate.de>
*
*/
public class Tcx extends FileImporter {
//private File tcxFile;
private GpxData gpxData;
public Tcx() {
super(new ExtensionFileFilter("tcx", "tcx", tr("TCX Files (*.tcx)")));
}
@Override
public void importData(File tcxFile, ProgressMonitor progressMonitor) throws IOException {
parseFile(tcxFile);
GpxData gpxData = getGpxData();
gpxData.storageFile = tcxFile;
GpxLayer gpxLayer = new GpxLayer(gpxData, tcxFile.getName());
Main.getLayerManager().addLayer(gpxLayer);
if (Main.pref.getBoolean("marker.makeautomarkers", true)) {
MarkerLayer ml = new MarkerLayer(gpxData, tr("Markers from {0}", tcxFile.getName()), tcxFile, gpxLayer);
if (ml.data.size() > 0) {
Main.getLayerManager().addLayer(ml);
}
}
}
/**
*
*/
@SuppressWarnings("unchecked") private void parseFile(File tcxFile) {
try {
JAXBContext jc = JAXBContext
.newInstance(TrainingCenterDatabaseT.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
JAXBElement<TrainingCenterDatabaseT> element = (JAXBElement<TrainingCenterDatabaseT>) unmarshaller
.unmarshal(tcxFile);
TrainingCenterDatabaseT tcd = element.getValue();
gpxData = new GpxData();
// Usually logged activities are in the activities tag.
parseDataFromActivities(tcd);
// GPS tracks in the course tag are generated by the user.
// Maybe not a good idea to import them.
parseDataFromCourses(tcd);
} catch (JAXBException e) {
throw new RuntimeException(e);
}
}
/** Convert a TrackpointT to a WayPoint.
* @param tp TrackpointT to convert
* @return tp converted to WayPoint, or null
*/
private static WayPoint convertPoint(TrackpointT tp) {
PositionT p = tp.getPosition();
if (p == null)
// If the TrackPointT lacks a position, return null.
return null;
WayPoint waypt = new WayPoint(new LatLon(p.getLatitudeDegrees(),
p.getLongitudeDegrees()));
Double altitudeMeters = tp.getAltitudeMeters();
if (altitudeMeters != null) {
waypt.attr.put("ele", altitudeMeters.toString());
}
XMLGregorianCalendar time = tp.getTime();
if (time != null) {
waypt.attr.put("time", time.toString());
waypt.time = .001 * time.toGregorianCalendar().getTimeInMillis();
}
return waypt;
}
private void parseDataFromActivities(TrainingCenterDatabaseT tcd) {
int lap = 0;
if ((tcd.getActivities() != null)
&& (tcd.getActivities().getActivity() != null)) {
for (ActivityT activity : tcd.getActivities().getActivity()) {
if (activity.getLap() != null) {
for (ActivityLapT activityLap : activity.getLap()) {
if (activityLap.getTrack() != null) {
XMLGregorianCalendar startTime = activityLap
.getStartTime();
Collection<Collection<WayPoint>> currentTrack = new ArrayList<>();
for (TrackT track : activityLap.getTrack()) {
if (track.getTrackpoint() != null) {
Collection<WayPoint> currentTrackSeg = new ArrayList<>();
currentTrack.add(currentTrackSeg);
for (TrackpointT tp :
track.getTrackpoint()) {
WayPoint waypt = convertPoint(tp);
if (waypt != null) {
if (startTime != null) {
waypt.attr.put("name", "LAP"
+ (++lap));
gpxData.waypoints.add(waypt);
startTime = null;
}
currentTrackSeg.add(waypt);
}
}
}
}
gpxData.tracks.add(new ImmutableGpxTrack(currentTrack, Collections.<String, Object>emptyMap()));
}
}
}
}
}
}
private void parseDataFromCourses(TrainingCenterDatabaseT tcd) {
if ((tcd.getCourses() != null)
&& (tcd.getCourses().getCourse() != null)) {
for (CourseT course : tcd.getCourses().getCourse()) {
if (course.getTrack() != null) {
Collection<Collection<WayPoint>> currentTrack = new ArrayList<>();
for (TrackT track : course.getTrack()) {
if (track.getTrackpoint() != null) {
Collection<WayPoint> currentTrackSeg = new ArrayList<>();
currentTrack.add(currentTrackSeg);
for (TrackpointT tp : track.getTrackpoint()) {
WayPoint waypt = convertPoint(tp);
if (waypt != null) {
currentTrackSeg.add(waypt);
}
}
}
}
gpxData.tracks.add(new ImmutableGpxTrack(currentTrack, Collections.<String, Object>emptyMap()));
}
}
}
}
private GpxData getGpxData() {
return gpxData;
}
}