Flint2-Examples-0.1.0.0: app/complex_plot/ColorFunction.hs
module ColorFunction where
import Data.List (findIndex)
import Data.Complex
colorFunction mode z
| not (isInfinite r || isNaN r) = colorFunction' mode z
| otherwise = (0.5, 0.5, 0.5)
where r = magnitude z
colorFunction' 0 z = toRGB (h, l, s) where
phi = phase z
tmp = (phi + pi)/(2*pi) + 1/2
h = tmp - fromIntegral (floor tmp)
l | log (magnitude z) > 200 = 1
| log (magnitude z) < -200 = 0
| otherwise = 1 - 1 / (1 + (magnitude z) ** 0.2)
s = 0.8
colorFunction' 1 z = (r, g, b) where
phi = phase z
h = max (min (phi/pi) 1) (-1)
Just j = findIndex ((>h) . head) blueOrangeColors
[ha, ra, ga, ba] = blueOrangeColors !! (j-1)
[hb, rb, gb, bb] = blueOrangeColors !! j
s = (h - ha) / (hb - ha)
r = ra + (rb - ra) * s
g = ga + (gb - ga) * s
b = ba + (bb - ba) * s
blueOrangeColors = [
[-1.0, 0.0, 0.0, 0.0],
[-0.95, 0.1, 0.2, 0.5],
[-0.5, 0.0, 0.5, 1.0],
[-0.05, 0.4, 0.8, 0.8],
[ 0.0, 1.0, 1.0, 1.0],
[ 0.05, 1.0, 0.9, 0.3],
[ 0.5, 0.9, 0.5, 0.0],
[ 0.95, 0.7, 0.1, 0.0],
[ 1.0, 0.0, 0.0, 0.0],
[ 2.0, 0.0, 0.0, 0.0]
]
colorFunction' mode z
| mode == 2 = (r, g, b)
| mode == 3 = mix 0.0 (-0.5) 0.2 0.0 0.0 (-0.1) 0.0 (-1.0) (-0.2)
| mode == 4 = mix 0.0 (-0.5) 0.2 0.0 0.5 (-0.1) 0.0 (-0.3) (-1.0)
| mode == 5 = mix 0.0 (-0.5) (-1.0) 0.0 (-0.1) (-0.67) 0.0 (-0.55) (-0.12)
| mode == 6 = mix 0.86 0.0 0.13 0.57 0.19 (-0.52) 0.31 (-0.30) (-0.94)
where
(r1, g1, b1) = colorFunction 0 z
(r2, g2, b2) = colorFunction 1 z
f x y = blend x (clamp (dodge x y))
[r, g, b] = zipWith f [r1, g1, b1] [r2, g2, b2]
mix = balance (r, g, b)
toRGB (h, l, s)
| s == 0 = (l, l, l)
| otherwise = (vv m1 m2 (h+1/3), vv m1 m2 h, vv m1 m2 (h-1/3))
where
m2 = if l <= 0.5 then l * (1 + s) else l + s - l*s
m1 = 2*l - m2
vv m1 m2 hue
| 6*h < 1 = m1 + (m2 - m1)*h*6
| 2*h < 1 = m2
| 3*h < 2 = m1 + (m2 - m1)*(2/3 - h)*6
| otherwise = m1
where h = hue - fromIntegral (floor hue)
toHLS (r, g, b)
| hi == lo = (0, l, 0)
| l <= 0.5 = (h', l, d / (hi + lo))
| otherwise = (h', l, d / (2 - hi - lo))
where
hi = max (max r g) b
lo = min (min r g) b
l = 0.5 * (lo + hi)
d = hi -lo
d' = if d /= 0 then d else 1
h | r == hi = (g - b) / d'
| g == hi = (b - r) / d' + 2
| otherwise = (r - g) / d' + 4
h' = h / 6
h'' = if h' < 0 then h' + 1 else h'
clamp x = max 0 (min x 1)
blend x y = (x + y)/2
dodge a b = a / ((1 - b) + 1/256)
balanceChannel value x (shadows, midtones, highlights) = value' where
[a, b, scale] = [1/4, 1/3, 7/10]
shadows' = clamp ((x - b) / (-a) + 0.5) * scale * shadows
midtones' = clamp ((x - b) / a + 0.5) *
clamp ((x + b - 1.0) / (-a) + 0.5) * scale * midtones
highlights' = clamp ((x + b - 1.0) / a + 0.5) * scale * highlights
value' = clamp (value + shadows' + midtones' + highlights')
balance (r, g, b) u' u'' u''' v' v'' v''' w' w'' w''' = (r'', g'', b'') where
[u, v, w] = [(u', u'', u'''), (v', v'', v'''), (w', w'', w''')]
[r', g', b'] = zipWith (\c x -> balanceChannel c c x) [r, g, b] [u, v, w]
(h, l, s ) = toHLS (r, g, b )
(h', l', s') = toHLS (r', g', b')
(r'', g'', b'') = toRGB (h', l, s')
hlsFunction 0 z = (h, l, s) where
x = realPart z
y = imagPart z
phi = atan2 y x
tmp = (phi + pi)/(2*pi) + 1/2
h = tmp - fromIntegral (floor tmp)
l | log(magnitude z) > 138 = 1
| log(magnitude z) < -138 = 0
| otherwise = 1 - 1 / (1 + (magnitude z) ** 0.2)
s = 0.8