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_MANIPULATIONSi 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.
HAS_MENUBAR = true; HAS_PANEL_OF_WIDGETS = true;dans Constant.java.