packages feed

gps2htmlReport (empty) → 0.1

raw patch · 9 files changed

+516/−0 lines, 9 filesdep +Chartdep +basedep +cairosetup-changed

Dependencies added: Chart, base, cairo, colour, data-accessor, directory, filepath, gd, gps, html, process, random, time, xsd

Files

+ Data/GPS/Gps2HtmlReport/HTMLGenerator.hs view
@@ -0,0 +1,84 @@+{-# LANGUAGE ScopedTypeVariables  #-}++-- | The `HTMLGenerator' module generates the HTML content for the index.html generated+module Data.GPS.Gps2HtmlReport.HTMLGenerator where++import Text.Html+import Data.GPS hiding (src,link,href)+import Text.Printf+import Data.Maybe++import Data.GPS.Gps2HtmlReport.JourneyStats++-- | Takes all the WayPoints and generates the HTML file+generateHtmlPage :: [WptType] -> Html+generateHtmlPage points = +   let header1 = h1 $ stringToHtml "Journey Statistics"+       header2 = h1 $ stringToHtml "Charts of the Journey"+       header3 = h1 $ stringToHtml "OpenStreetMap Chart"+       title = thetitle $ stringToHtml "GPX Track Report"+       theStyle = style (stringToHtml cssContent) ! [thetype "text/css"]+       theHeader = header $ concatHtml [title,theStyle]+       mainArea = thediv (concatHtml [header1,statsTable points,br,header2,chartTable,header3,osmImg]) -- ! [identifier "main"]+       theBody = body mainArea+   in concatHtml [theHeader,theBody,pgFooter]++-- | The OpenStreetMap image area+osmImg :: Html+osmImg = center $ image ! [src "osm.png"]++-- | Takes all the WayPoints and calculates the journey statistics+statsTable :: [WptType] -> Html+statsTable points = +   let tblHeader1 = th $ stringToHtml "Journey Details"+       tblHeader2 = th $ stringToHtml "Elevation"+       tblHeader3 = th $ stringToHtml "Speed"+       distTravelled = printf "%.2f" $ journeyDistance points+       maybeMaxElePt = findPoint points (head points) ele (>)+       maybeMinElePt = findPoint points (head points) ele (<)+       maxElevation = printf "%.1f" (if isJust maybeMaxElePt then snd $ fromJust maybeMaxElePt else 0.0)+       minElevation = printf "%.1f" (if isJust maybeMinElePt then snd $ fromJust maybeMinElePt else 0.0)+       meanEle = printf "%.1f" $ meanElevation points+       journeyMins = show $ round (journeyTime points) `div` 60+       journeySecs = show $ round (journeyTime points) `rem` 60+       mxSpd = printf "%.1f" $ maxSpeed points+       meanSpd = printf "%.1f" $ meanJourneySpeed points+       maybeDateOfJourney = dateOfJourney points+       journeyDate = (if isJust maybeDateOfJourney then show $ fromJust maybeDateOfJourney else "") +       li1c1 = li $ stringToHtml ("Journey Date: "++ journeyDate)+       li2c1 = li $ stringToHtml ("Distance Travelled: "++ distTravelled++"m")+       li3c1 = li $ stringToHtml ("Journey Time: "++journeyMins++"m "++journeySecs++"s")+       li1c2 = li $ stringToHtml ("Maximum Elevation: "++ maxElevation++"m")+       li2c2 = li $ stringToHtml ("Minimum Elevation: "++minElevation++"m")+       li3c2 = li $ stringToHtml ("Mean Elevation: "++ meanEle++"m")+       li1c3 = li $ stringToHtml ("Maximum speed: "++ mxSpd++"m/s")+       li2c3 = li $ stringToHtml ("Mean speed: "++meanSpd++"m/s")+       col1 = td (concatHtml [li1c1,li2c1,li3c1]) ! [valign "top"]+       col2 = td  (concatHtml [li1c2,li2c2,li3c2]) ! [valign "top"]+       col3 = td  (concatHtml [li1c3,li2c3]) ! [valign "top"]+       row1 = tr $ concatHtml [tblHeader1,tblHeader2,tblHeader3]+       row2 = tr $ concatHtml [col1,col2,col3]+       tbl = table (concatHtml [row1,row2]) -- ! [cellspacing 10]+   in center tbl+   +-- | The CSS style text to format the rendering of the HTML page. It would be good to replace with Haskell HTML combinator library functions+cssContent = "h1 {font-size: 22px;color: #335577;font-weight: bold; margin-top: 20px;margin-left: 70px;font-family: New Century Schoolbook, serif;} div {    width: 900px; margin-top: 50px; margin:0 auto;} table {border-spacing: 20px 0px;} footer {text-align:right; background-color:#EEEEEE; width:900px; margin:0 auto; margin-top: 30px}"++-- | The area holding the Cairo charts+chartTable = +   let img1 = image ! [src "chart1.png"]+       img2 = image ! [src "chart2.png"]+       cell1 =  td img1+       cell2 = td img2+       row1 = tr $ concatHtml [cell1,cell2]+       tbl = table row1+   in center tbl++-- | The footer+pgFooter = +   let projectLink = anchor (stringToHtml "gps2htmlReport") ! [href "https://github.com/robstewart57/Gps2HtmlReport"]+       infoStr = stringToHtml "Report generated by "+   in footer (concatHtml [infoStr,projectLink]) ! [identifier "main"]++-- | This appears to be missing from the `html' package+footer = tag "FOOTER"
+ Data/GPS/Gps2HtmlReport/JourneyCharts.hs view
@@ -0,0 +1,114 @@+-- | This module uses the JourneyStats module to generate+-- the statistics about the journey WayPoints, then+-- uses the Cairo bindings to generate the charts+module Data.GPS.Gps2HtmlReport.JourneyCharts where++import Data.GPS+import Data.Maybe+import Graphics.Rendering.Chart+import Data.Accessor+import Data.Colour+import Data.Colour.Names++import Data.GPS.Gps2HtmlReport.JourneyStats++data OutputType = Window | PNG | PS | PDF | SVG++chooseLineWidth Window = 1.0+chooseLineWidth PNG = 1.0+chooseLineWidth PDF = 0.25+chooseLineWidth PS = 0.25+chooseLineWidth SVG = 0.25++-- | Generates the Cairo chart showing speed and elevation over time+speedAndElevationOverTimeChart :: [WptType] -> OutputType -> Renderable ()+speedAndElevationOverTimeChart points otype = toRenderable layout+  where+    layout = layout1_title ^="Speed, Average Speed & Elevation"+           $ layout1_title_style ^= defaultFontStyle { font_size_ = 12.0 }+           $ layout1_background ^= solidFillStyle (opaque white)+           $ layout1_right_axis ^= defaultLayoutAxis { laxis_title_ = "Elevation (metres)", laxis_override_ = axisGridHide }+           $ layout1_left_axis ^: laxis_title ^= "Speed (metres)"+ 	   $ layout1_plots ^= [ Right (toPlot elevationArea),+                                Left (toPlot speedLine),+                                Left (toPlot avrSpeedLine)  +                              ]+           $ setLayout1Foreground fg+           defaultLayout1++    lineStyle c = line_width ^= 1 * chooseLineWidth otype+                $ line_color ^= c+                $ defaultPlotLines ^. plot_lines_style++    theSpeeds = [(theTime,spd) | (theTime,spd) <- speedAtPoints points]++    speedLine = plot_lines_style ^= lineStyle (opaque blue)+           $ plot_lines_values ^= [[ (theTime,speed) | (theTime,speed) <- theSpeeds]]+           $ plot_lines_title ^= "Speed"+           $ defaultPlotLines++    avrSpeedLine = plot_lines_style ^= lineStyle (red `withOpacity` 0.5)+           $ plot_lines_values ^= [[ (theTime,speed) | (theTime,speed) <- avrSpeedOverTime theSpeeds 0.0 0.0 []]]+           $ plot_lines_title ^= "Avr Speed"+           $ defaultPlotLines ++    elevationArea = plot_fillbetween_style ^= solidFillStyle (green `withOpacity` 0.1)+           $ plot_fillbetween_values ^= [ (theTime,(0,elevation)) | (theTime,elevation) <- ptsElevation points]+           $ plot_fillbetween_title ^= "Elevation"+           $ defaultPlotFillBetween++    fg = opaque black+++-- |  Generates the Cairo chart showing accumulative distance and elevation over time, with spots showing maximum and minimum elevation points+accumDistanceAndElevationChart :: [WptType] -> OutputType -> Renderable ()+accumDistanceAndElevationChart points otype = toRenderable layout+  where+    layout = layout1_title ^="Accumulative Distance & Elevation"+           $ layout1_title_style ^= defaultFontStyle { font_size_ = 12.0 }+           $ layout1_background ^= solidFillStyle (opaque white)+           $ layout1_right_axis ^= defaultLayoutAxis { laxis_title_ = "Distance (metres)", laxis_override_ = axisGridHide }+           $ layout1_left_axis ^: laxis_title ^= "Elevation (metres)"+           $ layout1_plots ^= [ Right (toPlot accumDistanceArea),+                                Left (toPlot elevationLine),+                                Left (toPlot spots)+                              ]+           $ setLayout1Foreground fg+           defaultLayout1++    lineStyle c = line_width ^= 1 * chooseLineWidth otype+                $ line_color ^= c+                $ defaultPlotLines ^. plot_lines_style++    elevationLine = plot_lines_style ^= lineStyle (opaque black)+           $ plot_lines_values ^= [[ (theTime,elevation) | (theTime,elevation) <- ptsElevation points]]+           $ plot_lines_title ^= "Elevation"+           $ defaultPlotLines ++    accumDistanceArea = plot_fillbetween_style ^= solidFillStyle (red `withOpacity` 0.2)+           $ plot_fillbetween_values ^= [ (theTime,(0,accumDist)) | (theTime,accumDist) <- accumDistance points 0.0]+           $ plot_fillbetween_title ^= "Distance"+           $ defaultPlotFillBetween++    spotMaxPoint = let point = findPoint points (head points) ele (>)+                   in (if isJust point then Just (fst $ fromJust point, snd $ fromJust point, 5 :: Double) else Nothing)++    spotMinPoint = let point = findPoint points (head points) ele (<)+                   in (if isJust point then Just (fst $ fromJust point, snd $ fromJust point, 5 :: Double) else Nothing)++    spots = area_spots_title ^= "Altitude"+          $ area_spots_max_radius ^= 5+          $ area_spots_values ^= (if  isJust spotMinPoint && isJust spotMaxPoint then [fromJust spotMinPoint,fromJust spotMaxPoint] else [])+          $ defaultAreaSpots++    fg = opaque black++renderToPng :: (t, OutputType -> Renderable a) -> FilePath -> IO (PickFn a)+renderToPng (_,ir) = renderableToPNGFile (ir Window) 384 288++chart1 :: [WptType] -> (String, OutputType -> Renderable ())+chart1 points = ("speedAndElevationOverTimeChart", speedAndElevationOverTimeChart points)++chart2 :: [WptType] -> (String, OutputType -> Renderable ())+chart2 points = ("accumDistanceAndElevationChart", accumDistanceAndElevationChart points)+
+ Data/GPS/Gps2HtmlReport/JourneyStats.hs view
@@ -0,0 +1,107 @@+-- | This module provides the JourneyCharts and HTMLGenerator +-- modules with statistics for the charts, and the journey statistics+module Data.GPS.Gps2HtmlReport.JourneyStats where++import Data.GPS hiding (speed)+import Data.Maybe+import Data.Time.LocalTime+import Data.Time.Clock+import Data.Time.Calendar+import Text.XML.XSD.DateTime++-- | Takes all WayPoints, and creates a list of tuples containing (TimeStamp,Elevation)+ptsElevation :: [WptType] -> [(LocalTime,Double)]+ptsElevation = map (\point -> (utcToLocalTime dfltTZ (Text.XML.XSD.DateTime.toUTCTime (fromJust $ time point)) , fromJust $ ele point))++-- | Takes all WayPoints, and creates a list of tuples containing (TimeStamp,AvrSpeedAtThisPoint)+avrSpeedOverTime :: [(LocalTime,Speed)] -> Double -> Double -> [(LocalTime,Speed)] -> [(LocalTime,Speed)]+avrSpeedOverTime [] _ _ _ = []+avrSpeedOverTime [spd] totalSpeed numPoints iteratedAvr = iteratedAvr ++ [(fst spd, (snd spd + totalSpeed) / (numPoints+1))]+avrSpeedOverTime (spd:spds) totalSpeed numPoints iteratedAvr = avrSpeedOverTime [spd] totalSpeed numPoints iteratedAvr ++ avrSpeedOverTime spds (snd spd + totalSpeed) (numPoints+1) iteratedAvr++-- | Takes all WayPoints, and creates a list of tuples containing (TimeStamp,SpeedAtThisPoint) +speedAtPoints :: [WptType] -> [(LocalTime,Speed)]+speedAtPoints [] = []+speedAtPoints (point:points) = (lclTime $ fromJust (time point),0.0) : speedAtPoints' point points++speedAtPoints' :: WptType -> [WptType] -> [(LocalTime, Speed)]+speedAtPoints' _ [] = []+speedAtPoints' prev [x]+         | isJust (time x) = [(lclTime $ fromJust (time x), fromJust $ speed prev x)]+         | otherwise = []+speedAtPoints' prev (x:xs)+         | isJust (time x) = (lclTime $ fromJust (time x), fromJust $ speed prev x) : speedAtPoints' x xs+         | otherwise = [] ++ speedAtPoints' x xs++-- | Takes all WayPoints, and creates a list of tuples containing (TimeStamp,JourneyDistanceAtPoint)+accumDistance :: [WptType] -> Double -> [(LocalTime,Distance)]+accumDistance [] _ = []+accumDistance [x] _ = [(lclTime $ fromJust (time x),0.0)]+accumDistance (x:xs) acc = +   let dist = distance x (head xs)           +   in (lclTime $ fromJust (time x), dist + acc ) : accumDistance (tail xs) (dist + acc)++-- | Takes all WayPoints, an element in wptType, and an Eq function, returning a single WayPoint+findPoint :: [WptType] -> WptType -> (WptType -> Maybe Double) -> (Double -> Double -> Bool) -> Maybe (LocalTime,Double)+findPoint [] _ _ _ = Nothing+findPoint (point:points) currSelected wayPointElement equalityF+   | equalityF (fromJust $ wayPointElement point) (fromJust $ wayPointElement currSelected) = findPoint points point wayPointElement equalityF+   | otherwise = if null points+                      then Just (lclTime (fromJust $ time currSelected), fromJust $ ele currSelected)+                      else findPoint points currSelected wayPointElement equalityF++-- | Calculates the total journey distance+journeyDistance :: (Lat a, Lon a) => [a] -> Distance+journeyDistance [] = 0.0+journeyDistance [_] = 0.0+journeyDistance (point:points) = distance point (head points) + journeyDistance points++-- | Calculates the average speed of the journey+meanJourneySpeed :: (Lat a, Lon a) => [a] -> Distance+meanJourneySpeed points = journeyDistance points / fromIntegral (length points)++-- | Calculates the maximum speed+maxSpeed :: [WptType] -> Speed+maxSpeed points =+            let speedTuple = speedAtPoints points+                speedList = map snd speedTuple+                maxSpeed = foldr max 0.0 speedList+            in maxSpeed++-- | Calculates the average elevation throughout the journey+meanElevation :: Ele a => [a] -> Double+meanElevation points = +            let elevationVals = map (fromJust . ele) points+                totalElevation = foldr (+) 0.0 elevationVals+                theMean = totalElevation / fromIntegral (length points)+            in theMean++-- | Calculates the total journey time+journeyTime :: Time a => [a] -> NominalDiffTime+journeyTime [] = fromInteger 0+journeyTime [_] = fromInteger 0+journeyTime (point:points) = +             let startTime = toUTCTime (fromJust (time point))+                 endTime = toUTCTime (fromJust (time $ last points))+             in diffUTCTime endTime startTime++-- | Extracts the date of the journey (from the first WayPoint)+dateOfJourney :: Time a => [a] -> Maybe Day+dateOfJourney [] = Nothing+dateOfJourney (point:_) = Just $ utctDay $ toUTCTime $ fromJust (time point)++lclTime :: DateTime -> LocalTime+lclTime dteTime = utcToLocalTime dfltTZ (Text.XML.XSD.DateTime.toUTCTime dteTime)++dfltTZ :: TimeZone+dfltTZ = TimeZone {timeZoneMinutes=0,timeZoneSummerOnly=False,timeZoneName="GMT"}++-- | Overides the `speed' function in the `gps' package+speed :: (Lat loc, Lon loc, Time loc) => loc -> loc -> Maybe Speed+speed a b = +	case (getUTCTime b, getUTCTime a) of+		(Just x, Just y) -> Just $ distance a b / realToFrac (diffUTCTime x y) +		_ -> Nothing++getUTCTime :: (Lat a, Lon a, Time a) => a -> Maybe UTCTime+getUTCTime = fmap toUTCTime . time
+ Data/GPS/Gps2HtmlReport/Main.hs view
@@ -0,0 +1,41 @@+module Main where++import Data.GPS+import System.FilePath+import System.Directory+import Text.Html++import Data.GPS.Gps2HtmlReport.OsmChart+import Data.GPS.Gps2HtmlReport.HTMLGenerator+import Data.GPS.Gps2HtmlReport.JourneyCharts++-- | Reads the current directory for all .gpx files, then maps to `generateReport' for each one+main :: IO [()]+main = do+   curDir <- getCurrentDirectory+   allFiles <- getDirectoryContents curDir+   let allFilesSplit = map splitExtension allFiles+   let gpxFiles = filter (\(_,b) -> b==".gpx") allFilesSplit+   putStr ("Processing "++show (length gpxFiles)++" file(s)...\n")+   mapM (\(a,b) -> generateReport (curDir++"/"++a) (a++b)) gpxFiles++-- | Creates empty directory for each web report+createEmptyDir :: FilePath -> IO ()+createEmptyDir dir = do+       exists <- doesDirectoryExist dir+       (if exists then removeDirectoryRecursive dir >> createDirectory dir else createDirectory dir)++-- | Generates the HTML report for each .gpx file+generateReport :: FilePath -> FilePath -> IO ()+generateReport webDir gpxFile  = do+         points <- readGPX gpxFile+         case length points of+          0 -> putStr "Unable to parse GPX file. Skipping..."+          otherwise -> do+           createEmptyDir webDir+           renderToPng (chart1 points) (webDir++"/chart1.png")+           renderToPng (chart2 points) (webDir++"/chart2.png")+           writeFile (webDir++"/index.html") $ renderHtml $ generateHtmlPage points+           createOsmMap webDir gpxFile+           putStr $ "Processing '"++gpxFile++"' complete. Report saved in: "++webDir++"/index.html\n"+           return ()
+ Data/GPS/Gps2HtmlReport/OsmChart.hs view
@@ -0,0 +1,40 @@+-- {-# LANGUAGE ScopedTypeVariables #-}++-- | This module utilizes the perl gpx2png program+-- to download the OSM tiles, and the GraphicsMagick bindings+-- to resize the OSM image if necessary+module Data.GPS.Gps2HtmlReport.OsmChart where++import System.FilePath+import System.Directory+import System.Process+import Graphics.GD+import Control.Monad++-- | If the generated OSM image has a greater width than 800 pixels, it is scaled to have a width of 800 pixels.+fitToWidth :: FilePath -> IO ()+fitToWidth imgPath = do+   img <- loadPngFile imgPath+   dimensions <- imageSize img+   let width = fst dimensions+   when (width > 800) $ resizeImg imgPath img dimensions++-- | Uses the GraphicsMagick bindings the resize the image+resizeImg :: FilePath -> Image -> (Int,Int) -> IO ()  +resizeImg imgPath img dimensions = do+   let resizeRatio = fromIntegral (fst dimensions) / 800.0+       height = round (fromIntegral (snd dimensions) / resizeRatio)+   resizedImg <- resizeImage 800 height img+   savePngFile imgPath resizedImg+       +-- | Calls the perl `gpx2png' utility to download the relevant OSM tiles+createOsmMap :: String -> String -> IO [()]+createOsmMap webDir gpxFile = do+   (_,_,_,pid) <- createProcess (shell ("perl gpx2png/gpx2png.pl -q -o "++webDir++"/osm.png "++ gpxFile))+   waitForProcess pid+   fitToWidth $ webDir++"/osm.png"+   curDir <- getCurrentDirectory+   allFiles <- getDirectoryContents curDir+   let allFilesSplit = map splitExtension allFiles+   let tmpPngFiles = filter (\(_,b) -> b==".png") allFilesSplit+   mapM (\(a,b) -> removeFile (a++b) ) tmpPngFiles
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Robert Stewart 2011++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of the author nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,74 @@+GPS 2 HTML Report+================++This is a utility written in Haskell, to generate HTML reports from GPS track files.++Included in the report:++* Details of the journey... journey time, distance travelled etc..+* Diagrams charting speed, elevation, accumulated distance etc..+* OpenStreetMap diagram highlighting the GPS track++An example can be seen [HERE](http://www.macs.hw.ac.uk/~rs46/gps2htmlreport/3/index.html).++The Haddock documentation pages can be found [here](http://www.macs.hw.ac.uk/~rs46/gps2htmlreport/doc/).++Installation+------------+It is assumed that you have the Haskell Platform installed.++Just run these commands to configure and install the `gps2HtmlReport' utility, run these commands:++```+cabal configure+cabal install+```++This Haskell program also makes use of the bindings to **GraphcsMagick** and **Cairo**, and so the necessary system packages need to be installed, via a *nix package manager.++On an RPM-based package manager, run this command as root:++```+yum install GraphicsMagick cairo+```++Prerequisites+-------------+First of all, you need to have your GPS date in a GPX file. There are many gpx exporters available. I use my Android phone to take GPX tracks, with a great application, [OSMTracker](https://code.google.com/p/osmtracker-android/). This application allows you to export your GPS tracks to GPX.++Usage+-----+The program will search for all files ending in ".gpx", and for each one, generate a HTML report.++```+$ cd $location_of_gpx_files+$ ls+1.gpx 2.gpx 3.gpx+$ gps2HtmlReport+Processing 3 file(s)...+Processing '1.gpx' complete. Report saved in: /home/foo/gps_tracks/1/index.html+Processing '2.gpx' complete. Report saved in: /home/foo/gps_tracks/2/index.html+Processing '3.gpx' complete. Report saved in: /home/foo/gps_tracks/3/index.html+```++Notes+-----+This project requires testing!++If you are able to use the utility to generate HTML reports, then I'd like to hear suggestions for improvements. If you are **unable** to run it, then I **really** want to hear from you. What the problem is; How far did you get; or better still, send me the .gpx file.++I'd also like to know what is required to make this utility work on non-Linux systems. This has been tested on a Fedora Linux machine. Does it work on Mac OSX? Windows? What needs doing to run it on other Linux distro's?++Either way, get in touch!++To Do+-----++* It would be great to port the perl `gpx2png' utility to Haskell, eliminating this dependency.+* This Haskell program currently makes use of elevation, latitude and longitude. There are many other attributes possibly available in WptType. Ideas for what to do with these attributes [here](http://hackage.haskell.org/packages/archive/GPX/0.4.8/doc/html/Data-Geo-GPX-WptType.html#t:WptType) most welcome.++Credits+-------+Thanks goes to the developers of the [gpx2png project](http://wiki.openstreetmap.org/wiki/Gpx2png), which is used to generate the OpenStreetMap image.++In addition, thanks to [Thomas DuBuisson](http://www.haskellers.com/user/TomMD), for implementing the `gps' package and contributing it to Hackage.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ gps2htmlReport.cabal view
@@ -0,0 +1,24 @@+Name:                gps2htmlReport+Version:             0.1+Cabal-Version:       >=1.2+Description:         Generate a HTML summary report of GPS tracks+synopsis:            GPS to HTML Summary Report+License:             BSD3+License-file:        LICENSE+Author:              Rob Stewart <robstewart57@googlemail.com>+Maintainer:          Rob Stewart <robstewart57@googlemail.com>+Homepage:	     https://github.com/robstewart57/Gps2HtmlReport+bug-reports:	     https://github.com/robstewart57/Gps2HtmlReport+Build-Type:          Simple+stability:	     alpha+category:	     Data+extra-source-files:  README.md+tested-with:         GHC ==7.0.2++Executable gps2htmlReport+  Main-is:	     Data/GPS/Gps2HtmlReport/Main.hs++library+  Build-Depends:     base >= 4 && < 5, html, gps, time, cairo, Chart, random, data-accessor, colour, xsd, filepath, directory, process, gd+  Extensions:        ScopedTypeVariables+  Exposed-Modules:   Data.GPS.Gps2HtmlReport.HTMLGenerator, Data.GPS.Gps2HtmlReport.JourneyStats, Data.GPS.Gps2HtmlReport.JourneyCharts, Data.GPS.Gps2HtmlReport.OsmChart