Menu

A

|

A

Surface : Affine2DManipulationProcessor

Quand on travaille sur Microsoft Surface, il y a une chose qui nous préoccupe, c’est la compréhension des gestuelles que peuvent faire les utilisateurs sur la table. Tap, ContactDown, agrandissement, rotation, translation, etc… Comment savoir, et surtout comment traiter cette information de façon efficace.

Le SDK Microsoft Surface nous apporte un outil pour cette problématique, l’Affine2DManipulationProcessor. Cette classe assez méconnue, qui se trouve dans le namespace Microsoft.Surface.Presentation.Manipulations, permet facilement de connaitre les gestuelles présente sur la table, voir même de les filtrer.

Le principe est simple, une fois instancié, cette classe permet de scruter et d’analyser les contacts sur la table. Pour faire simple, on donne à l’Affine2DManipulationProcessor des contacts à scruter et celle-ci les analyses pendant tout leur cycle de vie et nous informe des gestuelles qui peuvent être déduite de l’évolution de ses contacts.

Les manipulations sont calculées par rappart à un container UIElement donné. Au moment de l’instanciation de l’Affine2DManipulationProcessor, il y a deux paramètres. Le premier est le type de manipulation que l’on veut observer et le second dans quel contexte graphique. Ainsi, une manipulation est toujours déterminée par son container source, même si celui-ci subit des transformations (rotation, translation, etc..) l’Affine2DManipulationProcessor fournira des informations de manipulation comme si celui-ci n’avait subit ses transformations.

Pour cela, il suffit sur un ContactDown par exemple, de fournir ce contact via la méthode BeginTrack(Contact) à l’Affine2DManipulationProcessor pour que de suite il nous fournisse des informations via trois événements :

Affine2DManipulationStarted : Cet événement est déclenché lors du premier BeginTrack(Contact) et initialise la séquence de manipulation.

Affine2DManipulationDelta : Cet événement est déclenché à chaque fois qu’un contact suivi par l’Affine2DManipulationProcessor est modifié.

Affine2DManipulationCompleted : Cet événement est déclenché quand plus aucun des contacts suivis par l’Affine2DManipulationProcessor n’es présent sur la surface.

Il est à noter que l’on peut ajouter autant de contact que l’on veut via BeginTrack(Contact) et ce à n’importe quel moment de la manipulation, ils seront pris en compte automatiquement et l’Affine2DManipulationDelta sera déclenché automatiquement.

using System;
using Microsoft.Surface.Presentation;
using Microsoft.Surface.Presentation.Controls;
using Microsoft.Surface.Presentation.Manipulations;

namespace MonApplication
{
    public partial class MaSurfaceWindow: SurfaceWindow
    {
        private Affine2DManipulationProcessor traker;

        public MaSurfaceWindow()
        {
            this.InitializeComponent();

            // On défini ce que la classe doit scruter
            traker = new Affine2DManipulationProcessor(Affine2DManipulations.Scale | Affine2DManipulations.Rotate | Affine2DManipulations.TranslateX | Affine2DManipulations.TranslateY, this);

            // On s'abonne aux handlers pour connaitre l'état des contacts
            // et les gestuelles qui en ressortent
            traker.Affine2DManipulationStarted += new EventHandler<Affine2DOperationStartedEventArgs>(this.traker_Affine2DManipulationStarted);
            traker.Affine2DManipulationDelta += new EventHandler<Affine2DOperationDeltaEventArgs>(this.traker_Affine2DManipulationDelta);
            traker.Affine2DManipulationCompleted += new EventHandler<Affine2DOperationCompletedEventArgs>(this.traker_Affine2DManipulationCompleted);
        }

        private void Grid_ContactDown(object sender, ContactEventArgs e)
        {
            // On indique a l'Affine2DManipulationProcessor qu'il
            // doit scruter le contact passé en paramètre
            traker.BeginTrack(e.Contact);
        }

        private void traker_Affine2DManipulationStarted(object sender, Affine2DOperationStartedEventArgs e)
        {
            // Ici le code quand la manipulation commence
        }

