BarGolf.net

HST2KML (Garmin HST to Google Earth KML conversion)

This is a fairly simple PHP script designed to run as a CGI (although could easily be adapted to run from a command line) that translates a Garmin HST file into Google Earth KML. Its main use is for ‘on-the-fly’ conversions of MyMotionBased users MotionBased activities into somewhat prettier KML that the standard MotionBased.com conversion manages.

The conversion translates speed from the HST into the Z-Axis (height), and also colour code’s the segment based on heart-rate information (if available). It also provides waypoint information such as maximum speed, distance, calories etc.

Download HST2KML source.


/*
hst2kml, simple PHP script to convert Garmin Training Centre .HST files into Google Earth compatible KML
Copyright (C) 2006 Matthew Underwood

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

*/

if($_REQUEST["file"])
{
$szTitle = 'Import of '.$szFile;
if($_REQUEST["title"])
$szTitle = $_REQUEST["title"];
ConvertHstFile($_REQUEST["file"], $szTitle);
}
else
{
header("HTTP/1.0 404 Not Found");
}

function ConvertHstFile($szFile, $szTitle)
{
header("content-disposition: attachment;filename=\"MyMotionBasedExport.kml\"");
header("content-type: application/vnd.google-earth.kml+xml");
echo '';
echo '';

// not interested in the namespace
$sxmltxt=file_get_contents($szFile);
$sxmltxt=str_replace('xmlns=','a=',$sxmltxt);
$objHst=simplexml_load_string($sxmltxt);

echo '';
echo ''.$szTitle.'';

$arrRuns = $objHst->xpath('//Running');
if((count($arrRuns) > 0)&&(count($arrRuns[0]) > 0))
{
ShowRuns($arrRuns[0],"Running");
}

$arrRuns = $objHst->xpath('//Biking');
if((count($arrRuns) > 0)&&(count($arrRuns[0]) > 0))
{
ShowRuns($arrRuns[0],"Biking");
}

$arrRuns = $objHst->xpath('//Other');
if((count($arrRuns) > 0)&&(count($arrRuns[0]) > 0))
{
ShowRuns($arrRuns[0],"Other");
}

$arrMultiSportSessions = $objHst->xpath('//MultiSport//MultiSportSession');
if(count($arrMultiSportSessions) > 0)
{
ShowMultiSportSessions($arrMultiSportSessions);
}

echo '';
echo '';
}

function ShowRuns($arrRuns, $szType)
{
echo '';
echo ''.$szType.'';
if(isset($arrRuns->Notes))
{
echo '';
echo $arrRuns->Notes;
echo '
';
}

foreach($arrRuns as $arrRun)
{
ShowRun($arrRun);
}
echo '';
}

function ShowRun($arrRun, $szType = false)
{
echo '';
echo '';
if($szType !== false)
echo $szType.' - ';
echo FormatTime($arrRun->Lap["StartTime"],"%c").'
';

$szDescr = "

";

$fTotalTimeSeconds = GetLapTotal($arrRun,"TotalTimeSeconds");
if($fTotalTimeSeconds !== false)
$szDescr .= "

";

$fTotalDistanceMetres = GetLapTotal($arrRun,"DistanceMeters");
if($fTotalDistanceMetres !== false)
$szDescr .= "

";

$fMaximumSpeedMs = GetLapMaximum($arrRun,"MaximumSpeed");
if($fMaximumSpeedMs !== false)
$szDescr .= "

";

$fTotalCalories = GetLapTotal($arrRun,"Calories");
if($fTotalCalories !== false)
$szDescr .= "

";

$fAverageHeartRateBpm = GetLapTotal($arrRun,"AverageHeartRateBpm");
if($fAverageHeartRateBpm !== false)
$szDescr .= "

";

$fMaximumHeartRateBpm = GetLapMaximum($arrRun,"MaximumHeartRateBpm");
if($fMaximumHeartRateBpm !== false)
$szDescr .= "

";

if(isset($arrRun->Notes))
{
$szDescr .= "

";
}

$szDescr .= "

Duration ".gmstrftime("%H:%M:%S", round($fTotlTimeSeconds))."
Distance ".($fTotalDistanceMetres/1000)."km
Max Speed ".($fMaximumSpeedMs*3600/1000)."kp/h
Calories ".$fTotalCalories."
Avg HR ".$fAverageHeartRateBpm / count($arrRun->Lap)."bpm
Max HR ".$fMaximumHeartRateBpm."bpm
Notes ".$arrRun->Notes."

";

if($szDescr != "")
{
echo '';
echo ' echo $szDescr;
echo ']]>';
echo '
';
}

ShowLaps($arrRun, $lat, $long);

echo '';
echo ''.$long.'';
echo ''.$lat.'';
echo '1000';
echo '10';
echo '0';
echo '
';
echo '';
}

function GetLapTotal($arrRun,$szItem)
{
$fTotal = false;

foreach($arrRun->Lap as $arrLap)
{
if(isset($arrLap->$szItem))
{
if($fTotal === false)
$fTotal = 0;

$fTotal += $arrLap->$szItem;
}
}

return $fTotal;
}

function GetLapMaximum($arrRun,$szItem)
{
$fMax = false;

foreach($arrRun->Lap as $arrLap)
{
if(isset($arrLap->$szItem))
{
if($fMax === false)
$fMax = $arrLap->$szItem;
else
$fMax = max($fMax, $arrLap->$szItem);
}
}

return $fMax;
}

function ShowMultiSportSessions($arrMultiSportSessions)
{
echo '';
echo 'MultiSport Sessions';
if(isset($arrMultiSportSessions->Notes))
{
echo '';
echo $arrMultiSportSessions->Notes;
echo '
';
}

foreach($arrMultiSportSessions as $arrMultiSportSession)
{
ShowMultiSportSession($arrMultiSportSession);
}

echo '';
}

