Frédéric Mélantois
WPF : Les transformations et les calculs matriciels
Le framework WPF permet d’effectuer un grand nombre de transformations sur des éléments héritant de la classe UIElement. Nous allons détailler les calculs matriciels.
Par Frédéric Mélantois publié le 16/11/2008 à 22:30, lu 3408 fois, 5 pages
 1 | Rotations et translations de base
Le framework WPF offre une facilité impressionnante de mise en œuvre des transformations et animations. Ceci n’a rien d’étonnant puisque WPF a été conçu pour la présentation comme son nom l’indique (Windows Presentation Foundation). Appliquer une rotation à un objet ne nécessite aucune compétence mathématique particulière puisque la mise en œuvre est purement déclarative.
Prenons l’exemple d’une ligne que nous souhaiterions voir animer par une rotation sur elle-même. Au lieu d’une ligne, il pourrait s’agir bien entendu de n’importe quels éléments du Framework héritant de la classe UIElement, et même de nos propres classes personnalisées comme nous le verrons plus loin.
La mise en œuvre en Xaml se résume à la simple déclaration :

< Window x : Class ="WindowsFormsHostWPF.MatriceTransformation"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   Height="900" Width="900">

    < Window.Resources >

        < Storyboard x : Key ="storyBoard1">

            < DoubleAnimation Duration ="0:0:20" From ="0" To ="360"

                            Storyboard.TargetName="rotateTransform1" Storyboard.TargetProperty="Angle"/>

        </ Storyboard >

    </ Window.Resources >

    < Window.Triggers >

        < EventTrigger RoutedEvent ="FrameworkElement.Loaded">

            < BeginStoryboard Storyboard ="{ StaticResource storyBoard1 }"/>

        </ EventTrigger >

    </ Window.Triggers >

    < Canvas >

        < Line X1 ="300" Y1 ="300" X2 ="600" Y2 ="600" x : Name ="line1" Stroke ="Black" StrokeThickness ="2">

            < Line.RenderTransform >

                < RotateTransform CenterX ="450" CenterY ="450" x : Name ="rotateTransform1"/>

            </ Line.RenderTransform >

        </ Line >

    </ Canvas >

</ Window >

La ligne effectue une rotation sur elle-même au point (450,450). Si nous souhaitons ajouter une translation de ce point vers le point (700,200), nous utiliserons la possibilité offerte par WPF de constituer facilement un groupe de transformations constitué d’une rotation (RotateTransform) et d’une translation (TranslateTransform). Nous pouvons ainsi animer la ligne d’une rotation sur elle-même du point (450,450) vers le point (700,200).

< Window x : Class ="WindowsFormsHostWPF.MatriceTransformation"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   Height="900" Width="900">

    < Window.Resources >

        < Storyboard x : Key ="storyBoard1">

            < DoubleAnimation Duration ="0:0:20" From ="0" To ="360"

                            Storyboard.TargetName="rotateTransform1" Storyboard.TargetProperty="Angle"/>

            < DoubleAnimation Duration ="0:0:20" To ="250"

                            Storyboard.TargetName="translateTransform1" Storyboard.TargetProperty="X"/>

            < DoubleAnimation To ="-250" Duration ="0:0:20"

                            Storyboard.TargetName="translateTransform1" Storyboard.TargetProperty="Y"/>

        </ Storyboard >

    </ Window.Resources >

    < Window.Triggers >

        < EventTrigger RoutedEvent ="FrameworkElement.Loaded">

            < BeginStoryboard Storyboard ="{ StaticResource storyBoard1 }"/>

        </ EventTrigger >

    </ Window.Triggers >

    < Canvas >

        < Line X1 ="300" Y1 ="300" X2 ="600" Y2 ="600" x : Name ="line1" Stroke ="Black" StrokeThickness ="2">

            < Line.RenderTransform >

                < TransformGroup >

                    < RotateTransform CenterX ="450" CenterY ="450" x : Name ="rotateTransform1"/>

                    < TranslateTransform x : Name ="translateTransform1"/>

                </ TransformGroup >

            </ Line.RenderTransform >

        </ Line >

    </ Canvas >

</ Window >

La translation du point (450, 450) au point (700, 200) correspond à un déplacement de la ligne de (700-450) soit 250 suivant l’axe des abscisses et de (200-450) = -250 suivant l’axe des ordonnées.
Un équivalent par le code à la méthode déclarative ci-dessus pourrait être :

Line l = new Line();

l.Stroke = new SolidColorBrush(Colors.Black);

l.StrokeThickness = 2;

l.X1 = 300;

l.X2 = 600;

l.Y1 = 300;

l.Y2 = 600;

 

canvas1.Children.Add(l);

 

TransformGroup tg = new TransformGroup();

RotateTransform rt = new RotateTransform();

rt.CenterX = 450;

rt.CenterY = 450;

 

DoubleAnimation da = new DoubleAnimation(0, 360, new Duration(new TimeSpan(0, 0, 20)));

rt.BeginAnimation(RotateTransform.AngleProperty, da);

 

TranslateTransform tt = new TranslateTransform();

 

DoubleAnimation datt1 = new DoubleAnimation(700 - 450, new Duration(new TimeSpan(0, 0, 20)));

DoubleAnimation datt2 = new DoubleAnimation(200 - 450, new Duration(new TimeSpan(0, 0, 20)));

tt.BeginAnimation(TranslateTransform.XProperty, datt1);

tt.BeginAnimation(TranslateTransform.YProperty, datt2);

 

tg.Children.Add(rt);

tg.Children.Add(tt);

 

l.RenderTransform = tg;

Pour les précédentes mises en œuvre, nous n’avons pas eu besoin de faire appel à nos connaissances mathématiques puisque que le Framework propose un niveau d’abstraction important. Avec les Winforms, nous aurions dû écrire beaucoup plus de code GDI+ pour effectuer le même effet, en particulier, nous aurions dû, dans un premier temps, écrire une classe Matrice pour pouvoir effectuer les transformations reposant sur des calculs matriciels.
 
» Démarrer une discussion