        private void traker_Affine2DManipulationDelta(object sender, Affine2DOperationDeltaEventArgs e)
        {
            // Ici le code a chaque changement d'état d'un contact
        }

        private void traker_Affine2DManipulationCompleted(object sender, Affine2DOperationCompletedEventArgs e)
        {
            // Ici le code a la fin de la manipulation
        }
    }
}

Le cycle de vie d’une manipulation est le suivant, au premier contact ajouté dans l’instance la manipulation commence, ensuite elle vie tant que des contacts sont actifs et en scrutation, même si le premier contact se termine, si d’autre ont été ajouté entre temps la manipulation continue. Quand plus aucun contact n’est actif la manipulation se termine.

Une fois que vous avez commencé une manipulation, vous pouvez sur l’Affine2DManipulationDelta obtenir via l’argument de l’événement, des informations sur les manipulations détectées.

Delta (Vector) : Permet de connaitre la modification de coordonnée en X et Y de la manipulation depuis le dernier Affine2DManipulationDelta.

CumulativeTranslation (Vector) : Permet de connaitre la modification de coordonnée en X et Y de la manipulation depuis le début de celle-ci.

RotationDelta (double) : Permet de connaitre la rotation effectuée par la manipulation depuis le dernier Affine2DManipulationDelta.

CumulativeRotation (double) : Permet de connaitre la rotation effectuée par la manipulation depuis le début de celle-ci.

ScaleDelta (double) : Permet de connaitre le coefficient d’agrandissement effectué par la manipulation depuis le dernier Affine2DManipulationDelta.

CumulativeScale (double) : Permet de connaitre le coefficient d’agrandissement effectué par la manipulation depuis le début de celle-ci.

C’est une classe indispensable pour toute personne désireuse de faire une interface tactile. Dans le Framework 4.0 WPF, cette classe sera intégrée aussi dans chaque élément graphique, ce qui permettra de ne plus avoir à l’instancier systématiquement, sauf pour des manipulations sortant du cadre de l’élément.

Surface : Affine2DManipulationProcessor

Quand on travaille sur Microsoft Surface, il y a une chose qui nous préoccupe, c’est la compréhension des gestuelles que peuvent faire les utilisateurs sur la table. Tap, ContactDown, agrandissement, rotation, translation, etc… Comment savoir, et surtout comment traiter cette information de façon efficace.

Le SDK Microsoft Surface nous apporte un outil pour cette problématique, l’Affine2DManipulationProcessor. Cette classe assez méconnue, qui se trouve dans le namespace Microsoft.Surface.Presentation.Manipulations, permet facilement de connaitre les gestuelles présente sur la table, voir même de les filtrer.

Le principe est simple, une fois instancié, cette classe permet de scruter et d’analyser les contacts sur la table. Pour faire simple, on donne à l’Affine2DManipulationProcessor des contacts à scruter et celle-ci les analyses pendant tout leur cycle de vie et nous informe des gestuelles qui peuvent être déduite de l’évolution de ses contacts.

Les manipulations sont calculées par rappart à un container UIElement donné. Au moment de l’instanciation de l’Affine2DManipulationProcessor, il y a deux paramètres. Le premier est le type de manipulation que l’on veut observer et le second dans quel contexte graphique. Ainsi, une manipulation est toujours déterminée par son container source, même si celui-ci subit des transformations (rotation, translation, etc..) l’Affine2DManipulationProcessor fournira des informations de manipulation comme si celui-ci n’avait subit ses transformations.

Pour cela, il suffit sur un ContactDown par exemple, de fournir ce contact via la méthode BeginTrack(Contact) à l’Affine2DManipulationProcessor pour que de suite il nous fournisse des informations via trois événements :

Affine2DManipulationStarted : Cet événement est déclenché lors du premier BeginTrack(Contact) et initialise la séquence de manipulation.

Affine2DManipulationDelta : Cet événement est déclenché à chaque fois qu’un contact suivi par l’Affine2DManipulationProcessor est modifié.

