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 .= "
Duration
".gmstrftime("%H:%M:%S", round($fTotlTimeSeconds))."
";
$fTotalDistanceMetres = GetLapTotal($arrRun,"DistanceMeters");
if($fTotalDistanceMetres !== false)
$szDescr .= "
Distance
".($fTotalDistanceMetres/1000)."km
";
$fMaximumSpeedMs = GetLapMaximum($arrRun,"MaximumSpeed");
if($fMaximumSpeedMs !== false)
$szDescr .= "
Max Speed
".($fMaximumSpeedMs*3600/1000)."kp/h
";
$fTotalCalories = GetLapTotal($arrRun,"Calories");
if($fTotalCalories !== false)
$szDescr .= "
Calories
".$fTotalCalories."
";
$fAverageHeartRateBpm = GetLapTotal($arrRun,"AverageHeartRateBpm");
if($fAverageHeartRateBpm !== false)
$szDescr .= "
Avg HR
".$fAverageHeartRateBpm / count($arrRun->Lap)."bpm
";
$fMaximumHeartRateBpm = GetLapMaximum($arrRun,"MaximumHeartRateBpm");
if($fMaximumHeartRateBpm !== false)
$szDescr .= "
Max HR
".$fMaximumHeartRateBpm."bpm
";
if(isset($arrRun->Notes))
{
$szDescr .= "
Notes
".$arrRun->Notes."
";
}
$szDescr .= "
";
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 .= '
Started
'.$lap['StartTime']."
";
if(isset($lap->DistanceMeters))
$szDescription .= '
Distance
'.$lap->DistanceMeters."m
";
if(isset($lap->TotalTimeSeconds))
{
$szDescription .= '
Time
'.strftime("%-Mm:%Ss",round($lap->TotalTimeSeconds))."
";
}
if(isset($lap->Notes))
{
$szDescription .= "
Notes
".$lap->Notes."
";
}
$szDescription .= '
';
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 .= '
HR
'.$lastBpm.'bpm
';
if(isset($xmlTrackpoint->AltitudeMeters))
{
$szDescription .= "
Altitude
".round($xmlTrackpoint->AltitudeMeters).'m
';
}
$szDescription .= "
Speed
".(round($speed * 3600 / 100) / 10)."kph
";
if(isset($xmlTrackpoint->Notes))
{
$szDescription .= "
Notes
".$xmlTrackpoint->Notes."
";
}
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!
Archives
All entries, chronologically...