Compare commits

..

No commits in common. "dcaa38e5fe86ff660053800d83181f7d0999eb9a" and "7860a189b35c73835929ad4fd2e807dedd5e0056" have entirely different histories.

6 changed files with 77 additions and 11581 deletions

View File

@ -55,8 +55,9 @@ _Do not look below this line_
## WIP, Puzzles and TODO ## WIP, Puzzles and TODO
* [done] Pos can't include elevation if it's sometimes unknown
* do we even need Track? will it ever be anything more than a collection * do we even need Track? will it ever be anything more than a collection
of Points? of Points?
* can we lose this "if isJust lat && isJust lon && isJust ts" wart? * [done] need a real gpx file with namespace decls before we can parse power and stuff
* probably we should store points in a more efficient form than * [done] tests seem to pass without <gpx> element?
a singly-linked list * [done] stop returning bogus data when missing required elements (e.g. time)

View File

@ -1,10 +1,4 @@
module Main where module Main where
import Control.Exception
import Track(parseFile)
import Data.List as List
main :: IO () main :: IO ()
main = do main = putStrLn "Hello, Haskell!"
points <- Track.parseFile "track.gpx"
putStrLn ("loaded " ++ (show (List.length points)))

View File

@ -10,7 +10,6 @@ module Track
heartRate, heartRate,
time, time,
parse, parse,
parseFile,
Track.length, Track.length,
) )
where where
@ -21,16 +20,14 @@ import Data.List as List
import Data.List qualified import Data.List qualified
import Data.Map as Map import Data.Map as Map
import Data.Maybe import Data.Maybe
import Data.Either
import Data.Text qualified import Data.Text qualified
import Data.Text.Lazy as T import Data.Text.Lazy as T
import Data.Time import Data.Time
import Data.Time.ISO8601 qualified import Data.Time.ISO8601 qualified
import Debug.Trace (trace, traceShow) import Debug.Trace (trace, traceShow)
import Text.Read (readMaybe)
import Text.XML import Text.XML
import Text.XML.Cursor as Cursor import Text.XML.Cursor as Cursor
import Text.Read (readMaybe)
data Pos = Pos Float Float (Maybe Float) deriving (Show, Eq) data Pos = Pos Float Float (Maybe Float) deriving (Show, Eq)
type Power = Maybe Int type Power = Maybe Int
@ -63,12 +60,14 @@ instance Exception BadFile
elToPoint :: Cursor -> Either SomeException Point elToPoint :: Cursor -> Either SomeException Point
elToPoint c = elToPoint c =
let lat = listToMaybe (attribute "lat" c) >>= asFloat case node c of
lon = listToMaybe (attribute "lon" c) >>= asFloat NodeElement (Element _ attrs _) ->
let lat = (listToMaybe $ attribute "lat" c ) >>= asFloat
lon = (listToMaybe $ attribute "lon" c ) >>= asFloat
ele = listToMaybe $ child c >>= element (gpxNS "ele") >>= child >>= content
ts = ts =
listToMaybe (child c >>= element (gpxNS "time") >>= child >>= content) listToMaybe (child c >>= element (gpxNS "time") >>= child >>= content)
>>= (Data.Time.ISO8601.parseISO8601 . Data.Text.unpack) >>= (Data.Time.ISO8601.parseISO8601 . Data.Text.unpack)
ele = listToMaybe (child c >>= element (gpxNS "ele") >>= child >>= content) >>= asFloat
gpxtpx = gpxtpx =
child c child c
>>= element (gpxNS "extensions") >>= element (gpxNS "extensions")
@ -85,15 +84,16 @@ elToPoint c =
then then
Right $ Right $
Point Point
(Pos (fromJust lat) (fromJust lon) ele) (Pos (fromJust lat) (fromJust lon) (ele >>= asFloat))
(fromJust ts) (fromJust ts)
(listToMaybe cadence >>= asInt) (listToMaybe cadence >>= asInt)
(listToMaybe power >>= asInt) (listToMaybe power >>= asInt)
(listToMaybe hr >>= asInt) (listToMaybe hr >>= asInt)
else Left (toException (BadFile "missing a required attribute")) else Left (toException (BadFile "missing a required attribute"))
where where
asFloat v = (readMaybe :: String -> Maybe Float) (Data.Text.unpack v) asFloat v = return (Data.Text.unpack v) >>= (readMaybe :: String -> Maybe Float)
asInt v = (readMaybe :: String -> Maybe Int) (Data.Text.unpack v) asInt v = return (Data.Text.unpack v) >>= (readMaybe :: String -> Maybe Int)
_ -> Left (toException (BadFile "did not find trkpt"))
getPoints :: Cursor -> Either SomeException [Point] getPoints :: Cursor -> Either SomeException [Point]
getPoints c = getPoints c =
@ -112,10 +112,3 @@ parse str = do
length :: Track -> Int length :: Track -> Int
length = Data.List.length length = Data.List.length
-- parseFile :: FilePath -> IO [Point]
parseFile name = do
gpx <- Text.XML.readFile def name
return $ case getPoints (fromDocument gpx) of
Left err -> []
Right points -> points

View File

@ -68,9 +68,7 @@ executable souplesse
-- other-extensions: -- other-extensions:
-- Other library packages from which modules are imported. -- Other library packages from which modules are imported.
build-depends: build-depends: base ^>=4.18.2.1
base ^>=4.18.2.1
, souplesse-lib
-- Directories containing source files. -- Directories containing source files.
hs-source-dirs: app hs-source-dirs: app

View File

@ -4,8 +4,8 @@ module Main where
import Control.Exception import Control.Exception
import Data.Either import Data.Either
import Data.List as List
import Data.Time qualified import Data.Time qualified
import Data.List as List
import Debug.Trace (trace, traceShow) import Debug.Trace (trace, traceShow)
import System.Exit qualified as Exit import System.Exit qualified as Exit
import Test.HUnit import Test.HUnit
@ -84,8 +84,8 @@ testMalformed =
in assertBool "catches syntax error" (isLeft trk) in assertBool "catches syntax error" (isLeft trk)
testMissingAttrs = testMissingAttrs =
let els = let els = [
[ [r| [r|
<trkpt lon="2" latsdf="51"> <trkpt lon="2" latsdf="51">
<time>2024-10-23T08:34:59.779+01:00</time> <time>2024-10-23T08:34:59.779+01:00</time>
</trkpt> </trkpt>
@ -101,14 +101,18 @@ testMissingAttrs =
</trkpt> </trkpt>
|] |]
] ]
in TestCase $ in
TestCase $
assertBool assertBool
"failed to catch missing/malformed attribute" "failed to catch missing/malformed attribute"
(List.all (isLeft . Track.parse . wrapPoint) els) (List.all isLeft
(List.map (\ text -> Track.parse (wrapPoint text))
els))
test2 = test2 =
TestList TestList [
[ TestCase $ TestCase $
either either
(assertFailure . displayException) (assertFailure . displayException)
( \(p : _) -> ( \(p : _) ->
@ -130,6 +134,7 @@ test2 =
(Track.parse onepointWithAttrs) (Track.parse onepointWithAttrs)
] ]
test3 = test3 =
TestCase $ TestCase $
either either

11495
track.gpx

File diff suppressed because it is too large Load Diff