Animated line art

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
13 messages Options
Reply | Threaded
Open this post in threaded view
|

Animated line art

Andrew Coppin
So, the muse has taken me. I'm going to attempt to produce some animated
mathematical drawings involving lines and curves.

Gtk2hs has a Cairo binding that should make rendering the stuff fairly
straight-forward. So no problems there.

Now, what I *could* do is write a new Haskell program for each drawing I
want, hard-coding in the necessary imperative loops for updating
coordinates, looping over multiple lines, etc. But that wasn't be very
Haskell, would it? ;-)

It seems that the "correct" course of action is to design a DSL for
declaratively describing animated line art. Does anybody have ideas
about what such a thing might look like?

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Animated line art

Martijn van Steenbergen-2
Andrew Coppin wrote:
> It seems that the "correct" course of action is to design a DSL for
> declaratively describing animated line art. Does anybody have ideas
> about what such a thing might look like?

You could take a look at Fran [1] and Yampa [2] which both seem to do
animations in Haskell.

[1] http://conal.net/Fran/
[2] http://www.haskell.org/yampa/

Martijn.
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

RE: Animated line art

Tim Docker
In reply to this post by Andrew Coppin
> It seems that the "correct" course of action is to design a DSL for
declaratively describing animated line art. Does anybody have ideas
about what such a thing might look like?

Someone else already mentioned FRAN and it's ilk. But perhaps you don't
need something that fancy. If you implement your drawing logic as a
function from time to the appropriate render actions, ie

| import qualified Graphics.Rendering.Cairo as C
|
| type Animation = Time -> C.Render ()

then you just need to call this function multiple times to generate
sucessive frames.

Tim
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Animated line art

Dan Weston
Andrew,

I can think of several reasons why simple time-indexed animation may be
a bad idea. Some important aspects of animation are usually:

1) A main use case is playback, where time change is continuous and
monotonic.

2) Differential action is often much cheaper than time jumping (i.e.
between adjacent time steps most lines do not move and do not need to be
recomputed. It is cheaper to modify the previous animation.)

3) Time is a topological space, with lots of nice properties: change of
time is a group, intervals are decomposable, etc. Animation inherits
this structure as a G-torsor (e.g. between two close enough times the
line art should look very similar, there is no canonical start time).
You are throwing this all away if you just treat line art like a point set.

4) Although your Time set may be discrete, you may want to pretend it is
smooth to facilitate e.g. motion blur and simulation, which strongly
favor a differential approach. There is often a need for run-up or
adaptive time interval subdivision. Clip start and stop times are often
changed interactively.

Instead of defining a calculus (line art indexed by time), you may want
to define an algebra (action of time change on line art). You can
manipulate the algebra independently for efficiency (e.g. combine
adjacent time intervals into one big interval if pointwise evaluation is
cheap, or subdivide an interval if differential change is cheap) and
then apply the final result to line art defined at some time origin.

Take a quick read of http://en.wikipedia.org/wiki/Principal_bundle where
the (group) G is time change and the (fiber bundle) P is the line art.

At minimum, implement your time argument as a start time + delta time,
and consider a State monad (or StateT monad transformer) to hold future
optimizations like cached (time,art) pairs in case you change your mind.

Dan

Tim Docker wrote:

>> It seems that the "correct" course of action is to design a DSL for
> declaratively describing animated line art. Does anybody have ideas
> about what such a thing might look like?
>
> Someone else already mentioned FRAN and it's ilk. But perhaps you don't
> need something that fancy. If you implement your drawing logic as a
> function from time to the appropriate render actions, ie
>
> | import qualified Graphics.Rendering.Cairo as C
> |
> | type Animation = Time -> C.Render ()
>
> then you just need to call this function multiple times to generate
> sucessive frames.
>
> Tim
> _______________________________________________
> Haskell-Cafe mailing list
> [hidden email]
> http://www.haskell.org/mailman/listinfo/haskell-cafe
>
>


_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Animated line art

Ben Lippmeier
In reply to this post by Tim Docker



On 05/12/2008, at 10:46 AM, Tim Docker wrote:

