packages feed

SVG2Q-0.3: PathCommand.hs

module PathCommand where

import Point
import Data.List(groupBy)
import Helpers (replace,isFloat)
import Debug.Trace(trace)


type Command = Char
type Angle = Double

data PathCommand = 
     PathClosePath 
     | PathMoveTo {
     pMoveTo :: Point
     }
     | PathLineTo {
     pLineTo :: Point
     }
     | PathHLineTo {
     pHLineTo :: Float
     }
     | PathVLineTo {
     pVLineTo :: Float
     }
     | PathCurveTo {
     pCurveToC1 :: Point
     , pCurveToC2 :: Point
     , pCurveTo :: Point
     }
     | PathShorthandCurveTo {
     pCurveToC2 :: Point
     , pCurveTo :: Point
     }
     | PathQuadraticCurveTo {
     pCurveToC :: Point
     , pCurveTo :: Point
     }
     | PathShorthandQuadraticCurveTo {
     pCurveTo :: Point
     }
     | PathEllipticalArc {
     pArcRX :: Float
     , pArcRY :: Float
     , pArcxRotation :: Angle
     , pArcLargeArcFlag :: Bool
     , pArcSweepFlag :: Bool
     , pArcTo :: Point
     }
     | PathNothingYet
     deriving (Show, Eq)


-- inserts spaces after each path-command-character
sanatize :: String -> String
sanatize s = 
         let
         helper r "" = r
         helper r (x:xs) = 
                if x `elem` "MmZzLlHhVvCcSsQqTtAa"
                then helper (r ++ (' ':x:" ")) xs
                else helper (r ++ (x:"")) xs
         in
         helper "" (replace s "," " ")

createPathCommands:: Maybe String -> [PathCommand]
createPathCommands Nothing = trace "Warning: createPathCommands got\
                                   \ Nothing. Returning empty list" []
createPathCommands (Just s) = let x = createCmdAndArgList (words (sanatize s))
                                  cpch [] = []
                                  cpch input@(((x:_):_):[]) = 
                                       if x `elem` "Zz"
                                          then [[PathClosePath]]
                                          else error ("Other command than\
                                                     \ \"Z\" supplied \
                                                      \with no arguments\
                                                      \ in Path:"++show input)
                                  cpch ((x:_):args:xs) = createCmds x args:cpch xs
                                  pc = concat (cpch x)
                              in optimizePath (head pc) pc     

createCmds :: String -> [String] -> [PathCommand]
createCmds _ [] = []
createCmds s@(c:_) (a0:as)
          | c =='H' = PathHLineTo (read a0):createCmds s as
          | c == 'V' = PathVLineTo (read a0):createCmds s as
createCmds s@(c:_) (a0:a1:as)
          | c == 'M' = PathMoveTo (Point (read a0) (read a1)):createCmds s as
          | c == 'L' = PathLineTo (Point (read a0) (read a1)):createCmds s as
          | c == 'T' = PathShorthandQuadraticCurveTo (Point (read a0) (read a1)):createCmds s as
createCmds s@(c:_) (a0:a1:a2:a3:as)
          | c == 'S' = PathShorthandCurveTo (Point (read a0) (read a1)) (Point (read a2) (read a3)):createCmds s as
          | c == 'Q' = PathQuadraticCurveTo (Point (read a0) (read a1)) (Point (read a2) (read a3)):createCmds s as
createCmds s@(c:_) (a0:a1:a2:a3:a4:a5:as)
          | c == 'C' = PathCurveTo (Point (read a0) (read a1)) (Point (read a2) (read a3)) (Point (read a4) (read a5)):createCmds s as 
createCmds s@(c:_) (a0:a1:a2:a3:a4:a5:a6:as)
          | c == 'A' = PathNothingYet:createCmds s as

createCmds s l = error $ "createCmd: Nothing \
                         \ matched for createCmds "++s++" "++show l

createCmdAndArgList :: [String] -> [[String]]
createCmdAndArgList = groupBy (\x y -> isFloat x == isFloat y)

        
optimizePath :: PathCommand -> [PathCommand] -> [PathCommand]
optimizePath (PathMoveTo x) (PathClosePath:[]) = [PathLineTo x]
optimizePath _ (x:[]) = [x]
optimizePath _ [] = []
optimizePath c (PathMoveTo x0:PathMoveTo x1: xs) = 
             optimizePath c (PathMoveTo x1:xs)
optimizePath c (x@(PathCurveTo c1 c2 p1):PathShorthandCurveTo sc2 sp1:xs) =
             x : optimizePath c (PathCurveTo (reflect c2 p1) sc2 sp1:xs)
optimizePath c (x@(PathQuadraticCurveTo c0 p0):PathShorthandQuadraticCurveTo p1:xs) =
             x : optimizePath c (PathQuadraticCurveTo (reflect c0 p0) p1:xs)
optimizePath c (x:xs) = x : optimizePath c xs