function ShowMultiSportSession($arrMultiSportSession)
{
echo '';
echo 'MultiSport Session - ';
echo FormatTime($arrMultiSportSession->FirstSport->Run->Lap[0]["StartTime"],"%c");
echo '
';
if(isset($arrMultiSportSession->Notes))
{
echo '';
echo $arrMultiSportSession->Notes;
echo '
';
}

ShowRun($arrMultiSportSession->FirstSport[0]->Run,$arrMultiSportSession->FirstSport["Sport"]);

if(isset($arrMultiSportSession->NextSport))
{
foreach($arrMultiSportSession->NextSport as $arrNextSport)
{
ShowRun($arrNextSport->Run,$arrNextSport["Sport"]);
}
}

echo '';
}

function FormatTime($szHSTTime, $szFmt)
{
$t = strtotime($szHSTTime);
return strftime($szFmt, $t);
}

function ShowLaps($arrRun,&$lat,&$long)
{
$iLap = 0;
foreach($arrRun->Lap as $lap)
{
$iLap++;

echo '';
echo 'Lap '.$iLap.'';
$szDescription = '

';

if(isset($lap['StartTime']))
$szDescription .= '

";

if(isset($lap->DistanceMeters))
$szDescription .= '

";

if(isset($lap->TotalTimeSeconds))
{
$szDescription .= '

";
}

if(isset($lap->Notes))
{
$szDescription .= "

";
}

$szDescription .= '

Started '.$lap['StartTime']."
Distance '.$lap->DistanceMeters."m
Time '.strftime("%-Mm:%Ss",round($lap->TotalTimeSeconds))."
Notes ".$lap->Notes."

';

echo '';

ShowTrackPoints($lap->Track->Trackpoint,$lat,$long);

echo '';
echo ''.$long.'';
echo ''.$lat.'';
echo '1000';
echo '10';
echo '0';
echo '
';

echo '';
}
}

function ShowTrackPoints($arrTrackpoints,&$lat,&$long)
{
$lastBpm = 0;
$oldLat = false;
$oldLong = false;
$oldTime = false;
$oldSpeed = 0;

foreach($arrTrackpoints as $xmlTrackpoint)
{
if(isset($xmlTrackpoint->HeartRateBpm))
$lastBpm = $xmlTrackpoint->HeartRateBpm;

if(isset($xmlTrackpoint->Position->LongitudeDegrees) && isset($xmlTrackpoint->Position->LatitudeDegrees))
{
$szColor = "7f00ff00";

if($lastBpm > 167)
$szColor = "7f0000ff";
else if($lastBpm > 148)
$szColor = "7f0099ff";
else if($lastBpm > 130)
$szColor = "7f00ff99";
else if($lastBpm > 111)
$szColor = "7f00ff66";

$time = strtotime($xmlTrackpoint->Time);

$a1 = deg2rad($oldLat);
$b1 = deg2rad($oldLong);
$a2 = deg2rad($xmlTrackpoint->Position->LatitudeDegrees);
$b2 = deg2rad($xmlTrackpoint->Position->LongitudeDegrees);

if($oldLat === false)
{
$dist = 0;
$speed = 0;
$lat = $xmlTrackpoint->Position->LatitudeDegrees;
$long = $xmlTrackpoint->Position->LongitudeDegrees;
}
else
{
$r = 637800; // Earth radius in metres
// distance is in metres as well then
//
// Formulae from http://jan.ucc.nau.edu/~cvm/latlongdist.html
//
// Chris.Michels@nau.edu
//

$dist = acos(cos($a1)*cos($b1)*cos($a2)*cos($b2) + cos($a1)*sin($b1)*cos($a2)*sin($b2) + sin($a1)*sin($a2)) * $r;

// speed in m/s is
$speed = $dist / ($time - $oldTime) * 10;
}

$szDescription = '

';

$szDescription .= '

';

if(isset($xmlTrackpoint->AltitudeMeters))
{
$szDescription .= "

';
}

$szDescription .= "

";

if(isset($xmlTrackpoint->Notes))
{
$szDescription .= "

";
}

if($oldLat !== false)
{
echo '';
echo '';
echo FormatTime($xmlTrackpoint->Time,"%c");
echo '
';
echo '';
echo '1';
echo '';
echo ''.$xmlTrackpoint->Position->LongitudeDegrees.'';
echo ''.$xmlTrackpoint->Position->LatitudeDegrees.'';
echo '1000';
echo '10';
echo '0';
echo '
';
echo '0';
echo '';
echo '';
echo '1';
echo '1';
echo 'relativeToGround';
echo '';

echo $oldLong.',';
echo $oldLat.',';
echo ($oldSpeed * 10)."\r\n";

echo $xmlTrackpoint->Position->LongitudeDegrees.',';
echo $xmlTrackpoint->Position->LatitudeDegrees.',';
echo ($speed * 10)."\r\n";

echo '';
echo '';
echo '';
}

$oldLat = $xmlTrackpoint->Position->LatitudeDegrees;
$oldLong = $xmlTrackpoint->Position->LongitudeDegrees;
$oldTime = $time;
$oldSpeed = $speed;
}
}
}

?>

Looking for something?

Use the form below to search the site:

Still not finding what you're looking for? Drop a comment on a post or contact us so we can take care of it!

HR '.$lastBpm.'bpm
Altitude ".round($xmlTrackpoint->AltitudeMeters).'m
Speed ".(round($speed * 3600 / 100) / 10)."kph
Notes ".$xmlTrackpoint->Notes."