Add initial files
This commit is contained in:
131
src/Main.purs
Normal file
131
src/Main.purs
Normal file
@@ -0,0 +1,131 @@
|
||||
module Main where
|
||||
|
||||
import Prelude (discard, class Monoid, class Semigroup, Unit, ($), (<>), (>>>))
|
||||
|
||||
import Data.Array (range, cons)
|
||||
import Data.Field (div)
|
||||
import Data.Functor (map)
|
||||
import Data.Int (toNumber)
|
||||
import Data.Number (cos, pi, sin)
|
||||
import Data.Number.Format (toString)
|
||||
import Data.List (fold)
|
||||
import Data.Ord ((<))
|
||||
import Data.Ring (add, mul, negate, sub)
|
||||
import Data.Tuple.Nested (Tuple3, tuple3, get1, get2, get3)
|
||||
import Effect (Effect)
|
||||
import Effect.Console (log)
|
||||
|
||||
type Point =
|
||||
{ x :: Number
|
||||
, y :: Number
|
||||
}
|
||||
|
||||
type Line =
|
||||
{ start :: Point
|
||||
, end :: Point
|
||||
}
|
||||
|
||||
-- TODO: How to do more normal math expressions?
|
||||
rotate :: Number -> Point -> Point
|
||||
rotate angle { x: x, y: y} = {
|
||||
x: sub (mul (cos angle) x) (mul (sin angle) y),
|
||||
y: add (mul (sin angle) x) (mul (cos angle) y)
|
||||
}
|
||||
|
||||
transform :: Number -> Number -> Number -> Point -> Point
|
||||
transform scale xOffset yOffset { x: x, y: y} = {
|
||||
x: (add (mul scale x) xOffset),
|
||||
y: (add (mul scale y) yOffset)
|
||||
}
|
||||
|
||||
rotateLine :: Number -> Line -> Line
|
||||
rotateLine angle { start: p1, end: p2} = {
|
||||
start: rotate angle p1,
|
||||
end: rotate angle p2
|
||||
}
|
||||
|
||||
transformLine :: Number -> Number -> Number -> Line -> Line
|
||||
transformLine scale xOffset yOffset { start: start, end: end } = {
|
||||
start : t start,
|
||||
end : t end
|
||||
}
|
||||
where t = transform scale xOffset yOffset
|
||||
|
||||
-- How to handle the different coordinate systems?
|
||||
-- These things should be generated in the basic coordinate system
|
||||
-- * ticks via generateTicks
|
||||
-- * axis labels
|
||||
-- * axis lines
|
||||
-- There should be a transform function that these should be passed through directly after generation
|
||||
|
||||
newtype XMLFragment = XMLFragment String
|
||||
|
||||
derive newtype instance xmlFragmentSemiGroup :: Semigroup XMLFragment
|
||||
derive newtype instance xmlFragmentMonoid :: Monoid XMLFragment
|
||||
|
||||
-- TODO: Add style configuration
|
||||
svgLine :: Line -> XMLFragment
|
||||
svgLine { start: {x: x1, y: y1}, end: {x: x2, y: y2} } =
|
||||
XMLFragment $ """<path style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
""" <> (toString x1) <> "," <> (toString y1) <> " " <> (toString x2) <> "," <> (toString y2) <> "\"/>"
|
||||
|
||||
-- TODO: Make axis tick size a parameter
|
||||
getTick :: Number -> Int -> Int -> Line
|
||||
getTick scale numTicks tickI =
|
||||
{start: {x: x, y: negate (add 0.5 (div 5.0 scale))}, end: {x: x, y: y}}
|
||||
where
|
||||
x = (sub (div (mul 2.0 (mul (sin (div pi 3.0)) (toNumber tickI))) (toNumber numTicks)) (sin (div pi 3.0)))
|
||||
y = if tickI < (div numTicks 2)
|
||||
then (add 1.0 (mul x (div 1.5 (sin (div pi 3.0)))))
|
||||
else (sub 1.0 (mul x (div 1.5 (sin (div pi 3.0)))))
|
||||
|
||||
getTicks :: Number -> Number -> Int -> Tuple3 (Array Line) (Array Line) (Array Line)
|
||||
getTicks scale angle numTicks = --tuple3 [] [] []
|
||||
tuple3 axis1Lines axis2Lines axis3Lines
|
||||
where
|
||||
foo = map (getTick scale numTicks) (range 0 numTicks)
|
||||
axis1Lines = map (rotateLine angle) foo
|
||||
axis2Lines = map (rotateLine (mul 2.0 (div pi 3.0))) axis1Lines
|
||||
axis3Lines = map (rotateLine (mul 2.0 (div pi 3.0))) axis2Lines
|
||||
|
||||
-- There's probably a better way to do this
|
||||
unfragment :: XMLFragment -> String
|
||||
unfragment (XMLFragment frag) = frag
|
||||
|
||||
ternaryGraphSvg :: Array XMLFragment -> String
|
||||
ternaryGraphSvg fragments = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg
|
||||
width="150mm"
|
||||
height="120mm"
|
||||
viewBox="-50 -50 200 200"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
""" <> unfragment (fold fragments) <> "</svg>"
|
||||
|
||||
axesPoints :: Number -> Array Point
|
||||
axesPoints angle = [
|
||||
rotate angle { x: 0, y: 1 },
|
||||
rotate angle { x: (negate (sin (mul 2.0 (div pi 3.0)))), y : (negate 0.5)},
|
||||
rotate angle { x: (sin (mul (div pi 3.0))), y: (negate 0.5) }
|
||||
]
|
||||
|
||||
ternaryGraph :: Number -> Number -> Number -> Int -> String
|
||||
ternaryGraph scale xOffset yOffset numTicks = ternaryGraphSvg [tickLinesSvg, axesPathSvg, axisTitleSvg, tickLabelsSvg]
|
||||
where
|
||||
axisTickLines = getTicks scale pi numTicks
|
||||
axis1TickLines = get1 axisTickLines
|
||||
axis2TickLines = get2 axisTickLines
|
||||
axis3TickLines = get3 axisTickLines
|
||||
tickLines = (cons axis1TickLines (cons axis2TickLines axis3TickLines))
|
||||
transformMyLine = transformLine scale xOffset yOffset
|
||||
tickLinesSvg = fold $ map (svgLine >>> transformMyLine) tickLines
|
||||
|
||||
axesPathSvg =
|
||||
|
||||
main :: Effect Unit
|
||||
main = do
|
||||
log $ ternaryGraphSvg [XMLFragment "<asdf/>", XMLFragment "<foobar/>"]
|
||||
log $ toString $ toNumber (div 5 3)
|
||||
Reference in New Issue
Block a user