> Someone else already mentioned FRAN and it's ilk. But perhaps you  
> don't
> need something that fancy. If you implement your drawing logic as a
> function from time to the appropriate render actions, ie
>
> | import qualified Graphics.Rendering.Cairo as C
> |
> | type Animation = Time -> C.Render ()
>
> then you just need to call this function multiple times to generate
> sucessive frames.

The ANUPlot graphics library I wrote does exactly this.
The darcs repo is at http://code.haskell.org/ANUPlot/ANUPlot-HEAD/
It comes with lots of examples that do the sort of things you describe.

Ben.

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Animated line art

Andrew Coppin
In reply to this post by Martijn van Steenbergen-2
Martijn van Steenbergen wrote:

> Andrew Coppin wrote:
>> It seems that the "correct" course of action is to design a DSL for
>> declaratively describing animated line art. Does anybody have ideas
>> about what such a thing might look like?
>
> You could take a look at Fran [1] and Yampa [2] which both seem to do
> animations in Haskell.
>
> [1] http://conal.net/Fran/
> [2] http://www.haskell.org/yampa/

I don't think either of them will do precisely what I want, but they
give me lots of useful stuff to think about.

PS. The flying heads were disturbing though.

PPS. "Yampa is still in active development. [...] This page last updated
March 22 2004."

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Animated line art

Andrew Coppin
In reply to this post by Tim Docker
Tim Docker wrote:

> Someone else already mentioned FRAN and it's ilk. But perhaps you don't
> need something that fancy. If you implement your drawing logic as a
> function from time to the appropriate render actions, ie
>
> | import qualified Graphics.Rendering.Cairo as C
> |
> | type Animation = Time -> C.Render ()
>
> then you just need to call this function multiple times to generate
> sucessive frames.
>  

That was my initial idea... but I'm not sure how well it would work. I
want to do stuff like fade elements in and out, move complex structures
around on the screen, etc. I think it might end up being a little
tangled if I go with this approach. I might be wrong though...

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Animated line art

Andrew Coppin
In reply to this post by Ben Lippmeier
Ben Lippmeier wrote:
> The ANUPlot graphics library I wrote does exactly this.
> The darcs repo is at http://code.haskell.org/ANUPlot/ANUPlot-HEAD/
> It comes with lots of examples that do the sort of things you describe.

Does it handle drawing lines and circles (with antialiasing)? Can I save
the output as PNG?

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Animated line art

Andrew Coppin
In reply to this post by Andrew Coppin
Today I sat down and had a think about this problem. After reading about
various FRP systems (Yampa et al) I had a few ideas in my head.

The main idea is that I want to be able to draw lines and curves and so
forth, and I want to add them to and remove them from the display at
various times, and move them around, change their colour and opacity,
etc. I also want to be able to run one piece of animation, and then
another, and then another. So I want some sort of sequencing primitives.

