{-# LANGUAGE FlexibleInstances#-}
{-|
Module      : TikzObjects
Description : Defines data structures representing TikZ paths
Copyright   : Anthony Wang, 2021
License     : MIT
Maintainer  : anthony.y.wang.math@gmail.com

@TikzObjects@ defines data structures to represent
    objects such as coordinates and paths.
See the tikzpgf manual for more details.
-}

module TikzObjects where

-- | A class for data structures which can be converted into LaTeX code.
class ShowLatex a where
    showLatex :: a -> String

-- | Data structure representing points on a 2 dimensional TikZ canvas.
data TikzCoordinate = 
    -- | Specifies a point by its coordinates
    Canvas 
    { TikzCoordinate -> Float
canvas_x :: !Float
    , TikzCoordinate -> Float
canvas_y :: !Float
    } |
    -- | Specifies a coordinate by a name.
    -- A node or coordinate path operation can create a new named coordinate.
    NamedCoordinate 
    { TikzCoordinate -> String
coord_name :: !String
    } deriving (Int -> TikzCoordinate -> ShowS
[TikzCoordinate] -> ShowS
TikzCoordinate -> String
(Int -> TikzCoordinate -> ShowS)
-> (TikzCoordinate -> String)
-> ([TikzCoordinate] -> ShowS)
-> Show TikzCoordinate
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [TikzCoordinate] -> ShowS
$cshowList :: [TikzCoordinate] -> ShowS
show :: TikzCoordinate -> String
$cshow :: TikzCoordinate -> String
showsPrec :: Int -> TikzCoordinate -> ShowS
$cshowsPrec :: Int -> TikzCoordinate -> ShowS
Show)

instance ShowLatex TikzCoordinate where
    showLatex :: TikzCoordinate -> String
showLatex (Canvas Float
x Float
y) = String
"(" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Float -> String
forall a. Show a => a -> String
show(Float
x) String -> ShowS
forall a. [a] -> [a] -> [a]
++String
","String -> ShowS
forall a. [a] -> [a] -> [a]
++Float -> String
forall a. Show a => a -> String
show(Float
y)String -> ShowS
forall a. [a] -> [a] -> [a]
++String
")"
    showLatex (NamedCoordinate String
s) = String
"("String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
sString -> ShowS
forall a. [a] -> [a] -> [a]
++String
")"

-- | A data structure for specifying path operations, which are chained to create paths.
-- See the tikz manual for details on these operations.
data TikzPathOperation = PathOpMoveTo
    { TikzPathOperation -> TikzCoordinate
pop_move_to_coord :: !TikzCoordinate
    } |
    PathOpLineTo
    { TikzPathOperation -> TikzCoordinate
pop_line_to_coord :: !TikzCoordinate
    } |
    PathOpVertHorz
    { TikzPathOperation -> TikzCoordinate
pop_vert_horz_coord :: !TikzCoordinate
    } | 
    PathOpHorzVert
    { TikzPathOperation -> TikzCoordinate
pop_horz_vert_coord :: !TikzCoordinate
    } |
    PathOpCurveToOneControl
    { TikzPathOperation -> TikzCoordinate
pop_curve_to_1c_coord :: !TikzCoordinate
    , TikzPathOperation -> TikzCoordinate
pop_curve_to_1c_control :: !TikzCoordinate
    } |
    PathOpCurveToTwoControls
    { TikzPathOperation -> TikzCoordinate
pop_curve_to_2c_coord :: !TikzCoordinate
    , TikzPathOperation -> TikzCoordinate
pop_curve_to_2c_control1 :: !TikzCoordinate
    , TikzPathOperation -> TikzCoordinate
pop_curve_to_2c_control2 :: !TikzCoordinate
    } |
    PathOpOption
    { TikzPathOperation -> String
pop_option_string :: !String
    } |
    PathOpScopedOption
    { TikzPathOperation -> String
pop_scoped_option_string :: !String
    , TikzPathOperation -> TikzPath
pop_scoped_option_scope :: !TikzPath
    } |
    PathOpCycle |
    PathOpRectangle 
    { TikzPathOperation -> TikzCoordinate
pop_rectangle_corner :: !TikzCoordinate
    } |
    PathOpNode 
    { TikzPathOperation -> String
pop_node_options :: !String
    , TikzPathOperation -> String
pop_node_name :: !String --cannot contain punctuation like dot, comma or semicolon
    , TikzPathOperation -> TikzCoordinate
pop_node_coordinate :: !TikzCoordinate
    , TikzPathOperation -> String
pop_node_text :: !String
    } |
    PathOpCoordinate
    { TikzPathOperation -> String
pop_coord_options :: !String
    , TikzPathOperation -> String
pop_coord_name :: !String
    , TikzPathOperation -> TikzCoordinate
pop_coord_coordinate :: !TikzCoordinate
    } |
    PathOpRelativeNode
    { TikzPathOperation -> String
pop_rel_node_options :: !String
    , TikzPathOperation -> String
pop_rel_node_text :: !String
    } deriving (Int -> TikzPathOperation -> ShowS
TikzPath -> ShowS
TikzPathOperation -> String
(Int -> TikzPathOperation -> ShowS)
-> (TikzPathOperation -> String)
-> (TikzPath -> ShowS)
-> Show TikzPathOperation
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: TikzPath -> ShowS
$cshowList :: TikzPath -> ShowS
show :: TikzPathOperation -> String
$cshow :: TikzPathOperation -> String
showsPrec :: Int -> TikzPathOperation -> ShowS
$cshowsPrec :: Int -> TikzPathOperation -> ShowS
Show)

instance ShowLatex TikzPathOperation where
    showLatex :: TikzPathOperation -> String
showLatex (PathOpMoveTo TikzCoordinate
c) = String
" "String -> ShowS
forall a. [a] -> [a] -> [a]
++(TikzCoordinate -> String
forall a. ShowLatex a => a -> String
showLatex TikzCoordinate
c)
    showLatex (PathOpLineTo TikzCoordinate
c) = String
" --"String -> ShowS
forall a. [a] -> [a] -> [a]
++(TikzCoordinate -> String
forall a. ShowLatex a => a -> String
showLatex TikzCoordinate
c)
    showLatex (PathOpVertHorz TikzCoordinate
c) = String
" |-"String -> ShowS
forall a. [a] -> [a] -> [a]
++(TikzCoordinate -> String
forall a. ShowLatex a => a -> String
showLatex TikzCoordinate
c)
    showLatex (PathOpHorzVert TikzCoordinate
c) = String
" -|"String -> ShowS
forall a. [a] -> [a] -> [a]
++(TikzCoordinate -> String
forall a. ShowLatex a => a -> String
showLatex TikzCoordinate
c)
    showLatex (PathOpCurveToOneControl TikzCoordinate
c TikzCoordinate
d) = String
" ..controls"String -> ShowS
forall a. [a] -> [a] -> [a]
++(TikzCoordinate -> String
forall a. ShowLatex a => a -> String
showLatex TikzCoordinate
d)String -> ShowS
forall a. [a] -> [a] -> [a]
++String
".."String -> ShowS
forall a. [a] -> [a] -> [a]
++(TikzCoordinate -> String
forall a. ShowLatex a => a -> String
showLatex TikzCoordinate
c)
    showLatex (PathOpCurveToTwoControls TikzCoordinate
c TikzCoordinate
d1 TikzCoordinate
d2) = String
" ..controls"String -> ShowS
forall a. [a] -> [a] -> [a]
++(TikzCoordinate -> String
forall a. ShowLatex a => a -> String
showLatex TikzCoordinate
d1)String -> ShowS
forall a. [a] -> [a] -> [a]
++String
"and"String -> ShowS
forall a. [a] -> [a] -> [a]
++(TikzCoordinate -> String
forall a. ShowLatex a => a -> String
showLatex TikzCoordinate
d2)String -> ShowS
forall a. [a] -> [a] -> [a]
++String
".."String -> ShowS
forall a. [a] -> [a] -> [a]
++(TikzCoordinate -> String
forall a. ShowLatex a => a -> String
showLatex TikzCoordinate
c)
    showLatex (PathOpOption String
s) = String
" ["String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
s String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"]"
    showLatex (PathOpScopedOption String
s TikzPath
p) = String
" {["String -> ShowS
forall a. [a] -> [a] -> [a]
++String
sString -> ShowS
forall a. [a] -> [a] -> [a]
++String
"] "String -> ShowS
forall a. [a] -> [a] -> [a]
++(TikzPath -> String
partialShowLatex TikzPath
p)String -> ShowS
forall a. [a] -> [a] -> [a]
++String
"}"
    showLatex (TikzPathOperation
PathOpCycle) = String
" --cycle"
    showLatex (PathOpRectangle TikzCoordinate
c) = String
" rectangle"String -> ShowS
forall a. [a] -> [a] -> [a]
++(TikzCoordinate -> String
forall a. ShowLatex a => a -> String
showLatex TikzCoordinate
c)
    showLatex (PathOpNode String
o String
n TikzCoordinate
c String
t) = String
" node["String -> ShowS
forall a. [a] -> [a] -> [a]
++String
oString -> ShowS
forall a. [a] -> [a] -> [a]
++String
"] ("String -> ShowS
forall a. [a] -> [a] -> [a]
++String
nString -> ShowS
forall a. [a] -> [a] -> [a]
++String
") at "String -> ShowS
forall a. [a] -> [a] -> [a]
++(TikzCoordinate -> String
forall a. ShowLatex a => a -> String
showLatex TikzCoordinate
c)String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" {"String -> ShowS
forall a. [a] -> [a] -> [a]
++String
tString -> ShowS
forall a. [a] -> [a] -> [a]
++String
"}"
    showLatex (PathOpCoordinate String
o String
n TikzCoordinate
c) = String
" coordinate["String -> ShowS
forall a. [a] -> [a] -> [a]
++String
oString -> ShowS
forall a. [a] -> [a] -> [a]
++String
"] ("String -> ShowS
forall a. [a] -> [a] -> [a]
++String
nString -> ShowS
forall a. [a] -> [a] -> [a]
++String
") at "String -> ShowS
forall a. [a] -> [a] -> [a]
++(TikzCoordinate -> String
forall a. ShowLatex a => a -> String
showLatex TikzCoordinate
c)
    showLatex (PathOpRelativeNode String
o String
t) = String
" node["String -> ShowS
forall a. [a] -> [a] -> [a]
++String
oString -> ShowS
forall a. [a] -> [a] -> [a]
++String
"] {"String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
tString -> ShowS
forall a. [a] -> [a] -> [a]
++String
"}"

-- | If a path operation has a name, it defines a @NamedCoordinate@.
-- @toNamedCoord@ of a path operation returns @Just@ this named coordinate for operations with names, otherwise
-- it returns @Nothing@.
toNamedCoord :: TikzPathOperation -> Maybe TikzCoordinate
toNamedCoord :: TikzPathOperation -> Maybe TikzCoordinate
toNamedCoord (PathOpNode String
_o String
n TikzCoordinate
_c String
_t) = TikzCoordinate -> Maybe TikzCoordinate
forall a. a -> Maybe a
Just (TikzCoordinate -> Maybe TikzCoordinate)
-> TikzCoordinate -> Maybe TikzCoordinate
forall a b. (a -> b) -> a -> b
$ String -> TikzCoordinate
NamedCoordinate String
n
toNamedCoord (PathOpCoordinate String
_o String
n TikzCoordinate
_c) = TikzCoordinate -> Maybe TikzCoordinate
forall a. a -> Maybe a
Just (TikzCoordinate -> Maybe TikzCoordinate)
-> TikzCoordinate -> Maybe TikzCoordinate
forall a b. (a -> b) -> a -> b
$ String -> TikzCoordinate
NamedCoordinate String
n
toNamedCoord TikzPathOperation
_ = Maybe TikzCoordinate
forall a. Maybe a
Nothing

-- | A @TikzPath@ is made by sequencing @TikzPathOperation@s.
type TikzPath = [TikzPathOperation]

-- | A helper function used to define @showLatex@ of a @TikzPath@.
partialShowLatex :: TikzPath -> String
partialShowLatex :: TikzPath -> String
partialShowLatex TikzPath
p = (String -> ShowS) -> String -> [String] -> String
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl String -> ShowS
forall a. [a] -> [a] -> [a]
(++) String
"" ((TikzPathOperation -> String) -> TikzPath -> [String]
forall a b. (a -> b) -> [a] -> [b]
map TikzPathOperation -> String
forall a. ShowLatex a => a -> String
showLatex TikzPath
p)

instance ShowLatex TikzPath where
    showLatex :: TikzPath -> String
showLatex TikzPath
x = String
"\\path"String -> ShowS
forall a. [a] -> [a] -> [a]
++(TikzPath -> String
partialShowLatex TikzPath
x)String -> ShowS
forall a. [a] -> [a] -> [a]
++String
";"