Fichier Classe(s) définie(s) Description
Point2D.java Point2D Des classes de nature mathématique / géométrique
Vector2D.java Vector2D
AlignedRectangle2D.java AlignedRectangle2D
Point2DUtil.java Point2DUtil Une classe contenant des méthodes pour tester si un point est à l'intérieur d'un polygone (utile pour réaliser des effets de surbrilliance, et pour réaliser la sélection en lasso), pour calculer l'enveloppe convexe d'un ensemble de points (utile pour dessiner des "bulles" autour d'un ou plusieurs objets), et pour transformer un ensemble de points selon le déplacement d'un ou deux doigts (utile dans les interfaces multitactiles).
GraphicsWrapper.java GraphicsWrapper Pour dessiner en 2D en Java, souvent on utilise Graphics2D.  Toutefois, si on veut dessiner beaucoup d'objets 2D rapidement, il est plus performant d'utiliser OpenGL (à travers JOGL).  GraphicsWrapper facilite le dessin en 2D, et "emballe" les différences entre Graphics2D et OpenGL (le mot "wrapper" veut dire "emballeur").  Il y a trois intérêts à utiliser GraphicsWrapper au lieu d'utiliser Graphics2D ou OpenGL directement: d'abord, GraphicsWrapper facilite la gestion de zoom et pan dans une vue 2D (transformation entre les systèmes de coordonnées "pixels" et "espace monde" au moment du dessin et au moment de la réception d'événements de souris). Deuxièmement, elle permet de dessiner des formes géométriques simples (lignes, rectangles, cercles) en une seule ligne de code chaque, au lieu des quelques lignes de code nécessaires avec OpenGL (glBegin(), glVertex(), ..., glEnd()).  Troisièmement, l'implementation qui vous est fournie de GraphicsWrapper utilise OpenGL pour dessiner, mais on pourrait éventuellement changer cette implementation pour une autre version qui utilise Java2D/Graphics2D pour dessiner, ce qui permettrait de déployer le code sous forme d'Applet sur le web (si on enlevait les aspects multitactiles du code client).

Pour compiler et exécuter cette implementation de GraphicsWrapper, vous avez besoin de la librarie JOGL. Une copie se trouve au http://profs.etsmtl.ca/mmcguffin/code/java/lib/JOGL/
Constant.java Constant Quelques constantes.

Changez NUM_USERS pour changer le nombre de palettes qui sont créées.
MultitouchFramework.java MultitouchFramework Un cadriciel qui reçoit les événements multitactiles (soit via JWinPointer, ou de la souris permettant de simuler plusieurs points de contact) et ensuite appelle des méthodes dans le code client. Ce fichier contient le point d'entrée main(). Il y a deux versions de ce fichier, dans le répertoire "doNotCompile": MultitouchFramework-MOUSE.java, et MultitouchFramework-JWINPOINTER.java. Copiez une de ces versions par dessus le fichier MultitouchFramework.java, en changeant le nom de fichier, avant de compiler. Ne modifiez pas votre copie de MultitouchFramework.java, car ces modifications pourront être perdues, brisant votre code, lorsque vous copiez une autre version par dessus. La version "-MOUSE" est utile pour travailler hors du laboratoire, quand vous n'avez pas accès à un dispositif multitactile, car elle permet de simuler un ou plusieurs doigts avec la souris. La version "-JWINPOINTER" nécessite de compiler avec la librairie JWinPointer.jar, et fonctionne seulement avec Java 1.8 sur Windows. (Nous avons seulement testé sur Windows 10; il est possible que ça fonctionne sur Windows 7/8 aussi)

Pour compiler et exécuter la version "-JWINPOINTER", le fichier .jar nécessaire se trouve au http://www.michaelmcguffin.com/code/JWinPointer/

Quand vous utilisez la version "-MOUSE", pour simuler un seul doigt, faites Ctrl+bouton droit (appuyer, glisser, relâcher). Pour simuler plusieurs doigts, faites Ctrl-bouton gauche (appuyer, glisser, relâcher; plusieurs fois si vous voulez) pour chaque doigt que vous voulez simuler, ensuite pour faire relâcher un doigt virtuel faites Ctrl+bouton droit sur le curseur du doigt. En résumé:
Ctrl-clic gauche simule un doigt qui appuie et glisse et reste appuyé,
Ctrl-clic droit simule un doigt qui appuie et glisse et relâche.
SimpleWhiteboard.java Stroke, Drawing, MyCursor, CursorContainer, PaletteButton, Palette, UserContext, SimpleWhiteboard Les classes principales. SimpleWhiteboard est le client de MultitouchFramework.

La dernière méthode dans ce fichier, processMultitouchInputEvent(), est appellée quand un doigt (simulé ou non) appuie, glisse, ou relâche. Chaque doigt est assigné un identifiant unique (un entier). Les paramètres à la méthode processMultitouchInputEvent() sont
int id : l'identifiant unique du doigt
float x, float y : la position du doigt, en coordonnées pixels (x+ vers le droit, y+ vers le bas)
int type : soit MultitouchFramework.TOUCH_EVENT_DOWN, MultitouchFramework.TOUCH_EVENT_MOVE, ou MultitouchFramework.TOUCH_EVENT_UP



 
 
 
 
 
   Légende:

            :
            :   appelle
            v


            |
            |   contient
            v



   +-- MultitouchFramework.java ------------------+
   |                                              |
   |               class MultitouchFramework      |
   |                                      :       |
   +------------------------------------- : ------+
                                          :
                                          :
   +-- SimpleWhiteboard.java ------------ : ---------------------------------+
   |                                      :                                  |
   |   class SimpleWhiteboard             v                                  |
   |        |          |     SimpleWhiteboard.processMultitouchInputEvent()  |
   |        |          |                  :                                  |
   |        |          |                  :                                  |
   |        |          v                  :                                  |
   |        |   class UserContext         v                                  |
   |        |      |   |     UserContext.processMultitouchInputEvent()       |
   |        |      |   v                                                     |
   |        |      |  class Palette                                          |
   |        |      |     |                                                   |
   |        |      |     v                                                   |
   |        |      |   class PaletteButton                                   |
   |        |      v                                                         |
   |        |   class CursorContainer                                        |
   |        |             |                                                  |
   |        |             v                                                  |
   |        |     class MyCursor                                             |
   |        v                                                                |
   |     class Drawing                                                       |
   |           |                                                             |
   |           v                                                             |
   |      class Stroke                                                       |
   |                                                                         |
   +-------------------------------------------------------------------------+

La classe principale, SimpleWhiteboard, stocke un certain nombre d'instances de UserContext, un pour chaque utilisateur.

Chaque UserContext stocke une instance de Palette, et une instance de CursorContainer, et une liste des traits de crayon qui sont actuellement sélectionnés:

          class UserContext {
              ...
              ArrayList< Stroke > selectedStrokes = ...
              ...
          }

Chaque Palette stocke un certain nombre d'instances de PaletteButton.

Chaque CursorContainer stocke un certain nombre d'instances de MyCursor.

Une instance de MyCursor est stockée pour chaque doigt en contact avec l'écran multitactile. Lorsqu'un doigt touche l'écran pour la première fois, cela génère un événement de type MultitouchFramework.TOUCH_EVENT_DOWN, et SimpleWhiteboard.processMultitouchInputEvent() décide vers quel UserContext l'acheminer et appelle UserContext.processMultitouchInputEvent(). Ensuite, UserContext.processMultitouchInputEvent() demande au CursorContainer de créer une nouvelle instance de MyCursor pour le doigt. Plus tard, à chaque fois que le doigt se déplace et génère un événement de type MultitouchFramework.TOUCH_EVENT_MOVE, la nouvelle position du doigt est stockée dans l'instance correspondante de MyCursor. Finalement, quand le doigt perd contact avec l'écran, un événement de type MultitouchFramework.TOUCH_EVENT_UP est généré, et le MyCursor correspondant est supprimé.

Pendant les glissements de doigts, l'instance correspondante de MyCursor stocke un historique complet des positions du doigt, permettant de dessiner des traits de crayons ou des polygones de lasso pour la sélection.

Chaque instance de MyCursor a un type, stocké dans la variable Cursor.type, qui est égale à une des valeurs suivantes:

          MyCursor.TYPE_NOTHING
          MyCursor.TYPE_INTERACTING_WITH_WIDGET
          MyCursor.TYPE_INKING
          MyCursor.TYPE_CAMERA_PAN_ZOOM
          MyCursor.TYPE_SELECTION
          MyCursor.TYPE_DIRECT_MANIPULATION
Si le doigt correspondant a appuyé un bouton de palette, le type sera TYPE_INTERACTING_WITH_WIDGET. Si le doigt dessine un trait de crayon, le type sera TYPE_INKING. Etc.

Chaque instance de Palette a un mode actuel, stocké dans la variable Palette.currentlyActiveModalButton, qui est égale à une des quatre valeurs suivantes:

          Palette.ink_buttonIndex
          Palette.select_buttonIndex
          Palette.manipulate_buttonIndex
          Palette.camera_buttonIndex

La méthode UserContext.processMultitouchInputEvent() fait environ 400 lignes, et peut sembler complexe. Elle est au centre du traitement des événements générés par les doigts, et elle doit traiter plusieurs cas possibles. Dans cette méthode, on retrouve une sorte d'arborescence d'énoncés "if-else". Voici une vue d'ensemble de la méthode, qui pourra vous aider à vous retrouver dedans:

   if (l'événement n'a pas de MyCursor déjà correspondant)
       // On suppose que c'est un nouveau doigt qui vient de toucher.
       // On va devoir créer une nouvelle instance de MyCursor pour ce doigt.

       if (le doigt a touché par dessus la palette)
           if (il n'y a pas déjà d'autres doigts sur la palette)
               // On branche selon le bouton appuyé par le doigt actuel
               if ...
               else if ...
               else if ...
               ...
           else
               // On crée une nouvelle instance de MyCursor
               ...
               // On empêche que ce doigt fasse quoique ce soit
               cursor.setType( MyCursor.TYPE_NOTHING );
       else
           // Le doigt a touché près de la palette, par dessus la toile.
           // On branche selon le mode actuel
           if ( currentlyActiveModalButton == ... )
           else if ( currentlyActiveModalButton == ... )
           else if ...
           ...
   else
       // Il existe déjà un MyCursor pour le doigt.
       // On suppose que l'événement est un mouvement de doigt ou bien un relâchement de doigt.
       // On branche selon le type de MyCursor
       if ( cursor.type == ... )
       else if ( cursor.type == ... )
       else if ...
       ...


Il y a certaines méthodes dans le code qui vous serviront fort probablement pas, auxquelles vous pouvez porter peu d'attention.