I had a go at writing what I thought the interface might look like.
(Fortunately, I made no attempt to *implement* it - otherwise I would
doubtless have wasted huge amounts of time implementing something that
isn't designed right yet!) Unfortunately Haskell doesn't really provide
a way to write an "interface", and then write the implementation behind
it seperately somewhere else. So the "code" I wrote wasn't actually
compilable at all, but it was useful to sketch something out.

My initial idea was that I could have some kind of monad for controlling
adding and removing stuff. The monad could provide an "add" action that
adds a visual object to the frame and returns a unique ID. Then you
could have a "remove" action that removes the specified ID again. And a
"wait" action that makes the display stay the same for so many seconds.
(But the visual objects may internally be animated.)

Then I hit upon the idea that maybe one thread of control could "spawn"
a second one - so that for example one thread could generate a bunch of
snowflakes raining down the screen while a seperate thread rotates a
geometric figure in the center. Or something. Of course, these "threads"
have no need (or use) for actually running concurrently - they are only
"concurrent" in the sence that they both affect the same frame, rather
than their actions happening one after another on consecutive frames.

Next I got to thinking that maybe these threads of control might need to
communicate for synchronisation. E.g., when a rotating line reaches 90°
with another line, a signal is sent to another thread, which then adds
another visual element or stops the animation or something. The parent
thread *could* algebraicly _compute_ what time this will happen, but
sending a signal is much simpler. (E.g., if you change the speed of an
animation, the threads still stay synchronised without you having to
remember to adjust parameters in your calculations all over the place...)

There's still one little problem though. The "threads of control" are
for sequencing stuff. They are inherantly discrete; *add* this thing,
*remove* this other thing, *send* this signal, *wait* to receive a
signal, etc. But something like, say, rotating a line, is inherantly
continuous. So there's a discrete system for sequencing stuff - which I
seem to have worked out fairly well - and there also needs to be a
continuous system for doing all the things with are smooth functions of
time.

So maybe the continuous stuff should just be a type alias to a regular
Haskell function? Ah, but wait... I said I might want to send a signal
when an animation reaches a specific stage, right? So these "functions"
need to do more than just map time to some other variable; they need to
be able to send signals. And hey, actually, what are the chances of a
time sample exactly lining up with the instant that the notable event
occurs? How do I want to handle that?

...and at this point, it was time to go home! :-D

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Animated line art

Ben Lippmeier
In reply to this post by Andrew Coppin

On 06/12/2008, at 6:34 AM, Andrew Coppin wrote:

> Ben Lippmeier wrote:
>> The ANUPlot graphics library I wrote does exactly this.
>> The darcs repo is at http://code.haskell.org/ANUPlot/ANUPlot-HEAD/
>> It comes with lots of examples that do the sort of things you  
>> describe.
>
> Does it handle drawing lines and circles (with antialiasing)? Can I  
> save the output as PNG?

Lines and circles yes, antialiasing no. It uses OpenGL for rendering,  
so maybe there's a flag to turn it on. PNG isn't usually required for  
animations. When I need to make an image I just do a screenshot.

Ben.

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Animated line art

Christopher Lane Hinson
In reply to this post by Andrew Coppin

You may also want to at least look at RSAGL, in particular I've
implemented an arrow transformer that does much of what you describe with
threading, although I see that I probably need to go back and work on
documentation.

The basic idea revolves around giving threads an identity type that
implements Eq.  The parent thread can cull threads it doesn't want, while
the threads themselves can spawn new threads or self-terminate.  If a
thread spawns a thread ID that already exists, the new duplicate is
disregarded (unless you choose to provide a different behaviour).
Anonymous threads are implemented using Maybe.

Threads have an explicit ultimate input and output type, and can
explicitly switch themselves over to another thread with matching input
and output types.

Both the spawn and switch directives take a continuous input, which is a
list or Maybe respectively containing information about what spawn or
switch should be dispatched at that moment.

Since it's an arrow transformer, you can for example pass
messages between threads by layering it on top of a StateArrow.

I have also used a StateArrow to accumulate rendering instructions and to
manage a transformation matrix context.

You talk about adding and removing "things", but I don't think that's a
good idea.  Rather the thing's existence and disposition is a continuous
function within a thread.

If it assists with understanding, the StatefulArrow is a stripped down
arrow transformer version of the YAMPA arrow, and the other arrows build
on that functionality until you get to the FRP arrow.

The git repo is browsable here:

http://roguestar.downstairspeople.org/gitweb?p=rsagl.git;a=summary

Relevant modules are ThreadedArrow, SwitchedArrow, StatefulArrow, FRPBase
and FRP.

I don't have any 2D support in RSAGL at all.

Hopefully this helps and I'd also appreciate any feedback.

--Lane
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Animated line art

Paul Johnson-2
In reply to this post by Andrew Coppin
Andrew Coppin wrote:
> So I want some sort of sequencing primitives.
Sequencing generally suggests a monad.  something = do { action1; delay
10; action2}

> I had a go at writing what I thought the interface might look like.
> (Fortunately, I made no attempt to *implement* it - otherwise I would
> doubtless have wasted huge amounts of time implementing something that
> isn't designed right yet!) Unfortunately Haskell doesn't really
> provide a way to write an "interface", and then write the
> implementation behind it seperately somewhere else. So the "code" I
> wrote wasn't actually compilable at all, but it was useful to sketch
> something out.
When I do this I generally write functions like   foo = error "foo: Not
implemented yet"

> My initial idea was that I could have some kind of monad for
> controlling adding and removing stuff. The monad could provide an
> "add" action that adds a visual object to the frame and returns a
> unique ID. Then you could have a "remove" action that removes the
> specified ID again. And a "wait" action that makes the display stay
> the same for so many seconds. (But the visual objects may internally
> be animated.)
I'd suggest that each object has its own action to animate it.  You will
need to write a custom monad to interleave actions.  See
http://www.cs.chalmers.se/~koen/pubs/jfp99-monad.ps for something along
the right lines.
> Then I hit upon the idea that maybe one thread of control could
> "spawn" a second one - so that for example one thread could generate a
> bunch of snowflakes raining down the screen while a seperate thread
> rotates a geometric figure in the center. Or something.
Sounds right.

> Of course, these "threads" have no need (or use) for actually running
> concurrently - they are only "concurrent" in the sence that they both
> affect the same frame, rather than their actions happening one after
> another on consecutive frames.
>
> Next I got to thinking that maybe these threads of control might need
> to communicate for synchronisation. E.g., when a rotating line reaches
> 90° with another line, a signal is sent to another thread, which then
> adds another visual element or stops the animation or something. The
> parent thread *could* algebraicly _compute_ what time this will
> happen, but sending a signal is much simpler. (E.g., if you change the
> speed of an animation, the threads still stay synchronised without you
> having to remember to adjust parameters in your calculations all over
> the place...)
Yup.  I did exactly this, albeit for a very different application.  
Unfortunately the code belongs to my employer so I can't post it.  But
if you look at the paper above and also read about the "ContT" monad you
will get the right idea.  Its a bit mind-bending, but you suspend a
thread by getting its continuation (using callCC) and stuffing it into
whatever data structure is being used to hold pending threads (e.g. a
semaphore queue).

Or you could use the existing concurrent threads mechanism, which is
kludgier but less work.
> There's still one little problem though. The "threads of control" are
> for sequencing stuff. They are inherantly discrete; *add* this thing,
> *remove* this other thing, *send* this signal, *wait* to receive a
> signal, etc. But something like, say, rotating a line, is inherantly
> continuous. So there's a discrete system for sequencing stuff - which
> I seem to have worked out fairly well - and there also needs to be a
> continuous system for doing all the things with are smooth functions
> of time.
Thats where Reactive stuff comes in.
>
> So maybe the continuous stuff should just be a type alias to a regular
> Haskell function? Ah, but wait... I said I might want to send a signal
> when an animation reaches a specific stage, right? So these
> "functions" need to do more than just map time to some other variable;
> they need to be able to send signals. And hey, actually, what are the
> chances of a time sample exactly lining up with the instant that the
> notable event occurs? How do I want to handle that?
Events are part of reactive frameworks.

Paul.
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Animated line art

Tim Docker-3
In reply to this post by Andrew Coppin

On 06/12/2008, at 6:32 AM, Andrew Coppin wrote:

> Tim Docker wrote:
>> If you implement your drawing logic as a
>> function from time to the appropriate render actions, ie
>>
>> | import qualified Graphics.Rendering.Cairo as C
>> | | type Animation = Time -> C.Render ()
>>
>> then you just need to call this function multiple times to generate
>> sucessive frames.
>>
>
> That was my initial idea... but I'm not sure how well it would  
> work. I want to do stuff like fade elements in and out, move  
> complex structures around on the screen, etc. I think it might end  
> up being a little tangled if I go with this approach. I might be  
> wrong though...

This model of animation as "a function of time to a picture" is  
probably described in many places. I first saw it described in Paul  
Hudaks book "The haskell School of Expression: Learning functional  
programming through multimedia". It shows how primitive animations  
can be combined in various ways, including overlays and time  
transformations. You can download the code from the books web-site,  
which might be of interest even if you can't get hold of a copy of  
the book. It's intended for pedagogical purposes, rather than a  
comprehensive animation system, of course.

Tim
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe