module Reanimate.Builtin.TernaryPlot
( ACoord
, BCoord
, CCoord
, ternaryPlot
, toCartesianCoords
, toOffsetCartesianCoords
, fromCartesianCoords
) where
import Codec.Picture (PixelRGBA8 (..), generateImage)
import Graphics.SvgTree (Tree)
import Reanimate.Raster (embedImage)
import Reanimate.Svg (flipYAxis, scaleToWidth, translate)
type ACoord = Double
type BCoord = Double
type CCoord = Double
ternaryPlot :: Int
-> (ACoord -> BCoord -> CCoord -> PixelRGBA8)
-> Tree
ternaryPlot :: Int -> (ACoord -> ACoord -> ACoord -> PixelRGBA8) -> Tree
ternaryPlot Int
density ACoord -> ACoord -> ACoord -> PixelRGBA8
fn =
ACoord -> Tree -> Tree
scaleToWidth ACoord
stdWidth (Tree -> Tree) -> Tree -> Tree
forall a b. (a -> b) -> a -> b
$
ACoord -> ACoord -> Tree -> Tree
translate (-ACoord
cX) (-ACoord
cY) (Tree -> Tree) -> Tree -> Tree
forall a b. (a -> b) -> a -> b
$
ACoord -> Tree -> Tree
scaleToWidth ACoord
1 (Tree -> Tree) -> Tree -> Tree
forall a b. (a -> b) -> a -> b
$
Tree -> Tree
flipYAxis (Tree -> Tree) -> Tree -> Tree
forall a b. (a -> b) -> a -> b
$
ACoord -> ACoord -> Tree -> Tree
translate (Int -> ACoord
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
densityACoord -> ACoord -> ACoord
forall a. Fractional a => a -> a -> a
/ACoord
2) (-Int -> ACoord
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
heightACoord -> ACoord -> ACoord
forall a. Fractional a => a -> a -> a
/ACoord
2) (Tree -> Tree) -> Tree -> Tree
forall a b. (a -> b) -> a -> b
$
Image PixelRGBA8 -> Tree
forall a. PngSavable a => Image a -> Tree
embedImage (Image PixelRGBA8 -> Tree) -> Image PixelRGBA8 -> Tree
forall a b. (a -> b) -> a -> b
$ (Int -> Int -> PixelRGBA8) -> Int -> Int -> Image PixelRGBA8
forall px. Pixel px => (Int -> Int -> px) -> Int -> Int -> Image px
generateImage Int -> Int -> PixelRGBA8
forall a a. (Integral a, Integral a) => a -> a -> PixelRGBA8
gen Int
density Int
height
where
stdWidth :: ACoord
stdWidth = ACoord
5
(ACoord
cX, ACoord
cY) = ACoord -> ACoord -> (ACoord, ACoord)
toCartesianCoords (ACoord
1ACoord -> ACoord -> ACoord
forall a. Fractional a => a -> a -> a
/ACoord
3) (ACoord
1ACoord -> ACoord -> ACoord
forall a. Fractional a => a -> a -> a
/ACoord
3)
height :: Int
height = ACoord -> Int
forall a b. (RealFrac a, Integral b) => a -> b
round (Int -> ACoord
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
density ACoord -> ACoord -> ACoord
forall a. Num a => a -> a -> a
* (ACoord -> ACoord
forall a. Floating a => a -> a
sqrt ACoord
3 ACoord -> ACoord -> ACoord
forall a. Fractional a => a -> a -> a
/ ACoord
2) :: Double)
gen :: a -> a -> PixelRGBA8
gen a
x a
y =
let
x' :: ACoord
x' = (a -> ACoord
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
x ACoord -> ACoord -> ACoord
forall a. Fractional a => a -> a -> a
/ Int -> ACoord
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
density)
y' :: ACoord
y' = (a -> ACoord
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
y ACoord -> ACoord -> ACoord
forall a. Fractional a => a -> a -> a
/ Int -> ACoord
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
density)
aCoord :: ACoord
aCoord = (ACoord
x'ACoord -> ACoord -> ACoord
forall a. Num a => a -> a -> a
*ACoord
2ACoord -> ACoord -> ACoord
forall a. Num a => a -> a -> a
-ACoord
bCoord)ACoord -> ACoord -> ACoord
forall a. Fractional a => a -> a -> a
/ACoord
2
bCoord :: ACoord
bCoord = ACoord
y' ACoord -> ACoord -> ACoord
forall a. Fractional a => a -> a -> a
/ (ACoord -> ACoord
forall a. Floating a => a -> a
sqrt ACoord
3 ACoord -> ACoord -> ACoord
forall a. Fractional a => a -> a -> a
/ ACoord
2)
cCoord :: ACoord
cCoord = ACoord
1 ACoord -> ACoord -> ACoord
forall a. Num a => a -> a -> a
- ACoord
aCoord ACoord -> ACoord -> ACoord
forall a. Num a => a -> a -> a
- ACoord
bCoord
in if ACoord
aCoord ACoord -> ACoord -> ACoord
forall a. Num a => a -> a -> a
+ ACoord
bCoord ACoord -> ACoord -> Bool
forall a. Ord a => a -> a -> Bool
> ACoord
1 Bool -> Bool -> Bool
|| ACoord
aCoord ACoord -> ACoord -> Bool
forall a. Ord a => a -> a -> Bool
< ACoord
0 Bool -> Bool -> Bool
|| ACoord
bCoord ACoord -> ACoord -> Bool
forall a. Ord a => a -> a -> Bool
< ACoord
0 Bool -> Bool -> Bool
|| ACoord
cCoord ACoord -> ACoord -> Bool
forall a. Ord a => a -> a -> Bool
< ACoord
0
then Pixel8 -> Pixel8 -> Pixel8 -> Pixel8 -> PixelRGBA8
PixelRGBA8 Pixel8
0 Pixel8
0 Pixel8
0 Pixel8
0
else ACoord -> ACoord -> ACoord -> PixelRGBA8
fn ACoord
aCoord ACoord
bCoord ACoord
cCoord
toCartesianCoords :: ACoord -> BCoord -> (Double, Double)
toCartesianCoords :: ACoord -> ACoord -> (ACoord, ACoord)
toCartesianCoords ACoord
a ACoord
b = (ACoord
x, ACoord
y)
where
x :: ACoord
x = (ACoord
aACoord -> ACoord -> ACoord
forall a. Num a => a -> a -> a
+ACoord
2ACoord -> ACoord -> ACoord
forall a. Num a => a -> a -> a
*ACoord
b)ACoord -> ACoord -> ACoord
forall a. Fractional a => a -> a -> a
/ACoord
2
y :: ACoord
y = (ACoord -> ACoord
forall a. Floating a => a -> a
sqrt ACoord
3 ACoord -> ACoord -> ACoord
forall a. Fractional a => a -> a -> a
/ ACoord
2) ACoord -> ACoord -> ACoord
forall a. Num a => a -> a -> a
* ACoord
a
toOffsetCartesianCoords :: ACoord -> BCoord -> (Double, Double)
toOffsetCartesianCoords :: ACoord -> ACoord -> (ACoord, ACoord)
toOffsetCartesianCoords ACoord
a ACoord
b =
(ACoord
txACoord -> ACoord -> ACoord
forall a. Num a => a -> a -> a
-ACoord
zx, ACoord
tyACoord -> ACoord -> ACoord
forall a. Num a => a -> a -> a
-ACoord
zy)
where
(ACoord
zx,ACoord
zy) = ACoord -> ACoord -> (ACoord, ACoord)
toCartesianCoords (ACoord
1ACoord -> ACoord -> ACoord
forall a. Fractional a => a -> a -> a
/ACoord
3) (ACoord
1ACoord -> ACoord -> ACoord
forall a. Fractional a => a -> a -> a
/ACoord
3)
(ACoord
tx,ACoord
ty) = ACoord -> ACoord -> (ACoord, ACoord)
toCartesianCoords ACoord
a ACoord
b
fromCartesianCoords :: Double -> Double -> (ACoord, BCoord, CCoord)
fromCartesianCoords :: ACoord -> ACoord -> (ACoord, ACoord, ACoord)
fromCartesianCoords ACoord
x ACoord
y = (ACoord
a,ACoord
b,ACoord
1ACoord -> ACoord -> ACoord
forall a. Num a => a -> a -> a
-ACoord
aACoord -> ACoord -> ACoord
forall a. Num a => a -> a -> a
-ACoord
b)
where
a :: ACoord
a = (ACoord
xACoord -> ACoord -> ACoord
forall a. Num a => a -> a -> a
*ACoord
2ACoord -> ACoord -> ACoord
forall a. Num a => a -> a -> a
-ACoord
b)ACoord -> ACoord -> ACoord
forall a. Fractional a => a -> a -> a
/ACoord
2
b :: ACoord
b = ACoord
y ACoord -> ACoord -> ACoord
forall a. Fractional a => a -> a -> a
/ (ACoord -> ACoord
forall a. Floating a => a -> a
sqrt ACoord
3 ACoord -> ACoord -> ACoord
forall a. Fractional a => a -> a -> a
/ ACoord
2)