hgeometry-0.5.0.0: examples/Demo/DrawGPX.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeOperators #-}
module Demo.DrawGPX where
import Algorithms.Geometry.PolyLineSimplification.DouglasPeucker
import Control.Applicative
import Control.Lens
import Data.Data
import Data.Ext
import qualified Data.Foldable as F
import Data.Geometry
import Data.Geometry.PolyLine
import Data.Geometry.Ipe
import Data.Geometry.Vector
import Data.List (isSuffixOf)
import Data.Maybe
import qualified Data.Sequence as S
import qualified Data.Text as T
import Data.Time.Calendar
import Data.Time.Clock
import Demo.GPXParser
import Options.Applicative
import System.Directory
import Text.Printf (printf)
--------------------------------------------------------------------------------
data Options = Options { _inPath :: FilePath
, _outPath :: FilePath
}
deriving Data
options :: ParserInfo Options
options = info (helper <*> parser)
( progDesc "Draws gpx trajectories in ipe"
<> header "DrawGPX"
)
where
parser = Options
<$> strOption (help "Input Directory"
<> short 'i'
<> metavar "INDIR"
)
<*> strOption (help "Output File"
<> short 'o'
<> metavar "TARGET"
)
--------------------------------------------------------------------------------
mainWith :: Options -> IO ()
mainWith (Options inPath outPath) = do
let inPath' = inPath ++ "/"
files <- map (inPath' ++) . filter (isSuffixOf ".gpx")
<$> getDirectoryContents inPath'
tks <- concatMap (_tracks . combineTracks) <$> mapM readGPXFile files
let polies = mapMaybe asPolyLine tks
polies' = map (douglasPeucker 0.01 . scaleUniformlyBy 100) polies
pg = singlePageFromContent $ map (asIpeObject' mempty) polies'
-- print pg
writeIpeFile outPath pg
colors :: [T.Text]
colors = map (T.unwords . map (T.pack . printf "%.4f" . (/ 256.0))) colors'
where
colors' :: [[Double]]
-- colors' = [ [84,48,5]
-- , [140,81,10]
-- , [191,129,45]
-- , [223,194,125]
-- , [246,232,195]
-- , [245,245,245]
-- , [199,234,229]
-- , [128,205,193]
-- , [53,151,143]
-- , [1,102,94]
-- , [0,60,48]
-- , [0,0,0]
-- ]
colors' = [ [166,206,227]
, [31,120,180]
, [178,223,138]
, [51,160,44]
, [251,154,153]
, [227,26,28]
, [253,191,111]
, [255,127,0]
, [202,178,214]
, [106,61,154]
, [255,255,153]
, [177,89,40]
]
-- readCoords :: FilePath -> IO (PolyLine 2 () Double)
-- readCoords fp = fromPoints .
-- map ((\[x,y] -> point2 x y :+ ()) . map read . words) . lines
-- <$> readFile fp
-- readCoords' :: FilePath -> IO [PolyLine 2 () Double]
-- readCoords' fp = mapMaybe (fmap fromPoints . g . f) . group' . lines <$> readFile fp
-- where
-- f = map ((\[x,y] -> point2 x y :+ ()) . map read . words)
-- g xs@(_:_:_) = Just xs
-- g _ = Nothing
-- group' lst = case break (== "NL") lst of
-- ([],[]) -> []
-- ([],"NL":r) -> group' r
-- (pr,"NL":r) -> pr:group' r
-- (pr,[]) -> [pr]
-- maps = mapM (\f -> readCoords $ "/Users/frank/tmp/bikerides/maps/" ++ f)
-- [ "nld_coords.txt"
-- , "bel_coords.txt"
-- , "dnk_coords.txt"
-- , "fra_coords.txt"
-- ]
-- -- do
-- -- nld <- readCoords
-- -- writePolyLineFile "/tmp/nld.ipe" $ map (flip stroke "black") [nld]
asPolyLine :: Track -> Maybe (PolyLine 2 UTCTime Double)
asPolyLine = fmap fromPoints . f . map toPt . _trackPoints
where
f xs@(_:_:_) = Just xs
f _ = Nothing
toPt :: TrackPoint -> Point 2 Double :+ Time
toPt (TP (pos :+ t)) = point2 (pos^.longitude) (pos^.latitude) :+ t
ssFactor = 1
worldWidth = 1000
worldHeight = 1000
world = (worldWidth,worldHeight)
-- colors = [ "red" , "purple" , "blue" , "green" , "orange" ]
strokeByMonth p = stroke p c
where
dt = p^.points.to F.toList.to head.extra
(_,m,_) = toGregorian $ utctDay dt
c = colors !! (m -1)
stroke p c = (p&points.traverse.extra .~ (),[("stroke",c)])
groupsOf :: Int -> [a] -> [[a]]
groupsOf _ [] = []
groupsOf k xs = let (ys,xss) = splitAt k xs in ys : groupsOf k xss
subsample :: Int -> [a] -> [a]
subsample k = map head . groupsOf k
subsampleTrack :: Int -> Track -> Track
subsampleTrack k = over trackPoints (subsample k)
-- | Given the width and height of the map and a Position, compute a Mercato Projection of
-- the position. See
-- <http://en.wikipedia.org/wiki/Mercator_projection#Derivation_of_the_Mercator_projection
-- WikiPedia> for more info.
mercatoProject :: (Double,Double)
-> Position
-> Point 2 Double
mercatoProject (width,height) pos = point2 x y
where
x = (width / 360) * pos^.longitude
y = (height / 2) - (width / (2*pi)) * (log . tan $ (pi / 4) + (latR / 2))
latR = -1 * pos^.latitude * pi / 180