elmflame/flame.elm

151 lines
4 KiB
Elm
Raw Permalink Normal View History

2013-01-08 17:05:54 +00:00
module Flame where
import Random
-- Basic functions
-- nth element of a list
l !! n = if n == 0 then head l else (tail l) !! (n-1)
-- negative of a number (I don't like writing 0-x).
neg x = 0-x
2013-01-11 15:31:24 +00:00
-- too useful
concatmap f l = concat (map f l)
-- Colors (theme is solarized)
2013-01-08 17:05:54 +00:00
base03 = rgb 0 43 54
base02 = rgb 7 54 66
base01 = rgb 88 110 117
base00 = rgb 101 123 131
base0 = rgb 131 148 150
base1 = rgb 147 161 161
base2 = rgb 238 232 213
base3 = rgb 253 246 227
yellow = rgb 181 137 0
orange = rgb 203 75 22
red = rgb 220 50 47
magenta = rgb 211 54 130
violet = rgb 108 113 196
blue = rgb 38 139 210
cyan = rgb 42 161 152
green = rgb 133 153 0
-- Default text color
2013-01-09 14:37:54 +00:00
mybase = rgba 108 113 196 (2/3)
2013-01-08 17:05:54 +00:00
-- draw a point at position (x,y)
2013-01-09 14:37:54 +00:00
point = filled mybase . rect 1 1
2013-01-11 15:31:24 +00:00
colorpoint ((x,y),n) = filled (rgb n n n) . rect 1 1 $ (x,y)
2013-01-08 17:05:54 +00:00
-- fill the background with color base3
2013-01-11 15:31:24 +00:00
background w h = collage w h
[filled base03 $ rect w h (div w 2,div h 2)]
2013-01-08 17:05:54 +00:00
-- RANDOM PART
2013-01-08 17:05:54 +00:00
nextint n =
let
a = 22695477
c = 1
m = 2^32
in
(a*n + c) `rem` m
-- generate a random sequence of length k starting with some seed
2013-01-08 17:05:54 +00:00
randlist seed k = if (k<0) then [] else (nextint seed):randlist (nextint seed) (k-1)
-- generate a random sequence of points of length k starting with some seed
2013-01-08 17:05:54 +00:00
randcouples seed k = if (k<0) then []
else
let ns = nextint seed
nns = nextint ns
in (ns,nns):randcouples nns (k-1)
-- END OF PSEUDO RANDOM NUMBER GENERATION
{-
- Flame Set
-
- S = U_{i} F_i(S)
-
- F_i being transformations
- General form:
- F = affine . linearcomp [variation] . affine
- affine is a linear function (x,y) -> (ax+by+c,dx+ey+f)
- variation is some kind of function with some contraction properties
ex: (x,y) -> (x,y), (sin x, sin y), etc...
- linearcomp [f] is a linear composition of functions: (x,y) -> Sum vi*f(x,y)
-}
data Matrice = M Float Float Float Float Float Float
aff (M a b c d e f) (x,y) = (a*x + b*y + c, d*x + e*y +f)
-- Some affine functions to generate the sierpinsky set
-- Equivalent to
-- sierp = [ \(x,y)->(x/2,y/2)
-- , \(x,y)->((x+1)/2,y/2)
-- , \(x,y)->(x/2,(y+1)/2) ]
sierp = [ aff $ M
0.5 0.0 0.0
0.0 0.5 0.0
, aff $ M
0.5 0.0 0.5
0.0 0.5 0.0
, aff $ M
0.5 0.0 0.0
0.0 0.5 0.5
]
2013-01-08 17:05:54 +00:00
-- Some variations
2013-01-09 14:37:54 +00:00
vs = [ \(x,y) -> (x,y)
, \(x,y) -> (sin x, sin y)
, \(x,y) -> let r2 = x*x+y*y in (x/r2,y/r2)
, \(x,y) -> let r2 = x*x+y*y in (x*(sin r2) - y*(cos r2),x*(cos r2) + y * (sin r2))
, \(x,y) -> let r = sqrt (x^2+y^2) in ((x - y)*(x + y)/r,2*x*y/r)
]
-- Some final functions
fs = [ (vs !! 3) . (sierp !! 0)
, (vs !! 3) . (sierp !! 1)
, (vs !! 3) . (sierp !! 2)]
2013-01-09 14:37:54 +00:00
-- Transformation functions
-- translate
trans (tx,ty) = aff $ M 1 0 tx 0 1 ty
-- rotate
rot phi = aff $ M (cos phi) (sin phi) 0.0 (neg (sin phi)) (cos phi) 0.0
-- zoom
zoom z = aff $ M z 0 0 0 z 0
2013-01-09 14:37:54 +00:00
-- The final transformation to transform the final result (zoom,rotate,translate)
2013-01-11 15:31:24 +00:00
final = trans (280,200) . zoom 300 . rot (neg 0.747)
2013-01-09 14:37:54 +00:00
2013-01-11 15:31:24 +00:00
sierpset startpoint rands tmpres =
2013-01-09 14:37:54 +00:00
if rands == []
2013-01-11 15:31:24 +00:00
then tmpres
2013-01-09 14:37:54 +00:00
else
let
randval=(head rands) `rem` (length fs)
newpoint = (fs !! randval) startpoint
2013-01-11 15:31:24 +00:00
roundPoint (x,y) = (round x,round y)
savepoint = roundPoint ( final newpoint )
oldvalue = Dict.lookup savepoint tmpres
newvalue = 1 + (Maybe.fromMaybe 0 oldvalue)
newtmpres = Dict.insert savepoint newvalue tmpres
2013-01-09 14:37:54 +00:00
in
2013-01-11 15:31:24 +00:00
(sierpset newpoint (tail rands) newtmpres)
2013-01-09 14:37:54 +00:00
2013-01-11 15:31:24 +00:00
sierpinsky = sierpset (0.0,0.0) (randlist 0 1000000) Dict.empty
scene (x,y) (w,h) =
let
2013-01-11 15:31:24 +00:00
inpoint ((x,y),_) = x>=0 && x<=w && y>=0 && y<=h
in layers
[ background w h
, collage w h $
map colorpoint $
filter inpoint $
Dict.toList $ sierpinsky
]
2013-01-08 17:05:54 +00:00
2013-01-11 15:31:24 +00:00
main = scene (0,0) (500,500)