mirror of
https://github.com/reanimate/reanimate.git
synced 2026-09-11 16:12:20 +00:00
Improve README examples (#68)
- Move examples higher, above any technical details. - Use a consistent off-white background color. - Use more interesting and less trivial examples. - Play at 50fps rather than 25fps. - Host offsite (imgur) as to not take up repo space. - Link to source file for each example. Former-commit-id: 7e62a3a1ca99e9abc5781568ff920066c94783ee
This commit is contained in:
parent
a753342955
commit
fd2935c2ba
14 changed files with 159 additions and 201 deletions
40
README.md
40
README.md
|
|
@ -16,15 +16,29 @@ scripting.
|
|||
In more practical terms, reanimate is a library for turning code like this:
|
||||
|
||||
```haskell
|
||||
main = reanimate $ docEnv $ playThenReverseA $ mkAnimation duration $ \t ->
|
||||
partialSvg t $ pathify $ mkCircle radius
|
||||
where duration = 2; radius = screenHeight/3
|
||||
main = reanimate $ docEnv $ playThenReverseA drawCircle
|
||||
```
|
||||
|
||||
... into animations like this:
|
||||
|
||||

|
||||
[](examples/doc_playThenReverseA.hs)
|
||||
|
||||
# What is reanimate good at?
|
||||
|
||||
## Vector graphics and math
|
||||
[](examples/demo_tangent.hs)
|
||||
[](examples/tut_glue_fourier.hs)
|
||||
|
||||
## Mapping and tracing
|
||||
[](videos/map-projection/gif.hs)
|
||||
[](examples/tut_glue_potrace.hs)
|
||||
|
||||
## Mathematical typesetting
|
||||
[](examples/tut_glue_latex.hs)
|
||||
|
||||
## 2D physics and 3D graphics
|
||||
[](examples/tut_glue_physics.hs)
|
||||
[](examples/tut_glue_povray.hs)
|
||||
|
||||
# Prerequisites
|
||||
|
||||
|
|
@ -62,22 +76,6 @@ animation source code, the browser window will automatically reload and show the
|
|||
* Design overview: https://reanimate.readthedocs.io/en/latest/glue_tut/
|
||||
* Gallery with source code: https://reanimate.readthedocs.io/en/latest/gallery/
|
||||
|
||||
# Examples
|
||||
|
||||
The example gifs are displayed at 25 fps.
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
# Authors
|
||||
|
||||
* David Himmelstrup.
|
||||
|
|
@ -104,4 +102,4 @@ means.
|
|||
|
||||
Completed animations are uploaded to the [Reanimated Science](https://www.youtube.com/channel/UCbZujyI7i6JbI-I0shPvDgg) channel.
|
||||
|
||||
Animation snippets are uploaded to the [Reanimated Science Playground](https://www.youtube.com/channel/UCL7MwXLtQbhJeb6Ts3_HooA) channel.
|
||||
Animation snippets are uploaded to the [Reanimated Science Shorts](https://www.youtube.com/channel/UCL7MwXLtQbhJeb6Ts3_HooA) channel.
|
||||
|
|
|
|||
110
examples/demo_tangent.hs
Executable file
110
examples/demo_tangent.hs
Executable file
|
|
@ -0,0 +1,110 @@
|
|||
#!/usr/bin/env stack
|
||||
-- stack runghc --package reanimate
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
module Main(main) where
|
||||
|
||||
import Control.Lens ((^.))
|
||||
import Control.Monad.State
|
||||
import qualified Data.Vector.Unboxed as V
|
||||
import Geom2D.CubicBezier (AnyBezier (..), Point (..),
|
||||
evalBezierDeriv)
|
||||
import Graphics.SvgTree (Coord, Tree (..), mapTree,
|
||||
pathDefinition)
|
||||
import Linear.Metric
|
||||
import Linear.V2 (V2 (..))
|
||||
import Linear.Vector
|
||||
import Reanimate
|
||||
import Reanimate.Builtin.Documentation
|
||||
|
||||
main :: IO ()
|
||||
main = reanimate $ docEnv $ mkAnimation 30 $ \t ->
|
||||
let piSvg = pathify $ lowerTransformations $ center $ scale 10 $ latex "s" in
|
||||
mkGroup
|
||||
[ mkBackgroundPixel rtfdBackgroundColor
|
||||
, piSvg
|
||||
, drawTangent t piSvg ]
|
||||
|
||||
drawTangent :: Double -> SVG -> SVG
|
||||
drawTangent alpha | alpha >= 1 = id
|
||||
drawTangent alpha = mapTree worker
|
||||
where
|
||||
worker (PathTree path) =
|
||||
let (V2 posX posY, tangent) =
|
||||
atPartial alpha $ toLineCommands $ path^.pathDefinition
|
||||
normed@(V2 tangentX tangentY) = normalize tangent ^* 4
|
||||
V2 midX midY = lerp 0.5 0 normed
|
||||
V2 normVectX normVectY = normalize tangent ^* (svgWidth normalTxt*1.1)
|
||||
tangentSvg =
|
||||
translate (posX) (posY) $
|
||||
rotate (unangle normed/pi*180 + 180) $
|
||||
translate 0 (svgHeight tangentTxt/2) $
|
||||
tangentTxt
|
||||
normalSvg =
|
||||
translate (posX) (posY) $
|
||||
rotate (unangle normed/pi*180 + 90) $
|
||||
translate (svgWidth normalTxt/2*1.1) (svgHeight normalTxt/2*1.3) $
|
||||
normalTxt
|
||||
in mkGroup
|
||||
[ withStrokeWidth (defaultStrokeWidth) $
|
||||
withStrokeColor "black" $
|
||||
translate (posX-midX) (posY-midY) $
|
||||
mkLine (0, 0) (tangentX, tangentY)
|
||||
, withStrokeWidth (defaultStrokeWidth) $
|
||||
withStrokeColor "black" $
|
||||
translate (posX) (posY) $
|
||||
mkLine (0, 0) (-normVectY, normVectX)
|
||||
, withStrokeWidth (defaultStrokeWidth*2) $
|
||||
withStrokeColor "white" $
|
||||
tangentSvg
|
||||
, withFillOpacity 1 $ withFillColor "black" $ withStrokeWidth 0 $
|
||||
tangentSvg
|
||||
, withStrokeWidth (defaultStrokeWidth*2) $
|
||||
withStrokeColor "white" $
|
||||
normalSvg
|
||||
, withFillOpacity 1 $ withFillColor "black" $ withStrokeWidth 0 $
|
||||
normalSvg
|
||||
]
|
||||
worker t = t
|
||||
tangentTxt = scale 1.1 $ center $ latex "tangent"
|
||||
normalTxt = scale 1.1 $ center $ latex "normal"
|
||||
|
||||
atPartial :: Double -> [LineCommand] -> (V2 Double, V2 Double)
|
||||
atPartial alpha cmds = evalState (worker 0 cmds) zero
|
||||
where
|
||||
worker _d [] = pure (0, 0)
|
||||
worker d (cmd:xs) = do
|
||||
from <- get
|
||||
len <- lineLength cmd
|
||||
let frac = (targetLen-d) / len
|
||||
if len == 0 || frac >= 1
|
||||
then worker (d+len) xs
|
||||
else do
|
||||
let bezier = lineCommandToBezier from cmd
|
||||
(pos, tangent) = evalBezierDeriv bezier frac
|
||||
pure $ (fromPoint pos, fromPoint tangent)
|
||||
totalLen = evalState (sum <$> mapM lineLength cmds) zero
|
||||
targetLen = totalLen * alpha
|
||||
|
||||
lineCommandToBezier :: V2 Coord -> LineCommand -> AnyBezier Coord
|
||||
lineCommandToBezier from line =
|
||||
case line of
|
||||
LineBezier [a] ->
|
||||
AnyBezier $ V.fromList [toTuple from, toTuple a]
|
||||
LineBezier [a,b] ->
|
||||
AnyBezier $ V.fromList [toTuple from, toTuple a, toTuple b]
|
||||
LineBezier [a,b,c] ->
|
||||
AnyBezier $ V.fromList [toTuple from, toTuple a, toTuple b, toTuple c]
|
||||
_ -> error (show line)
|
||||
|
||||
fromPoint :: Point a -> V2 a
|
||||
fromPoint (Point x y) = V2 x y
|
||||
|
||||
toTuple :: V2 a -> (a,a)
|
||||
toTuple (V2 x y) = (x, y)
|
||||
|
||||
unangle :: (Floating a, Ord a) => V2 a -> a
|
||||
unangle a@(V2 ax ay) =
|
||||
let alpha = asin $ ay / norm a
|
||||
in if ax < 0
|
||||
then pi - alpha
|
||||
else alpha
|
||||
|
|
@ -12,8 +12,9 @@ import Codec.Picture
|
|||
|
||||
-- layer 3
|
||||
main :: IO ()
|
||||
main = reanimate $ parA bg $ sceneAnimation $ do
|
||||
play $ fourierA (fromToS 0 15) -- Rotate 15 times
|
||||
main = reanimate $ setDuration 30 $ sceneAnimation $ do
|
||||
_ <- newSpriteSVG $ mkBackgroundPixel (PixelRGBA8 252 252 252 0xFF)
|
||||
play $ fourierA (fromToS 0 5) -- Rotate 15 times
|
||||
# setDuration 50
|
||||
# signalA (reverseS . powerS 2 . reverseS) -- Start fast, end slow
|
||||
# pauseAtEnd 2
|
||||
|
|
@ -22,8 +23,6 @@ main = reanimate $ parA bg $ sceneAnimation $ do
|
|||
# reverseA
|
||||
# signalA (powerS 2) -- Start slow, end fast
|
||||
# pauseAtEnd 2
|
||||
where
|
||||
bg = animate $ const $ mkBackgroundPixel (PixelRGBA8 252 252 252 0xFF)
|
||||
|
||||
-- layer 2
|
||||
fourierA :: (Double -> Double) -> Animation
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ latexExample = sceneAnimation $ do
|
|||
-- Draw equation
|
||||
play $ drawAnimation strokedSvg
|
||||
sprites <- forM glyphs $ \(fn, _, elt) ->
|
||||
newSpriteA $ animate $ const $ fn elt
|
||||
newSpriteSVG $ fn elt
|
||||
-- Yoink each glyph
|
||||
forM_ (reverse sprites) $ \sprite -> do
|
||||
spriteE sprite (overBeginning 1 $ aroundCenterE $ highlightE)
|
||||
|
|
|
|||
|
|
@ -18,13 +18,10 @@ main = reanimate $ parA bg $ sceneAnimation $ do
|
|||
xRot <- newVar (-45)
|
||||
yRot <- newVar 220
|
||||
wf <- newSprite $ wireframe <$> unVar xRot <*> unVar yRot
|
||||
tweenVar yRot spinDur (\t v -> fromToS v (v+60*3) $ curveS 2 (t/spinDur))
|
||||
fork $ tweenVar yRot spinDur $ \v -> fromToS v (v+60*3) . curveS 2
|
||||
replicateM_ wobbles $ do
|
||||
tweenVar xRot (wobbleDur/2) (\t v -> fromToS v (v+90) $ curveS 2 (t/(wobbleDur/2)))
|
||||
fork $ do
|
||||
wait (wobbleDur/2)
|
||||
tweenVar xRot (wobbleDur/2) (\t v -> fromToS v (v-90) $ curveS 2 (t/(wobbleDur/2)))
|
||||
wait wobbleDur
|
||||
tweenVar xRot (wobbleDur/2) $ \v -> fromToS v (v+90) . curveS 2
|
||||
tweenVar xRot (wobbleDur/2) $ \v -> fromToS v (v-90) . curveS 2
|
||||
destroySprite wf
|
||||
play $ mkAnimation drawDuration (\t -> partialSvg t (wireframe (-45) 220))
|
||||
# reverseA
|
||||
|
|
|
|||
|
|
@ -22,7 +22,8 @@ import System.Random.Shuffle
|
|||
|
||||
|
||||
main :: IO ()
|
||||
main = reanimate $ parA bg $ sceneAnimation $ do
|
||||
main = reanimate $ sceneAnimation $ do
|
||||
newSpriteSVG $ mkBackgroundPixel $ PixelRGBA8 252 252 252 0xFF
|
||||
zPos <- newVar 0
|
||||
xRot <- newVar 0
|
||||
zRot <- newVar 0
|
||||
|
|
@ -41,8 +42,6 @@ main = reanimate $ parA bg $ sceneAnimation $ do
|
|||
fork $ tweenVar zRot 9 $ \v -> fromToS v 360 . curveS 2
|
||||
wait 10
|
||||
tweenVar zPos 2 $ \v -> fromToS v 0 . curveS 3
|
||||
where
|
||||
bg = animate $ const $ mkBackgroundPixel $ PixelRGBA8 252 252 252 0xFF
|
||||
|
||||
texture :: Double -> SVG
|
||||
texture t = frameAt (t*duration latexExample) latexExample
|
||||
|
|
@ -92,7 +91,7 @@ latexExample = sceneAnimation $ do
|
|||
-- Draw equation
|
||||
play $ drawAnimation strokedSvg
|
||||
sprites <- forM glyphs $ \(fn, _, elt) ->
|
||||
newSpriteA $ animate $ const $ fn elt
|
||||
newSpriteSVG $ fn elt
|
||||
-- Yoink each glyph
|
||||
forM_ (reverse sprites) $ \sprite -> do
|
||||
spriteE sprite (overBeginning 1 $ aroundCenterE $ highlightE)
|
||||
|
|
|
|||
|
|
@ -1,53 +0,0 @@
|
|||
# blender --background --python 01_cube.py -- </path/to/output/image> <resolution_percentage>
|
||||
|
||||
import bpy
|
||||
import os
|
||||
import sys
|
||||
import math
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import utils
|
||||
|
||||
|
||||
def get_output_file_path() -> str:
|
||||
return str(sys.argv[sys.argv.index('--') + 1])
|
||||
|
||||
|
||||
def get_resolution_percentage() -> int:
|
||||
return int(sys.argv[sys.argv.index('--') + 2])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Args
|
||||
output_file_path = get_output_file_path()
|
||||
resolution_percentage = get_resolution_percentage()
|
||||
|
||||
# Setting
|
||||
default_scene = bpy.context.scene
|
||||
default_camera_object = bpy.data.objects["Camera"]
|
||||
|
||||
bpy.ops.object.empty_add(location=(0.0, 0, 0.0))
|
||||
focus_target = bpy.context.object
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
default_camera_object.select_set(True)
|
||||
focus_target.select_set(True)
|
||||
bpy.ops.object.parent_set()
|
||||
focus_target.rotation_mode = 'XYZ'
|
||||
focus_target.rotation_euler = (0,0,0)
|
||||
focus_target.keyframe_insert(data_path='rotation_euler', frame=1)
|
||||
focus_target.rotation_euler = (0,0,math.pi*2)
|
||||
focus_target.keyframe_insert(data_path='rotation_euler', frame=120)
|
||||
|
||||
for k in focus_target.animation_data.action.fcurves.find('rotation_euler', index=2).keyframe_points:
|
||||
k.interpolation = 'LINEAR'
|
||||
|
||||
|
||||
num_samples = 32
|
||||
|
||||
utils.set_animation(default_scene, fps=60, frame_start=1, frame_end=120)
|
||||
|
||||
utils.set_cycles_renderer(default_scene, resolution_percentage, output_file_path, default_camera_object,
|
||||
num_samples, use_denoising=True)
|
||||
|
||||
# Rendering
|
||||
bpy.ops.render.render(animation=True, write_still=True)
|
||||
45
misc/bend.py
45
misc/bend.py
|
|
@ -1,45 +0,0 @@
|
|||
import os
|
||||
import math
|
||||
|
||||
import bpy
|
||||
|
||||
cam = bpy.data.objects['Camera']
|
||||
origin = bpy.data.objects['Cube']
|
||||
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
origin.select_set(True)
|
||||
bpy.ops.object.delete()
|
||||
|
||||
#bpy.ops.mesh.primitive_ico_sphere_add(subdivisions=4)
|
||||
#bpy.ops.mesh.primitive_uv_sphere_add()
|
||||
x = 0.9
|
||||
bpy.ops.mesh.primitive_plane_add()
|
||||
plane = bpy.context.object
|
||||
plane.scale = (1,1.778,1)
|
||||
plane.scale = (1,2,1)
|
||||
bpy.ops.object.shade_smooth()
|
||||
modifier = plane.modifiers.new(name='Subsurf', type='SUBSURF')
|
||||
modifier.levels = 5
|
||||
modifier.render_levels = 5
|
||||
modifier.subdivision_type = 'SIMPLE'
|
||||
|
||||
bpy.ops.object.empty_add(type='ARROWS',rotation=(math.pi/2,0,0))
|
||||
empty = bpy.context.object
|
||||
|
||||
bendUp = plane.modifiers.new(name='Bend up', type='SIMPLE_DEFORM')
|
||||
bendUp.deform_method = 'BEND'
|
||||
bendUp.origin = empty
|
||||
bendUp.deform_axis = 'Z'
|
||||
bendUp.factor = math.pi*x
|
||||
|
||||
bendAround = plane.modifiers.new(name='Bend up', type='SIMPLE_DEFORM')
|
||||
bendAround.deform_method = 'BEND'
|
||||
bendAround.origin = empty
|
||||
bendAround.deform_axis = 'X'
|
||||
bendAround.factor = math.pi*2*x
|
||||
|
||||
scn = bpy.context.scene
|
||||
# scn.render.engine = 'CYCLES'
|
||||
scn.render.film_transparent = True
|
||||
|
||||
bpy.ops.render.render( write_still=True )
|
||||
43
misc/test.py
43
misc/test.py
|
|
@ -1,43 +0,0 @@
|
|||
import os
|
||||
|
||||
import bpy
|
||||
|
||||
cam = bpy.data.objects['Camera']
|
||||
origin = bpy.data.objects['Cube']
|
||||
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
origin.select_set(True)
|
||||
bpy.ops.object.delete()
|
||||
|
||||
#bpy.ops.mesh.primitive_ico_sphere_add(subdivisions=4)
|
||||
bpy.ops.mesh.primitive_uv_sphere_add()
|
||||
bpy.ops.object.shade_smooth()
|
||||
|
||||
# bpy.data.materials.new('Prog mat')
|
||||
bpy.context.object.active_material = bpy.data.materials['Material']
|
||||
mat = bpy.context.object.active_material
|
||||
image_node = mat.node_tree.nodes.new('ShaderNodeTexImage')
|
||||
texture = mat.node_tree.nodes['Principled BSDF']
|
||||
texture.inputs['Roughness'].default_value = 1
|
||||
mat.node_tree.links.new(image_node.outputs['Color'], texture.inputs['Base Color'])
|
||||
|
||||
bpy.ops.image.open(filepath='/home/lemmih/Downloads/earth.jpg')
|
||||
image_node.image = bpy.data.images['earth.jpg']
|
||||
|
||||
|
||||
|
||||
# image_node.image = bpy.data.images['earth.jpg']
|
||||
# bpy.ops.image.open(filepath='/home/lemmih/Downloads/earth.jpg')
|
||||
# image_node = mat.node_tree.nodes.new('ShaderNodeTexImage')
|
||||
# image_node = mat.node_tree.nodes[1]
|
||||
# texture = mat.node_tree.nodes[2]
|
||||
# mat.node_tree.links.new(image_node.outputs[0], texture.inputs[0])
|
||||
# bpy.data.materials.new('Prog mat')
|
||||
# bpy.context.object.active_material = bpy.data.materials['Prog mat']
|
||||
|
||||
scn = bpy.context.scene
|
||||
# scn.render.engine = 'CYCLES'
|
||||
scn.render.film_transparent = True
|
||||
|
||||
bpy.data.scenes["Scene"].render.filepath = '/tmp/blender.png'
|
||||
bpy.ops.render.render( write_still=True )
|
||||
|
|
@ -91,7 +91,7 @@ library
|
|||
JuicyPixels, attoparsec, parallel,
|
||||
cubicbezier, websockets,
|
||||
hashable, fsnotify, open-browser, random-shuffle, base64-bytestring,
|
||||
vector, colour, cassava, ansi-wl-pprint, here, temporary,
|
||||
vector >= 0.12.0.0, colour, cassava, ansi-wl-pprint, here, temporary,
|
||||
optparse-applicative, chiphunk >= 0.1.2.1,
|
||||
geojson, aeson >= 1.3.0.0
|
||||
ghc-options: -Wall
|
||||
|
|
|
|||
|
|
@ -48,3 +48,6 @@ showColorMap f = center $ scaleToSize screenWidth screenHeight $ embedImage img
|
|||
height = 1
|
||||
img = generateImage pixelRenderer width height
|
||||
pixelRenderer x _y = f (fromIntegral x / fromIntegral (width-1))
|
||||
|
||||
rtfdBackgroundColor :: PixelRGBA8
|
||||
rtfdBackgroundColor = PixelRGBA8 252 252 252 0xFF
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
resolver: lts-13.14
|
||||
resolver: lts-13.19
|
||||
|
||||
allow-newer: false
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ packages:
|
|||
hackage: matrices-0.5.0@sha256:b2761813f6a61c84224559619cc60a16a858ac671c8436bbac8ec89e85473058
|
||||
snapshots:
|
||||
- completed:
|
||||
size: 497078
|
||||
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/13/14.yaml
|
||||
sha256: 9e5ba48e5188aeb52bb0df9bc65dbd858a12c33f5b8d495a3eb588dc9ffcb15a
|
||||
original: lts-13.14
|
||||
size: 498155
|
||||
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/13/19.yaml
|
||||
sha256: b9367a80d4393d02e58a46b8a9fdfbd7bc19f59c0c2bbf90034ba15cf52cf213
|
||||
original: lts-13.19
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import Reanimate
|
|||
import Reanimate.Animation
|
||||
import Reanimate.Scene
|
||||
import Reanimate.GeoProjection
|
||||
import Reanimate.Builtin.Documentation
|
||||
import System.IO.Unsafe
|
||||
import Data.Geospatial hiding (LonLat)
|
||||
import Data.LinearRing
|
||||
|
|
@ -27,8 +28,8 @@ import Control.Lens ((^.))
|
|||
|
||||
|
||||
main :: IO ()
|
||||
main = seq equirectangular $ reanimate $ sceneAnimation $ do
|
||||
newSpriteSVG $ mkBackground "white"
|
||||
main = reanimate $ sceneAnimation $ do
|
||||
newSpriteSVG $ mkBackgroundPixel rtfdBackgroundColor
|
||||
prevProj <- newVar equirectangularP
|
||||
let push label proj = do
|
||||
prev <- readVar prevProj
|
||||
|
|
@ -43,24 +44,24 @@ main = seq equirectangular $ reanimate $ sceneAnimation $ do
|
|||
-- [ grid equirectangularP ]
|
||||
|
||||
-- push "Lambert" lambertP
|
||||
push "Web Mercator" mercatorP
|
||||
--push "Web Mercator" mercatorP
|
||||
push "Mollweide" mollweideP
|
||||
-- push "Bottomley 30\\degree" (bottomleyP (toRads 30))
|
||||
push "Bottomley 30\\degree" (bottomleyP (toRads 30))
|
||||
-- 4
|
||||
-- pushInterp "Werner" wernerP
|
||||
push "Werner" wernerP
|
||||
-- 5
|
||||
-- pushInterp "Bonne 45\\degree" (bonneP (toRads 45))
|
||||
-- push "Bonne 45\\degree" (bonneP (toRads 45))
|
||||
-- pushT
|
||||
-- (\t -> "Bonne " <> T.pack (show $ round $ fromToS 45 0 t) <> "\\degree")
|
||||
-- (bonneP . toRads . fromToS 45 0)
|
||||
-- 6
|
||||
-- pushInterp "Eckert I" eckert1P
|
||||
-- pushInterp "Eckert III" eckert3P
|
||||
-- pushInterp "Eckert IV" eckert5P
|
||||
-- push "Eckert I" eckert1P
|
||||
-- push "Eckert III" eckert3P
|
||||
-- push "Eckert IV" eckert5P
|
||||
-- 7
|
||||
-- push "Fahey" faheyP
|
||||
-- 8
|
||||
push "August" augustP
|
||||
-- push "August" augustP
|
||||
-- 9
|
||||
push "Foucaut" foucautP
|
||||
-- 10
|
||||
|
|
@ -70,17 +71,9 @@ main = seq equirectangular $ reanimate $ sceneAnimation $ do
|
|||
play $ signalA (curveS 2) $
|
||||
mkAnimation morphT $ grid . mergeP prev equirectangularP
|
||||
where
|
||||
src = equirectangular
|
||||
waitT = 0
|
||||
morphT = 1
|
||||
|
||||
equirectangular :: Image PixelRGB8
|
||||
equirectangular = unsafePerformIO $ do
|
||||
dat <- BS.readFile "earth.jpg"
|
||||
case decodeJpeg dat of
|
||||
Left err -> error err
|
||||
Right img -> return $ convertRGB8 img
|
||||
|
||||
toRads :: Double -> Double
|
||||
toRads dec = dec/180 * pi
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue