April 14, 2004

Thinking through MVC animation

Ooh! Paolo likes JUNG!

And from here on, this is just thinking-through a problem, in the hopes that moving my fingers will cause my brain to fire. This is highly techie! Feel free to ignore, unless thinking about java paintComponent loops makes you happy...

One of my not-so-minor side projects for a little while has been the JUNG project. I've found that one of its most useful features is the visualizaiton module, and so I've spent the bulk of my time on it. Fighting with it has been a useful exercise in ... well, in lots of things. Thread control. Animation. Synchronization.

Here's the basic scenario:
# Vertices are laid out in some intial location
# An animation loop then moves them forward to more "relaxed" positions
# A renderer draws them on screen

All of these are modular, so that users can create whatever layouts, renderers, and what have you that they wish...

Now, there are a few subtleties here. For one thing, step (2) can be slow. Very slow, if you're using a sufficiently detailed algorithm. (So can step (1), but in a certain sense, I don't care about that--it's startup time, not interactive time.) Worse, Step (2) happens over, and over, and over again.

Now, in the first release of JUNG, we just drew whatever step (2) had just produced. Inconsistent? No problem. Just throw it on up there. Of course, sometimes the render loop would happen to paint right in the middle of a calculation, so that vertices and edges wouldn't be connected. But go on, paint it, paint it!

The upcoming release seeks to fix that. I'm also trying to allow...

  • mutating the graph (e.g. add or remove nodes)
    • animating smoothly between two different states, as in GTV
  • meta-layout operations
    • this layout is placing vertices from (0,0) to (300, 300), but we want to display them from (20,20) to (180, 180).
    • this layout consists of four smaller layouts, each of which has a separate graph component inside of it
  • Click-to-select for vertices and edges
  • Click-and-drag for vertices

Now, the meta-layout causes some problems. Let's go back to that sequence of operations and add one.

  1. Vertices are laid out in some intial location
  2. An animation loop then moves them forward to more "relaxed" positions
  3. A meta layout re-sizes and re-places them
  4. A renderer draws them on screen

Now, the new step 3 can happen as often as step 2 updates, and may happen even more often--say, when the user pulls on the bottom corner of the screen to resize. (Hey! The resize handler is just a metalayout! The algorithm doesn't need to care!)

Where do we get the data for 3? Well, presumably, we cached the last result from the animation loop. And the renderer had better cache the last result from the metalayout, since the metalayout may be busily processing when the renderer gets started.

I could, to be sure, throw a lock in any of these steps--make them share data, but force them to be synchronous. But I don't trust any of them in particular to be highly efficient. Perhaps changes in the metalayout could wait for the next animation frame to come through.

--

But that's not what's worrying me today. What's worrying me is that I want to allow for graph mutation. When the graph changes, the various calculation in the animation loop ("how close is this edge to that one?") immediately change. But I don't do the various graph overhead tasks--assigning locations to new vertices, for example, and removing other vertices from the animation--until a few moments later, when the user calls visualization.updateGraph( graph ). In the mean time, we start seeing the errors that Java throws when a data source is changing as you use it: ConcurrentModificationError, mostly.

So how do I handle this?

Well, the thing that's coming to mind, anti-climactically, is to say "DONT DO THAT!". If you want to change a graph, copy your current graph, change it, and then tell the animation system to work off of your changed version.

But that's even more memory, more space, more CPU load.

The other version would be freeze step 2 midsteam, modify the graph, then unfreeze step 2. That's doable, I guess, but computationally tough. For one thing, every graph change would have to emit two different events: "About to change ..." and then "...changed."

--

Anyone have experience with this? A solution to how the model-view-controller works when the model keeps shifting under your feet, and the view is not as synchronous as you might wish?

April 14, 2004 11:32 AM | TrackBack | in Other
Comments
Post a comment









Remember personal info?