Affine2DManipulationCompleted : Cet événement est déclenché quand plus aucun des contacts suivis par l’Affine2DManipulationProcessor n’es présent sur la surface.

Il est à noter que l’on peut ajouter autant de contact que l’on veut via BeginTrack(Contact) et ce à n’importe quel moment de la manipulation, ils seront pris en compte automatiquement et l’Affine2DManipulationDelta sera déclenché automatiquement.

using System;
using Microsoft.Surface.Presentation;
using Microsoft.Surface.Presentation.Controls;
using Microsoft.Surface.Presentation.Manipulations;

namespace MonApplication
{
    public partial class MaSurfaceWindow: SurfaceWindow
    {
        private Affine2DManipulationProcessor traker;

        public MaSurfaceWindow()
        {
            this.InitializeComponent();

            // On défini ce que la classe doit scruter
            traker = new Affine2DManipulationProcessor(Affine2DManipulations.Scale | Affine2DManipulations.Rotate | Affine2DManipulations.TranslateX | Affine2DManipulations.TranslateY, this);

            // On s'abonne aux handlers pour connaitre l'état des contacts
            // et les gestuelles qui en ressortent
            traker.Affine2DManipulationStarted += new EventHandler<Affine2DOperationStartedEventArgs>(this.traker_Affine2DManipulationStarted);
            traker.Affine2DManipulationDelta += new EventHandler<Affine2DOperationDeltaEventArgs>(this.traker_Affine2DManipulationDelta);
            traker.Affine2DManipulationCompleted += new EventHandler<Affine2DOperationCompletedEventArgs>(this.traker_Affine2DManipulationCompleted);
        }

        private void Grid_ContactDown(object sender, ContactEventArgs e)
        {
            // On indique a l'Affine2DManipulationProcessor qu'il
            // doit scruter le contact passé en paramètre
            traker.BeginTrack(e.Contact);
        }

        private void traker_Affine2DManipulationStarted(object sender, Affine2DOperationStartedEventArgs e)
        {
            // Ici le code quand la manipulation commence
        }

        private void traker_Affine2DManipulationDelta(object sender, Affine2DOperationDeltaEventArgs e)
        {
            // Ici le code a chaque changement d'état d'un contact
        }

        private void traker_Affine2DManipulationCompleted(object sender, Affine2DOperationCompletedEventArgs e)
        {
            // Ici le code a la fin de la manipulation
        }
    }
}

Le cycle de vie d’une manipulation est le suivant, au premier contact ajouté dans l’instance la manipulation commence, ensuite elle vie tant que des contacts sont actifs et en scrutation, même si le premier contact se termine, si d’autre ont été ajouté entre temps la manipulation continue. Quand plus aucun contact n’est actif la manipulation se termine.

Une fois que vous avez commencé une manipulation, vous pouvez sur l’Affine2DManipulationDelta obtenir via l’argument de l’événement, des informations sur les manipulations détectées.

Delta (Vector) : Permet de connaitre la modification de coordonnée en X et Y de la manipulation depuis le dernier Affine2DManipulationDelta.

CumulativeTranslation (Vector) : Permet de connaitre la modification de coordonnée en X et Y de la manipulation depuis le début de celle-ci.

RotationDelta (double) : Permet de connaitre la rotation effectuée par la manipulation depuis le dernier Affine2DManipulationDelta.

CumulativeRotation (double) : Permet de connaitre la rotation effectuée par la manipulation depuis le début de celle-ci.

ScaleDelta (double) : Permet de connaitre le coefficient d’agrandissement effectué par la manipulation depuis le dernier Affine2DManipulationDelta.

CumulativeScale (double) : Permet de connaitre le coefficient d’agrandissement effectué par la manipulation depuis le début de celle-ci.

C’est une classe indispensable pour toute personne désireuse de faire une interface tactile. Dans le Framework 4.0 WPF, cette classe sera intégrée aussi dans chaque élément graphique, ce qui permettra de ne plus avoir à l’instancier systématiquement, sauf pour des manipulations sortant du cadre de l’élément.