Inspired By Flash Math Creativity #3: WPF Flag

There is a clever sample up on Flash Math Creativity by Lifaros that fundamentally does 2D morph meshing by chopping up an image into sections and then animating the sections, resulting in the effect of a flag waving.  I decided to implement something similar in WPF.  When I started thinking about how to chop up something in WPF, I remembered the Slide Puzzle sample from the SDK and I used it the foundation for how to chop, well, anything up in WPF.  (If you haven't checked out this sample, definitely do so!)

In my sample, I only chop up an image, but nothing is stopping you from using this same technique to chop up a video, a document or the UI itself.  Once again, I used the custom animation classes to create the animation using Math.Sin.  The slider allows you to modify the intensity of the wave. The result? The UN flag waving in the desert.  I'm not sure why.  Download source or run it.

Here's the crux of the code:

private void Chop()
{
    stackPanel.Children.Clear();
    Image image = (Image)this.Resources["image"];
    BitmapSource bitmap = (BitmapSource)image.Source;
    Size size = new Size(bitmap.PixelWidth / 5, bitmap.PixelHeight / 5);
    image.Width = size.Width;
    image.Height = size.Height;

    float edgesize = 1.0f / numCols;

    // Set up viewbox appropriately for each tile.
    for (int i = 0; i < numCols; i++)
    {
        Rectangle r = new Rectangle();
        TranslateTransform t = new TranslateTransform();
        r.RenderTransform = t;
        //this confused me at first!
        r.SnapsToDevicePixels = true;
        VisualBrush vb = new VisualBrush(image);
        //viewboxes are all relative to 1
        vb.Viewbox = new Rect(edgesize * i, 0, edgesize, 1);
        vb.ViewboxUnits = BrushMappingMode.RelativeToBoundingBox;
        r.Fill = vb;
        r.Height = image.Height;
        r.Width = image.Width / numCols;

        CircleAnimation ca = new CircleAnimation();
        ca.Direction = CircleAnimation.DirectionEnum.YDirection;
        ca.Radius = slider.Value;
        ca.Duration = TimeSpan.FromSeconds(1);
        ca.BeginTime = TimeSpan.FromMilliseconds(i * 10);
        ca.RepeatBehavior = RepeatBehavior.Forever;
        t.BeginAnimation(TranslateTransform.YProperty, ca);
        stackPanel.Children.Add(r);

    }

}