Skip to content

Instantly share code, notes, and snippets.

@k9ordon
Created July 16, 2012 08:35
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save k9ordon/3121560 to your computer and use it in GitHub Desktop.
Save k9ordon/3121560 to your computer and use it in GitHub Desktop.
exports nike+ runs to gpx
<pre>
strt importing gpx files ...
<?php
require_once 'lib/init.php'; // init $n stuff (login)
$dir = "import";
$runs = $n->activities();
foreach($runs->activities as $a) {
$runId = $a->activityId;
$fileName = sprintf('%s/%s.gpx', $dir, $runId);
if(!file_exists($fileName)) {
echo "importing run " . $fileName . "\n";
$run = $n->run($runId);
if($run === NULL) {
echo "cannot import " . $runId . "\n";
continue;
}
file_put_contents($fileName, $n->toGpx($run));
}
}
?>
eof
<?
class NikePlusPHPGpxExport extends NikePlusPHP {
/**
* toGpx()
* outputs a run object to a runtastic importable gpx document
*
* @param object $run output from run()
*
* @return string gpx string
*/
public function toGpx($run) {
$activity = $run->activity;
$waypoints = $run->activity->geo->waypoints;
$startTime = strtotime($run->activity->startTimeUtc);
$name = 'Nike+ ' . $run->activity->name;
$description = $run->activity->tags->note;
$heartRate = null;
$distance = null;
foreach($run->activity->history as $hi) {
if($hi->type == 'HEARTRATE') $heartRate = $hi;
if($hi->type == 'DISTANCE') $distance = $hi;
}
$b = new XMLWriter();
$b->openMemory();
$b->setIndent(true);
$b->setIndentString(" ");
$b->startDocument("1.0", "UTF-8");
$b->startElement('gpx');
$b->writeAttribute('version', '0.1');
$b->writeAttribute('creator', 'nikeplusphp');
$b->writeAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
$b->writeAttribute('xmlns', 'http://www.topografix.com/GPX/1/1');
$b->writeAttribute('xsi:schemaLocation', 'http://www.topografix.com/GPX/1/1 http://www.topografix.com/gpx/1/1/gpx.xsd');
$b->writeAttribute('xmlns:gpxtpx', 'http://www.garmin.com/xmlschemas/TrackPointExtension/v1');
$b->writeAttribute('xmlns:gpxx', 'http://www.garmin.com/xmlschemas/GpxExtensions/v3');
// metadata
$b->startElement('metadata');
$b->writeElement('name', $name);
$b->writeElement('desc', $description);
// get min/max lat/lng
$minLon = 10000;
$maxLon = -10000;
$minLat = 10000;
$maxLat = -10000;
foreach($waypoints as $wp) {
if($wp->lon > $maxLon) $maxLon = $wp->lon;
if($wp->lon < $minLon) $minLon = $wp->lon;
if($wp->lat > $maxLat) $maxLat = $wp->lat;
if($wp->lat < $minLat) $minLat = $wp->lat;
}
$b->startElement('bounds');
$b->writeAttribute('maxlon', $maxLon);
$b->writeAttribute('minlon', $minLon);
$b->writeAttribute('maxlat', $maxLat);
$b->writeAttribute('minlat', $minLat);
$b->endElement(); // EO bounds
$b->endElement(); // EO metadata
// track
$b->startElement('trk');
$b->writeElement('name', 'trkName ' . time());
$b->writeElement('type', 'Run');
$b->startElement('trkseg');
foreach($waypoints as $index => $wp) {
$b->startElement('trkpt');
$b->writeAttribute('lat', $wp->lat);
$b->writeAttribute('lon', $wp->lon);
$b->writeElement('ele', $wp->ele);
$b->writeElement('time', date('Y-m-d\TH:i:s', $startTime+$index));
$b->startElement('extensions');
$b->startElement('gpxtpx:TrackPointExtension');
if($heartRate !== null) {
$hrKey = (int) floor($index/$heartRate->intervalMetric);
if(array_key_exists($hrKey, $heartRate->values)) {
$b->writeElement('gpxtpx:hr', $heartRate->values[$hrKey]);
}
}
$b->endElement(); // EO gpxtpx:TrackPointExtension
$b->endElement(); // EO extensions
$b->endElement(); // EO trkpt
}
$b->endElement(); // EO trkseg
$b->endElement(); // EO trk
$b->endElement(); // EO gpx
$b->endDocument();
return $b->outputMemory();
}
}
@babydraz
Copy link

babydraz commented Nov 8, 2012

I only found this issue after I imported a GPX file into another running app and was told I'd managed to run at over 17 miles per hour. I don't know if this is the result of a change by Nike or if it's always been an issue. $index taken from the way points array is not a duration reference, so the times being set for each way point in the GPX are wrong. For whatever reason the Nike output does not include a time or duration value with their way point data. They do have separate KM and Mile split arrays which include a duration for each point, but then you lose a load of way points and I imagine the map would be messed up. The only solution I could come up with was to create an even increment based on the duration and number of way points.

$incr = ($duration/1000)/count($waypoints);
foreach($waypoints as $index => $wp) {
...
if ($index == 0) {
$b->writeElement('time', date('Y-m-d\TH:i:s', $startTime));
} else if ($index == (count($waypoints) - 1)) {
$b->writeElement('time', date('Y-m-d\TH:i:s', $startTime+($duration/1000)));
} else {
$b->writeElement('time', date('Y-m-d\TH:i:s', $startTime+($incr*$index)));
}
...
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment