module Data.Matrix.AsXYZ (
fromXYZ,
fromXYZ',
fromABC,
prettyXYZ,
prettyABC,
) where
import Control.Monad (join)
import Data.Char (isAlpha)
import Data.List (intercalate)
import Data.Ratio (Ratio)
import Data.Matrix (Matrix,fromList,fromLists,toLists,identity,zero,(<->))
import Text.ParserCombinators.Parsec (parse,ParseError)
import Data.Ratio.Slash (getRatio,Slash(..))
import Data.Matrix.AsXYZ.Parse (equivalentPositions,transformPpABC,ratio)
fromXYZ :: Integral a => String -> Matrix (Ratio a)
fromXYZ input = unsafeGet $ makeMatrix <$> parse (equivalentPositions ratio) input input
fromXYZ' :: Integral a => String -> Maybe (Matrix (Ratio a))
fromXYZ' input = get $ makeMatrix <$> parse (equivalentPositions ratio) input input
fromABC :: Integral a => String -> Matrix (Ratio a)
fromABC input = unsafeGet $ makeMatrix <$> parse (transformPpABC ratio) input input
makeMatrix :: Num a => [[a]] -> Matrix a
makeMatrix m = fromLists m <-> fromLists [[0,0,0,1]]
unsafeGet :: Either ParseError a -> a
unsafeGet e = case e of
Left s -> error $ show s
Right m -> m
get :: Either ParseError a -> Maybe a
get e = case e of
Left s -> Nothing
Right m -> Just m
addPlusSign :: String -> String
addPlusSign xs@('-':_) = xs
addPlusSign xs = '+' : xs
numStr :: (Integral a) => Ratio a -> String
numStr = addPlusSign . show . Slash
varString :: (Integral a) => Ratio a -> String -> String
varString num label
| num == 0 = ""
| null label = numStr num
| num == 1 = "+" ++ label
| num == -1 = "-" ++ label
| otherwise = numStr num ++ label
isPrimary :: String -> Bool
isPrimary x = (hasLetter . reverse) x && isPositive x
hasLetter :: String -> Bool
hasLetter (x:_) = isAlpha x
hasLetter _ = False
isPositive :: String -> Bool
isPositive ('+':_) = True
isPositive _ = False
varSort :: [String] -> [String]
varSort parts = filter isPrimary parts ++ filter (not . isPrimary) parts
row :: (Integral a) => [String] -> [Ratio a] -> String
row labels line = join . varSort $ zipWith varString line labels
refineRow :: String -> String
refineRow s
| null s = "0"
| head s == '+' = tail s
| otherwise = s
rowString :: (Integral a) => [String] -> [Ratio a] -> String
rowString labels line = refineRow (row labels line)
xyzLabel :: [String]
xyzLabel = ["x","y","z",""]
abcLabel :: [String]
abcLabel = ["a","b","c",""]
showAs :: (Integral a) => [String] -> Matrix (Ratio a) -> String
showAs labels = intercalate "," . map (rowString labels) . take 3 . toLists
prettyXYZ :: (Integral a) =>
Matrix (Ratio a)
-> String
prettyXYZ = showAs xyzLabel
prettyABC :: (Integral a) =>
Matrix (Ratio a)
-> String
prettyABC = showAs abcLabel