module LineHelpers exposing (..)
-- Maybe should just be doubles or nums
import Debug
fromJust : Maybe a -> a
fromJust x = case x of
Just y -> y
Nothing -> Debug.crash "error: fromJust Nothing"
toPointString : List (number, number) -> String
toPointString xs =
case xs of
(x,y) :: ys -> (toString x) ++ "," ++ (toString y) ++ " " ++ (toPointString ys)
_ -> ""
crossProd : (number,number,number) -> (number,number,number) -> (number,number,number)
crossProd (a,b,c) (d,e,f) = (b * f - c * e, c * d - a * f, a * e - b * d)
type alias PointListH number = List (number,number,number)
type alias LineListH number = List (number,number,number)
-- gives the mapping function the list and the list shifted by 1
neighbormap f a = let a_ = fromJust (List.tail a) in List.map2 f a a_
crossNeighbor = neighbormap crossProd
norm a b = sqrt (a * a + b * b)
shiftLine delta (a,b,c) = (a,b, (norm a b) * delta + c)
connectingLines = crossNeighbor
shiftLines delta = List.map (shiftLine delta)
intersections = crossNeighbor
-- nearly striaght lines will find their intersection at infinity.
-- maybe filter out a lower threshold on c
-- keep first and last point
last xs = let l = List.length xs in fromJust (List.head (List.drop (l - 1) xs))
timestep : Float -> List (Float,Float, Float) -> List (Float,Float, Float)
timestep delta points = let
firstpoint = fromJust (List.head points)
lastpoint = last points
connectlines = connectingLines points
newlines = shiftLines delta connectlines
newpoints = intersections newlines
filterednewpoints = List.filter (\(a,b,c) -> (abs c) > 0.01) newpoints
normpoints = List.map normalize filterednewpoints
result = firstpoint :: (normpoints ++ [lastpoint])
resample = List.map (maxfunc (List.map dehomogenize result)) initx
--result2 = removeoutoforder (-100000, 0,00) result
in List.map homogenize (zip initx resample)
homogenize (a,b) = (a,b,1)
dehomogenize (a,b,c) = (a / c, b / c)
normalize = dehomogenize >> homogenize
zip = List.map2 (,)
initx = List.map (toFloat >>((*) 4.5)) (List.range -200 400)
--inity = List.map (\x -> x * x / 50) initx
--inity = List.map (\x -> 300 + x * x / -50) initx
--inity = List.map (\x -> 25 * sin (x / 20) + 250) initx
inity = List.map (\x -> 25 * sin (x / 20) + 250 + 15 * sin (x/13)) initx
initxy = zip initx inity
initxyh = List.map homogenize initxy
iterate n f x = if n == 0 then [] else (f x) :: iterate (n - 1) f (f x)
paths = (List.map << List.map) dehomogenize (iterate 60 (timestep 5.0) initxyh)
colors = List.concat (List.repeat (List.length paths) ["red", "blue", "yellow"] )
removeoutoforder prev xs = case xs of
y :: ys -> if prev < y then (y :: removeoutoforder y ys) else removeoutoforder prev ys
_ -> []
neighborzip a = let a_ = fromJust (List.tail a) in zip a a_
linearinterp x ((x1,y1), (x2,y2)) = (y1 * (x2 - x) + y2 * (x - x1)) / (x2 - x1)
maxfunc : List (Float, Float) -> Float -> Float
maxfunc points x = let
pairs = neighborzip points
filterfunc ((x1,y1), (x2,y2)) = (xor (x < x1) (x < x2))
candidates = List.filter filterfunc pairs
yvals = List.map (linearinterp x) candidates in Maybe.withDefault 100 (List.maximum yvals)