aboutsummaryrefslogtreecommitdiffstats
path: root/src/Main.hs
blob: db1b06ed7f99baf2df9033f723192c4cd63bf225 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
module Main where

import qualified Data.List as List

data Ribbon = Ribbon [Bool] Double
  deriving (Eq, Show)

newtype RawData = RawData [Ribbon]
  deriving (Eq, Show)

data Limits = Limits {limitsLow :: Double, limitsHigh :: Double}
  deriving (Eq, Show)

data Coord = Coord {coordX :: Double, coordY :: Double}
  deriving (Eq)

instance Show Coord where
  show (Coord x y) = "(" <> show x <> "," <> show y <> ")"

boolToCoords :: Limits -> Double -> Bool -> Coord
boolToCoords (Limits _ h) x True = Coord x h
boolToCoords (Limits l _) x False = Coord x l

moveX :: Double -> Coord -> Coord
moveX d (Coord x y) = Coord (x + d) y

incrX :: Double -> (Double, [Coord]) -> (Limits, Bool) -> (Double, [Coord])
incrX len (d, coords) (l, b) = (d + len, boolToCoords l d b : coords)

drawRibbon :: Double -> [Limits] -> [Bool] -> [Coord]
drawRibbon len l b =
  snd $ foldl (incrX len) (0, []) $ zip l b

drawCoords :: String -> [Coord] -> String
drawCoords connection coords =
  mconcat $ List.intersperse connection (show <$> coords)

inBetween :: Coord -> Coord -> Coord
inBetween (Coord x1 y1) (Coord x2 y2) =
  Coord ((x1 + x2) / 2) ((y1 + y2) / 2)

condOp :: (Double -> Double) -> [Bool] -> [Double] -> [Double]
condOp f b d =
  fmap condOp' $ zip b d
  where
    condOp' (True, d') = f d'
    condOp' (False, d') = d'

condNotOp :: (Double -> Double) -> [Bool] -> [Double] -> [Double]
condNotOp f b d =
  fmap condOp' $ zip b d
  where
    condOp' (False, d') = f d'
    condOp' (True, d') = d'

drawArrow ::
  Double ->
  Double ->
  (Int, [Double], [Double], String) ->
  Ribbon ->
  (Int, [Double], [Double], String)
drawArrow ratio len (it, start, end, s) (Ribbon b i) =
  ( it + 1,
    condOp (\x -> x - i) b start,
    condNotOp (\x -> x - i) b end,
    s
      <> "\\fill[ribbon"
      <> show it
      <> "] "
      <> (drawCoords " to [out=0,in=180] " . reverse $ drawRibbon len upper_limit b)
      <> " -- "
      <> drawCoords
        " -- "
        [ mid1,
          moveX (i * ratio) (inBetween mid1 mid2),
          mid2
        ]
      <> " -- "
      <> (drawCoords " to [out=180,in=0] " $ drawRibbon len lower_limit b)
      <> ";\n"
  )
  where
    upper_limit =
      fmap
        ( \(st, e) ->
            Limits (e * ratio) (st * ratio)
        )
        $ zip start end
    lower_limit =
      fmap
        ( \(st, e) ->
            Limits ((e - i) * ratio) ((st - i) * ratio)
        )
        $ zip start end
    mid1 = boolToCoords (last upper_limit) ((fromIntegral $ length b) * len) (last b)
    mid2 = boolToCoords (last lower_limit) ((fromIntegral $ length b) * len) (last b)

fourth :: (a, b, c, d) -> d
fourth (_, _, _, d) = d

toListLength :: [Double] -> Ribbon -> [Double]
toListLength d (Ribbon r i) =
  fmap boolToDouble (zip d r)
  where
    boolToDouble (d', True) = d' + i
    boolToDouble (d', False) = d'

initColumns :: Double -> [Ribbon] -> [Double]
initColumns d (Ribbon r _ : _) = replicate (length r) d
initColumns _ _ = []

calcMaxColumns :: [Ribbon] -> [Double]
calcMaxColumns rs = foldl toListLength (initColumns 0 rs) rs

drawRibbons :: Double -> Double -> [Ribbon] -> String
drawRibbons ratio len rs =
  fourth $ foldl (drawArrow ratio len) (1, total, ends, "") rs
  where
    total = initColumns ((+ (0.5 / ratio)) . sum $ fmap (\(Ribbon _ d) -> d) rs) rs
    ends = fmap (\(m, t) -> t - m - 0.5 / ratio) $ zip (calcMaxColumns rs) total

fpga2020 :: [Ribbon]
fpga2020 =
  [ Ribbon [True, True, True, True] 15,
    Ribbon [True, True, True, False] 1,
    Ribbon [True, True, False, False] 6,
    Ribbon [False, False, True, True] 11,
    Ribbon [False, False, True, False] 1,
    Ribbon [False, False, False, True] 17
  ]

printAll :: IO ()
printAll = putStrLn $ drawRibbons 0.05 2.0 fpga2020

main :: IO ()
main = putStrLn "Hello, Haskell!"