Commit 593e0a0eb65ac4498e30424b230366c3b286c9e9

Authored by rlentieu
1 parent 3ac09c86

ajout fichiers projet

Showing 228 changed files with 14305 additions and 0 deletions   Show diff stats

Too many changes.

To preserve performance only 100 of 228 files are displayed.

WiimoteWhiteboard/WiimoteWhiteboard.jar 0 → 100755
No preview for this file type
WiimoteWhiteboard/WiimoteWhiteboard.sh 0 → 100755
... ... @@ -0,0 +1,2 @@
  1 +#!/bin/sh
  2 +java -jar WiimoteWhiteboard.jar
0 3 \ No newline at end of file
... ...
WiimoteWhiteboard/src/apple/dts/samplecode/osxadapter/OSXAdapter.java 0 → 100644
... ... @@ -0,0 +1,152 @@
  1 +package apple.dts.samplecode.osxadapter;
  2 +
  3 +import java.lang.reflect.InvocationHandler;
  4 +import java.lang.reflect.InvocationTargetException;
  5 +import java.lang.reflect.Method;
  6 +import java.lang.reflect.Proxy;
  7 +
  8 +
  9 +public class OSXAdapter implements InvocationHandler {
  10 +
  11 + protected Object targetObject;
  12 + protected Method targetMethod;
  13 + protected String proxySignature;
  14 +
  15 + static Object macOSXApplication;
  16 +
  17 + // Pass this method an Object and Method equipped to perform application shutdown logic
  18 + // The method passed should return a boolean stating whether or not the quit should occur
  19 + public static void setQuitHandler(Object target, Method quitHandler) {
  20 + setHandler(new OSXAdapter("handleQuit", target, quitHandler));
  21 + }
  22 +
  23 + // Pass this method an Object and Method equipped to display application info
  24 + // They will be called when the About menu item is selected from the application menu
  25 + public static void setAboutHandler(Object target, Method aboutHandler) {
  26 + boolean enableAboutMenu = (target != null && aboutHandler != null);
  27 + if (enableAboutMenu) {
  28 + setHandler(new OSXAdapter("handleAbout", target, aboutHandler));
  29 + }
  30 + // If we're setting a handler, enable the About menu item by calling
  31 + // com.apple.eawt.Application reflectively
  32 + try {
  33 + Method enableAboutMethod = macOSXApplication.getClass().getDeclaredMethod("setEnabledAboutMenu", new Class[] { boolean.class });
  34 + enableAboutMethod.invoke(macOSXApplication, new Object[] { Boolean.valueOf(enableAboutMenu) });
  35 + } catch (Exception ex) {
  36 + System.err.println("OSXAdapter could not access the About Menu");
  37 + ex.printStackTrace();
  38 + }
  39 + }
  40 +
  41 + // Pass this method an Object and a Method equipped to display application options
  42 + // They will be called when the Preferences menu item is selected from the application menu
  43 + public static void setPreferencesHandler(Object target, Method prefsHandler) {
  44 + boolean enablePrefsMenu = (target != null && prefsHandler != null);
  45 + if (enablePrefsMenu) {
  46 + setHandler(new OSXAdapter("handlePreferences", target, prefsHandler));
  47 + }
  48 + // If we're setting a handler, enable the Preferences menu item by calling
  49 + // com.apple.eawt.Application reflectively
  50 + try {
  51 + Method enablePrefsMethod = macOSXApplication.getClass().getDeclaredMethod("setEnabledPreferencesMenu", new Class[] { boolean.class });
  52 + enablePrefsMethod.invoke(macOSXApplication, new Object[] { Boolean.valueOf(enablePrefsMenu) });
  53 + } catch (Exception ex) {
  54 + System.err.println("OSXAdapter could not access the About Menu");
  55 + ex.printStackTrace();
  56 + }
  57 + }
  58 +
  59 + // Pass this method an Object and a Method equipped to handle document events from the Finder
  60 + // Documents are registered with the Finder via the CFBundleDocumentTypes dictionary in the
  61 + // application bundle's Info.plist
  62 + public static void setFileHandler(Object target, Method fileHandler) {
  63 + setHandler(new OSXAdapter("handleOpenFile", target, fileHandler) {
  64 + // Override OSXAdapter.callTarget to send information on the
  65 + // file to be opened
  66 + @Override
  67 + public boolean callTarget(Object appleEvent) {
  68 + if (appleEvent != null) {
  69 + try {
  70 + Method getFilenameMethod = appleEvent.getClass().getDeclaredMethod("getFilename", (Class[])null);
  71 + String filename = (String) getFilenameMethod.invoke(appleEvent, (Object[])null);
  72 + this.targetMethod.invoke(this.targetObject, new Object[] { filename });
  73 + } catch (Exception ex) {
  74 +
  75 + }
  76 + }
  77 + return true;
  78 + }
  79 + });
  80 + }
  81 +
  82 + // setHandler creates a Proxy object from the passed OSXAdapter and adds it as an ApplicationListener
  83 + public static void setHandler(OSXAdapter adapter) {
  84 + try {
  85 + Class<?> applicationClass = Class.forName("com.apple.eawt.Application");
  86 + if (macOSXApplication == null) {
  87 + macOSXApplication = applicationClass.getConstructor((Class[])null).newInstance((Object[])null);
  88 + }
  89 + Class<?> applicationListenerClass = Class.forName("com.apple.eawt.ApplicationListener");
  90 + Method addListenerMethod = applicationClass.getDeclaredMethod("addApplicationListener", new Class[] { applicationListenerClass });
  91 + // Create a proxy object around this handler that can be reflectively added as an Apple ApplicationListener
  92 + Object osxAdapterProxy = Proxy.newProxyInstance(OSXAdapter.class.getClassLoader(), new Class[] { applicationListenerClass }, adapter);
  93 + addListenerMethod.invoke(macOSXApplication, new Object[] { osxAdapterProxy });
  94 + } catch (ClassNotFoundException cnfe) {
  95 + System.err.println("This version of Mac OS X does not support the Apple EAWT. ApplicationEvent handling has been disabled (" + cnfe + ")");
  96 + } catch (Exception ex) { // Likely a NoSuchMethodException or an IllegalAccessException loading/invoking eawt.Application methods
  97 + System.err.println("Mac OS X Adapter could not talk to EAWT:");
  98 + ex.printStackTrace();
  99 + }
  100 + }
  101 +
  102 + // Each OSXAdapter has the name of the EAWT method it intends to listen for (handleAbout, for example),
  103 + // the Object that will ultimately perform the task, and the Method to be called on that Object
  104 + protected OSXAdapter(String proxySignature, Object target, Method handler) {
  105 + this.proxySignature = proxySignature;
  106 + this.targetObject = target;
  107 + this.targetMethod = handler;
  108 + }
  109 +
  110 + // Override this method to perform any operations on the event
  111 + // that comes with the various callbacks
  112 + // See setFileHandler above for an example
  113 + public boolean callTarget(Object appleEvent) throws InvocationTargetException, IllegalAccessException {
  114 + Object result = targetMethod.invoke(targetObject, (Object[])null);
  115 + if (result == null) {
  116 + return true;
  117 + }
  118 + return Boolean.valueOf(result.toString()).booleanValue();
  119 + }
  120 +
  121 + // InvocationHandler implementation
  122 + // This is the entry point for our proxy object; it is called every time an ApplicationListener method is invoked
  123 + public Object invoke (Object proxy, Method method, Object[] args) throws Throwable {
  124 + if (isCorrectMethod(method, args)) {
  125 + boolean handled = callTarget(args[0]);
  126 + setApplicationEventHandled(args[0], handled);
  127 + }
  128 + // All of the ApplicationListener methods are void; return null regardless of what happens
  129 + return null;
  130 + }
  131 +
  132 + // Compare the method that was called to the intended method when the OSXAdapter instance was created
  133 + // (e.g. handleAbout, handleQuit, handleOpenFile, etc.)
  134 + protected boolean isCorrectMethod(Method method, Object[] args) {
  135 + return (targetMethod != null && proxySignature.equals(method.getName()) && args.length == 1);
  136 + }
  137 +
  138 + // It is important to mark the ApplicationEvent as handled and cancel the default behavior
  139 + // This method checks for a boolean result from the proxy method and sets the event accordingly
  140 + protected void setApplicationEventHandled(Object event, boolean handled) {
  141 + if (event != null) {
  142 + try {
  143 + Method setHandledMethod = event.getClass().getDeclaredMethod("setHandled", new Class[] { boolean.class });
  144 + // If the target method returns a boolean, use that as a hint
  145 + setHandledMethod.invoke(event, new Object[] { Boolean.valueOf(handled) });
  146 + } catch (Exception ex) {
  147 + System.err.println("OSXAdapter was unable to handle an ApplicationEvent: " + event);
  148 + ex.printStackTrace();
  149 + }
  150 + }
  151 + }
  152 +}
... ...
WiimoteWhiteboard/src/apple/dts/samplecode/osxadapter/OSXAdapter.java~ 0 → 100644
... ... @@ -0,0 +1,152 @@
  1 +package apple.dts.samplecode.osxadapter;
  2 +
  3 +import java.lang.reflect.InvocationHandler;
  4 +import java.lang.reflect.InvocationTargetException;
  5 +import java.lang.reflect.Method;
  6 +import java.lang.reflect.Proxy;
  7 +
  8 +
  9 +public class OSXAdapter implements InvocationHandler {
  10 +
  11 + protected Object targetObject;
  12 + protected Method targetMethod;
  13 + protected String proxySignature;
  14 +
  15 + static Object macOSXApplication;
  16 +
  17 + // Pass this method an Object and Method equipped to perform application shutdown logic
  18 + // The method passed should return a boolean stating whether or not the quit should occur
  19 + public static void setQuitHandler(Object target, Method quitHandler) {
  20 + setHandler(new OSXAdapter("handleQuit", target, quitHandler));
  21 + }
  22 +
  23 + // Pass this method an Object and Method equipped to display application info
  24 + // They will be called when the About menu item is selected from the application menu
  25 + public static void setAboutHandler(Object target, Method aboutHandler) {
  26 + boolean enableAboutMenu = (target != null && aboutHandler != null);
  27 + if (enableAboutMenu) {
  28 + setHandler(new OSXAdapter("handleAbout", target, aboutHandler));
  29 + }
  30 + // If we're setting a handler, enable the About menu item by calling
  31 + // com.apple.eawt.Application reflectively
  32 + try {
  33 + Method enableAboutMethod = macOSXApplication.getClass().getDeclaredMethod("setEnabledAboutMenu", new Class[] { boolean.class });
  34 + enableAboutMethod.invoke(macOSXApplication, new Object[] { Boolean.valueOf(enableAboutMenu) });
  35 + } catch (Exception ex) {
  36 + System.err.println("OSXAdapter could not access the About Menu");
  37 + ex.printStackTrace();
  38 + }
  39 + }
  40 +
  41 + // Pass this method an Object and a Method equipped to display application options
  42 + // They will be called when the Preferences menu item is selected from the application menu
  43 + public static void setPreferencesHandler(Object target, Method prefsHandler) {
  44 + boolean enablePrefsMenu = (target != null && prefsHandler != null);
  45 + if (enablePrefsMenu) {
  46 + setHandler(new OSXAdapter("handlePreferences", target, prefsHandler));
  47 + }
  48 + // If we're setting a handler, enable the Preferences menu item by calling
  49 + // com.apple.eawt.Application reflectively
  50 + try {
  51 + Method enablePrefsMethod = macOSXApplication.getClass().getDeclaredMethod("setEnabledPreferencesMenu", new Class[] { boolean.class });
  52 + enablePrefsMethod.invoke(macOSXApplication, new Object[] { Boolean.valueOf(enablePrefsMenu) });
  53 + } catch (Exception ex) {
  54 + System.err.println("OSXAdapter could not access the About Menu");
  55 + ex.printStackTrace();
  56 + }
  57 + }
  58 +
  59 + // Pass this method an Object and a Method equipped to handle document events from the Finder
  60 + // Documents are registered with the Finder via the CFBundleDocumentTypes dictionary in the
  61 + // application bundle's Info.plist
  62 + public static void setFileHandler(Object target, Method fileHandler) {
  63 + setHandler(new OSXAdapter("handleOpenFile", target, fileHandler) {
  64 + // Override OSXAdapter.callTarget to send information on the
  65 + // file to be opened
  66 + @Override
  67 + public boolean callTarget(Object appleEvent) {
  68 + if (appleEvent != null) {
  69 + try {
  70 + Method getFilenameMethod = appleEvent.getClass().getDeclaredMethod("getFilename", (Class[])null);
  71 + String filename = (String) getFilenameMethod.invoke(appleEvent, (Object[])null);
  72 + this.targetMethod.invoke(this.targetObject, new Object[] { filename });
  73 + } catch (Exception ex) {
  74 +
  75 + }
  76 + }
  77 + return true;
  78 + }
  79 + });
  80 + }
  81 +
  82 + // setHandler creates a Proxy object from the passed OSXAdapter and adds it as an ApplicationListener
  83 + public static void setHandler(OSXAdapter adapter) {
  84 + try {
  85 + Class<?> applicationClass = Class.forName("com.apple.eawt.Application");
  86 + if (macOSXApplication == null) {
  87 + macOSXApplication = applicationClass.getConstructor((Class[])null).newInstance((Object[])null);
  88 + }
  89 + Class<?> applicationListenerClass = Class.forName("com.apple.eawt.ApplicationListener");
  90 + Method addListenerMethod = applicationClass.getDeclaredMethod("addApplicationListener", new Class[] { applicationListenerClass });
  91 + // Create a proxy object around this handler that can be reflectively added as an Apple ApplicationListener
  92 + Object osxAdapterProxy = Proxy.newProxyInstance(OSXAdapter.class.getClassLoader(), new Class[] { applicationListenerClass }, adapter);
  93 + addListenerMethod.invoke(macOSXApplication, new Object[] { osxAdapterProxy });
  94 + } catch (ClassNotFoundException cnfe) {
  95 + System.err.println("This version of Mac OS X does not support the Apple EAWT. ApplicationEvent handling has been disabled (" + cnfe + ")");
  96 + } catch (Exception ex) { // Likely a NoSuchMethodException or an IllegalAccessException loading/invoking eawt.Application methods
  97 + System.err.println("Mac OS X Adapter could not talk to EAWT:");
  98 + ex.printStackTrace();
  99 + }
  100 + }
  101 +
  102 + // Each OSXAdapter has the name of the EAWT method it intends to listen for (handleAbout, for example),
  103 + // the Object that will ultimately perform the task, and the Method to be called on that Object
  104 + protected OSXAdapter(String proxySignature, Object target, Method handler) {
  105 + this.proxySignature = proxySignature;
  106 + this.targetObject = target;
  107 + this.targetMethod = handler;
  108 + }
  109 +
  110 + // Override this method to perform any operations on the event
  111 + // that comes with the various callbacks
  112 + // See setFileHandler above for an example
  113 + public boolean callTarget(Object appleEvent) throws InvocationTargetException, IllegalAccessException {
  114 + Object result = targetMethod.invoke(targetObject, (Object[])null);
  115 + if (result == null) {
  116 + return true;
  117 + }
  118 + return Boolean.valueOf(result.toString()).booleanValue();
  119 + }
  120 +
  121 + // InvocationHandler implementation
  122 + // This is the entry point for our proxy object; it is called every time an ApplicationListener method is invoked
  123 + public Object invoke (Object proxy, Method method, Object[] args) throws Throwable {
  124 + if (isCorrectMethod(method, args)) {
  125 + boolean handled = callTarget(args[0]);
  126 + setApplicationEventHandled(args[0], handled);
  127 + }
  128 + // All of the ApplicationListener methods are void; return null regardless of what happens
  129 + return null;
  130 + }
  131 +
  132 + // Compare the method that was called to the intended method when the OSXAdapter instance was created
  133 + // (e.g. handleAbout, handleQuit, handleOpenFile, etc.)
  134 + protected boolean isCorrectMethod(Method method, Object[] args) {
  135 + return (targetMethod != null && proxySignature.equals(method.getName()) && args.length == 1);
  136 + }
  137 +
  138 + // It is important to mark the ApplicationEvent as handled and cancel the default behavior
  139 + // This method checks for a boolean result from the proxy method and sets the event accordingly
  140 + protected void setApplicationEventHandled(Object event, boolean handled) {
  141 + if (event != null) {
  142 + try {
  143 + Method setHandledMethod = event.getClass().getDeclaredMethod("setHandled", new Class[] { boolean.class });
  144 + // If the target method returns a boolean, use that as a hint
  145 + setHandledMethod.invoke(event, new Object[] { Boolean.valueOf(handled) });
  146 + } catch (Exception ex) {
  147 + System.err.println("OSXAdapter was unable to handle an ApplicationEvent: " + event);
  148 + ex.printStackTrace();
  149 + }
  150 + }
  151 + }
  152 +}
... ...
WiimoteWhiteboard/src/javax/media/jai/PerspectiveTransform.java 0 → 100644
... ... @@ -0,0 +1,1095 @@
  1 +package javax.media.jai;
  2 +import java.awt.geom.AffineTransform;
  3 +import java.awt.geom.Point2D;
  4 +import java.awt.geom.NoninvertibleTransformException;
  5 +import java.io.Serializable;
  6 +
  7 +public final class PerspectiveTransform implements Cloneable, Serializable {
  8 +
  9 + private static final double PERSPECTIVE_DIVIDE_EPSILON = 1.0e-10;
  10 +
  11 + double m00, m01, m02, m10, m11, m12, m20, m21, m22;
  12 +
  13 + /** Constructs an identity PerspectiveTransform. */
  14 + public PerspectiveTransform() {
  15 + m00 = m11 = m22 = 1.0;
  16 + m01 = m02 = m10 = m12 = m20 = m21 = 0.0;
  17 + }
  18 +
  19 + /**
  20 + * Constructs a new PerspectiveTransform from 9 floats.
  21 + */
  22 + public PerspectiveTransform(float m00, float m01, float m02,
  23 + float m10, float m11, float m12,
  24 + float m20, float m21, float m22) {
  25 + this.m00 = m00;
  26 + this.m01 = m01;
  27 + this.m02 = m02;
  28 + this.m10 = m10;
  29 + this.m11 = m11;
  30 + this.m12 = m12;
  31 + this.m20 = m20;
  32 + this.m21 = m21;
  33 + this.m22 = m22;
  34 + }
  35 +
  36 + /**
  37 + * Constructs a new PerspectiveTransform from 9 doubles.
  38 + */
  39 + public PerspectiveTransform(double m00, double m01, double m02,
  40 + double m10, double m11, double m12,
  41 + double m20, double m21, double m22) {
  42 + this.m00 = m00;
  43 + this.m01 = m01;
  44 + this.m02 = m02;
  45 + this.m10 = m10;
  46 + this.m11 = m11;
  47 + this.m12 = m12;
  48 + this.m20 = m20;
  49 + this.m21 = m21;
  50 + this.m22 = m22;
  51 + }
  52 +
  53 + public PerspectiveTransform(float[] flatmatrix) {
  54 + if ( flatmatrix == null ) {
  55 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  56 + }
  57 +
  58 + m00 = flatmatrix[0];
  59 + m01 = flatmatrix[1];
  60 + m02 = flatmatrix[2];
  61 + m10 = flatmatrix[3];
  62 + m11 = flatmatrix[4];
  63 + m12 = flatmatrix[5];
  64 + m20 = flatmatrix[6];
  65 + m21 = flatmatrix[7];
  66 + m22 = flatmatrix[8];
  67 + }
  68 +
  69 + public PerspectiveTransform(float[][] matrix) {
  70 + if ( matrix == null ) {
  71 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  72 + }
  73 +
  74 + m00 = matrix[0][0];
  75 + m01 = matrix[0][1];
  76 + m02 = matrix[0][2];
  77 + m10 = matrix[1][0];
  78 + m11 = matrix[1][1];
  79 + m12 = matrix[1][2];
  80 + m20 = matrix[2][0];
  81 + m21 = matrix[2][1];
  82 + m22 = matrix[2][2];
  83 + }
  84 +
  85 + public PerspectiveTransform(double[] flatmatrix) {
  86 + if ( flatmatrix == null ) {
  87 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  88 + }
  89 +
  90 + m00 = flatmatrix[0];
  91 + m01 = flatmatrix[1];
  92 + m02 = flatmatrix[2];
  93 + m10 = flatmatrix[3];
  94 + m11 = flatmatrix[4];
  95 + m12 = flatmatrix[5];
  96 + m20 = flatmatrix[6];
  97 + m21 = flatmatrix[7];
  98 + m22 = flatmatrix[8];
  99 + }
  100 +
  101 + /**
  102 + * Constructs a new PerspectiveTransform from a two-dimensional
  103 + * array of doubles.
  104 + */
  105 + public PerspectiveTransform(double[][] matrix) {
  106 + if ( matrix == null ) {
  107 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  108 + }
  109 +
  110 + m00 = matrix[0][0];
  111 + m01 = matrix[0][1];
  112 + m02 = matrix[0][2];
  113 + m10 = matrix[1][0];
  114 + m11 = matrix[1][1];
  115 + m12 = matrix[1][2];
  116 + m20 = matrix[2][0];
  117 + m21 = matrix[2][1];
  118 + m22 = matrix[2][2];
  119 + }
  120 +
  121 + /**
  122 + * Constructs a new PerspectiveTransform with the same effect
  123 + * as an existing AffineTransform.
  124 + * @throws IllegalArgumentException if transform is null
  125 + */
  126 + public PerspectiveTransform(AffineTransform transform) {
  127 + if ( transform == null ) {
  128 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  129 + }
  130 +
  131 + m00 = transform.getScaleX();
  132 + m01 = transform.getShearX();
  133 + m02 = transform.getTranslateX();
  134 + m10 = transform.getShearY();
  135 + m11 = transform.getScaleY();
  136 + m12 = transform.getTranslateY();
  137 + m20 = 0.0;
  138 + m21 = 0.0;
  139 + m22 = 1.0;
  140 + }
  141 +
  142 + /**
  143 + * Replaces the matrix with its adjoint.
  144 + */
  145 + private final void makeAdjoint() {
  146 + double m00p = m11*m22 - m12*m21;
  147 + double m01p = m12*m20 - m10*m22;
  148 + double m02p = m10*m21 - m11*m20;
  149 + double m10p = m02*m21 - m01*m22;
  150 + double m11p = m00*m22 - m02*m20;
  151 + double m12p = m01*m20 - m00*m21;
  152 + double m20p = m01*m12 - m02*m11;
  153 + double m21p = m02*m10 - m00*m12;
  154 + double m22p = m00*m11 - m01*m10;
  155 +
  156 + m00 = m00p;
  157 + m01 = m10p;
  158 + m02 = m20p;
  159 + m10 = m01p;
  160 + m11 = m11p;
  161 + m12 = m21p;
  162 + m20 = m02p;
  163 + m21 = m12p;
  164 + m22 = m22p;
  165 + }
  166 +
  167 + private final void normalize() {
  168 + double invscale = 1.0/m22;
  169 + m00 *= invscale;
  170 + m01 *= invscale;
  171 + m02 *= invscale;
  172 + m10 *= invscale;
  173 + m11 *= invscale;
  174 + m12 *= invscale;
  175 + m20 *= invscale;
  176 + m21 *= invscale;
  177 + m22 = 1.0;
  178 + }
  179 +
  180 + private static final void getSquareToQuad(double x0, double y0,
  181 + double x1, double y1,
  182 + double x2, double y2,
  183 + double x3, double y3,
  184 + PerspectiveTransform tx) {
  185 + double dx3 = x0 - x1 + x2 - x3;
  186 + double dy3 = y0 - y1 + y2 - y3;
  187 +
  188 + tx.m22 = 1.0F;
  189 +
  190 + if ((dx3 == 0.0F) && (dy3 == 0.0F)) {
  191 + tx.m00 = x1 - x0;
  192 + tx.m01 = x2 - x1;
  193 + tx.m02 = x0;
  194 + tx.m10 = y1 - y0;
  195 + tx.m11 = y2 - y1;
  196 + tx.m12 = y0;
  197 + tx.m20 = 0.0F;
  198 + tx.m21 = 0.0F;
  199 + } else {
  200 + double dx1 = x1 - x2;
  201 + double dy1 = y1 - y2;
  202 + double dx2 = x3 - x2;
  203 + double dy2 = y3 - y2;
  204 +
  205 + double invdet = 1.0F/(dx1*dy2 - dx2*dy1);
  206 + tx.m20 = (dx3*dy2 - dx2*dy3)*invdet;
  207 + tx.m21 = (dx1*dy3 - dx3*dy1)*invdet;
  208 + tx.m00 = x1 - x0 + tx.m20*x1;
  209 + tx.m01 = x3 - x0 + tx.m21*x3;
  210 + tx.m02 = x0;
  211 + tx.m10 = y1 - y0 + tx.m20*y1;
  212 + tx.m11 = y3 - y0 + tx.m21*y3;
  213 + tx.m12 = y0;
  214 + }
  215 + }
  216 +
  217 + public static PerspectiveTransform getSquareToQuad(double x0, double y0,
  218 + double x1, double y1,
  219 + double x2, double y2,
  220 + double x3, double y3) {
  221 + PerspectiveTransform tx = new PerspectiveTransform();
  222 + getSquareToQuad(x0, y0, x1, y1, x2, y2, x3, y3, tx);
  223 + return tx;
  224 + }
  225 +
  226 +
  227 + public static PerspectiveTransform getSquareToQuad(float x0, float y0,
  228 + float x1, float y1,
  229 + float x2, float y2,
  230 + float x3, float y3) {
  231 + return getSquareToQuad((double)x0, (double)y0,
  232 + (double)x1, (double)y1,
  233 + (double)x2, (double)y2,
  234 + (double)x3, (double)y3);
  235 + }
  236 +
  237 +
  238 + /**
  239 + * Creates a PerspectiveTransform that maps an arbitrary
  240 + * quadrilateral onto the unit square.
  241 + */
  242 + public static PerspectiveTransform getQuadToSquare(double x0, double y0,
  243 + double x1, double y1,
  244 + double x2, double y2,
  245 + double x3, double y3) {
  246 + PerspectiveTransform tx = new PerspectiveTransform();
  247 + getSquareToQuad(x0, y0, x1, y1, x2, y2, x3, y3, tx);
  248 + tx.makeAdjoint();
  249 + return tx;
  250 + }
  251 +
  252 + /**
  253 + * Creates a PerspectiveTransform that maps an arbitrary
  254 + * quadrilateral onto the unit square.
  255 + */
  256 + public static PerspectiveTransform getQuadToSquare(float x0, float y0,
  257 + float x1, float y1,
  258 + float x2, float y2,
  259 + float x3, float y3) {
  260 + return getQuadToSquare((double)x0, (double)y0,
  261 + (double)x1, (double)y1,
  262 + (double)x2, (double)y2,
  263 + (double)x3, (double)y3);
  264 + }
  265 +
  266 + /**
  267 + * Creates a PerspectiveTransform that maps an arbitrary
  268 + * quadrilateral onto another arbitrary quadrilateral.
  269 + */
  270 + public static PerspectiveTransform getQuadToQuad(double x0, double y0,
  271 + double x1, double y1,
  272 + double x2, double y2,
  273 + double x3, double y3,
  274 + double x0p, double y0p,
  275 + double x1p, double y1p,
  276 + double x2p, double y2p,
  277 + double x3p, double y3p) {
  278 + PerspectiveTransform tx1 =
  279 + getQuadToSquare(x0, y0, x1, y1, x2, y2, x3, y3);
  280 +
  281 + PerspectiveTransform tx2 =
  282 + getSquareToQuad(x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p);
  283 +
  284 + tx1.concatenate(tx2);
  285 + return tx1;
  286 + }
  287 +
  288 +
  289 + /**
  290 + * Creates a PerspectiveTransform that maps an arbitrary
  291 + * quadrilateral onto another arbitrary quadrilateral.
  292 + */
  293 + public static PerspectiveTransform getQuadToQuad(float x0, float y0,
  294 + float x1, float y1,
  295 + float x2, float y2,
  296 + float x3, float y3,
  297 + float x0p, float y0p,
  298 + float x1p, float y1p,
  299 + float x2p, float y2p,
  300 + float x3p, float y3p) {
  301 + return getQuadToQuad((double)x0, (double)y0,
  302 + (double)x1, (double)y1,
  303 + (double)x2, (double)y2,
  304 + (double)x3, (double)y3,
  305 + (double)x0p, (double)y0p,
  306 + (double)x1p, (double)y1p,
  307 + (double)x2p, (double)y2p,
  308 + (double)x3p, (double)y3p);
  309 + }
  310 +
  311 + /**
  312 + * Returns the determinant of the matrix representation of the
  313 + * transform.
  314 + */
  315 + public double getDeterminant() {
  316 + return ( (m00 * ((m11 * m22) - (m12 * m21))) -
  317 + (m01 * ((m10 * m22) - (m12 * m20))) +
  318 + (m02 * ((m10 * m21) - (m11 * m20))) );
  319 +
  320 + }
  321 +
  322 + /**
  323 + * Retrieves the 9 specifiable values in the 3x3 affine
  324 + * transformation matrix into an array of double precision values.
  325 + * The values are stored into the array as
  326 + * { m00 m01 m02 m10 m11 m12 m20 m21 m22 }.
  327 + */
  328 + public double[] getMatrix(double[] flatmatrix) {
  329 + if (flatmatrix == null) {
  330 + flatmatrix = new double[9];
  331 + }
  332 +
  333 + flatmatrix[0] = m00;
  334 + flatmatrix[1] = m01;
  335 + flatmatrix[2] = m02;
  336 + flatmatrix[3] = m10;
  337 + flatmatrix[4] = m11;
  338 + flatmatrix[5] = m12;
  339 + flatmatrix[6] = m20;
  340 + flatmatrix[7] = m21;
  341 + flatmatrix[8] = m22;
  342 +
  343 + return flatmatrix;
  344 + }
  345 +
  346 + /**
  347 + * Retrieves the 9 specifiable values in the 3x3 affine
  348 + * transformation matrix into a 2-dimensional array of double
  349 + * precision values. The values are stored into the 2-dimensional
  350 + * array using the row index as the first subscript and the column
  351 + * index as the second.
  352 + *
  353 + */
  354 + public double[][] getMatrix(double[][] matrix) {
  355 + if (matrix == null) {
  356 + matrix = new double[3][3];
  357 + }
  358 +
  359 + matrix[0][0] = m00;
  360 + matrix[0][1] = m01;
  361 + matrix[0][2] = m02;
  362 + matrix[1][0] = m10;
  363 + matrix[1][1] = m11;
  364 + matrix[1][2] = m12;
  365 + matrix[2][0] = m20;
  366 + matrix[2][1] = m21;
  367 + matrix[2][2] = m22;
  368 +
  369 + return matrix;
  370 + }
  371 +
  372 + /**
  373 + * Concatenates this transform with a translation transformation.
  374 + */
  375 + public void translate(double tx, double ty) {
  376 + PerspectiveTransform Tx = new PerspectiveTransform();
  377 + Tx.setToTranslation(tx, ty);
  378 + concatenate(Tx);
  379 + }
  380 +
  381 + /**
  382 + * Concatenates this transform with a rotation transformation.
  383 + */
  384 + public void rotate(double theta) {
  385 + PerspectiveTransform Tx = new PerspectiveTransform();
  386 + Tx.setToRotation(theta);
  387 + concatenate(Tx);
  388 + }
  389 +
  390 + /**
  391 + * Concatenates this transform with a translated rotation transformation.
  392 + */
  393 + public void rotate(double theta, double x, double y) {
  394 + PerspectiveTransform Tx = new PerspectiveTransform();
  395 + Tx.setToRotation(theta, x, y);
  396 + concatenate(Tx);
  397 + }
  398 +
  399 + /**
  400 + * Concatenates this transform with a scaling transformation.
  401 + */
  402 + public void scale(double sx, double sy) {
  403 + PerspectiveTransform Tx = new PerspectiveTransform();
  404 + Tx.setToScale(sx, sy);
  405 + concatenate(Tx);
  406 + }
  407 +
  408 + /**
  409 + * Concatenates this transform with a shearing transformation.
  410 + */
  411 + public void shear(double shx, double shy) {
  412 + PerspectiveTransform Tx = new PerspectiveTransform();
  413 + Tx.setToShear(shx, shy);
  414 + concatenate(Tx);
  415 + }
  416 +
  417 + /**
  418 + * Resets this transform to the Identity transform.
  419 + */
  420 + public void setToIdentity() {
  421 + m00 = m11 = m22 = 1.0;
  422 + m01 = m10 = m02 = m20 = m12 = m21 = 0.0;
  423 + }
  424 +
  425 + /**
  426 + * Sets this transform to a translation transformation.
  427 + */
  428 + public void setToTranslation(double tx, double ty) {
  429 + m00 = 1.0;
  430 + m01 = 0.0;
  431 + m02 = tx;
  432 + m10 = 0.0;
  433 + m11 = 1.0;
  434 + m12 = ty;
  435 + m20 = 0.0;
  436 + m21 = 0.0;
  437 + m22 = 1.0;
  438 + }
  439 +
  440 + /**
  441 + * Sets this transform to a rotation transformation.
  442 + */
  443 + public void setToRotation(double theta) {
  444 + m00 = Math.cos(theta);
  445 + m01 = -Math.sin(theta);
  446 + m02 = 0.0;
  447 + m10 = - m01;
  448 + m11 = m00;
  449 + m12 = 0.0;
  450 + m20 = 0.0;
  451 + m21 = 0.0;
  452 + m22 = 1.0;
  453 + }
  454 +
  455 + public void setToRotation(double theta, double x, double y) {
  456 + setToRotation(theta);
  457 + double sin = m10;
  458 + double oneMinusCos = 1.0 - m00;
  459 + m02 = x * oneMinusCos + y * sin;
  460 + m12 = y * oneMinusCos - x * sin;
  461 + }
  462 +
  463 + public void setToScale(double sx, double sy) {
  464 + m00 = sx;
  465 + m01 = 0.0;
  466 + m02 = 0.0;
  467 + m10 = 0.0;
  468 + m11 = sy;
  469 + m12 = 0.0;
  470 + m20 = 0.0;
  471 + m21 = 0.0;
  472 + m22 = 1.0;
  473 + }
  474 +
  475 + /**
  476 + * Sets this transform to a shearing transformation
  477 + * with shear factors sx and sy.
  478 + */
  479 + public void setToShear(double shx, double shy) {
  480 + m00 = 1.0;
  481 + m01 = shx;
  482 + m02 = 0.0;
  483 + m10 = shy;
  484 + m11 = 1.0;
  485 + m12 = 0.0;
  486 + m20 = 0.0;
  487 + m21 = 0.0;
  488 + m22 = 1.0;
  489 + }
  490 +
  491 + /**
  492 + * Sets this transform to a given AffineTransform.
  493 + * @throws IllegalArgumentException if Tx is null
  494 + */
  495 + public void setTransform(AffineTransform Tx) {
  496 + if ( Tx == null ) {
  497 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  498 + }
  499 +
  500 + m00 = Tx.getScaleX();
  501 + m01 = Tx.getShearX();
  502 + m02 = Tx.getTranslateX();
  503 + m10 = Tx.getShearY();
  504 + m11 = Tx.getScaleY();
  505 + m12 = Tx.getTranslateY();
  506 + m20 = 0.0;
  507 + m21 = 0.0;
  508 + m22 = 1.0;
  509 + }
  510 +
  511 + /**
  512 + * Sets this transform to a given PerspectiveTransform.
  513 + * @throws IllegalArgumentException if Tx is null
  514 + */
  515 + public void setTransform(PerspectiveTransform Tx) {
  516 + if ( Tx == null ) {
  517 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  518 + }
  519 +
  520 + m00 = Tx.m00;
  521 + m01 = Tx.m01;
  522 + m02 = Tx.m02;
  523 + m10 = Tx.m10;
  524 + m11 = Tx.m11;
  525 + m12 = Tx.m12;
  526 + m20 = Tx.m20;
  527 + m21 = Tx.m21;
  528 + m22 = Tx.m22;
  529 + }
  530 +
  531 + public void setTransform(float m00, float m10, float m20,
  532 + float m01, float m11, float m21,
  533 + float m02, float m12, float m22) {
  534 + this.m00 = (double)m00;
  535 + this.m01 = (double)m01;
  536 + this.m02 = (double)m02;
  537 + this.m10 = (double)m10;
  538 + this.m11 = (double)m11;
  539 + this.m12 = (double)m12;
  540 + this.m20 = (double)m20;
  541 + this.m21 = (double)m21;
  542 + this.m22 = (double)m22;
  543 + }
  544 +
  545 + public void setTransform(double[][] matrix) {
  546 + if ( matrix == null ) {
  547 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  548 + }
  549 +
  550 + m00 = matrix[0][0];
  551 + m01 = matrix[0][1];
  552 + m02 = matrix[0][2];
  553 + m10 = matrix[1][0];
  554 + m11 = matrix[1][1];
  555 + m12 = matrix[1][2];
  556 + m20 = matrix[2][0];
  557 + m21 = matrix[2][1];
  558 + m22 = matrix[2][2];
  559 + }
  560 +
  561 + /**
  562 + * Post-concatenates a given AffineTransform to this transform.
  563 + * @throws IllegalArgumentException if Tx is null
  564 + */
  565 + public void concatenate(AffineTransform Tx) {
  566 + if ( Tx == null ) {
  567 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  568 + }
  569 +
  570 + double tx_m00 = Tx.getScaleX();
  571 + double tx_m01 = Tx.getShearX();
  572 + double tx_m02 = Tx.getTranslateX();
  573 + double tx_m10 = Tx.getShearY();
  574 + double tx_m11 = Tx.getScaleY();
  575 + double tx_m12 = Tx.getTranslateY();
  576 +
  577 + double m00p = m00*tx_m00 + m10*tx_m01 + m20*tx_m02;
  578 + double m01p = m01*tx_m00 + m11*tx_m01 + m21*tx_m02;
  579 + double m02p = m02*tx_m00 + m12*tx_m01 + m22*tx_m02;
  580 + double m10p = m00*tx_m10 + m10*tx_m11 + m20*tx_m12;
  581 + double m11p = m01*tx_m10 + m11*tx_m11 + m21*tx_m12;
  582 + double m12p = m02*tx_m10 + m12*tx_m11 + m22*tx_m12;
  583 + double m20p = m20;
  584 + double m21p = m21;
  585 + double m22p = m22;
  586 +
  587 + m00 = m00p;
  588 + m10 = m10p;
  589 + m20 = m20p;
  590 + m01 = m01p;
  591 + m11 = m11p;
  592 + m21 = m21p;
  593 + m02 = m02p;
  594 + m12 = m12p;
  595 + m22 = m22p;
  596 + }
  597 +
  598 + /**
  599 + * Post-concatenates a given PerspectiveTransform to this transform.
  600 + * @throws IllegalArgumentException if Tx is null
  601 + */
  602 + public void concatenate(PerspectiveTransform Tx) {
  603 + if ( Tx == null ) {
  604 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  605 + }
  606 +
  607 + double m00p = m00*Tx.m00 + m10*Tx.m01 + m20*Tx.m02;
  608 + double m10p = m00*Tx.m10 + m10*Tx.m11 + m20*Tx.m12;
  609 + double m20p = m00*Tx.m20 + m10*Tx.m21 + m20*Tx.m22;
  610 + double m01p = m01*Tx.m00 + m11*Tx.m01 + m21*Tx.m02;
  611 + double m11p = m01*Tx.m10 + m11*Tx.m11 + m21*Tx.m12;
  612 + double m21p = m01*Tx.m20 + m11*Tx.m21 + m21*Tx.m22;
  613 + double m02p = m02*Tx.m00 + m12*Tx.m01 + m22*Tx.m02;
  614 + double m12p = m02*Tx.m10 + m12*Tx.m11 + m22*Tx.m12;
  615 + double m22p = m02*Tx.m20 + m12*Tx.m21 + m22*Tx.m22;
  616 +
  617 + m00 = m00p;
  618 + m10 = m10p;
  619 + m20 = m20p;
  620 + m01 = m01p;
  621 + m11 = m11p;
  622 + m21 = m21p;
  623 + m02 = m02p;
  624 + m12 = m12p;
  625 + m22 = m22p;
  626 + }
  627 +
  628 + /**
  629 + * Pre-concatenates a given AffineTransform to this transform.
  630 + * @throws IllegalArgumentException if Tx is null
  631 + */
  632 + public void preConcatenate(AffineTransform Tx) {
  633 + if ( Tx == null ) {
  634 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  635 + }
  636 +
  637 + // Extend Tx: Tx.m20 = 0, Tx.m21 = 0, Tx.m22 = 1
  638 +
  639 + double tx_m00 = Tx.getScaleX();
  640 + double tx_m01 = Tx.getShearX();
  641 + double tx_m02 = Tx.getTranslateX();
  642 + double tx_m10 = Tx.getShearY();
  643 + double tx_m11 = Tx.getScaleY();
  644 + double tx_m12 = Tx.getTranslateY();
  645 +
  646 + double m00p = tx_m00*m00 + tx_m10*m01;
  647 + double m01p = tx_m01*m00 + tx_m11*m01;
  648 + double m02p = tx_m02*m00 + tx_m12*m01 + m02;
  649 + double m10p = tx_m00*m10 + tx_m10*m11;
  650 + double m11p = tx_m01*m10 + tx_m11*m11;
  651 + double m12p = tx_m02*m10 + tx_m12*m11 + m12;
  652 + double m20p = tx_m00*m20 + tx_m10*m21;
  653 + double m21p = tx_m01*m20 + tx_m11*m21;
  654 + double m22p = tx_m02*m20 + tx_m12*m21 + m22;
  655 +
  656 + m00 = m00p;
  657 + m10 = m10p;
  658 + m20 = m20p;
  659 + m01 = m01p;
  660 + m11 = m11p;
  661 + m21 = m21p;
  662 + m02 = m02p;
  663 + m12 = m12p;
  664 + m22 = m22p;
  665 + }
  666 +
  667 + /**
  668 + * Pre-concatenates a given PerspectiveTransform to this transform.
  669 + * @throws IllegalArgumentException if Tx is null
  670 + */
  671 + public void preConcatenate(PerspectiveTransform Tx) {
  672 + if ( Tx == null ) {
  673 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  674 + }
  675 +
  676 + double m00p = Tx.m00*m00 + Tx.m10*m01 + Tx.m20*m02;
  677 + double m10p = Tx.m00*m10 + Tx.m10*m11 + Tx.m20*m12;
  678 + double m20p = Tx.m00*m20 + Tx.m10*m21 + Tx.m20*m22;
  679 + double m01p = Tx.m01*m00 + Tx.m11*m01 + Tx.m21*m02;
  680 + double m11p = Tx.m01*m10 + Tx.m11*m11 + Tx.m21*m12;
  681 + double m21p = Tx.m01*m20 + Tx.m11*m21 + Tx.m21*m22;
  682 + double m02p = Tx.m02*m00 + Tx.m12*m01 + Tx.m22*m02;
  683 + double m12p = Tx.m02*m10 + Tx.m12*m11 + Tx.m22*m12;
  684 + double m22p = Tx.m02*m20 + Tx.m12*m21 + Tx.m22*m22;
  685 +
  686 + m00 = m00p;
  687 + m10 = m10p;
  688 + m20 = m20p;
  689 + m01 = m01p;
  690 + m11 = m11p;
  691 + m21 = m21p;
  692 + m02 = m02p;
  693 + m12 = m12p;
  694 + m22 = m22p;
  695 + }
  696 +
  697 + /**
  698 + * Returns a new PerpectiveTransform that is the inverse
  699 + * of the current transform.
  700 + * @throws NoninvertibleTransformException if transform cannot be inverted
  701 + */
  702 + public PerspectiveTransform createInverse()
  703 + throws NoninvertibleTransformException, CloneNotSupportedException {
  704 +
  705 + PerspectiveTransform tx = (PerspectiveTransform)clone();
  706 + tx.makeAdjoint();
  707 + if (Math.abs(tx.m22) < PERSPECTIVE_DIVIDE_EPSILON) {
  708 + throw new NoninvertibleTransformException(JaiI18N.getString("PerspectiveTransform0"));
  709 + }
  710 + tx.normalize();
  711 + return tx;
  712 + }
  713 +
  714 + /**
  715 + * Returns a new PerpectiveTransform that is the adjoint,
  716 + * of the current transform. The adjoint is defined as
  717 + * the matrix of cofactors, which in turn are the determinants
  718 + * of the submatrices defined by removing the row and column
  719 + * of each element from the original matrix in turn.
  720 + */
  721 + public PerspectiveTransform createAdjoint()
  722 + throws CloneNotSupportedException{
  723 +
  724 + PerspectiveTransform tx = (PerspectiveTransform)clone();
  725 + tx.makeAdjoint();
  726 + return tx;
  727 + }
  728 +
  729 + /**
  730 + * Transforms the specified ptSrc and stores the result in ptDst.
  731 + * If ptDst is null, a new Point2D object will be allocated before
  732 + * storing. In either case, ptDst containing the transformed point
  733 + * is returned for convenience.
  734 + * Note that ptSrc and ptDst can the same. In this case, the input
  735 + * point will be overwritten with the transformed point.
  736 + * @throws IllegalArgumentException if ptSrc is null
  737 + */
  738 + public Point2D transform(Point2D ptSrc, Point2D ptDst) {
  739 + if ( ptSrc == null ) {
  740 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  741 + }
  742 +
  743 + if (ptDst == null) {
  744 + if (ptSrc instanceof Point2D.Double) {
  745 + ptDst = new Point2D.Double();
  746 + } else {
  747 + ptDst = new Point2D.Float();
  748 + }
  749 + }
  750 +
  751 + double x = ptSrc.getX();
  752 + double y = ptSrc.getY();
  753 + double w = m20 * x + m21 * y + m22;
  754 + ptDst.setLocation((m00 * x + m01 * y + m02) / w,
  755 + (m10 * x + m11 * y + m12) / w);
  756 +
  757 + return ptDst;
  758 + }
  759 +
  760 + /**
  761 + * Transforms an array of point objects by this transform.
  762 + * @throws IllegalArgumentException if ptSrc is null
  763 + * @throws IllegalArgumentException if ptDst is null
  764 + * @throws ArrayIndexOutOfBoundsException if ptSrc is too small
  765 + */
  766 + public void transform(Point2D[] ptSrc, int srcOff,
  767 + Point2D[] ptDst, int dstOff,
  768 + int numPts) {
  769 +
  770 + if ( ptSrc == null || ptDst == null ) {
  771 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  772 + }
  773 +
  774 + while (numPts-- > 0) {
  775 + Point2D src = ptSrc[srcOff++];
  776 + Point2D dst = ptDst[dstOff++];
  777 + if (dst == null) {
  778 + if (src instanceof Point2D.Double) {
  779 + dst = new Point2D.Double();
  780 + } else {
  781 + dst = new Point2D.Float();
  782 + }
  783 + ptDst[dstOff - 1] = dst;
  784 + }
  785 +
  786 + double x = src.getX();
  787 + double y = src.getY();
  788 + double w = m20 * x + m21 * y + m22;
  789 +
  790 + if (w == 0) {
  791 + dst.setLocation(x, y);
  792 + } else {
  793 + dst.setLocation((m00 * x + m01 * y + m02) / w,
  794 + (m10 * x + m11 * y + m12) / w);
  795 + }
  796 + }
  797 + }
  798 +
  799 + /**
  800 + * Transforms an array of floating point coordinates by this transform.
  801 + * @throws IllegalArgumentException if srcPts is null
  802 + * @throws ArrayIndexOutOfBoundsException if srcPts is too small
  803 + */
  804 + public void transform(float[] srcPts, int srcOff,
  805 + float[] dstPts, int dstOff,
  806 + int numPts) {
  807 +
  808 + if ( srcPts == null ) {
  809 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  810 + }
  811 +
  812 + if (dstPts == null) {
  813 + dstPts = new float[numPts * 2 + dstOff];
  814 + }
  815 +
  816 + while (numPts-- > 0) {
  817 + float x = srcPts[srcOff++];
  818 + float y = srcPts[srcOff++];
  819 + double w = m20 * x + m21 * y + m22;
  820 +
  821 + if (w == 0) {
  822 + dstPts[dstOff++] = x;
  823 + dstPts[dstOff++] = y;
  824 + } else {
  825 + dstPts[dstOff++] = (float)((m00 * x + m01 * y + m02) / w);
  826 + dstPts[dstOff++] = (float)((m10 * x + m11 * y + m12) / w);
  827 + }
  828 + }
  829 + }
  830 +
  831 + /**
  832 + * Transforms an array of double precision coordinates by this transform.
  833 + * @throws IllegalArgumentException if srcPts is null
  834 + * @throws ArrayIndexOutOfBoundsException if srcPts is too small
  835 + */
  836 + public void transform(double[] srcPts, int srcOff,
  837 + double[] dstPts, int dstOff,
  838 + int numPts) {
  839 +
  840 + if ( srcPts == null ) {
  841 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  842 + }
  843 +
  844 + if (dstPts == null) {
  845 + dstPts = new double[numPts * 2 + dstOff];
  846 + }
  847 +
  848 + while (numPts-- > 0) {
  849 + double x = srcPts[srcOff++];
  850 + double y = srcPts[srcOff++];
  851 + double w = m20 * x + m21 * y + m22;
  852 +
  853 + if (w == 0) {
  854 + dstPts[dstOff++] = x;
  855 + dstPts[dstOff++] = y;
  856 + } else {
  857 + dstPts[dstOff++] = (m00 * x + m01 * y + m02) / w;
  858 + dstPts[dstOff++] = (m10 * x + m11 * y + m12) / w;
  859 + }
  860 + }
  861 + }
  862 +
  863 + /**
  864 + * Transforms an array of floating point coordinates by this transform,
  865 + * storing the results into an array of doubles.
  866 + * @throws IllegalArgumentException if srcPts is null
  867 + * @throws ArrayIndexOutOfBoundsException if srcPts is too small
  868 + */
  869 + public void transform(float[] srcPts, int srcOff,
  870 + double[] dstPts, int dstOff,
  871 + int numPts) {
  872 +
  873 + if ( srcPts == null ) {
  874 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  875 + }
  876 +
  877 + if (dstPts == null) {
  878 + dstPts = new double[numPts * 2 + dstOff];
  879 + }
  880 +
  881 + while (numPts-- > 0) {
  882 + float x = srcPts[srcOff++];
  883 + float y = srcPts[srcOff++];
  884 + double w = m20 * x + m21 * y + m22;
  885 +
  886 + if (w == 0) {
  887 + dstPts[dstOff++] = x;
  888 + dstPts[dstOff++] = y;
  889 + } else {
  890 + dstPts[dstOff++] = (m00 * x + m01 * y + m02) / w;
  891 + dstPts[dstOff++] = (m10 * x + m11 * y + m12) / w;
  892 + }
  893 + }
  894 + }
  895 +
  896 + /**
  897 + * Transforms an array of double precision coordinates by this transform,
  898 + * storing the results into an array of floats.
  899 + * @throws IllegalArgumentException if srcPts is null
  900 + * @throws ArrayIndexOutOfBoundsException if srcPts is too small
  901 + */
  902 + public void transform(double[] srcPts, int srcOff,
  903 + float[] dstPts, int dstOff,
  904 + int numPts) {
  905 +
  906 + if ( srcPts == null ) {
  907 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  908 + }
  909 +
  910 + if (dstPts == null) {
  911 + dstPts = new float[numPts * 2 + dstOff];
  912 + }
  913 +
  914 + while (numPts-- > 0) {
  915 + double x = srcPts[srcOff++];
  916 + double y = srcPts[srcOff++];
  917 + double w = m20 * x + m21 * y + m22;
  918 +
  919 + if (w == 0) {
  920 + dstPts[dstOff++] = (float)x;
  921 + dstPts[dstOff++] = (float)y;
  922 + } else {
  923 + dstPts[dstOff++] = (float)((m00 * x + m01 * y + m02) / w);
  924 + dstPts[dstOff++] = (float)((m10 * x + m11 * y + m12) / w);
  925 + }
  926 + }
  927 + }
  928 +
  929 + /**
  930 + * Inverse transforms the specified ptSrc and stores the result in ptDst.
  931 + * If ptDst is null, a new Point2D object will be allocated before
  932 + * storing. In either case, ptDst containing the transformed point
  933 + * is returned for convenience.
  934 +
  935 + * @throws NoninvertibleTransformException if the matrix cannot be inverted.
  936 + * @throws IllegalArgumentException if ptSrc is null
  937 + */
  938 + public Point2D inverseTransform(Point2D ptSrc, Point2D ptDst)
  939 + throws NoninvertibleTransformException
  940 + {
  941 + if ( ptSrc == null ) {
  942 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  943 + }
  944 +
  945 + if (ptDst == null) {
  946 + if (ptSrc instanceof Point2D.Double) {
  947 + ptDst = new Point2D.Double();
  948 + } else {
  949 + ptDst = new Point2D.Float();
  950 + }
  951 + }
  952 + // Copy source coords into local variables in case src == dst
  953 + double x = ptSrc.getX();
  954 + double y = ptSrc.getY();
  955 +
  956 + double tmp_x = (m11*m22 - m12*m21) * x +
  957 + (m02*m21 - m01*m22) * y +
  958 + (m01*m12 - m02*m11);
  959 + double tmp_y = (m12*m20 - m10*m22) * x +
  960 + (m00*m22 - m02*m20) * y +
  961 + (m02*m10 - m00*m12);
  962 + double w = (m10*m21 - m11*m20) * x +
  963 + (m01*m20 - m00*m21) * y +
  964 + (m00*m11 - m01*m10);
  965 +
  966 + double wabs = w;
  967 + if (w < 0) {
  968 + wabs = - w;
  969 + }
  970 + if (wabs < PERSPECTIVE_DIVIDE_EPSILON) {
  971 + throw new
  972 + NoninvertibleTransformException(
  973 + JaiI18N.getString("PerspectiveTransform1"));
  974 + }
  975 +
  976 + ptDst.setLocation(tmp_x/w, tmp_y/w);
  977 +
  978 + return ptDst;
  979 + }
  980 +
  981 + /**
  982 + * Inverse transforms an array of double precision coordinates by
  983 + * this transform.
  984 + * @throws NoninvertibleTransformException if the matrix cannot be inverted.
  985 + * @throws IllegalArgumentException if srcPts is null
  986 + * @throws ArrayIndexOutOfBoundsException if srcPts is too small
  987 + * @throws NoninvertibleTransformException transform cannot be inverted
  988 + */
  989 + public void inverseTransform(double[] srcPts, int srcOff,
  990 + double[] dstPts, int dstOff,
  991 + int numPts)
  992 + throws NoninvertibleTransformException
  993 + {
  994 + if ( srcPts == null ) {
  995 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  996 + }
  997 +
  998 + if (dstPts == null) {
  999 + dstPts = new double[numPts * 2 + dstOff];
  1000 + }
  1001 +
  1002 + while (numPts-- > 0) {
  1003 + double x = srcPts[srcOff++];
  1004 + double y = srcPts[srcOff++];
  1005 +
  1006 + double tmp_x = (m11*m22 - m12*m21) * x +
  1007 + (m02*m21 - m01*m22) * y +
  1008 + (m01*m12 - m02*m11);
  1009 + double tmp_y = (m12*m20 - m10*m22) * x +
  1010 + (m00*m22 - m02*m20) * y +
  1011 + (m02*m10 - m00*m12);
  1012 + double w = (m10*m21 - m11*m20) * x +
  1013 + (m01*m20 - m00*m21) * y +
  1014 + (m00*m11 - m01*m10);
  1015 +
  1016 + double wabs = w;
  1017 + if (w < 0) {
  1018 + wabs = - w;
  1019 + }
  1020 + if (wabs < PERSPECTIVE_DIVIDE_EPSILON) {
  1021 + throw new NoninvertibleTransformException(
  1022 + JaiI18N.getString("PerspectiveTransform1"));
  1023 + }
  1024 +
  1025 + dstPts[dstOff++] = tmp_x / w;
  1026 + dstPts[dstOff++] = tmp_y / w;
  1027 + }
  1028 + }
  1029 +
  1030 + /**
  1031 + * Returns a String that represents the value of this Object.
  1032 + */
  1033 + public String toString() {
  1034 + StringBuffer sb = new StringBuffer();
  1035 + sb.append("Perspective transform matrix\n");
  1036 + sb.append(this.m00);
  1037 + sb.append("\t");
  1038 + sb.append(this.m01);
  1039 + sb.append("\t");
  1040 + sb.append(this.m02);
  1041 + sb.append("\n");
  1042 + sb.append(this.m10);
  1043 + sb.append("\t");
  1044 + sb.append(this.m11);
  1045 + sb.append("\t");
  1046 + sb.append(this.m12);
  1047 + sb.append("\n");
  1048 + sb.append(this.m20);
  1049 + sb.append("\t");
  1050 + sb.append(this.m21);
  1051 + sb.append("\t");
  1052 + sb.append(this.m22);
  1053 + sb.append("\n");
  1054 + return new String(sb);
  1055 + }
  1056 +
  1057 + /**
  1058 + * Returns the boolean true value if this PerspectiveTransform is an
  1059 + * identity transform. Returns false otherwise.
  1060 + */
  1061 + public boolean isIdentity() {
  1062 + return m01 == 0.0 && m02 == 0.0 &&
  1063 + m10 == 0.0 && m12 == 0.0 &&
  1064 + m20 == 0.0 && m21 == 0.0 &&
  1065 + m22 != 0.0 && m00/m22 == 1.0 && m11/m22 == 1.0;
  1066 + }
  1067 +
  1068 + /**
  1069 + * Returns a copy of this PerspectiveTransform object.
  1070 + */
  1071 + public Object clone() {
  1072 + try {
  1073 + return super.clone();
  1074 + } catch (CloneNotSupportedException e) {
  1075 + // this shouldn't happen, since we are Cloneable
  1076 + throw new InternalError();
  1077 + }
  1078 + }
  1079 +
  1080 +
  1081 + /**
  1082 + * Tests if this PerspectiveTransform equals a supplied one.
  1083 + */
  1084 + public boolean equals(Object obj) {
  1085 + if (!(obj instanceof PerspectiveTransform)) {
  1086 + return false;
  1087 + }
  1088 +
  1089 + PerspectiveTransform a = (PerspectiveTransform)obj;
  1090 +
  1091 + return ((m00 == a.m00) && (m10 == a.m10) && (m20 == a.m20) &&
  1092 + (m01 == a.m01) && (m11 == a.m11) && (m21 == a.m21) &&
  1093 + (m02 == a.m02) && (m12 == a.m12) && (m22 == a.m22));
  1094 + }
  1095 +}
... ...
WiimoteWhiteboard/src/javax/media/jai/PerspectiveTransform.java~ 0 → 100644
... ... @@ -0,0 +1,1439 @@
  1 +/*
  2 + * $RCSfile: PerspectiveTransform.java,v $
  3 + *
  4 + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
  5 + *
  6 + * Use is subject to license terms.
  7 + *
  8 + * $Revision: 1.1 $
  9 + * $Date: 2005/02/11 04:57:15 $
  10 + * $State: Exp $
  11 + */
  12 +package javax.media.jai;
  13 +import java.awt.geom.AffineTransform;
  14 +import java.awt.geom.Point2D;
  15 +import java.awt.geom.NoninvertibleTransformException;
  16 +import java.io.Serializable;
  17 +
  18 +
  19 +/**
  20 + * A 2D perspective (or projective) transform, used by various OpImages.
  21 + *
  22 + * <p> A perspective transformation is capable of mapping an arbitrary
  23 + * quadrilateral into another arbitrary quadrilateral, while
  24 + * preserving the straightness of lines. Unlike an affine
  25 + * transformation, the parallelism of lines in the source is not
  26 + * necessarily preserved in the output.
  27 + *
  28 + * <p> Such a coordinate transformation can be represented by a 3x3
  29 + * matrix which transforms homogenous source coordinates
  30 + * <code>(x,&nbsp;y,&nbsp;1)</code> into destination coordinates
  31 + * <code>(x',&nbsp;y',&nbsp;w)</code>. To convert back into non-homogenous
  32 + * coordinates (X, Y), <code>x'</code> and <code>y'</code> are divided by
  33 + * <code>w</code>.
  34 + *
  35 + * <pre>
  36 + * [ x'] [ m00 m01 m02 ] [ x ] [ m00x + m01y + m02 ]
  37 + * [ y'] = [ m10 m11 m12 ] [ y ] = [ m10x + m11y + m12 ]
  38 + * [ w ] [ m20 m21 m22 ] [ 1 ] [ m20x + m21y + m22 ]
  39 + *
  40 + * x' = (m00x + m01y + m02)
  41 + * y' = (m10x + m11y + m12)
  42 + *
  43 + * w = (m20x + m21y + m22)
  44 + *
  45 + * X = x' / w
  46 + * Y = y' / w
  47 + * </pre>
  48 + */
  49 +public final class PerspectiveTransform implements Cloneable, Serializable {
  50 +
  51 + private static final double PERSPECTIVE_DIVIDE_EPSILON = 1.0e-10;
  52 +
  53 + /** An element of the transform matrix. */
  54 + double m00, m01, m02, m10, m11, m12, m20, m21, m22;
  55 +
  56 + /** Constructs an identity PerspectiveTransform. */
  57 + public PerspectiveTransform() {
  58 + m00 = m11 = m22 = 1.0;
  59 + m01 = m02 = m10 = m12 = m20 = m21 = 0.0;
  60 + }
  61 +
  62 + /**
  63 + * Constructs a new PerspectiveTransform from 9 floats.
  64 + * @deprecated as of JAI 1.1 Use PerspectiveTransform(double[][]) instead.
  65 + */
  66 + public PerspectiveTransform(float m00, float m01, float m02,
  67 + float m10, float m11, float m12,
  68 + float m20, float m21, float m22) {
  69 + this.m00 = m00;
  70 + this.m01 = m01;
  71 + this.m02 = m02;
  72 + this.m10 = m10;
  73 + this.m11 = m11;
  74 + this.m12 = m12;
  75 + this.m20 = m20;
  76 + this.m21 = m21;
  77 + this.m22 = m22;
  78 + }
  79 +
  80 + /**
  81 + * Constructs a new PerspectiveTransform from 9 doubles.
  82 + * @deprecated as of JAI 1.1 Use PerspectiveTransform(double[][]) instead.
  83 + */
  84 + public PerspectiveTransform(double m00, double m01, double m02,
  85 + double m10, double m11, double m12,
  86 + double m20, double m21, double m22) {
  87 + this.m00 = m00;
  88 + this.m01 = m01;
  89 + this.m02 = m02;
  90 + this.m10 = m10;
  91 + this.m11 = m11;
  92 + this.m12 = m12;
  93 + this.m20 = m20;
  94 + this.m21 = m21;
  95 + this.m22 = m22;
  96 + }
  97 +
  98 + /**
  99 + * Constructs a new PerspectiveTransform from a one-dimensional
  100 + * array of 9 floats, in row-major order.
  101 + * The values in the array are assumed to be
  102 + * { m00 m01 m02 m10 m11 m12 m20 m21 m22 }.
  103 + * @throws IllegalArgumentException if flatmatrix is null
  104 + * @throws ArrayIndexOutOfBoundsException if flatmatrix is too small
  105 + * @deprecated as of JAI 1.1 Use PerspectiveTransform(double[][]) instead.
  106 + */
  107 + public PerspectiveTransform(float[] flatmatrix) {
  108 + if ( flatmatrix == null ) {
  109 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  110 + }
  111 +
  112 + m00 = flatmatrix[0];
  113 + m01 = flatmatrix[1];
  114 + m02 = flatmatrix[2];
  115 + m10 = flatmatrix[3];
  116 + m11 = flatmatrix[4];
  117 + m12 = flatmatrix[5];
  118 + m20 = flatmatrix[6];
  119 + m21 = flatmatrix[7];
  120 + m22 = flatmatrix[8];
  121 + }
  122 +
  123 + /**
  124 + * Constructs a new PerspectiveTransform from a two-dimensional
  125 + * array of floats.
  126 + * @throws IllegalArgumentException if matrix is null
  127 + * @throws ArrayIndexOutOfBoundsException if matrix is too small
  128 + *
  129 + * @deprecated as of JAI 1.1 Use PerspectiveTransform(double[][]) instead.
  130 + */
  131 + public PerspectiveTransform(float[][] matrix) {
  132 + if ( matrix == null ) {
  133 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  134 + }
  135 +
  136 + m00 = matrix[0][0];
  137 + m01 = matrix[0][1];
  138 + m02 = matrix[0][2];
  139 + m10 = matrix[1][0];
  140 + m11 = matrix[1][1];
  141 + m12 = matrix[1][2];
  142 + m20 = matrix[2][0];
  143 + m21 = matrix[2][1];
  144 + m22 = matrix[2][2];
  145 + }
  146 +
  147 + /**
  148 + * Constructs a new PerspectiveTransform from a one-dimensional
  149 + * array of 9 doubles, in row-major order.
  150 + * The values in the array are assumed to be
  151 + * { m00 m01 m02 m10 m11 m12 m20 m21 m22 }.
  152 + * @throws IllegalArgumentException if flatmatrix is null
  153 + * @throws ArrayIndexOutOfBoundsException if flatmatrix is too small
  154 + *
  155 + * @deprecated as of JAI 1.1 Use PerspectiveTransform(double[][]) instead.
  156 + */
  157 + public PerspectiveTransform(double[] flatmatrix) {
  158 + if ( flatmatrix == null ) {
  159 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  160 + }
  161 +
  162 + m00 = flatmatrix[0];
  163 + m01 = flatmatrix[1];
  164 + m02 = flatmatrix[2];
  165 + m10 = flatmatrix[3];
  166 + m11 = flatmatrix[4];
  167 + m12 = flatmatrix[5];
  168 + m20 = flatmatrix[6];
  169 + m21 = flatmatrix[7];
  170 + m22 = flatmatrix[8];
  171 + }
  172 +
  173 + /**
  174 + * Constructs a new PerspectiveTransform from a two-dimensional
  175 + * array of doubles.
  176 + * @throws IllegalArgumentException if matrix is null
  177 + * @throws ArrayIndexOutOfBoundsException if matrix is too small
  178 + */
  179 + public PerspectiveTransform(double[][] matrix) {
  180 + if ( matrix == null ) {
  181 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  182 + }
  183 +
  184 + m00 = matrix[0][0];
  185 + m01 = matrix[0][1];
  186 + m02 = matrix[0][2];
  187 + m10 = matrix[1][0];
  188 + m11 = matrix[1][1];
  189 + m12 = matrix[1][2];
  190 + m20 = matrix[2][0];
  191 + m21 = matrix[2][1];
  192 + m22 = matrix[2][2];
  193 + }
  194 +
  195 + /**
  196 + * Constructs a new PerspectiveTransform with the same effect
  197 + * as an existing AffineTransform.
  198 + * @throws IllegalArgumentException if transform is null
  199 + */
  200 + public PerspectiveTransform(AffineTransform transform) {
  201 + if ( transform == null ) {
  202 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  203 + }
  204 +
  205 + m00 = transform.getScaleX();
  206 + m01 = transform.getShearX();
  207 + m02 = transform.getTranslateX();
  208 + m10 = transform.getShearY();
  209 + m11 = transform.getScaleY();
  210 + m12 = transform.getTranslateY();
  211 + m20 = 0.0;
  212 + m21 = 0.0;
  213 + m22 = 1.0;
  214 + }
  215 +
  216 + /**
  217 + * Replaces the matrix with its adjoint.
  218 + */
  219 + private final void makeAdjoint() {
  220 + double m00p = m11*m22 - m12*m21;
  221 + double m01p = m12*m20 - m10*m22; // flipped sign
  222 + double m02p = m10*m21 - m11*m20;
  223 + double m10p = m02*m21 - m01*m22; // flipped sign
  224 + double m11p = m00*m22 - m02*m20;
  225 + double m12p = m01*m20 - m00*m21; // flipped sign
  226 + double m20p = m01*m12 - m02*m11;
  227 + double m21p = m02*m10 - m00*m12; // flipped sign
  228 + double m22p = m00*m11 - m01*m10;
  229 +
  230 + // Transpose and copy sub-determinants
  231 + m00 = m00p;
  232 + m01 = m10p;
  233 + m02 = m20p;
  234 + m10 = m01p;
  235 + m11 = m11p;
  236 + m12 = m21p;
  237 + m20 = m02p;
  238 + m21 = m12p;
  239 + m22 = m22p;
  240 + }
  241 +
  242 + /**
  243 + * Scales the matrix elements so m22 is equal to 1.0.
  244 + * m22 must not be equal to 0.
  245 + */
  246 + private final void normalize() {
  247 + double invscale = 1.0/m22;
  248 + m00 *= invscale;
  249 + m01 *= invscale;
  250 + m02 *= invscale;
  251 + m10 *= invscale;
  252 + m11 *= invscale;
  253 + m12 *= invscale;
  254 + m20 *= invscale;
  255 + m21 *= invscale;
  256 + m22 = 1.0;
  257 + }
  258 +
  259 + private static final void getSquareToQuad(double x0, double y0,
  260 + double x1, double y1,
  261 + double x2, double y2,
  262 + double x3, double y3,
  263 + PerspectiveTransform tx) {
  264 + double dx3 = x0 - x1 + x2 - x3;
  265 + double dy3 = y0 - y1 + y2 - y3;
  266 +
  267 + tx.m22 = 1.0F;
  268 +
  269 + if ((dx3 == 0.0F) && (dy3 == 0.0F)) { // to do: use tolerance
  270 + tx.m00 = x1 - x0;
  271 + tx.m01 = x2 - x1;
  272 + tx.m02 = x0;
  273 + tx.m10 = y1 - y0;
  274 + tx.m11 = y2 - y1;
  275 + tx.m12 = y0;
  276 + tx.m20 = 0.0F;
  277 + tx.m21 = 0.0F;
  278 + } else {
  279 + double dx1 = x1 - x2;
  280 + double dy1 = y1 - y2;
  281 + double dx2 = x3 - x2;
  282 + double dy2 = y3 - y2;
  283 +
  284 + double invdet = 1.0F/(dx1*dy2 - dx2*dy1);
  285 + tx.m20 = (dx3*dy2 - dx2*dy3)*invdet;
  286 + tx.m21 = (dx1*dy3 - dx3*dy1)*invdet;
  287 + tx.m00 = x1 - x0 + tx.m20*x1;
  288 + tx.m01 = x3 - x0 + tx.m21*x3;
  289 + tx.m02 = x0;
  290 + tx.m10 = y1 - y0 + tx.m20*y1;
  291 + tx.m11 = y3 - y0 + tx.m21*y3;
  292 + tx.m12 = y0;
  293 + }
  294 + }
  295 +
  296 + /**
  297 + * Creates a PerspectiveTransform that maps the unit square
  298 + * onto an arbitrary quadrilateral.
  299 + *
  300 + * <pre>
  301 + * (0, 0) -> (x0, y0)
  302 + * (1, 0) -> (x1, y1)
  303 + * (1, 1) -> (x2, y2)
  304 + * (0, 1) -> (x3, y3)
  305 + * </pre>
  306 + */
  307 + public static PerspectiveTransform getSquareToQuad(double x0, double y0,
  308 + double x1, double y1,
  309 + double x2, double y2,
  310 + double x3, double y3) {
  311 + PerspectiveTransform tx = new PerspectiveTransform();
  312 + getSquareToQuad(x0, y0, x1, y1, x2, y2, x3, y3, tx);
  313 + return tx;
  314 + }
  315 +
  316 +
  317 + /**
  318 + * Creates a PerspectiveTransform that maps the unit square
  319 + * onto an arbitrary quadrilateral.
  320 + *
  321 + * <pre>
  322 + * (0, 0) -> (x0, y0)
  323 + * (1, 0) -> (x1, y1)
  324 + * (1, 1) -> (x2, y2)
  325 + * (0, 1) -> (x3, y3)
  326 + * </pre>
  327 + */
  328 + public static PerspectiveTransform getSquareToQuad(float x0, float y0,
  329 + float x1, float y1,
  330 + float x2, float y2,
  331 + float x3, float y3) {
  332 + return getSquareToQuad((double)x0, (double)y0,
  333 + (double)x1, (double)y1,
  334 + (double)x2, (double)y2,
  335 + (double)x3, (double)y3);
  336 + }
  337 +
  338 +
  339 + /**
  340 + * Creates a PerspectiveTransform that maps an arbitrary
  341 + * quadrilateral onto the unit square.
  342 + *
  343 + * <pre>
  344 + * (x0, y0) -> (0, 0)
  345 + * (x1, y1) -> (1, 0)
  346 + * (x2, y2) -> (1, 1)
  347 + * (x3, y3) -> (0, 1)
  348 + * </pre>
  349 + */
  350 + public static PerspectiveTransform getQuadToSquare(double x0, double y0,
  351 + double x1, double y1,
  352 + double x2, double y2,
  353 + double x3, double y3) {
  354 + PerspectiveTransform tx = new PerspectiveTransform();
  355 + getSquareToQuad(x0, y0, x1, y1, x2, y2, x3, y3, tx);
  356 + tx.makeAdjoint();
  357 + return tx;
  358 + }
  359 +
  360 + /**
  361 + * Creates a PerspectiveTransform that maps an arbitrary
  362 + * quadrilateral onto the unit square.
  363 + *
  364 + * <pre>
  365 + * (x0, y0) -> (0, 0)
  366 + * (x1, y1) -> (1, 0)
  367 + * (x2, y2) -> (1, 1)
  368 + * (x3, y3) -> (0, 1)
  369 + * </pre>
  370 + */
  371 + public static PerspectiveTransform getQuadToSquare(float x0, float y0,
  372 + float x1, float y1,
  373 + float x2, float y2,
  374 + float x3, float y3) {
  375 + return getQuadToSquare((double)x0, (double)y0,
  376 + (double)x1, (double)y1,
  377 + (double)x2, (double)y2,
  378 + (double)x3, (double)y3);
  379 + }
  380 +
  381 + /**
  382 + * Creates a PerspectiveTransform that maps an arbitrary
  383 + * quadrilateral onto another arbitrary quadrilateral.
  384 + *
  385 + * <pre>
  386 + * (x0, y0) -> (x0p, y0p)
  387 + * (x1, y1) -> (x1p, y1p)
  388 + * (x2, y2) -> (x2p, y2p)
  389 + * (x3, y3) -> (x3p, y3p)
  390 + * </pre>
  391 + */
  392 + public static PerspectiveTransform getQuadToQuad(double x0, double y0,
  393 + double x1, double y1,
  394 + double x2, double y2,
  395 + double x3, double y3,
  396 + double x0p, double y0p,
  397 + double x1p, double y1p,
  398 + double x2p, double y2p,
  399 + double x3p, double y3p) {
  400 + PerspectiveTransform tx1 =
  401 + getQuadToSquare(x0, y0, x1, y1, x2, y2, x3, y3);
  402 +
  403 + PerspectiveTransform tx2 =
  404 + getSquareToQuad(x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p);
  405 +
  406 + tx1.concatenate(tx2);
  407 + return tx1;
  408 + }
  409 +
  410 +
  411 + /**
  412 + * Creates a PerspectiveTransform that maps an arbitrary
  413 + * quadrilateral onto another arbitrary quadrilateral.
  414 + *
  415 + * <pre>
  416 + * (x0, y0) -> (x0p, y0p)
  417 + * (x1, y1) -> (x1p, y1p)
  418 + * (x2, y2) -> (x2p, y2p)
  419 + * (x3, y3) -> (x3p, y3p)
  420 + * </pre>
  421 + */
  422 + public static PerspectiveTransform getQuadToQuad(float x0, float y0,
  423 + float x1, float y1,
  424 + float x2, float y2,
  425 + float x3, float y3,
  426 + float x0p, float y0p,
  427 + float x1p, float y1p,
  428 + float x2p, float y2p,
  429 + float x3p, float y3p) {
  430 + return getQuadToQuad((double)x0, (double)y0,
  431 + (double)x1, (double)y1,
  432 + (double)x2, (double)y2,
  433 + (double)x3, (double)y3,
  434 + (double)x0p, (double)y0p,
  435 + (double)x1p, (double)y1p,
  436 + (double)x2p, (double)y2p,
  437 + (double)x3p, (double)y3p);
  438 + }
  439 +
  440 + /**
  441 + * Returns the determinant of the matrix representation of the
  442 + * transform.
  443 + */
  444 + public double getDeterminant() {
  445 + return ( (m00 * ((m11 * m22) - (m12 * m21))) -
  446 + (m01 * ((m10 * m22) - (m12 * m20))) +
  447 + (m02 * ((m10 * m21) - (m11 * m20))) );
  448 +
  449 + }
  450 +
  451 + /**
  452 + * Retrieves the 9 specifiable values in the 3x3 affine
  453 + * transformation matrix into an array of double precision values.
  454 + * The values are stored into the array as
  455 + * { m00 m01 m02 m10 m11 m12 m20 m21 m22 }.
  456 + *
  457 + * @param flatmatrix The double array used to store the returned
  458 + * values. The length of the array is assumed to be at
  459 + * least 9.
  460 + * @throws ArrayIndexOutOfBoundsException if flatmatrix is too small
  461 + * @deprecated as of JAI 1.1 Use double[][] getMatrix(double[][] matrix) instead.
  462 + */
  463 + public double[] getMatrix(double[] flatmatrix) {
  464 + if (flatmatrix == null) {
  465 + flatmatrix = new double[9];
  466 + }
  467 +
  468 + flatmatrix[0] = m00;
  469 + flatmatrix[1] = m01;
  470 + flatmatrix[2] = m02;
  471 + flatmatrix[3] = m10;
  472 + flatmatrix[4] = m11;
  473 + flatmatrix[5] = m12;
  474 + flatmatrix[6] = m20;
  475 + flatmatrix[7] = m21;
  476 + flatmatrix[8] = m22;
  477 +
  478 + return flatmatrix;
  479 + }
  480 +
  481 + /**
  482 + * Retrieves the 9 specifiable values in the 3x3 affine
  483 + * transformation matrix into a 2-dimensional array of double
  484 + * precision values. The values are stored into the 2-dimensional
  485 + * array using the row index as the first subscript and the column
  486 + * index as the second.
  487 + *
  488 + * @param matrix The 2-dimensional double array to store the
  489 + * returned values. The array is assumed to be at least 3x3.
  490 + * @throws ArrayIndexOutOfBoundsException if matrix is too small
  491 + */
  492 + public double[][] getMatrix(double[][] matrix) {
  493 + if (matrix == null) {
  494 + matrix = new double[3][3];
  495 + }
  496 +
  497 + matrix[0][0] = m00;
  498 + matrix[0][1] = m01;
  499 + matrix[0][2] = m02;
  500 + matrix[1][0] = m10;
  501 + matrix[1][1] = m11;
  502 + matrix[1][2] = m12;
  503 + matrix[2][0] = m20;
  504 + matrix[2][1] = m21;
  505 + matrix[2][2] = m22;
  506 +
  507 + return matrix;
  508 + }
  509 +
  510 + /**
  511 + * Concatenates this transform with a translation transformation.
  512 + * This is equivalent to calling concatenate(T), where T is an
  513 + * PerspectiveTransform represented by the following matrix:
  514 + * <pre>
  515 + * [ 1 0 tx ]
  516 + * [ 0 1 ty ]
  517 + * [ 0 0 1 ]
  518 + * </pre>
  519 + */
  520 + public void translate(double tx, double ty) {
  521 + PerspectiveTransform Tx = new PerspectiveTransform();
  522 + Tx.setToTranslation(tx, ty);
  523 + concatenate(Tx);
  524 + }
  525 +
  526 + /**
  527 + * Concatenates this transform with a rotation transformation.
  528 + * This is equivalent to calling concatenate(R), where R is an
  529 + * PerspectiveTransform represented by the following matrix:
  530 + * <pre>
  531 + * [ cos(theta) -sin(theta) 0 ]
  532 + * [ sin(theta) cos(theta) 0 ]
  533 + * [ 0 0 1 ]
  534 + * </pre>
  535 + * Rotating with a positive angle theta rotates points on the positive
  536 + * X axis toward the positive Y axis.
  537 + *
  538 + * @param theta The angle of rotation in radians.
  539 + */
  540 + public void rotate(double theta) {
  541 + PerspectiveTransform Tx = new PerspectiveTransform();
  542 + Tx.setToRotation(theta);
  543 + concatenate(Tx);
  544 + }
  545 +
  546 + /**
  547 + * Concatenates this transform with a translated rotation transformation.
  548 + * This is equivalent to the following sequence of calls:
  549 + * <pre>
  550 + * translate(x, y);
  551 + * rotate(theta);
  552 + * translate(-x, -y);
  553 + * </pre>
  554 + * Rotating with a positive angle theta rotates points on the positive
  555 + * X axis toward the positive Y axis.
  556 + *
  557 + * @param theta The angle of rotation in radians.
  558 + * @param x The X coordinate of the origin of the rotation
  559 + * @param y The Y coordinate of the origin of the rotation
  560 + */
  561 + public void rotate(double theta, double x, double y) {
  562 + PerspectiveTransform Tx = new PerspectiveTransform();
  563 + Tx.setToRotation(theta, x, y);
  564 + concatenate(Tx);
  565 + }
  566 +
  567 + /**
  568 + * Concatenates this transform with a scaling transformation.
  569 + * This is equivalent to calling concatenate(S), where S is an
  570 + * PerspectiveTransform represented by the following matrix:
  571 + * <pre>
  572 + * [ sx 0 0 ]
  573 + * [ 0 sy 0 ]
  574 + * [ 0 0 1 ]
  575 + * </pre>
  576 + *
  577 + * @param sx The X axis scale factor.
  578 + * @param sy The Y axis scale factor.
  579 + */
  580 + public void scale(double sx, double sy) {
  581 + PerspectiveTransform Tx = new PerspectiveTransform();
  582 + Tx.setToScale(sx, sy);
  583 + concatenate(Tx);
  584 + }
  585 +
  586 + /**
  587 + * Concatenates this transform with a shearing transformation.
  588 + * This is equivalent to calling concatenate(SH), where SH is an
  589 + * PerspectiveTransform represented by the following matrix:
  590 + * <pre>
  591 + * [ 1 shx 0 ]
  592 + * [ shy 1 0 ]
  593 + * [ 0 0 1 ]
  594 + * </pre>
  595 + *
  596 + * @param shx The factor by which coordinates are shifted towards
  597 + * the positive X axis direction according to their Y
  598 + * coordinate.
  599 + * @param shy The factor by which coordinates are shifted towards
  600 + * the positive Y axis direction according to their X
  601 + * coordinate.
  602 + */
  603 + public void shear(double shx, double shy) {
  604 + PerspectiveTransform Tx = new PerspectiveTransform();
  605 + Tx.setToShear(shx, shy);
  606 + concatenate(Tx);
  607 + }
  608 +
  609 + /**
  610 + * Resets this transform to the Identity transform.
  611 + */
  612 + public void setToIdentity() {
  613 + m00 = m11 = m22 = 1.0;
  614 + m01 = m10 = m02 = m20 = m12 = m21 = 0.0;
  615 + }
  616 +
  617 + /**
  618 + * Sets this transform to a translation transformation.
  619 + * The matrix representing this transform becomes:
  620 + * <pre>
  621 + * [ 1 0 tx ]
  622 + * [ 0 1 ty ]
  623 + * [ 0 0 1 ]
  624 + * </pre>
  625 + * @param tx The distance by which coordinates are translated in the
  626 + * X axis direction
  627 + * @param ty The distance by which coordinates are translated in the
  628 + * Y axis direction
  629 + */
  630 + public void setToTranslation(double tx, double ty) {
  631 + m00 = 1.0;
  632 + m01 = 0.0;
  633 + m02 = tx;
  634 + m10 = 0.0;
  635 + m11 = 1.0;
  636 + m12 = ty;
  637 + m20 = 0.0;
  638 + m21 = 0.0;
  639 + m22 = 1.0;
  640 + }
  641 +
  642 + /**
  643 + * Sets this transform to a rotation transformation.
  644 + * The matrix representing this transform becomes:
  645 + * <pre>
  646 + * [ cos(theta) -sin(theta) 0 ]
  647 + * [ sin(theta) cos(theta) 0 ]
  648 + * [ 0 0 1 ]
  649 + * </pre>
  650 + * Rotating with a positive angle theta rotates points on the positive
  651 + * X axis toward the positive Y axis.
  652 + * @param theta The angle of rotation in radians.
  653 + */
  654 + public void setToRotation(double theta) {
  655 + m00 = Math.cos(theta);
  656 + m01 = -Math.sin(theta);
  657 + m02 = 0.0;
  658 + m10 = - m01; // Math.sin(theta);
  659 + m11 = m00; // Math.cos(theta);
  660 + m12 = 0.0;
  661 + m20 = 0.0;
  662 + m21 = 0.0;
  663 + m22 = 1.0;
  664 + }
  665 +
  666 + /**
  667 + * Sets this transform to a rotation transformation
  668 + * about a specified point (x, y). This is equivalent
  669 + * to the following sequence of calls:
  670 + *
  671 + * <pre>
  672 + * setToTranslate(x, y);
  673 + * rotate(theta);
  674 + * translate(-x, -y);
  675 + * </pre>
  676 + *
  677 + * Rotating with a positive angle theta rotates points on the positive
  678 + * X axis toward the positive Y axis.
  679 + *
  680 + * @param theta The angle of rotation in radians.
  681 + * @param x The X coordinate of the origin of the rotation
  682 + * @param y The Y coordinate of the origin of the rotation
  683 + */
  684 + public void setToRotation(double theta, double x, double y) {
  685 + setToRotation(theta);
  686 + double sin = m10;
  687 + double oneMinusCos = 1.0 - m00;
  688 + m02 = x * oneMinusCos + y * sin;
  689 + m12 = y * oneMinusCos - x * sin;
  690 + }
  691 +
  692 + /**
  693 + * Sets this transform to a scale transformation
  694 + * with scale factors sx and sy.
  695 + * The matrix representing this transform becomes:
  696 + * <pre>
  697 + * [ sx 0 0 ]
  698 + * [ 0 sy 0 ]
  699 + * [ 0 0 1 ]
  700 + * </pre>
  701 + *
  702 + * @param sx The X axis scale factor.
  703 + * @param sy The Y axis scale factor.
  704 + */
  705 + public void setToScale(double sx, double sy) {
  706 + m00 = sx;
  707 + m01 = 0.0;
  708 + m02 = 0.0;
  709 + m10 = 0.0;
  710 + m11 = sy;
  711 + m12 = 0.0;
  712 + m20 = 0.0;
  713 + m21 = 0.0;
  714 + m22 = 1.0;
  715 + }
  716 +
  717 + /**
  718 + * Sets this transform to a shearing transformation
  719 + * with shear factors sx and sy.
  720 + * The matrix representing this transform becomes:
  721 + * <pre>
  722 + * [ 1 shx 0 ]
  723 + * [ shy 1 0 ]
  724 + * [ 0 0 1 ]
  725 + * </pre>
  726 + *
  727 + * @param shx The factor by which coordinates are shifted towards
  728 + * the positive X axis direction according to their Y
  729 + * coordinate.
  730 + * @param shy The factor by which coordinates are shifted towards
  731 + * the positive Y axis direction according to their X
  732 + * coordinate.
  733 + */
  734 + public void setToShear(double shx, double shy) {
  735 + m00 = 1.0;
  736 + m01 = shx;
  737 + m02 = 0.0;
  738 + m10 = shy;
  739 + m11 = 1.0;
  740 + m12 = 0.0;
  741 + m20 = 0.0;
  742 + m21 = 0.0;
  743 + m22 = 1.0;
  744 + }
  745 +
  746 + /**
  747 + * Sets this transform to a given AffineTransform.
  748 + * @throws IllegalArgumentException if Tx is null
  749 + */
  750 + public void setTransform(AffineTransform Tx) {
  751 + if ( Tx == null ) {
  752 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  753 + }
  754 +
  755 + m00 = Tx.getScaleX();
  756 + m01 = Tx.getShearX();
  757 + m02 = Tx.getTranslateX();
  758 + m10 = Tx.getShearY();
  759 + m11 = Tx.getScaleY();
  760 + m12 = Tx.getTranslateY();
  761 + m20 = 0.0;
  762 + m21 = 0.0;
  763 + m22 = 1.0;
  764 + }
  765 +
  766 + /**
  767 + * Sets this transform to a given PerspectiveTransform.
  768 + * @throws IllegalArgumentException if Tx is null
  769 + */
  770 + public void setTransform(PerspectiveTransform Tx) {
  771 + if ( Tx == null ) {
  772 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  773 + }
  774 +
  775 + m00 = Tx.m00;
  776 + m01 = Tx.m01;
  777 + m02 = Tx.m02;
  778 + m10 = Tx.m10;
  779 + m11 = Tx.m11;
  780 + m12 = Tx.m12;
  781 + m20 = Tx.m20;
  782 + m21 = Tx.m21;
  783 + m22 = Tx.m22;
  784 + }
  785 +
  786 + /**
  787 + * Sets this transform to a given PerspectiveTransform,
  788 + * expressed by the elements of its matrix. <i>Important Note: The
  789 + * matrix elements in the argument list are in column-major order
  790 + * unlike those of the constructor, which are in row-major order.</i>
  791 + * @deprecated as of JAI 1.1 Use double[][] getMatrix(double[][] matrix) instead.
  792 + */
  793 + public void setTransform(float m00, float m10, float m20,
  794 + float m01, float m11, float m21,
  795 + float m02, float m12, float m22) {
  796 + this.m00 = (double)m00;
  797 + this.m01 = (double)m01;
  798 + this.m02 = (double)m02;
  799 + this.m10 = (double)m10;
  800 + this.m11 = (double)m11;
  801 + this.m12 = (double)m12;
  802 + this.m20 = (double)m20;
  803 + this.m21 = (double)m21;
  804 + this.m22 = (double)m22;
  805 + }
  806 +
  807 + /**
  808 + * Sets this transform using a two-dimensional array of double precision
  809 + * values. The row index is first, and the column index is second.
  810 + *
  811 + * @param matrix The 2D double array to be used for setting this transform.
  812 + * The array is assumed to be at least 3x3.
  813 + * @throws IllegalArgumentException if matrix is null
  814 + * @throws ArrayIndexOutOfBoundsException if matrix is too small
  815 + * @since JAI 1.1
  816 + */
  817 + public void setTransform(double[][] matrix) {
  818 + if ( matrix == null ) {
  819 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  820 + }
  821 +
  822 + m00 = matrix[0][0];
  823 + m01 = matrix[0][1];
  824 + m02 = matrix[0][2];
  825 + m10 = matrix[1][0];
  826 + m11 = matrix[1][1];
  827 + m12 = matrix[1][2];
  828 + m20 = matrix[2][0];
  829 + m21 = matrix[2][1];
  830 + m22 = matrix[2][2];
  831 + }
  832 +
  833 + /**
  834 + * Post-concatenates a given AffineTransform to this transform.
  835 + * @throws IllegalArgumentException if Tx is null
  836 + */
  837 + public void concatenate(AffineTransform Tx) {
  838 + if ( Tx == null ) {
  839 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  840 + }
  841 +
  842 + // Extend Tx: Tx.m20 = 0, Tx.m21 = 0, Tx.m22 = 1
  843 +
  844 + double tx_m00 = Tx.getScaleX();
  845 + double tx_m01 = Tx.getShearX();
  846 + double tx_m02 = Tx.getTranslateX();
  847 + double tx_m10 = Tx.getShearY();
  848 + double tx_m11 = Tx.getScaleY();
  849 + double tx_m12 = Tx.getTranslateY();
  850 +
  851 + double m00p = m00*tx_m00 + m10*tx_m01 + m20*tx_m02;
  852 + double m01p = m01*tx_m00 + m11*tx_m01 + m21*tx_m02;
  853 + double m02p = m02*tx_m00 + m12*tx_m01 + m22*tx_m02;
  854 + double m10p = m00*tx_m10 + m10*tx_m11 + m20*tx_m12;
  855 + double m11p = m01*tx_m10 + m11*tx_m11 + m21*tx_m12;
  856 + double m12p = m02*tx_m10 + m12*tx_m11 + m22*tx_m12;
  857 + double m20p = m20;
  858 + double m21p = m21;
  859 + double m22p = m22;
  860 +
  861 + m00 = m00p;
  862 + m10 = m10p;
  863 + m20 = m20p;
  864 + m01 = m01p;
  865 + m11 = m11p;
  866 + m21 = m21p;
  867 + m02 = m02p;
  868 + m12 = m12p;
  869 + m22 = m22p;
  870 + }
  871 +
  872 + /**
  873 + * Post-concatenates a given PerspectiveTransform to this transform.
  874 + * @throws IllegalArgumentException if Tx is null
  875 + */
  876 + public void concatenate(PerspectiveTransform Tx) {
  877 + if ( Tx == null ) {
  878 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  879 + }
  880 +
  881 + double m00p = m00*Tx.m00 + m10*Tx.m01 + m20*Tx.m02;
  882 + double m10p = m00*Tx.m10 + m10*Tx.m11 + m20*Tx.m12;
  883 + double m20p = m00*Tx.m20 + m10*Tx.m21 + m20*Tx.m22;
  884 + double m01p = m01*Tx.m00 + m11*Tx.m01 + m21*Tx.m02;
  885 + double m11p = m01*Tx.m10 + m11*Tx.m11 + m21*Tx.m12;
  886 + double m21p = m01*Tx.m20 + m11*Tx.m21 + m21*Tx.m22;
  887 + double m02p = m02*Tx.m00 + m12*Tx.m01 + m22*Tx.m02;
  888 + double m12p = m02*Tx.m10 + m12*Tx.m11 + m22*Tx.m12;
  889 + double m22p = m02*Tx.m20 + m12*Tx.m21 + m22*Tx.m22;
  890 +
  891 + m00 = m00p;
  892 + m10 = m10p;
  893 + m20 = m20p;
  894 + m01 = m01p;
  895 + m11 = m11p;
  896 + m21 = m21p;
  897 + m02 = m02p;
  898 + m12 = m12p;
  899 + m22 = m22p;
  900 + }
  901 +
  902 + /**
  903 + * Pre-concatenates a given AffineTransform to this transform.
  904 + * @throws IllegalArgumentException if Tx is null
  905 + */
  906 + public void preConcatenate(AffineTransform Tx) {
  907 + if ( Tx == null ) {
  908 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  909 + }
  910 +
  911 + // Extend Tx: Tx.m20 = 0, Tx.m21 = 0, Tx.m22 = 1
  912 +
  913 + double tx_m00 = Tx.getScaleX();
  914 + double tx_m01 = Tx.getShearX();
  915 + double tx_m02 = Tx.getTranslateX();
  916 + double tx_m10 = Tx.getShearY();
  917 + double tx_m11 = Tx.getScaleY();
  918 + double tx_m12 = Tx.getTranslateY();
  919 +
  920 + double m00p = tx_m00*m00 + tx_m10*m01;
  921 + double m01p = tx_m01*m00 + tx_m11*m01;
  922 + double m02p = tx_m02*m00 + tx_m12*m01 + m02;
  923 + double m10p = tx_m00*m10 + tx_m10*m11;
  924 + double m11p = tx_m01*m10 + tx_m11*m11;
  925 + double m12p = tx_m02*m10 + tx_m12*m11 + m12;
  926 + double m20p = tx_m00*m20 + tx_m10*m21;
  927 + double m21p = tx_m01*m20 + tx_m11*m21;
  928 + double m22p = tx_m02*m20 + tx_m12*m21 + m22;
  929 +
  930 + m00 = m00p;
  931 + m10 = m10p;
  932 + m20 = m20p;
  933 + m01 = m01p;
  934 + m11 = m11p;
  935 + m21 = m21p;
  936 + m02 = m02p;
  937 + m12 = m12p;
  938 + m22 = m22p;
  939 + }
  940 +
  941 + /**
  942 + * Pre-concatenates a given PerspectiveTransform to this transform.
  943 + * @throws IllegalArgumentException if Tx is null
  944 + */
  945 + public void preConcatenate(PerspectiveTransform Tx) {
  946 + if ( Tx == null ) {
  947 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  948 + }
  949 +
  950 + double m00p = Tx.m00*m00 + Tx.m10*m01 + Tx.m20*m02;
  951 + double m10p = Tx.m00*m10 + Tx.m10*m11 + Tx.m20*m12;
  952 + double m20p = Tx.m00*m20 + Tx.m10*m21 + Tx.m20*m22;
  953 + double m01p = Tx.m01*m00 + Tx.m11*m01 + Tx.m21*m02;
  954 + double m11p = Tx.m01*m10 + Tx.m11*m11 + Tx.m21*m12;
  955 + double m21p = Tx.m01*m20 + Tx.m11*m21 + Tx.m21*m22;
  956 + double m02p = Tx.m02*m00 + Tx.m12*m01 + Tx.m22*m02;
  957 + double m12p = Tx.m02*m10 + Tx.m12*m11 + Tx.m22*m12;
  958 + double m22p = Tx.m02*m20 + Tx.m12*m21 + Tx.m22*m22;
  959 +
  960 + m00 = m00p;
  961 + m10 = m10p;
  962 + m20 = m20p;
  963 + m01 = m01p;
  964 + m11 = m11p;
  965 + m21 = m21p;
  966 + m02 = m02p;
  967 + m12 = m12p;
  968 + m22 = m22p;
  969 + }
  970 +
  971 + /**
  972 + * Returns a new PerpectiveTransform that is the inverse
  973 + * of the current transform.
  974 + * @throws NoninvertibleTransformException if transform cannot be inverted
  975 + */
  976 + public PerspectiveTransform createInverse()
  977 + throws NoninvertibleTransformException, CloneNotSupportedException {
  978 +
  979 + PerspectiveTransform tx = (PerspectiveTransform)clone();
  980 + tx.makeAdjoint();
  981 + if (Math.abs(tx.m22) < PERSPECTIVE_DIVIDE_EPSILON) {
  982 + throw new NoninvertibleTransformException(JaiI18N.getString("PerspectiveTransform0"));
  983 + }
  984 + tx.normalize();
  985 + return tx;
  986 + }
  987 +
  988 + /**
  989 + * Returns a new PerpectiveTransform that is the adjoint,
  990 + * of the current transform. The adjoint is defined as
  991 + * the matrix of cofactors, which in turn are the determinants
  992 + * of the submatrices defined by removing the row and column
  993 + * of each element from the original matrix in turn.
  994 + *
  995 + * <p> The adjoint is a scalar multiple of the inverse matrix.
  996 + * Because points to be transformed are converted into homogeneous
  997 + * coordinates, where scalar factors are irrelevant, the adjoint
  998 + * may be used in place of the true inverse. Since it is unnecessary
  999 + * to normalize the adjoint, it is both faster to compute and more
  1000 + * numerically stable than the true inverse.
  1001 + */
  1002 + public PerspectiveTransform createAdjoint()
  1003 + throws CloneNotSupportedException{
  1004 +
  1005 + PerspectiveTransform tx = (PerspectiveTransform)clone();
  1006 + tx.makeAdjoint();
  1007 + return tx;
  1008 + }
  1009 +
  1010 + /**
  1011 + * Transforms the specified ptSrc and stores the result in ptDst.
  1012 + * If ptDst is null, a new Point2D object will be allocated before
  1013 + * storing. In either case, ptDst containing the transformed point
  1014 + * is returned for convenience.
  1015 + * Note that ptSrc and ptDst can the same. In this case, the input
  1016 + * point will be overwritten with the transformed point.
  1017 + *
  1018 + * @param ptSrc The array containing the source point objects.
  1019 + * @param ptDst The array where the transform point objects are returned.
  1020 + * @throws IllegalArgumentException if ptSrc is null
  1021 + */
  1022 + public Point2D transform(Point2D ptSrc, Point2D ptDst) {
  1023 + if ( ptSrc == null ) {
  1024 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  1025 + }
  1026 +
  1027 + if (ptDst == null) {
  1028 + if (ptSrc instanceof Point2D.Double) {
  1029 + ptDst = new Point2D.Double();
  1030 + } else {
  1031 + ptDst = new Point2D.Float();
  1032 + }
  1033 + }
  1034 +
  1035 + double x = ptSrc.getX();
  1036 + double y = ptSrc.getY();
  1037 + double w = m20 * x + m21 * y + m22;
  1038 + ptDst.setLocation((m00 * x + m01 * y + m02) / w,
  1039 + (m10 * x + m11 * y + m12) / w);
  1040 +
  1041 + return ptDst;
  1042 + }
  1043 +
  1044 + /**
  1045 + * Transforms an array of point objects by this transform.
  1046 + * @param ptSrc The array containing the source point objects.
  1047 + * @param ptDst The array where the transform point objects are returned.
  1048 + * @param srcOff The offset to the first point object to be transformed
  1049 + * in the source array.
  1050 + * @param dstOff The offset to the location where the first transformed
  1051 + * point object is stored in the destination array.
  1052 + * @param numPts The number of point objects to be transformed.
  1053 + * @throws IllegalArgumentException if ptSrc is null
  1054 + * @throws IllegalArgumentException if ptDst is null
  1055 + * @throws ArrayIndexOutOfBoundsException if ptSrc is too small
  1056 + */
  1057 + public void transform(Point2D[] ptSrc, int srcOff,
  1058 + Point2D[] ptDst, int dstOff,
  1059 + int numPts) {
  1060 +
  1061 + if ( ptSrc == null || ptDst == null ) {
  1062 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  1063 + }
  1064 +
  1065 + while (numPts-- > 0) {
  1066 + /* Copy source coords into local variables in case src == dst. */
  1067 + Point2D src = ptSrc[srcOff++];
  1068 + Point2D dst = ptDst[dstOff++];
  1069 + if (dst == null) {
  1070 + if (src instanceof Point2D.Double) {
  1071 + dst = new Point2D.Double();
  1072 + } else {
  1073 + dst = new Point2D.Float();
  1074 + }
  1075 + ptDst[dstOff - 1] = dst;
  1076 + }
  1077 +
  1078 + double x = src.getX();
  1079 + double y = src.getY();
  1080 + double w = m20 * x + m21 * y + m22;
  1081 +
  1082 + if (w == 0) {
  1083 + dst.setLocation(x, y);
  1084 + } else {
  1085 + dst.setLocation((m00 * x + m01 * y + m02) / w,
  1086 + (m10 * x + m11 * y + m12) / w);
  1087 + }
  1088 + }
  1089 + }
  1090 +
  1091 + /**
  1092 + * Transforms an array of floating point coordinates by this transform.
  1093 + * @param srcPts The array containing the source point coordinates.
  1094 + * Each point is stored as a pair of x,y coordinates.
  1095 + * @param srcOff The offset to the first point to be transformed
  1096 + * in the source array.
  1097 + * @param dstPts The array where the transformed point coordinates are
  1098 + * returned. Each point is stored as a pair of x,y coordinates.
  1099 + * @param dstOff The offset to the location where the first transformed
  1100 + * point is stored in the destination array.
  1101 + * @param numPts The number of points to be transformed.
  1102 + * @throws IllegalArgumentException if srcPts is null
  1103 + * @throws ArrayIndexOutOfBoundsException if srcPts is too small
  1104 + */
  1105 + public void transform(float[] srcPts, int srcOff,
  1106 + float[] dstPts, int dstOff,
  1107 + int numPts) {
  1108 +
  1109 + if ( srcPts == null ) {
  1110 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  1111 + }
  1112 +
  1113 + if (dstPts == null) {
  1114 + dstPts = new float[numPts * 2 + dstOff];
  1115 + }
  1116 +
  1117 + while (numPts-- > 0) {
  1118 + float x = srcPts[srcOff++];
  1119 + float y = srcPts[srcOff++];
  1120 + double w = m20 * x + m21 * y + m22;
  1121 +
  1122 + if (w == 0) {
  1123 + dstPts[dstOff++] = x;
  1124 + dstPts[dstOff++] = y;
  1125 + } else {
  1126 + dstPts[dstOff++] = (float)((m00 * x + m01 * y + m02) / w);
  1127 + dstPts[dstOff++] = (float)((m10 * x + m11 * y + m12) / w);
  1128 + }
  1129 + }
  1130 + }
  1131 +
  1132 + /**
  1133 + * Transforms an array of double precision coordinates by this transform.
  1134 + * @param srcPts The array containing the source point coordinates.
  1135 + * Each point is stored as a pair of x,y coordinates.
  1136 + * @param dstPts The array where the transformed point coordinates are
  1137 + * returned. Each point is stored as a pair of x,y coordinates.
  1138 + * @param srcOff The offset to the first point to be transformed
  1139 + * in the source array.
  1140 + * @param dstOff The offset to the location where the first transformed
  1141 + * point is stored in the destination array.
  1142 + * @param numPts The number of point objects to be transformed.
  1143 + * @throws IllegalArgumentException if srcPts is null
  1144 + * @throws ArrayIndexOutOfBoundsException if srcPts is too small
  1145 + */
  1146 + public void transform(double[] srcPts, int srcOff,
  1147 + double[] dstPts, int dstOff,
  1148 + int numPts) {
  1149 +
  1150 + if ( srcPts == null ) {
  1151 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  1152 + }
  1153 +
  1154 + if (dstPts == null) {
  1155 + dstPts = new double[numPts * 2 + dstOff];
  1156 + }
  1157 +
  1158 + while (numPts-- > 0) {
  1159 + double x = srcPts[srcOff++];
  1160 + double y = srcPts[srcOff++];
  1161 + double w = m20 * x + m21 * y + m22;
  1162 +
  1163 + if (w == 0) {
  1164 + dstPts[dstOff++] = x;
  1165 + dstPts[dstOff++] = y;
  1166 + } else {
  1167 + dstPts[dstOff++] = (m00 * x + m01 * y + m02) / w;
  1168 + dstPts[dstOff++] = (m10 * x + m11 * y + m12) / w;
  1169 + }
  1170 + }
  1171 + }
  1172 +
  1173 + /**
  1174 + * Transforms an array of floating point coordinates by this transform,
  1175 + * storing the results into an array of doubles.
  1176 + * @param srcPts The array containing the source point coordinates.
  1177 + * Each point is stored as a pair of x,y coordinates.
  1178 + * @param srcOff The offset to the first point to be transformed
  1179 + * in the source array.
  1180 + * @param dstPts The array where the transformed point coordinates are
  1181 + * returned. Each point is stored as a pair of x,y coordinates.
  1182 + * @param dstOff The offset to the location where the first transformed
  1183 + * point is stored in the destination array.
  1184 + * @param numPts The number of points to be transformed.
  1185 + * @throws IllegalArgumentException if srcPts is null
  1186 + * @throws ArrayIndexOutOfBoundsException if srcPts is too small
  1187 + */
  1188 + public void transform(float[] srcPts, int srcOff,
  1189 + double[] dstPts, int dstOff,
  1190 + int numPts) {
  1191 +
  1192 + if ( srcPts == null ) {
  1193 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  1194 + }
  1195 +
  1196 + if (dstPts == null) {
  1197 + dstPts = new double[numPts * 2 + dstOff];
  1198 + }
  1199 +
  1200 + while (numPts-- > 0) {
  1201 + float x = srcPts[srcOff++];
  1202 + float y = srcPts[srcOff++];
  1203 + double w = m20 * x + m21 * y + m22;
  1204 +
  1205 + if (w == 0) {
  1206 + dstPts[dstOff++] = x;
  1207 + dstPts[dstOff++] = y;
  1208 + } else {
  1209 + dstPts[dstOff++] = (m00 * x + m01 * y + m02) / w;
  1210 + dstPts[dstOff++] = (m10 * x + m11 * y + m12) / w;
  1211 + }
  1212 + }
  1213 + }
  1214 +
  1215 + /**
  1216 + * Transforms an array of double precision coordinates by this transform,
  1217 + * storing the results into an array of floats.
  1218 + * @param srcPts The array containing the source point coordinates.
  1219 + * Each point is stored as a pair of x,y coordinates.
  1220 + * @param dstPts The array where the transformed point coordinates are
  1221 + * returned. Each point is stored as a pair of x,y coordinates.
  1222 + * @param srcOff The offset to the first point to be transformed
  1223 + * in the source array.
  1224 + * @param dstOff The offset to the location where the first transformed
  1225 + * point is stored in the destination array.
  1226 + * @param numPts The number of point objects to be transformed.
  1227 + * @throws IllegalArgumentException if srcPts is null
  1228 + * @throws ArrayIndexOutOfBoundsException if srcPts is too small
  1229 + */
  1230 + public void transform(double[] srcPts, int srcOff,
  1231 + float[] dstPts, int dstOff,
  1232 + int numPts) {
  1233 +
  1234 + if ( srcPts == null ) {
  1235 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  1236 + }
  1237 +
  1238 + if (dstPts == null) {
  1239 + dstPts = new float[numPts * 2 + dstOff];
  1240 + }
  1241 +
  1242 + while (numPts-- > 0) {
  1243 + double x = srcPts[srcOff++];
  1244 + double y = srcPts[srcOff++];
  1245 + double w = m20 * x + m21 * y + m22;
  1246 +
  1247 + if (w == 0) {
  1248 + dstPts[dstOff++] = (float)x;
  1249 + dstPts[dstOff++] = (float)y;
  1250 + } else {
  1251 + dstPts[dstOff++] = (float)((m00 * x + m01 * y + m02) / w);
  1252 + dstPts[dstOff++] = (float)((m10 * x + m11 * y + m12) / w);
  1253 + }
  1254 + }
  1255 + }
  1256 +
  1257 + /**
  1258 + * Inverse transforms the specified ptSrc and stores the result in ptDst.
  1259 + * If ptDst is null, a new Point2D object will be allocated before
  1260 + * storing. In either case, ptDst containing the transformed point
  1261 + * is returned for convenience.
  1262 + * Note that ptSrc and ptDst can the same. In this case, the input
  1263 + * point will be overwritten with the transformed point.
  1264 + * @param ptSrc The point to be inverse transformed.
  1265 + * @param ptDst The resulting transformed point.
  1266 + * @throws NoninvertibleTransformException if the matrix cannot be
  1267 + * inverted.
  1268 + * @throws IllegalArgumentException if ptSrc is null
  1269 + */
  1270 + public Point2D inverseTransform(Point2D ptSrc, Point2D ptDst)
  1271 + throws NoninvertibleTransformException
  1272 + {
  1273 + if ( ptSrc == null ) {
  1274 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  1275 + }
  1276 +
  1277 + if (ptDst == null) {
  1278 + if (ptSrc instanceof Point2D.Double) {
  1279 + ptDst = new Point2D.Double();
  1280 + } else {
  1281 + ptDst = new Point2D.Float();
  1282 + }
  1283 + }
  1284 + // Copy source coords into local variables in case src == dst
  1285 + double x = ptSrc.getX();
  1286 + double y = ptSrc.getY();
  1287 +
  1288 + double tmp_x = (m11*m22 - m12*m21) * x +
  1289 + (m02*m21 - m01*m22) * y +
  1290 + (m01*m12 - m02*m11);
  1291 + double tmp_y = (m12*m20 - m10*m22) * x +
  1292 + (m00*m22 - m02*m20) * y +
  1293 + (m02*m10 - m00*m12);
  1294 + double w = (m10*m21 - m11*m20) * x +
  1295 + (m01*m20 - m00*m21) * y +
  1296 + (m00*m11 - m01*m10);
  1297 +
  1298 + double wabs = w;
  1299 + if (w < 0) {
  1300 + wabs = - w;
  1301 + }
  1302 + if (wabs < PERSPECTIVE_DIVIDE_EPSILON) {
  1303 + throw new
  1304 + NoninvertibleTransformException(
  1305 + JaiI18N.getString("PerspectiveTransform1"));
  1306 + }
  1307 +
  1308 + ptDst.setLocation(tmp_x/w, tmp_y/w);
  1309 +
  1310 + return ptDst;
  1311 + }
  1312 +
  1313 + /**
  1314 + * Inverse transforms an array of double precision coordinates by
  1315 + * this transform.
  1316 + * @param srcPts The array containing the source point coordinates.
  1317 + * Each point is stored as a pair of x,y coordinates.
  1318 + * @param dstPts The array where the transformed point coordinates are
  1319 + * returned. Each point is stored as a pair of x,y coordinates.
  1320 + * @param srcOff The offset to the first point to be transformed
  1321 + * in the source array.
  1322 + * @param dstOff The offset to the location where the first transformed
  1323 + * point is stored in the destination array.
  1324 + * @param numPts The number of point objects to be transformed.
  1325 + * @throws NoninvertibleTransformException if the matrix cannot be
  1326 + * inverted.
  1327 + * @throws IllegalArgumentException if srcPts is null
  1328 + * @throws ArrayIndexOutOfBoundsException if srcPts is too small
  1329 + * @throws NoninvertibleTransformException transform cannot be inverted
  1330 + */
  1331 + public void inverseTransform(double[] srcPts, int srcOff,
  1332 + double[] dstPts, int dstOff,
  1333 + int numPts)
  1334 + throws NoninvertibleTransformException
  1335 + {
  1336 + if ( srcPts == null ) {
  1337 + throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
  1338 + }
  1339 +
  1340 + if (dstPts == null) {
  1341 + dstPts = new double[numPts * 2 + dstOff];
  1342 + }
  1343 +
  1344 + while (numPts-- > 0) {
  1345 + double x = srcPts[srcOff++];
  1346 + double y = srcPts[srcOff++];
  1347 +
  1348 + double tmp_x = (m11*m22 - m12*m21) * x +
  1349 + (m02*m21 - m01*m22) * y +
  1350 + (m01*m12 - m02*m11);
  1351 + double tmp_y = (m12*m20 - m10*m22) * x +
  1352 + (m00*m22 - m02*m20) * y +
  1353 + (m02*m10 - m00*m12);
  1354 + double w = (m10*m21 - m11*m20) * x +
  1355 + (m01*m20 - m00*m21) * y +
  1356 + (m00*m11 - m01*m10);
  1357 +
  1358 + double wabs = w;
  1359 + if (w < 0) {
  1360 + wabs = - w;
  1361 + }
  1362 + if (wabs < PERSPECTIVE_DIVIDE_EPSILON) {
  1363 + throw new NoninvertibleTransformException(
  1364 + JaiI18N.getString("PerspectiveTransform1"));
  1365 + }
  1366 +
  1367 + dstPts[dstOff++] = tmp_x / w;
  1368 + dstPts[dstOff++] = tmp_y / w;
  1369 + }
  1370 + }
  1371 +
  1372 + /**
  1373 + * Returns a String that represents the value of this Object.
  1374 + */
  1375 + public String toString() {
  1376 + StringBuffer sb = new StringBuffer();
  1377 + sb.append("Perspective transform matrix\n");
  1378 + sb.append(this.m00);
  1379 + sb.append("\t");
  1380 + sb.append(this.m01);
  1381 + sb.append("\t");
  1382 + sb.append(this.m02);
  1383 + sb.append("\n");
  1384 + sb.append(this.m10);
  1385 + sb.append("\t");
  1386 + sb.append(this.m11);
  1387 + sb.append("\t");
  1388 + sb.append(this.m12);
  1389 + sb.append("\n");
  1390 + sb.append(this.m20);
  1391 + sb.append("\t");
  1392 + sb.append(this.m21);
  1393 + sb.append("\t");
  1394 + sb.append(this.m22);
  1395 + sb.append("\n");
  1396 + return new String(sb);
  1397 + }
  1398 +
  1399 + /**
  1400 + * Returns the boolean true value if this PerspectiveTransform is an
  1401 + * identity transform. Returns false otherwise.
  1402 + */
  1403 + public boolean isIdentity() {
  1404 + return m01 == 0.0 && m02 == 0.0 &&
  1405 + m10 == 0.0 && m12 == 0.0 &&
  1406 + m20 == 0.0 && m21 == 0.0 &&
  1407 + m22 != 0.0 && m00/m22 == 1.0 && m11/m22 == 1.0;
  1408 + }
  1409 +
  1410 + /**
  1411 + * Returns a copy of this PerspectiveTransform object.
  1412 + */
  1413 + public Object clone() {
  1414 + try {
  1415 + return super.clone();
  1416 + } catch (CloneNotSupportedException e) {
  1417 + // this shouldn't happen, since we are Cloneable
  1418 + throw new InternalError();
  1419 + }
  1420 + }
  1421 +
  1422 +
  1423 + /**
  1424 + * Tests if this PerspectiveTransform equals a supplied one.
  1425 + *
  1426 + * @param obj The PerspectiveTransform to be compared to this one.
  1427 + */
  1428 + public boolean equals(Object obj) {
  1429 + if (!(obj instanceof PerspectiveTransform)) {
  1430 + return false;
  1431 + }
  1432 +
  1433 + PerspectiveTransform a = (PerspectiveTransform)obj;
  1434 +
  1435 + return ((m00 == a.m00) && (m10 == a.m10) && (m20 == a.m20) &&
  1436 + (m01 == a.m01) && (m11 == a.m11) && (m21 == a.m21) &&
  1437 + (m02 == a.m02) && (m12 == a.m12) && (m22 == a.m22));
  1438 + }
  1439 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/WiimoteConnector.java 0 → 100644
... ... @@ -0,0 +1,51 @@
  1 +package org.mote.wiimote.whiteboard;
  2 +
  3 +import org.mote.wiimote.whiteboard.preferences.WWPreferences;
  4 +
  5 +import wiiremotej.WiiRemote;
  6 +import wiiremotej.WiiRemoteJ;
  7 +
  8 +public class WiimoteConnector {
  9 +
  10 + private WiimoteDataHandler dh;
  11 +
  12 + public WiimoteConnector(WiimoteDataHandler dh) {
  13 + this.dh = dh;
  14 + }
  15 +
  16 + public void connect() {
  17 + if (!WWPreferences.WIIMOTE_BT_ADDRESSES.isEmpty()) {
  18 + WiimoteWhiteboard.getLogger().info(String.format("Directly connecting to bluetooth address(es) %s.", WWPreferences.WIIMOTE_BT_ADDRESSES));
  19 + for (int i = 0; i < Math.min(WWPreferences.WIIMOTE_BT_ADDRESSES.size(), WWPreferences.WIIMOTES); i++) {
  20 + connect(WWPreferences.WIIMOTE_BT_ADDRESSES.get(i));
  21 + }
  22 + } else {
  23 + WiiRemoteJ.findRemotes(dh, WWPreferences.WIIMOTES);
  24 + }
  25 + }
  26 +
  27 + private void connect(final String address) {
  28 + new Thread(new Runnable() {
  29 + private boolean done = false;
  30 + public void run() {
  31 + while (!done) {
  32 + try {
  33 + WiiRemote r = WiiRemoteJ.connectToRemote(address);
  34 + if (r != null && r.isConnected()) {
  35 + done = true;
  36 + dh.addRemote(r);
  37 + }
  38 + } catch (Exception e) {
  39 +
  40 + try {
  41 + Thread.sleep(1000);
  42 + } catch (InterruptedException e1) {
  43 + e1.printStackTrace();
  44 + }
  45 + }
  46 + }
  47 + }
  48 + }).start();
  49 + }
  50 +
  51 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/WiimoteConnector.java~ 0 → 100644
... ... @@ -0,0 +1,55 @@
  1 +package org.mote.wiimote.whiteboard;
  2 +
  3 +import org.mote.wiimote.whiteboard.preferences.WWPreferences;
  4 +
  5 +import wiiremotej.WiiRemote;
  6 +import wiiremotej.WiiRemoteJ;
  7 +
  8 +public class WiimoteConnector {
  9 +
  10 + private WiimoteDataHandler dh;
  11 +
  12 + public WiimoteConnector(WiimoteDataHandler dh) {
  13 + this.dh = dh;
  14 + }
  15 +
  16 + public void connect() {
  17 + if (!WWPreferences.WIIMOTE_BT_ADDRESSES.isEmpty()) {
  18 + WiimoteWhiteboard.getLogger().info(String.format("Directly connecting to bluetooth address(es) %s.", WWPreferences.WIIMOTE_BT_ADDRESSES));
  19 + for (int i = 0; i < Math.min(WWPreferences.WIIMOTE_BT_ADDRESSES.size(), WWPreferences.WIIMOTES); i++) {
  20 + connect(WWPreferences.WIIMOTE_BT_ADDRESSES.get(i));
  21 + }
  22 + } else {
  23 + WiiRemoteJ.findRemotes(dh, WWPreferences.WIIMOTES);
  24 + }
  25 + }
  26 +
  27 + private void connect(final String address) {
  28 + new Thread(new Runnable() {
  29 + private boolean done = false;
  30 + public void run() {
  31 + while (!done) {
  32 + try {
  33 + WiiRemote r = WiiRemoteJ.connectToRemote(address);
  34 + if (r != null && r.isConnected()) {
  35 + done = true;
  36 + dh.addRemote(r);
  37 + }
  38 + } catch (Exception e) {
  39 +// if (e.getCause().getMessage().startsWith("Failed to open baseband connection")) {
  40 +// // apparently simple timeout error
  41 +// } else {
  42 +// // "regular" connection error
  43 +// }
  44 + try {
  45 + Thread.sleep(1000);
  46 + } catch (InterruptedException e1) {
  47 + e1.printStackTrace();
  48 + }
  49 + }
  50 + }
  51 + }
  52 + }).start();
  53 + }
  54 +
  55 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/WiimoteDataHandler.java 0 → 100644
... ... @@ -0,0 +1,314 @@
  1 +package org.mote.wiimote.whiteboard;
  2 +
  3 +import java.awt.Point;
  4 +import java.util.Collection;
  5 +import java.util.Collections;
  6 +import java.util.EventObject;
  7 +import java.util.HashSet;
  8 +import java.util.LinkedHashMap;
  9 +import java.util.Map;
  10 +import java.util.Set;
  11 +import java.util.logging.Level;
  12 +
  13 +import org.jdesktop.application.Application;
  14 +import org.jdesktop.application.Application.ExitListener;
  15 +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration;
  16 +import org.mote.wiimote.whiteboard.ds.IRDot;
  17 +import org.mote.wiimote.whiteboard.ds.Wiimote;
  18 +import org.mote.wiimote.whiteboard.mouse.CursorControlStrategy;
  19 +import org.mote.wiimote.whiteboard.mouse.Mouse;
  20 +import org.mote.wiimote.whiteboard.mouse.smoothing.MouseSmoothingStrategy;
  21 +import org.mote.wiimote.whiteboard.preferences.WWPreferences;
  22 +import org.mote.wiimote.whiteboard.preferences.WWPreferences.PreferencesListener;
  23 +
  24 +import wiiremotej.WiiRemote;
  25 +import wiiremotej.WiiRemoteJ;
  26 +import wiiremotej.event.WRButtonEvent;
  27 +import wiiremotej.event.WRIREvent;
  28 +import wiiremotej.event.WRStatusEvent;
  29 +import wiiremotej.event.WiiDeviceDiscoveredEvent;
  30 +import wiiremotej.event.WiiDeviceDiscoveryListener;
  31 +import wiiremotej.event.WiiRemoteAdapter;
  32 +
  33 +public class WiimoteDataHandler extends WiiRemoteAdapter implements ExitListener, WiiDeviceDiscoveryListener, PreferencesListener {
  34 +
  35 + public static interface WiimoteDataListener {
  36 + public void wiimoteConnected(Wiimote wiimote);
  37 + public void wiimoteDisconnected(Wiimote wiimote);
  38 + public void irLights(Wiimote wiimote, IRDot[] lights);
  39 + public void irWarped(Map<Wiimote, IRDot[]> data, Point[] warped);
  40 + public void batteryLevel(Wiimote wiimote, double level);
  41 + }
  42 +
  43 + private Map<WiiRemote, Wiimote> remotes = new LinkedHashMap<WiiRemote, Wiimote>(WWPreferences.WIIMOTES, 1f);
  44 + private Map<WiiRemote, WRIREvent> events = new LinkedHashMap<WiiRemote, WRIREvent>(WWPreferences.WIIMOTES, 1f);
  45 + private final WiimoteCalibration calibration;
  46 + private static final WWPreferences prefs = WWPreferences.getPreferences();
  47 + private final Set<WiimoteDataListener> listener = Collections.synchronizedSet(new HashSet<WiimoteDataListener>());
  48 +
  49 + private boolean cursorControl = true;
  50 +
  51 + private MouseSmoothingStrategy mss[] = new MouseSmoothingStrategy[4];
  52 + private CursorControlStrategy cursorControlStrategy;
  53 +
  54 + public WiimoteDataHandler(WiimoteCalibration calibration) {
  55 + this.calibration = calibration;
  56 + Application.getInstance().addExitListener(this);
  57 + prefs.addPreferencesListener(this);
  58 + preferencesChanged();
  59 + new WiimoteConnector(this).connect();
  60 + }
  61 +
  62 + public void enableIR(Wiimote wiimote) throws Exception {
  63 + if (wiimote != null && wiimote.getWiiRemote().isConnected()) {
  64 + wiimote.getWiiRemote().setIRSensorEnabled(true, WRIREvent.BASIC, WWPreferences.SENSITIVITY_SETTINGS);
  65 + }
  66 + WiimoteWhiteboard.getLogger().info(String.format("(Re-)Setting IR sensor of Wiimote %d: %s", wiimote.getId(), (wiimote != null && wiimote.getWiiRemote().isConnected() ? "done" : "not connected")));
  67 + }
  68 +
  69 + void addRemote(final WiiRemote remote) {
  70 + try {
  71 + int id = remotes.size()+1;
  72 + final Wiimote wiimote = new Wiimote(remote, remote.getBluetoothAddress(), id);
  73 + remotes.put(remote, wiimote);
  74 + remote.setAccelerometerEnabled(false);
  75 + enableIR(wiimote);
  76 + remote.setLEDIlluminated(id-1, true);
  77 + remote.setUseMouse(false);
  78 +
  79 + synchronized (listener) {
  80 + for (WiimoteDataListener l : listener)
  81 + l.wiimoteConnected(wiimote);
  82 + }
  83 +
  84 + } catch (Exception e) {
  85 + e.printStackTrace();
  86 + WiimoteWhiteboard.getLogger().log(Level.SEVERE, "Error on configuring Wii Remote", e);
  87 + }
  88 +
  89 + remote.addWiiRemoteListener(this);
  90 +
  91 + // update battery level every minute
  92 + new Thread(new Runnable() {
  93 + public void run() {
  94 + while (true) {
  95 + try {
  96 + // triggers #statusReported(WRStatusEvent)
  97 + if (remote.isConnected())
  98 + remote.requestStatus();
  99 + } catch (Exception e) {
  100 + e.printStackTrace();
  101 + WiimoteWhiteboard.getLogger().log(Level.WARNING, "Error on requesting status from Wii Remote", e);
  102 + }
  103 + try {
  104 + Thread.sleep(60 * 1000);
  105 + } catch (InterruptedException e) {
  106 + e.printStackTrace();
  107 + }
  108 + }
  109 + }
  110 + }).start();
  111 + }
  112 +
  113 +
  114 + /*
  115 + * EXIT
  116 + */
  117 +
  118 + public void willExit(EventObject event) {
  119 + for (WiiRemote remote : remotes.keySet())
  120 + remote.disconnect();
  121 + }
  122 +
  123 + public boolean canExit(EventObject event) {
  124 + return true;
  125 + }
  126 +
  127 +
  128 + /*
  129 + * WIIREMOTEJ LISTENER
  130 + */
  131 +
  132 + @Override
  133 + public synchronized void IRInputReceived(WRIREvent e) {
  134 + events.put(e.getSource(), e);
  135 + // wait till data from all connected wiimotes was received once and only process input on data from first wiimote to reduce the number of times the function gets called
  136 + if (events.size() == getNumberOfConnectedWiimotes() && remotes.get(e.getSource()).getId() == 1)
  137 + IRInputReceived();
  138 + }
  139 +
  140 + private void IRInputReceived() {
  141 + boolean firstDotVisible = false;
  142 + Map<Wiimote, IRDot[]> data = new LinkedHashMap<Wiimote, IRDot[]>();
  143 + for (WiiRemote r : events.keySet()) {
  144 + Wiimote wiimote = remotes.get(r);
  145 + IRDot[] dots = IRDot.getIRDots(events.get(r).getIRLights());
  146 +
  147 + synchronized (listener) {
  148 + for (WiimoteDataListener l : listener)
  149 + l.irLights(wiimote, dots);
  150 + }
  151 +
  152 + // exclude points from uncalibrated wiimotes during "normal operation"
  153 + if (!calibration.isDone() || calibration.isCalibrated(wiimote)) {
  154 + firstDotVisible = firstDotVisible || dots[0] != null;
  155 + data.put(wiimote, dots);
  156 + }
  157 + }
  158 +
  159 + if (calibration.isDone()) {
  160 + // should always be true, but just in case...
  161 + if (calibration.isAnyCalibrated(data.keySet())) {
  162 + Point warped[] = calibration.warp(data);
  163 + for (int i = 0; i < 4; i++) {
  164 + if (warped[i] != null) {
  165 + warped[i] = mss[i].translate(warped[i]);
  166 + } else {
  167 + mss[i].reset();
  168 + }
  169 + }
  170 +
  171 + if (isCursorControl()) {
  172 + cursorControlStrategy.process(warped[0]);
  173 + } else {
  174 +// if (Mouse.LEFT_BUTTON.isPressed())
  175 + Mouse.LEFT_BUTTON.setPressed(false);
  176 +// if (Mouse.RIGHT_BUTTON.isPressed())
  177 + Mouse.RIGHT_BUTTON.setPressed(false);
  178 + }
  179 + synchronized (listener) {
  180 + for (WiimoteDataListener l : listener)
  181 + l.irWarped(data, warped);
  182 + }
  183 +
  184 + }
  185 + } else if (calibration.inProgress()) {
  186 + if (firstDotVisible)
  187 + calibration.process(data);
  188 + }
  189 +
  190 + }
  191 +
  192 + @Override
  193 + public void statusReported(WRStatusEvent e) {
  194 + synchronized (listener) {
  195 + for (WiimoteDataListener l : listener)
  196 + l.batteryLevel(remotes.get(e.getSource()), e.getBatteryLevel());
  197 + }
  198 + }
  199 +
  200 + @Override
  201 + public void buttonInputReceived(WRButtonEvent e) {
  202 + if (e.isOnlyPressed(WRButtonEvent.A)) {
  203 + calibration.start(getConnectedWiimotes());
  204 + } else if (e.isOnlyPressed(WRButtonEvent.HOME)) {
  205 + Application.getInstance().exit();
  206 + }
  207 + }
  208 +
  209 + public void wiiDeviceDiscovered(WiiDeviceDiscoveredEvent e) {
  210 + if (e.getWiiDevice() instanceof WiiRemote) {
  211 + addRemote((WiiRemote)e.getWiiDevice());
  212 + }
  213 + }
  214 +
  215 + public void findFinished(int numberFound) {
  216 + }
  217 +
  218 + @Override
  219 + public void disconnected() {
  220 + WiiRemoteJ.stopFind();
  221 + WiiRemote remove = null;
  222 + for (WiiRemote remote : remotes.keySet()) {
  223 + if (!remote.isConnected()) {
  224 + remove = remote;
  225 + synchronized (listener) {
  226 + for (WiimoteDataListener l : listener)
  227 + l.wiimoteDisconnected(remotes.get(remote));
  228 + }
  229 + break;
  230 + }
  231 + }
  232 + if (remove != null) remotes.remove(remove);
  233 + }
  234 +
  235 +
  236 + /*
  237 + * LISTENER
  238 + */
  239 +
  240 + public void addWiimoteDataListener(WiimoteDataListener l) {
  241 + listener.add(l);
  242 + }
  243 +
  244 + public void removeWiimoteDataListener(WiimoteDataListener l) {
  245 + listener.remove(l);
  246 + }
  247 +
  248 + /*
  249 + * PREFERENCES STUFF
  250 + */
  251 +
  252 + public void preferencesChanged() {
  253 + updateMSS();
  254 + updateCursorControlStrategy();
  255 +
  256 + @SuppressWarnings("unchecked")
  257 + private void updateCursorControlStrategy() {
  258 + if (cursorControlStrategy == null || !cursorControlStrategy.getClass().getName().equals(prefs.getCursorControl())) {
  259 + try {
  260 + Class<?> c = Class.forName(prefs.getCursorControl());
  261 + cursorControlStrategy = ((Class<? extends CursorControlStrategy>)c).newInstance();
  262 + } catch (Exception e) {
  263 + e.printStackTrace();
  264 + WiimoteWhiteboard.getLogger().log(Level.SEVERE, "Cursor Control Method error.", e);
  265 + }
  266 + }
  267 + }
  268 +
  269 + @SuppressWarnings("unchecked")
  270 + private void updateMSS() {
  271 + if (mss[0] == null || !mss[0].getClass().getName().equals(prefs.getMouseSmoothing())) {
  272 + try {
  273 + Class<?> c = Class.forName(prefs.getMouseSmoothing());
  274 + for (int i = 0; i < 4; i++)
  275 + mss[i] = ((Class<? extends MouseSmoothingStrategy>)c).newInstance();
  276 + } catch (Exception e) {
  277 + e.printStackTrace();
  278 + WiimoteWhiteboard.getLogger().log(Level.SEVERE, "Mouse Movement Smoothing error.", e);
  279 + }
  280 + }
  281 + }
  282 +
  283 + /*
  284 + * GETTER & SETTER
  285 + */
  286 +
  287 + public boolean isConnected() {
  288 + for (WiiRemote remote : remotes.keySet()) {
  289 + if (remote.isConnected()) return true;
  290 + }
  291 + return false;
  292 + }
  293 +
  294 + public boolean isConnected(Wiimote wiimote) {
  295 + return wiimote != null && wiimote.getWiiRemote().isConnected();
  296 + }
  297 +
  298 + public int getNumberOfConnectedWiimotes() {
  299 + return remotes.size();
  300 + }
  301 +
  302 + public Collection<Wiimote> getConnectedWiimotes() {
  303 + return remotes.values();
  304 + }
  305 +
  306 + public boolean isCursorControl() {
  307 + return cursorControl;
  308 + }
  309 +
  310 + public void setCursorControl(boolean cursorControl) {
  311 + this.cursorControl = cursorControl;
  312 + }
  313 +
  314 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/WiimoteDataHandler.java~ 0 → 100644
... ... @@ -0,0 +1,339 @@
  1 +package org.mote.wiimote.whiteboard;
  2 +
  3 +import java.awt.Point;
  4 +import java.util.Collection;
  5 +import java.util.Collections;
  6 +import java.util.EventObject;
  7 +import java.util.HashSet;
  8 +import java.util.LinkedHashMap;
  9 +import java.util.Map;
  10 +import java.util.Set;
  11 +import java.util.logging.Level;
  12 +
  13 +import org.jdesktop.application.Application;
  14 +import org.jdesktop.application.Application.ExitListener;
  15 +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration;
  16 +import org.mote.wiimote.whiteboard.ds.IRDot;
  17 +import org.mote.wiimote.whiteboard.ds.Wiimote;
  18 +import org.mote.wiimote.whiteboard.mouse.CursorControlStrategy;
  19 +import org.mote.wiimote.whiteboard.mouse.Mouse;
  20 +import org.mote.wiimote.whiteboard.mouse.smoothing.MouseSmoothingStrategy;
  21 +import org.mote.wiimote.whiteboard.preferences.WWPreferences;
  22 +import org.mote.wiimote.whiteboard.preferences.WWPreferences.PreferencesListener;
  23 +
  24 +import wiiremotej.WiiRemote;
  25 +import wiiremotej.WiiRemoteJ;
  26 +import wiiremotej.event.WRButtonEvent;
  27 +import wiiremotej.event.WRIREvent;
  28 +import wiiremotej.event.WRStatusEvent;
  29 +import wiiremotej.event.WiiDeviceDiscoveredEvent;
  30 +import wiiremotej.event.WiiDeviceDiscoveryListener;
  31 +import wiiremotej.event.WiiRemoteAdapter;
  32 +
  33 +public class WiimoteDataHandler extends WiiRemoteAdapter implements ExitListener, WiiDeviceDiscoveryListener, PreferencesListener {
  34 +
  35 + public static interface WiimoteDataListener {
  36 + public void wiimoteConnected(Wiimote wiimote);
  37 + public void wiimoteDisconnected(Wiimote wiimote);
  38 + public void irLights(Wiimote wiimote, IRDot[] lights);
  39 + public void irWarped(Map<Wiimote, IRDot[]> data, Point[] warped);
  40 + public void batteryLevel(Wiimote wiimote, double level);
  41 + }
  42 +
  43 + private Map<WiiRemote, Wiimote> remotes = new LinkedHashMap<WiiRemote, Wiimote>(WWPreferences.WIIMOTES, 1f);
  44 + private Map<WiiRemote, WRIREvent> events = new LinkedHashMap<WiiRemote, WRIREvent>(WWPreferences.WIIMOTES, 1f);
  45 + private final WiimoteCalibration calibration;
  46 + private static final WWPreferences prefs = WWPreferences.getPreferences();
  47 + private final Set<WiimoteDataListener> listener = Collections.synchronizedSet(new HashSet<WiimoteDataListener>());
  48 +
  49 + private boolean cursorControl = true;
  50 +
  51 + private MouseSmoothingStrategy mss[] = new MouseSmoothingStrategy[4];
  52 + private CursorControlStrategy cursorControlStrategy;
  53 +
  54 + public WiimoteDataHandler(WiimoteCalibration calibration) {
  55 + this.calibration = calibration;
  56 + Application.getInstance().addExitListener(this);
  57 + prefs.addPreferencesListener(this);
  58 + preferencesChanged();
  59 + new WiimoteConnector(this).connect();
  60 + }
  61 +
  62 + public void enableIR(Wiimote wiimote) throws Exception {
  63 + if (wiimote != null && wiimote.getWiiRemote().isConnected()) {
  64 + wiimote.getWiiRemote().setIRSensorEnabled(true, WRIREvent.BASIC, WWPreferences.SENSITIVITY_SETTINGS);
  65 + }
  66 + WiimoteWhiteboard.getLogger().info(String.format("(Re-)Setting IR sensor of Wiimote %d: %s", wiimote.getId(), (wiimote != null && wiimote.getWiiRemote().isConnected() ? "done" : "not connected")));
  67 + }
  68 +
  69 + void addRemote(final WiiRemote remote) {
  70 + try {
  71 + int id = remotes.size()+1;
  72 + final Wiimote wiimote = new Wiimote(remote, remote.getBluetoothAddress(), id);
  73 + remotes.put(remote, wiimote);
  74 + remote.setAccelerometerEnabled(false);
  75 + enableIR(wiimote);
  76 + remote.setLEDIlluminated(id-1, true);
  77 + remote.setUseMouse(false);
  78 +
  79 + synchronized (listener) {
  80 + for (WiimoteDataListener l : listener)
  81 + l.wiimoteConnected(wiimote);
  82 + }
  83 +
  84 + } catch (Exception e) {
  85 + e.printStackTrace();
  86 + WiimoteWhiteboard.getLogger().log(Level.SEVERE, "Error on configuring Wii Remote", e);
  87 + }
  88 +
  89 + remote.addWiiRemoteListener(this);
  90 +
  91 + // update battery level every minute
  92 + new Thread(new Runnable() {
  93 + public void run() {
  94 + while (true) {
  95 + try {
  96 + // triggers #statusReported(WRStatusEvent)
  97 + if (remote.isConnected())
  98 + remote.requestStatus();
  99 + } catch (Exception e) {
  100 + e.printStackTrace();
  101 + WiimoteWhiteboard.getLogger().log(Level.WARNING, "Error on requesting status from Wii Remote", e);
  102 + }
  103 + try {
  104 + Thread.sleep(60 * 1000);
  105 + } catch (InterruptedException e) {
  106 + e.printStackTrace();
  107 + }
  108 + }
  109 + }
  110 + }).start();
  111 + }
  112 +
  113 +
  114 + /*
  115 + * EXIT
  116 + */
  117 +
  118 + public void willExit(EventObject event) {
  119 + for (WiiRemote remote : remotes.keySet())
  120 + remote.disconnect();
  121 + }
  122 +
  123 + public boolean canExit(EventObject event) {
  124 + return true;
  125 + }
  126 +
  127 +
  128 + /*
  129 + * WIIREMOTEJ LISTENER
  130 + */
  131 +
  132 + @Override
  133 + public synchronized void IRInputReceived(WRIREvent e) {
  134 + events.put(e.getSource(), e);
  135 + // wait till data from all connected wiimotes was received once and only process input on data from first wiimote to reduce the number of times the function gets called
  136 + if (events.size() == getNumberOfConnectedWiimotes() && remotes.get(e.getSource()).getId() == 1)
  137 + IRInputReceived();
  138 + }
  139 +
  140 + private void IRInputReceived() {
  141 + boolean firstDotVisible = false;
  142 + Map<Wiimote, IRDot[]> data = new LinkedHashMap<Wiimote, IRDot[]>();
  143 + for (WiiRemote r : events.keySet()) {
  144 + Wiimote wiimote = remotes.get(r);
  145 + IRDot[] dots = IRDot.getIRDots(events.get(r).getIRLights());
  146 +
  147 + synchronized (listener) {
  148 + for (WiimoteDataListener l : listener)
  149 + l.irLights(wiimote, dots);
  150 + }
  151 +
  152 + // exclude points from uncalibrated wiimotes during "normal operation"
  153 + if (!calibration.isDone() || calibration.isCalibrated(wiimote)) {
  154 + firstDotVisible = firstDotVisible || dots[0] != null;
  155 + data.put(wiimote, dots);
  156 + }
  157 + }
  158 +
  159 + if (calibration.isDone()) {
  160 + // should always be true, but just in case...
  161 + if (calibration.isAnyCalibrated(data.keySet())) {
  162 + Point warped[] = calibration.warp(data);
  163 + for (int i = 0; i < 4; i++) {
  164 + if (warped[i] != null) {
  165 + warped[i] = mss[i].translate(warped[i]);
  166 + } else {
  167 + mss[i].reset();
  168 + }
  169 + }
  170 +
  171 + if (isCursorControl()) {
  172 + cursorControlStrategy.process(warped[0]);
  173 + } else {
  174 +// if (Mouse.LEFT_BUTTON.isPressed())
  175 + Mouse.LEFT_BUTTON.setPressed(false);
  176 +// if (Mouse.RIGHT_BUTTON.isPressed())
  177 + Mouse.RIGHT_BUTTON.setPressed(false);
  178 + }
  179 +
  180 +// if (warped[0] != null) {
  181 +// // normal operation after calibration has been done
  182 +// if (isCursorControl()) {
  183 +// Mouse.move(warped[0]);
  184 +// rcs.process(warped[0]);
  185 +// if (prefs.isLeftClick() && !(prefs.isRightClick() && rcs.trigger())) {
  186 +// Mouse.LEFT_BUTTON.setPressed(true);
  187 +// }
  188 +// }
  189 +// } else {
  190 +// rcs.process(null);
  191 +// Mouse.LEFT_BUTTON.setPressed(false);
  192 +// }
  193 +
  194 + synchronized (listener) {
  195 + for (WiimoteDataListener l : listener)
  196 + l.irWarped(data, warped);
  197 + }
  198 +
  199 + }
  200 + } else if (calibration.inProgress()) {
  201 + if (firstDotVisible)
  202 + calibration.process(data);
  203 + }
  204 +
  205 + }
  206 +
  207 + @Override
  208 + public void statusReported(WRStatusEvent e) {
  209 + synchronized (listener) {
  210 + for (WiimoteDataListener l : listener)
  211 + l.batteryLevel(remotes.get(e.getSource()), e.getBatteryLevel());
  212 + }
  213 + }
  214 +
  215 + @Override
  216 + public void buttonInputReceived(WRButtonEvent e) {
  217 + if (e.isOnlyPressed(WRButtonEvent.A)) {
  218 + calibration.start(getConnectedWiimotes());
  219 + } else if (e.isOnlyPressed(WRButtonEvent.HOME)) {
  220 + Application.getInstance().exit();
  221 + }
  222 + }
  223 +
  224 + public void wiiDeviceDiscovered(WiiDeviceDiscoveredEvent e) {
  225 + if (e.getWiiDevice() instanceof WiiRemote) {
  226 + addRemote((WiiRemote)e.getWiiDevice());
  227 + }
  228 + }
  229 +
  230 + public void findFinished(int numberFound) {
  231 + }
  232 +
  233 + @Override
  234 + public void disconnected() {
  235 + // TODO support dis-/reconnecting?
  236 + WiiRemoteJ.stopFind();
  237 + WiiRemote remove = null;
  238 + for (WiiRemote remote : remotes.keySet()) {
  239 + if (!remote.isConnected()) {
  240 + remove = remote;
  241 + synchronized (listener) {
  242 + for (WiimoteDataListener l : listener)
  243 + l.wiimoteDisconnected(remotes.get(remote));
  244 + }
  245 + break;
  246 + }
  247 + }
  248 + if (remove != null) remotes.remove(remove);
  249 + }
  250 +
  251 +
  252 + /*
  253 + * LISTENER
  254 + */
  255 +
  256 + public void addWiimoteDataListener(WiimoteDataListener l) {
  257 + listener.add(l);
  258 + }
  259 +
  260 + public void removeWiimoteDataListener(WiimoteDataListener l) {
  261 + listener.remove(l);
  262 + }
  263 +
  264 + /*
  265 + * PREFERENCES STUFF
  266 + */
  267 +
  268 + public void preferencesChanged() {
  269 + updateMSS();
  270 + updateCursorControlStrategy();
  271 +// final int newNumWiimotes = prefs.getNumberOfWiimotes();
  272 +// if (numWiimotes != newNumWiimotes) {
  273 +// WiiRemoteJ.stopFind();
  274 +// if (newNumWiimotes > getNumberOfConnectedWiimotes()) {
  275 +// WiiRemoteJ.findRemotes(this, newNumWiimotes - getNumberOfConnectedWiimotes());
  276 +// }
  277 +// numWiimotes = newNumWiimotes;
  278 +// }
  279 + }
  280 +
  281 + @SuppressWarnings("unchecked")
  282 + private void updateCursorControlStrategy() {
  283 + if (cursorControlStrategy == null || !cursorControlStrategy.getClass().getName().equals(prefs.getCursorControl())) {
  284 + try {
  285 + Class<?> c = Class.forName(prefs.getCursorControl());
  286 + cursorControlStrategy = ((Class<? extends CursorControlStrategy>)c).newInstance();
  287 + } catch (Exception e) {
  288 + e.printStackTrace();
  289 + WiimoteWhiteboard.getLogger().log(Level.SEVERE, "Cursor Control Method error.", e);
  290 + }
  291 + }
  292 + }
  293 +
  294 + @SuppressWarnings("unchecked")
  295 + private void updateMSS() {
  296 + if (mss[0] == null || !mss[0].getClass().getName().equals(prefs.getMouseSmoothing())) {
  297 + try {
  298 + Class<?> c = Class.forName(prefs.getMouseSmoothing());
  299 + for (int i = 0; i < 4; i++)
  300 + mss[i] = ((Class<? extends MouseSmoothingStrategy>)c).newInstance();
  301 + } catch (Exception e) {
  302 + e.printStackTrace();
  303 + WiimoteWhiteboard.getLogger().log(Level.SEVERE, "Mouse Movement Smoothing error.", e);
  304 + }
  305 + }
  306 + }
  307 +
  308 + /*
  309 + * GETTER & SETTER
  310 + */
  311 +
  312 + public boolean isConnected() {
  313 + for (WiiRemote remote : remotes.keySet()) {
  314 + if (remote.isConnected()) return true;
  315 + }
  316 + return false;
  317 + }
  318 +
  319 + public boolean isConnected(Wiimote wiimote) {
  320 + return wiimote != null && wiimote.getWiiRemote().isConnected();
  321 + }
  322 +
  323 + public int getNumberOfConnectedWiimotes() {
  324 + return remotes.size();
  325 + }
  326 +
  327 + public Collection<Wiimote> getConnectedWiimotes() {
  328 + return remotes.values();
  329 + }
  330 +
  331 + public boolean isCursorControl() {
  332 + return cursorControl;
  333 + }
  334 +
  335 + public void setCursorControl(boolean cursorControl) {
  336 + this.cursorControl = cursorControl;
  337 + }
  338 +
  339 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/WiimoteWhiteboard.java 0 → 100644
... ... @@ -0,0 +1,153 @@
  1 +package org.mote.wiimote.whiteboard;
  2 +
  3 +import java.util.Locale;
  4 +import java.util.logging.Level;
  5 +import java.util.logging.Logger;
  6 +
  7 +import javax.swing.JFrame;
  8 +import javax.swing.JOptionPane;
  9 +
  10 +import org.jdesktop.application.Action;
  11 +import org.jdesktop.application.Application;
  12 +import org.jdesktop.application.SingleFrameApplication;
  13 +import org.mote.wiimote.whiteboard.calibration.CalibrationPersistence;
  14 +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration;
  15 +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration.CalibrationEvent;
  16 +import org.mote.wiimote.whiteboard.gui.AboutWindow;
  17 +import org.mote.wiimote.whiteboard.gui.HelpHandler;
  18 +import org.mote.wiimote.whiteboard.gui.LogWindow;
  19 +import org.mote.wiimote.whiteboard.gui.MainPanel;
  20 +import org.mote.wiimote.whiteboard.gui.MenuBar;
  21 +import org.mote.wiimote.whiteboard.gui.PreferencesWindow;
  22 +import org.mote.wiimote.whiteboard.mouse.Mouse;
  23 +import org.mote.wiimote.whiteboard.preferences.WWPreferences;
  24 +import org.mote.wiimote.whiteboard.tuio.TuioTransmitter;
  25 +import org.mote.wiimote.whiteboard.util.BareBonesBrowserLaunch;
  26 +import org.mote.wiimote.whiteboard.util.UpdateNotifier;
  27 +import org.mote.wiimote.whiteboard.util.Util;
  28 +import org.mote.wiimote.whiteboard.util.WiiRemoteJErrorHandler;
  29 +
  30 +import wiiremotej.WiiRemoteJ;
  31 +import apple.dts.samplecode.osxadapter.OSXAdapter;
  32 +
  33 +public class WiimoteWhiteboard extends SingleFrameApplication {
  34 +
  35 + public static void main(String args[]) {
  36 + if (Util.MAC_OS_X && !Util.INSIDE_APP_BUNDLE) {
  37 + System.setProperty("apple.laf.useScreenMenuBar", "true");
  38 + System.setProperty("com.apple.mrj.application.apple.menu.about.name", getProperty("id"));
  39 + }
  40 + System.setProperty("bluecove.jsr82.psm_minimum_off", "true");
  41 +
  42 + String lang = WWPreferences.getPreferences().getLanguage();
  43 + if (lang.length() > 0) {
  44 + String[] langParts = lang.split("_");
  45 + switch (langParts.length) {
  46 + case 1:
  47 + Locale.setDefault(new Locale(langParts[0]));
  48 + break;
  49 + case 2:
  50 + Locale.setDefault(new Locale(langParts[0], langParts[1]));
  51 + break;
  52 + }
  53 + }
  54 + Application.launch(WiimoteWhiteboard.class, args);
  55 + }
  56 +
  57 + @Override
  58 + protected void startup() {
  59 + try {
  60 + new Thread(new Runnable() {
  61 + public void run() {
  62 + // blocking
  63 + if (WWPreferences.getPreferences().checkForUpdates())
  64 + UpdateNotifier.checkForUpdate(getProperty("version"));
  65 + }
  66 + }).start();
  67 +
  68 + Logger.getLogger("wiimotewhiteboard").setUseParentHandlers(false);
  69 +
  70 + final JFrame f = getMainFrame();
  71 + LogWindow lw = new LogWindow();
  72 +
  73 + final WiimoteCalibration calibration = new WiimoteCalibration();
  74 + WiimoteDataHandler dh = new WiimoteDataHandler(calibration);
  75 +
  76 +// new IRDotLogger(dh);
  77 +
  78 + MainPanel mp = new MainPanel(dh, calibration);
  79 + AboutWindow af = new AboutWindow();
  80 + HelpHandler hh = new HelpHandler();
  81 + PreferencesWindow pf = new PreferencesWindow(mp, hh);
  82 + f.setJMenuBar(new MenuBar(pf, af, hh, lw));
  83 + registerForMacOSXEvents(pf, af);
  84 +
  85 + // update Mouse's screen
  86 + calibration.addCalibrationEventListener(new WiimoteCalibration.CalibrationEventListener() {
  87 + public void calibrationEvent(CalibrationEvent e) {
  88 + if (e == CalibrationEvent.SCREEN_CHANGED)
  89 + Mouse.setScreen(calibration.getScreen());
  90 + }
  91 + });
  92 +
  93 + new CalibrationPersistence(calibration);
  94 + calibration.setScreen(WiimoteCalibration.DEFAULT_SCREEN);
  95 +
  96 + new TuioTransmitter(dh, calibration);
  97 +
  98 + WiiRemoteJ.setConsoleLoggingErrors();
  99 + Logger.getLogger("wiiremotej").setLevel(Level.ALL);
  100 + Logger.getLogger("wiiremotej").addHandler(new WiiRemoteJErrorHandler(dh));
  101 +
  102 + try {
  103 + getContext().getSessionStorage().restore(f, "mainFrame.session.xml");
  104 + } catch (Exception e) {}
  105 +
  106 + show(mp);
  107 + f.pack();
  108 +
  109 + } catch (Exception e) {
  110 + e.printStackTrace();
  111 + getLogger().log(Level.SEVERE, "Error on startup", e);
  112 + JOptionPane.showMessageDialog(null, e.getMessage(), getProperty("id"), JOptionPane.ERROR_MESSAGE);
  113 + exit();
  114 + }
  115 + }
  116 +
  117 + /*
  118 + * MAC OS X HOOKS
  119 + */
  120 + private void registerForMacOSXEvents(PreferencesWindow pf, AboutWindow af) {
  121 + if (Util.MAC_OS_X) {
  122 + try {
  123 + OSXAdapter.setQuitHandler(this, WiimoteWhiteboard.class.getDeclaredMethod("quitApp", (Class[])null));
  124 + if (!Util.INSIDE_APP_BUNDLE) {
  125 + OSXAdapter.setAboutHandler(af, AboutWindow.class.getDeclaredMethod("about", (Class[])null));
  126 + }
  127 + OSXAdapter.setPreferencesHandler(pf, PreferencesWindow.class.getDeclaredMethod("preferences", (Class[])null));
  128 + } catch (Exception e) {
  129 + e.printStackTrace();
  130 + }
  131 + }
  132 + }
  133 +
  134 + @Action
  135 + public boolean quitApp() {
  136 + exit();
  137 + return false;
  138 + }
  139 +
  140 + @Action
  141 + public void donate() {
  142 + BareBonesBrowserLaunch.openURL(getProperty("donateURL"));
  143 + }
  144 +
  145 + public static String getProperty(String key) {
  146 + return Util.getResourceMap(WiimoteWhiteboard.class).getString("Application."+key);
  147 + }
  148 +
  149 + public static Logger getLogger() {
  150 + return Logger.getLogger("wiimotewhiteboard");
  151 + }
  152 +
  153 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/WiimoteWhiteboard.java~ 0 → 100644
... ... @@ -0,0 +1,159 @@
  1 +package org.mote.wiimote.whiteboard;
  2 +
  3 +import java.util.Locale;
  4 +import java.util.logging.Level;
  5 +import java.util.logging.Logger;
  6 +
  7 +import javax.swing.JFrame;
  8 +import javax.swing.JOptionPane;
  9 +
  10 +import org.jdesktop.application.Action;
  11 +import org.jdesktop.application.Application;
  12 +import org.jdesktop.application.SingleFrameApplication;
  13 +import org.mote.wiimote.whiteboard.calibration.CalibrationPersistence;
  14 +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration;
  15 +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration.CalibrationEvent;
  16 +import org.mote.wiimote.whiteboard.gui.AboutWindow;
  17 +import org.mote.wiimote.whiteboard.gui.HelpHandler;
  18 +import org.mote.wiimote.whiteboard.gui.LogWindow;
  19 +import org.mote.wiimote.whiteboard.gui.MainPanel;
  20 +import org.mote.wiimote.whiteboard.gui.MenuBar;
  21 +import org.mote.wiimote.whiteboard.gui.PreferencesWindow;
  22 +import org.mote.wiimote.whiteboard.mouse.Mouse;
  23 +import org.mote.wiimote.whiteboard.preferences.WWPreferences;
  24 +import org.mote.wiimote.whiteboard.tuio.TuioTransmitter;
  25 +import org.mote.wiimote.whiteboard.util.BareBonesBrowserLaunch;
  26 +import org.mote.wiimote.whiteboard.util.UpdateNotifier;
  27 +import org.mote.wiimote.whiteboard.util.Util;
  28 +import org.mote.wiimote.whiteboard.util.WiiRemoteJErrorHandler;
  29 +
  30 +import wiiremotej.WiiRemoteJ;
  31 +import apple.dts.samplecode.osxadapter.OSXAdapter;
  32 +
  33 +public class WiimoteWhiteboard extends SingleFrameApplication {
  34 +
  35 + public static void main(String args[]) {
  36 + if (Util.MAC_OS_X && !Util.INSIDE_APP_BUNDLE) {
  37 + System.setProperty("apple.laf.useScreenMenuBar", "true");
  38 + System.setProperty("com.apple.mrj.application.apple.menu.about.name", getProperty("id"));
  39 + }
  40 + System.setProperty("bluecove.jsr82.psm_minimum_off", "true");
  41 +
  42 + String lang = WWPreferences.getPreferences().getLanguage();
  43 + if (lang.length() > 0) {
  44 + String[] langParts = lang.split("_");
  45 + switch (langParts.length) {
  46 + case 1:
  47 + Locale.setDefault(new Locale(langParts[0]));
  48 + break;
  49 + case 2:
  50 + Locale.setDefault(new Locale(langParts[0], langParts[1]));
  51 + break;
  52 + }
  53 + }
  54 + Application.launch(WiimoteWhiteboard.class, args);
  55 + }
  56 +
  57 + @Override
  58 + protected void startup() {
  59 + try {
  60 + new Thread(new Runnable() {
  61 + public void run() {
  62 + // blocking
  63 + if (WWPreferences.getPreferences().checkForUpdates())
  64 + UpdateNotifier.checkForUpdate(getProperty("version"));
  65 + }
  66 + }).start();
  67 +
  68 + Logger.getLogger("wiimotewhiteboard").setUseParentHandlers(false);
  69 +
  70 + final JFrame f = getMainFrame();
  71 + LogWindow lw = new LogWindow();
  72 +
  73 + final WiimoteCalibration calibration = new WiimoteCalibration();
  74 + WiimoteDataHandler dh = new WiimoteDataHandler(calibration);
  75 +
  76 +// new IRDotLogger(dh);
  77 +
  78 + MainPanel mp = new MainPanel(dh, calibration);
  79 + AboutWindow af = new AboutWindow();
  80 + HelpHandler hh = new HelpHandler();
  81 + PreferencesWindow pf = new PreferencesWindow(mp, hh);
  82 + f.setJMenuBar(new MenuBar(pf, af, hh, lw));
  83 + registerForMacOSXEvents(pf, af);
  84 +
  85 + // update Mouse's screen
  86 + calibration.addCalibrationEventListener(new WiimoteCalibration.CalibrationEventListener() {
  87 + public void calibrationEvent(CalibrationEvent e) {
  88 + if (e == CalibrationEvent.SCREEN_CHANGED)
  89 + Mouse.setScreen(calibration.getScreen());
  90 + }
  91 + });
  92 +
  93 + // add persistence as last listener because it indirectly generates new calibration events
  94 + new CalibrationPersistence(calibration);
  95 + // TODO save last used screen?
  96 + calibration.setScreen(WiimoteCalibration.DEFAULT_SCREEN);
  97 +
  98 + new TuioTransmitter(dh, calibration);
  99 +
  100 + WiiRemoteJ.setConsoleLoggingErrors();
  101 + Logger.getLogger("wiiremotej").setLevel(Level.ALL);
  102 + Logger.getLogger("wiiremotej").addHandler(new WiiRemoteJErrorHandler(dh));
  103 +
  104 + try {
  105 + // restore session manually before 'show' on the main panel is
  106 + // called. this is a fix to the problem that the session is not
  107 + // restored; apparently because mainFrame is not resizable
  108 + getContext().getSessionStorage().restore(f, "mainFrame.session.xml");
  109 + } catch (Exception e) {}
  110 +
  111 + show(mp);
  112 + // f.pack() is called in 'show' above if f.isValid() == false
  113 + f.pack();
  114 +
  115 + } catch (Exception e) {
  116 + e.printStackTrace();
  117 + getLogger().log(Level.SEVERE, "Error on startup", e);
  118 + JOptionPane.showMessageDialog(null, e.getMessage(), getProperty("id"), JOptionPane.ERROR_MESSAGE);
  119 + exit();
  120 + }
  121 + }
  122 +
  123 + /*
  124 + * MAC OS X HOOKS
  125 + */
  126 + private void registerForMacOSXEvents(PreferencesWindow pf, AboutWindow af) {
  127 + if (Util.MAC_OS_X) {
  128 + try {
  129 + OSXAdapter.setQuitHandler(this, WiimoteWhiteboard.class.getDeclaredMethod("quitApp", (Class[])null));
  130 + if (!Util.INSIDE_APP_BUNDLE) {
  131 + OSXAdapter.setAboutHandler(af, AboutWindow.class.getDeclaredMethod("about", (Class[])null));
  132 + }
  133 + OSXAdapter.setPreferencesHandler(pf, PreferencesWindow.class.getDeclaredMethod("preferences", (Class[])null));
  134 + } catch (Exception e) {
  135 + e.printStackTrace();
  136 + }
  137 + }
  138 + }
  139 +
  140 + @Action
  141 + public boolean quitApp() {
  142 + exit();
  143 + return false;
  144 + }
  145 +
  146 + @Action
  147 + public void donate() {
  148 + BareBonesBrowserLaunch.openURL(getProperty("donateURL"));
  149 + }
  150 +
  151 + public static String getProperty(String key) {
  152 + return Util.getResourceMap(WiimoteWhiteboard.class).getString("Application."+key);
  153 + }
  154 +
  155 + public static Logger getLogger() {
  156 + return Logger.getLogger("wiimotewhiteboard");
  157 + }
  158 +
  159 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/CalibrationPersistence.java 0 → 100644
... ... @@ -0,0 +1,53 @@
  1 +package org.mote.wiimote.whiteboard.calibration;
  2 +
  3 +import java.awt.DisplayMode;
  4 +import java.io.IOException;
  5 +
  6 +import org.jdesktop.application.Application;
  7 +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration.CalibrationEvent;
  8 +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration.CalibrationEventListener;
  9 +
  10 +public class CalibrationPersistence implements CalibrationEventListener {
  11 +
  12 + WiimoteCalibration calibration;
  13 +
  14 + public CalibrationPersistence(WiimoteCalibration calibration) {
  15 + this.calibration = calibration;
  16 + calibration.addCalibrationEventListener(this);
  17 + }
  18 +
  19 + public void calibrationEvent(CalibrationEvent e) {
  20 + switch (e) {
  21 + case SCREEN_CHANGED:
  22 + loadCalibrationData();
  23 + break;
  24 + case FINISHED:
  25 + saveCalibrationData();
  26 + break;
  27 + }
  28 + }
  29 +
  30 + private String calibrationFileName() {
  31 + DisplayMode dm = calibration.getScreen().getDisplayMode();
  32 + return String.format("calibration_%d_%dx%d.txt", calibration.getScreenNumber(), dm.getWidth(), dm.getHeight());
  33 + }
  34 +
  35 + private void loadCalibrationData() {
  36 + try {
  37 + String fileName = calibrationFileName();
  38 + calibration.load(Application.getInstance().getContext().getLocalStorage().openInputFile(fileName));
  39 + } catch (IOException e) {
  40 + // ignore
  41 + }
  42 + }
  43 +
  44 + private void saveCalibrationData() {
  45 + try {
  46 + String fileName = calibrationFileName();
  47 + calibration.save(Application.getInstance().getContext().getLocalStorage().openOutputFile(fileName));
  48 + } catch (IOException e) {
  49 + // ignore
  50 + }
  51 + }
  52 +
  53 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/CalibrationPersistence.java~ 0 → 100644
... ... @@ -0,0 +1,82 @@
  1 +/*
  2 + * Copyright (C) 2008-2009, Uwe Schmidt
  3 + *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a
  5 + * copy of this software and associated documentation files (the "Software"),
  6 + * to deal in the Software without restriction, including without limitation
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8 + * and/or sell copies of the Software, and to permit persons to whom the
  9 + * Software is furnished to do so, subject to the following conditions:
  10 + *
  11 + * The above copyright notice and this permission notice shall be included in
  12 + * all copies or substantial portions of the Software.
  13 + *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20 + * DEALINGS IN THE SOFTWARE.
  21 + *
  22 + * The Software uses a third-party library (WiiRemoteJ) which is not part of
  23 + * the Software and is subject to its own license.
  24 + */
  25 +
  26 +package org.uweschmidt.wiimote.whiteboard.calibration;
  27 +
  28 +import java.awt.DisplayMode;
  29 +import java.io.IOException;
  30 +
  31 +import org.jdesktop.application.Application;
  32 +import org.uweschmidt.wiimote.whiteboard.calibration.WiimoteCalibration.CalibrationEvent;
  33 +import org.uweschmidt.wiimote.whiteboard.calibration.WiimoteCalibration.CalibrationEventListener;
  34 +
  35 +public class CalibrationPersistence implements CalibrationEventListener {
  36 +
  37 + WiimoteCalibration calibration;
  38 +
  39 + public CalibrationPersistence(WiimoteCalibration calibration) {
  40 + this.calibration = calibration;
  41 + calibration.addCalibrationEventListener(this);
  42 + }
  43 +
  44 + public void calibrationEvent(CalibrationEvent e) {
  45 + switch (e) {
  46 + case SCREEN_CHANGED:
  47 + loadCalibrationData();
  48 + break;
  49 + case FINISHED:
  50 + saveCalibrationData();
  51 + break;
  52 + }
  53 + }
  54 +
  55 +// private String safeFilename(String rawName) {
  56 +// return rawName.replaceAll("[\\W]", "").toLowerCase();
  57 +// }
  58 +
  59 + private String calibrationFileName() {
  60 + DisplayMode dm = calibration.getScreen().getDisplayMode();
  61 + return String.format("calibration_%d_%dx%d.txt", calibration.getScreenNumber(), dm.getWidth(), dm.getHeight());
  62 + }
  63 +
  64 + private void loadCalibrationData() {
  65 + try {
  66 + String fileName = calibrationFileName();
  67 + calibration.load(Application.getInstance().getContext().getLocalStorage().openInputFile(fileName));
  68 + } catch (IOException e) {
  69 + // ignore
  70 + }
  71 + }
  72 +
  73 + private void saveCalibrationData() {
  74 + try {
  75 + String fileName = calibrationFileName();
  76 + calibration.save(Application.getInstance().getContext().getLocalStorage().openOutputFile(fileName));
  77 + } catch (IOException e) {
  78 + // ignore
  79 + }
  80 + }
  81 +
  82 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/PointClusterer.java 0 → 100644
... ... @@ -0,0 +1,72 @@
  1 +package org.mote.wiimote.whiteboard.calibration;
  2 +
  3 +import java.util.HashSet;
  4 +import java.util.Map;
  5 +import java.util.Set;
  6 +
  7 +import org.mote.wiimote.whiteboard.ds.IRDot;
  8 +import org.mote.wiimote.whiteboard.ds.Wiimote;
  9 +import org.mote.wiimote.whiteboard.preferences.WWPreferences;
  10 +
  11 +public class PointClusterer {
  12 +
  13 + static {
  14 + if (WWPreferences.WIIMOTES > 2)
  15 + throw new RuntimeException("Clustering for more than 2 Wiimotes not implemented yet.");
  16 + }
  17 +
  18 + public static IRDot[][] cluster(Map<Wiimote, IRDot[]> data) {
  19 + IRDot[][] cluster = new IRDot[4][];
  20 +
  21 + if (data.size() == 1) {
  22 + IRDot[] values = data.values().iterator().next();
  23 + int j = 0;
  24 + for (int i = 0; i < 4; i++)
  25 + if (values[i] != null)
  26 + cluster[j++] = new IRDot[] { values[i] };
  27 + return cluster;
  28 + }
  29 +
  30 + Wiimote[] wiimotes = new Wiimote[data.keySet().size()];
  31 + data.keySet().toArray(wiimotes);
  32 +
  33 + Set<IRDot> used = new HashSet<IRDot>();
  34 + int c = 0;
  35 +
  36 + for (int a = 0; a < 2; a++) {
  37 +
  38 + for (int i = 0; i < 4; i++) {
  39 + IRDot dot1 = data.get(wiimotes[a])[i];
  40 + if (dot1 == null || used.contains(dot1))
  41 + continue;
  42 +
  43 + IRDot minDot = null;
  44 + double minDist = Double.POSITIVE_INFINITY;
  45 +
  46 + for (int j = 0; j < 4; j++) {
  47 + IRDot dot2 = data.get(wiimotes[(a+1)%2])[j];
  48 + if (dot2 == null || used.contains(dot2))
  49 + continue;
  50 +
  51 + double dist = dot1.distance(dot2);
  52 + if (dist < minDist) {
  53 + minDot = dot2;
  54 + minDist = dist;
  55 + }
  56 + }
  57 +
  58 + used.add(dot1);
  59 + if (minDot == null) {
  60 + cluster[c++] = new IRDot[] { dot1 };
  61 + } else {
  62 + cluster[c++] = new IRDot[] { dot1, minDot };
  63 + used.add(minDot);
  64 + }
  65 +
  66 + }
  67 + }
  68 +
  69 + return cluster;
  70 + }
  71 +
  72 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/PointClusterer.java~ 0 → 100644
... ... @@ -0,0 +1,101 @@
  1 +/*
  2 + * Copyright (C) 2008-2009, Uwe Schmidt
  3 + *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a
  5 + * copy of this software and associated documentation files (the "Software"),
  6 + * to deal in the Software without restriction, including without limitation
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8 + * and/or sell copies of the Software, and to permit persons to whom the
  9 + * Software is furnished to do so, subject to the following conditions:
  10 + *
  11 + * The above copyright notice and this permission notice shall be included in
  12 + * all copies or substantial portions of the Software.
  13 + *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20 + * DEALINGS IN THE SOFTWARE.
  21 + *
  22 + * The Software uses a third-party library (WiiRemoteJ) which is not part of
  23 + * the Software and is subject to its own license.
  24 + */
  25 +
  26 +package org.uweschmidt.wiimote.whiteboard.calibration;
  27 +
  28 +import java.util.HashSet;
  29 +import java.util.Map;
  30 +import java.util.Set;
  31 +
  32 +import org.uweschmidt.wiimote.whiteboard.ds.IRDot;
  33 +import org.uweschmidt.wiimote.whiteboard.ds.Wiimote;
  34 +import org.uweschmidt.wiimote.whiteboard.preferences.WWPreferences;
  35 +
  36 +public class PointClusterer {
  37 +
  38 + static {
  39 + if (WWPreferences.WIIMOTES > 2)
  40 + throw new RuntimeException("Clustering for more than 2 Wiimotes not implemented yet.");
  41 + }
  42 +
  43 + /**
  44 + * @return array of clusters (first index = cluster number, second index = dots in cluster)
  45 + */
  46 + public static IRDot[][] cluster(Map<Wiimote, IRDot[]> data) {
  47 + IRDot[][] cluster = new IRDot[4][];
  48 +
  49 + // trivial case
  50 + if (data.size() == 1) {
  51 + IRDot[] values = data.values().iterator().next();
  52 + int j = 0;
  53 + for (int i = 0; i < 4; i++)
  54 + if (values[i] != null)
  55 + cluster[j++] = new IRDot[] { values[i] };
  56 + return cluster;
  57 + }
  58 +
  59 + Wiimote[] wiimotes = new Wiimote[data.keySet().size()];
  60 + data.keySet().toArray(wiimotes);
  61 +
  62 + Set<IRDot> used = new HashSet<IRDot>();
  63 + int c = 0;
  64 +
  65 + for (int a = 0; a < 2; a++) {
  66 +
  67 + for (int i = 0; i < 4; i++) {
  68 + IRDot dot1 = data.get(wiimotes[a])[i];
  69 + if (dot1 == null || used.contains(dot1))
  70 + continue;
  71 +
  72 + IRDot minDot = null;
  73 + double minDist = Double.POSITIVE_INFINITY;
  74 +
  75 + for (int j = 0; j < 4; j++) {
  76 + IRDot dot2 = data.get(wiimotes[(a+1)%2])[j];
  77 + if (dot2 == null || used.contains(dot2))
  78 + continue;
  79 +
  80 + double dist = dot1.distance(dot2);
  81 + if (dist < minDist) {
  82 + minDot = dot2;
  83 + minDist = dist;
  84 + }
  85 + }
  86 +
  87 + used.add(dot1);
  88 + if (minDot == null) {
  89 + cluster[c++] = new IRDot[] { dot1 };
  90 + } else {
  91 + cluster[c++] = new IRDot[] { dot1, minDot };
  92 + used.add(minDot);
  93 + }
  94 +
  95 + }
  96 + }
  97 +
  98 + return cluster;
  99 + }
  100 +
  101 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/WiimoteCalibration.java 0 → 100644
... ... @@ -0,0 +1,511 @@
  1 +package org.mote.wiimote.whiteboard.calibration;
  2 +import java.awt.Color;
  3 +import java.awt.Graphics;
  4 +import java.awt.Graphics2D;
  5 +import java.awt.GraphicsDevice;
  6 +import java.awt.GraphicsEnvironment;
  7 +import java.awt.Image;
  8 +import java.awt.Point;
  9 +import java.awt.Rectangle;
  10 +import java.awt.RenderingHints;
  11 +import java.awt.event.KeyAdapter;
  12 +import java.awt.event.KeyEvent;
  13 +import java.awt.geom.Point2D;
  14 +import java.io.BufferedReader;
  15 +import java.io.IOException;
  16 +import java.io.InputStream;
  17 +import java.io.InputStreamReader;
  18 +import java.io.OutputStream;
  19 +import java.io.PrintStream;
  20 +import java.util.Arrays;
  21 +import java.util.Collection;
  22 +import java.util.HashMap;
  23 +import java.util.HashSet;
  24 +import java.util.LinkedHashMap;
  25 +import java.util.LinkedHashSet;
  26 +import java.util.Locale;
  27 +import java.util.Map;
  28 +import java.util.Set;
  29 +
  30 +import javax.media.jai.PerspectiveTransform;
  31 +import javax.swing.Icon;
  32 +import javax.swing.ImageIcon;
  33 +import javax.swing.JFrame;
  34 +import javax.swing.JLabel;
  35 +import javax.swing.JOptionPane;
  36 +import javax.swing.JPanel;
  37 +import javax.swing.SwingConstants;
  38 +
  39 +import org.mote.wiimote.whiteboard.WiimoteWhiteboard;
  40 +import org.mote.wiimote.whiteboard.ds.IRDot;
  41 +import org.mote.wiimote.whiteboard.ds.Wiimote;
  42 +import org.mote.wiimote.whiteboard.util.Util;
  43 +
  44 +public class WiimoteCalibration {
  45 +
  46 + // list of all "rectangles" of the 3x3 calibration grid, larger to smaller
  47 + private static final CalibrationState[][] VALID_STATES = {
  48 + {CalibrationState.UPPER_LEFT, CalibrationState.UPPER_RIGHT, CalibrationState.LOWER_RIGHT, CalibrationState.LOWER_LEFT},
  49 + {CalibrationState.UPPER_LEFT, CalibrationState.TOP_MIDDLE, CalibrationState.BOTTOM_MIDDLE, CalibrationState.LOWER_LEFT},
  50 + {CalibrationState.TOP_MIDDLE, CalibrationState.UPPER_RIGHT, CalibrationState.LOWER_RIGHT, CalibrationState.BOTTOM_MIDDLE},
  51 + {CalibrationState.UPPER_LEFT, CalibrationState.UPPER_RIGHT, CalibrationState.EAST_MIDDLE, CalibrationState.WEST_MIDDLE},
  52 + {CalibrationState.WEST_MIDDLE, CalibrationState.EAST_MIDDLE, CalibrationState.LOWER_RIGHT, CalibrationState.LOWER_LEFT},
  53 + {CalibrationState.WEST_MIDDLE, CalibrationState.CENTER, CalibrationState.BOTTOM_MIDDLE, CalibrationState.LOWER_LEFT},
  54 + {CalibrationState.UPPER_LEFT, CalibrationState.TOP_MIDDLE, CalibrationState.CENTER, CalibrationState.WEST_MIDDLE},
  55 + {CalibrationState.TOP_MIDDLE, CalibrationState.UPPER_RIGHT, CalibrationState.EAST_MIDDLE, CalibrationState.CENTER},
  56 + {CalibrationState.CENTER, CalibrationState.EAST_MIDDLE, CalibrationState.LOWER_RIGHT, CalibrationState.BOTTOM_MIDDLE},
  57 + };
  58 +
  59 + public static final GraphicsDevice DEFAULT_SCREEN = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
  60 +
  61 + public static enum CalibrationEvent {
  62 + SCREEN_CHANGED, STARTED, FINISHED, ABORTED, LOADED, SAVED;
  63 + };
  64 +
  65 + public static interface CalibrationEventListener {
  66 + public void calibrationEvent(CalibrationEvent e);
  67 + }
  68 +
  69 + public static enum CalibrationState {
  70 + DONE(0, 0, null), CENTER(.5, .5, DONE), EAST_MIDDLE(.9, .5, CENTER), WEST_MIDDLE(.1, .5, EAST_MIDDLE), TOP_MIDDLE(.5, .1, WEST_MIDDLE), BOTTOM_MIDDLE(.5, .9, TOP_MIDDLE), LOWER_LEFT(.1, .9, BOTTOM_MIDDLE), LOWER_RIGHT(.9, .9, LOWER_LEFT), UPPER_RIGHT(.9, .1, LOWER_RIGHT), UPPER_LEFT(.1, .1, UPPER_RIGHT), PENDING(0, 0, UPPER_LEFT);
  71 +
  72 + public static final CalibrationState REGULAR_END = LOWER_LEFT;
  73 + private final double xMargin, yMargin;
  74 + private final CalibrationState next;
  75 +
  76 + private CalibrationState(double xMargin, double yMargin, CalibrationState next) {
  77 + this.xMargin = xMargin;
  78 + this.yMargin = yMargin;
  79 + this.next = next;
  80 + }
  81 +
  82 + public int getX(Rectangle bounds) {
  83 + return bounds.x + (int) Math.round(bounds.width * xMargin);
  84 + }
  85 +
  86 + public int getY(Rectangle bounds) {
  87 + return bounds.y + (int) Math.round(bounds.height * yMargin);
  88 + }
  89 +
  90 + public CalibrationState getNext() {
  91 + return next;
  92 + }
  93 + };
  94 +
  95 + private static final double EPS = .05;
  96 +
  97 + private final CalibrationFrame calibrationFrame;
  98 + private final Set<CalibrationEventListener> listener = new LinkedHashSet<CalibrationEventListener>();
  99 +
  100 +
  101 + private GraphicsDevice screen = null;
  102 + private int screenNumber = -1;
  103 + private Rectangle bounds;
  104 + private int sc = 0;
  105 + private boolean stepChange = false;
  106 + private boolean checkPoints = false;
  107 + private Collection<Wiimote> wiimotes;
  108 + private CalibrationState state = CalibrationState.PENDING;
  109 +
  110 + // last calibration point for a wiimote, always non-null
  111 + private Map<Wiimote, Point2D> last = new HashMap<Wiimote, Point2D>();
  112 + // transformer for wiimote
  113 + private Map<String, PerspectiveTransform> transformer = new LinkedHashMap<String, PerspectiveTransform>();
  114 + // all visible calibration points for each wiimote (can be more than 4)
  115 + private Map<Wiimote, Map<CalibrationState, Point2D>> points = new LinkedHashMap<Wiimote, Map<CalibrationState,Point2D>>();
  116 + // final 16 value double array (4<->4 mapping) for each wiimote, used to create transformer
  117 + private Map<String, Double[]> finals = new LinkedHashMap<String, Double[]>();
  118 +
  119 +
  120 +
  121 + public WiimoteCalibration() {
  122 + calibrationFrame = new CalibrationFrame();
  123 + }
  124 +
  125 + public boolean setScreen(GraphicsDevice screen) {
  126 + if (!inProgress()) {
  127 + this.screen = screen;
  128 + bounds = screen.getDefaultConfiguration().getBounds();
  129 + calibrationFrame.setBounds(bounds);
  130 +
  131 + // get "screen number"
  132 + GraphicsDevice[] gds = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices();
  133 + for (int i = 0; i < gds.length; i++) {
  134 + if (gds[i] == screen) {
  135 + screenNumber = i + 1;
  136 + break;
  137 + }
  138 + }
  139 +
  140 + state = CalibrationState.PENDING;
  141 + transformer.clear();
  142 + notifyListener(CalibrationEvent.SCREEN_CHANGED);
  143 + return true;
  144 + } else {
  145 + System.err.println("Calibration in Progress.");
  146 + return false;
  147 + }
  148 + }
  149 +
  150 + public GraphicsDevice getScreen() {
  151 + return screen;
  152 + }
  153 +
  154 + public int getScreenNumber() {
  155 + return screenNumber;
  156 + }
  157 +
  158 + @SuppressWarnings("serial")
  159 + private class CalibrationFrame extends JFrame {
  160 + private final ImageIcon VISIBLE = new ImageIcon(WiimoteCalibration.class.getResource("resources/icons/francisco-ok.png"));
  161 + private final ImageIcon NOT_VISIBLE = new ImageIcon(WiimoteCalibration.class.getResource("resources/icons/francisco-warning.png"));
  162 + private final Image CROSS_HAIR = new ImageIcon(WiimoteCalibration.class.getResource("resources/icons/francisco-crosshair.png")).getImage();
  163 +
  164 + public CalibrationFrame() {
  165 + super("Calibration");
  166 + setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
  167 + setBackground(Color.WHITE);
  168 + ((JPanel)getContentPane()).setOpaque(true);
  169 + setLayout(null);
  170 + setUndecorated(true);
  171 + setAlwaysOnTop(true);
  172 + addKeyListener(new KeyAdapter() {
  173 + @Override
  174 + public void keyPressed(KeyEvent e) {
  175 + if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
  176 + state = isAnyCalibrated(wiimotes) ? CalibrationState.DONE : CalibrationState.PENDING;
  177 + if (screen.getFullScreenWindow() == calibrationFrame)
  178 + screen.setFullScreenWindow(null);
  179 + setVisible(false);
  180 + notifyListener(CalibrationEvent.ABORTED);
  181 + }
  182 + }
  183 + });
  184 + }
  185 +
  186 + private JLabel statusLabel(Icon icon, int id, int x, int y) {
  187 + JLabel l = new JLabel(icon, SwingConstants.LEFT);
  188 + if (wiimotes.size() > 1) l.setText(String.valueOf(id));
  189 + int w = 100;
  190 + int h = icon.getIconHeight();
  191 + x = x - icon.getIconWidth()/2;
  192 + y = y - wiimotes.size()*h/2;
  193 + l.setBounds(x, y + (id-1)*h, w, h);
  194 + return l;
  195 + }
  196 +
  197 + public void finished(CalibrationState s) {
  198 + int x = s.getX(bounds) - bounds.x;
  199 + int y = s.getY(bounds) - bounds.y;
  200 +
  201 + for (Wiimote wiimote : points.keySet()) {
  202 + add(statusLabel(points.get(wiimote).get(s) != null ? VISIBLE : NOT_VISIBLE, wiimote.getId(), x, y));
  203 + }
  204 +
  205 + repaint();
  206 + }
  207 +
  208 + public void reset() {
  209 + getContentPane().removeAll();
  210 + JLabel info = Util.newComponent(JLabel.class, "infoLabel");
  211 + info.setFont(info.getFont().deriveFont(20f));
  212 + info.setHorizontalAlignment(SwingConstants.CENTER);
  213 + int w = bounds.width;
  214 + int h = 200;
  215 + info.setBounds(bounds.width/2 - w/2, bounds.height/3 - h/2, w, h);
  216 + add(info);
  217 + Util.getResourceMap(WiimoteCalibration.class).injectComponents(this);
  218 + }
  219 +
  220 + @Override
  221 + public void paint(Graphics g) {
  222 + super.paint(g);
  223 + ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
  224 +
  225 + if (state != CalibrationState.DONE && state != CalibrationState.PENDING) {
  226 + int x = state.getX(bounds) - bounds.x;
  227 + int y = state.getY(bounds) - bounds.y;
  228 + g.drawImage(CROSS_HAIR, x - CROSS_HAIR.getWidth(null)/2 + 1, y - CROSS_HAIR.getHeight(null)/2 + 1, null);
  229 + }
  230 + }
  231 +
  232 + }
  233 +
  234 + public void start(Collection<Wiimote> wiimotes) {
  235 + last.clear();
  236 + points.clear();
  237 + finals.clear();
  238 + calibrationFrame.reset();
  239 + stepChange = false;
  240 + sc = 0;
  241 + checkPoints = false;
  242 + state = CalibrationState.PENDING.getNext();
  243 +
  244 + this.wiimotes = wiimotes;
  245 + for (Wiimote wiimote : wiimotes) {
  246 + points.put(wiimote, new LinkedHashMap<CalibrationState, Point2D>());
  247 + last.put(wiimote, new Point2D.Double(-1,-1));
  248 + }
  249 +
  250 + if (screen == null)
  251 + setScreen(DEFAULT_SCREEN);
  252 +
  253 + if (Util.MAC_OS_X && screen == DEFAULT_SCREEN)
  254 + screen.setFullScreenWindow(calibrationFrame);
  255 +
  256 + calibrationFrame.repaint();
  257 + calibrationFrame.setVisible(true);
  258 + notifyListener(CalibrationEvent.STARTED);
  259 + }
  260 +
  261 + public boolean inProgress() {
  262 + return !isPending() && !isDone();
  263 + }
  264 +
  265 + public boolean isPending() {
  266 + return state == CalibrationState.PENDING;
  267 + }
  268 +
  269 + public boolean isDone() {
  270 + return state == CalibrationState.DONE;
  271 + }
  272 +
  273 + public Map<String, Double[]> getFinals() {
  274 + return finals;
  275 + }
  276 +
  277 + public boolean isCalibrated(Wiimote wiimote) {
  278 + return transformer.containsKey(wiimote.getAddress());
  279 + }
  280 +
  281 + public boolean isAnyCalibrated(Collection<Wiimote> wiimotes) {
  282 + for (Wiimote wiimote : wiimotes) {
  283 + if (isCalibrated(wiimote))
  284 + return true;
  285 + }
  286 + return false;
  287 + }
  288 +
  289 + public boolean process(Map<Wiimote, IRDot[]> data) {
  290 +
  291 + if (inProgress()) {
  292 +
  293 + for (Wiimote wiimote : points.keySet()) {
  294 + Point2D lastP = last.get(wiimote);
  295 + Point2D currentP = data.get(wiimote)[0];
  296 +
  297 + if (currentP != null && lastP.distance(currentP) > EPS) {
  298 +
  299 + points.get(wiimote).put(state, currentP);
  300 + last.put(wiimote, currentP);
  301 + stepChange = true;
  302 + }
  303 + }
  304 +
  305 + // process at least 5 points to not miss a signal
  306 + if (stepChange && ++sc > 5) {
  307 + sc = 0;
  308 + stepChange = false;
  309 + CalibrationState current = state;
  310 + state = state.getNext();
  311 + calibrationFrame.finished(current);
  312 +
  313 + if (checkPoints || current == CalibrationState.REGULAR_END) {
  314 + checkPoints = true;
  315 + if (calculateQuadsForWiimotes()) {
  316 + // OK, calibration finished
  317 + state = CalibrationState.DONE;
  318 + calculateTransformation();
  319 + if (screen.getFullScreenWindow() == calibrationFrame)
  320 + screen.setFullScreenWindow(null);
  321 + calibrationFrame.setVisible(false);
  322 + notifyListener(CalibrationEvent.FINISHED);
  323 + return true;
  324 + } else {
  325 + // Go on
  326 + }
  327 + }
  328 + }
  329 +
  330 + if (state == CalibrationState.DONE) {
  331 + // PROBLEM, no solution found
  332 + state = CalibrationState.PENDING;
  333 + if (screen.getFullScreenWindow() == calibrationFrame)
  334 + screen.setFullScreenWindow(null);
  335 + calibrationFrame.setVisible(false);
  336 + notifyListener(CalibrationEvent.ABORTED);
  337 + new Thread(new Runnable() {
  338 + public void run() {
  339 + JOptionPane.showMessageDialog(null, Util.getResourceMap(WiimoteCalibration.class).getString("coverageError"), Util.getResourceMap(WiimoteCalibration.class).getString("calibrationFailed"), JOptionPane.ERROR_MESSAGE);
  340 + }
  341 + }).start();
  342 + }
  343 +
  344 + return true;
  345 + }
  346 +
  347 + return false;
  348 + }
  349 +
  350 + private static boolean checkExist(Map<CalibrationState, Point2D> p, CalibrationState... states) {
  351 + for (CalibrationState s : states) {
  352 + if (p.get(s) == null)
  353 + return false;
  354 + }
  355 + return true;
  356 + }
  357 +
  358 + private boolean calculateQuadsForWiimotes() {
  359 + boolean success = true;
  360 + Set<CalibrationState> check = new HashSet<CalibrationState>();
  361 +
  362 + for (Wiimote wiimote : points.keySet()) {
  363 + boolean ok = false;
  364 +
  365 + for (int i = 0; i < VALID_STATES.length; i++) {
  366 + if (checkExist(points.get(wiimote), VALID_STATES[i])) {
  367 + Map<CalibrationState, Point2D> calibrated = points.get(wiimote);
  368 + CalibrationState[] states = VALID_STATES[i];
  369 + check.addAll(Arrays.asList(states));
  370 + finals.put(wiimote.getAddress(), new Double[] {
  371 + calibrated.get(states[0]).getX(), calibrated.get(states[0]).getY(),
  372 + calibrated.get(states[1]).getX(), calibrated.get(states[1]).getY(),
  373 + calibrated.get(states[2]).getX(), calibrated.get(states[2]).getY(),
  374 + calibrated.get(states[3]).getX(), calibrated.get(states[3]).getY(),
  375 + (double)states[0].getX(bounds), (double)states[0].getY(bounds),
  376 + (double)states[1].getX(bounds), (double)states[1].getY(bounds),
  377 + (double)states[2].getX(bounds), (double)states[2].getY(bounds),
  378 + (double)states[3].getX(bounds), (double)states[3].getY(bounds)
  379 + });
  380 + ok = true;
  381 + break;
  382 + }
  383 + }
  384 +
  385 + success = success && ok;
  386 + }
  387 + // check also if the whole screen is covered
  388 + return success && check.containsAll(Arrays.asList(VALID_STATES[0]));
  389 + }
  390 +
  391 + private void calculateTransformation() {
  392 + transformer.clear();
  393 + for (String address : finals.keySet()) {
  394 + Double[] d = finals.get(address);
  395 + transformer.put(address, PerspectiveTransform.getQuadToQuad(d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]));
  396 + }
  397 + }
  398 +
  399 + public Map<String, PerspectiveTransform> getTransformer() {
  400 + return transformer;
  401 + }
  402 +
  403 + public IRDot warp(int i, Wiimote wiimote, Map<Wiimote, IRDot[]> data) {
  404 + final PerspectiveTransform transform = transformer.get(wiimote.getAddress());
  405 + if (transform == null || data.get(wiimote)[i] == null) return null;
  406 + else {
  407 + return (IRDot) transform.transform(data.get(wiimote)[i], new IRDot(data.get(wiimote)[i]));
  408 + }
  409 + }
  410 +
  411 + private Map<Wiimote, IRDot[]> warpIndividually(Map<Wiimote, IRDot[]> data) {
  412 + Map<Wiimote, IRDot[]> warped = new LinkedHashMap<Wiimote, IRDot[]>();
  413 + IRDot[] p;
  414 + for (Wiimote wiimote : data.keySet()) {
  415 + warped.put(wiimote, p = new IRDot[4]);
  416 + for (int i = 0; i < 4; i++) {
  417 + p[i] = warp(i, wiimote, data);
  418 + }
  419 + }
  420 + return warped;
  421 + }
  422 +
  423 + public Point[] warp(Map<Wiimote, IRDot[]> data) {
  424 + Point[] warped = new Point[4];
  425 + if (isDone() && isAnyCalibrated(data.keySet())) {
  426 + IRDot[][] cluster = PointClusterer.cluster(warpIndividually(data));
  427 +
  428 + for (int i = 0; i < cluster.length; i++) {
  429 + if (cluster[i] == null) break;
  430 + double x = 0, y = 0;
  431 + int c = 0;
  432 + for (IRDot p : cluster[i]) {
  433 + x += p.getX();
  434 + y += p.getY();
  435 + c++;
  436 + break;
  437 + }
  438 + warped[i] = new Point((int) Math.round(x / c), (int) Math.round(y / c));
  439 + }
  440 + } else {
  441 + System.err.println("Not calibrated.");
  442 + }
  443 + return warped;
  444 + }
  445 +
  446 +
  447 + public boolean load(InputStream is) throws IOException {
  448 + try {
  449 + BufferedReader in = new BufferedReader(new InputStreamReader(is));
  450 + String address = null;
  451 +
  452 + while ((address = in.readLine()) != null) {
  453 + Double[] d = new Double[16];
  454 + finals.put(address, d);
  455 + for (int i = 0; i < 4; i++) {
  456 + String[] p = in.readLine().split(" ");
  457 + for (int j = 0; j < 2; j++) {
  458 + d[i*2+j+0] = Double.valueOf(p[j+0]);
  459 + d[i*2+j+8] = Double.valueOf(p[j+2]);
  460 + }
  461 + }
  462 + }
  463 +
  464 + calculateTransformation();
  465 + state = CalibrationState.DONE;
  466 + notifyListener(CalibrationEvent.LOADED);
  467 + return true;
  468 +
  469 + } catch (Exception e) {
  470 + e.printStackTrace();
  471 + return false;
  472 + }
  473 + }
  474 +
  475 + public void save(OutputStream os) throws IOException {
  476 + PrintStream out = new PrintStream(os);
  477 +
  478 + for (String address : finals.keySet()) {
  479 + out.print(address);
  480 + Double[] d = finals.get(address);
  481 + for (int i = 0; i < 4; i++) {
  482 + out.printf(Locale.ENGLISH, "\n%f %f %.0f %.0f", d[i*2+0+0], d[i*2+1+0], d[i*2+0+8], d[i*2+1+8]);
  483 + }
  484 + out.println();
  485 + }
  486 + out.close();
  487 +
  488 + notifyListener(CalibrationEvent.SAVED);
  489 + }
  490 +
  491 +
  492 + /*
  493 + * LISTENER
  494 + */
  495 +
  496 + public void addCalibrationEventListener(CalibrationEventListener l) {
  497 + listener.add(l);
  498 + }
  499 +
  500 + public void removeCalibrationEventListener(CalibrationEventListener l) {
  501 + listener.remove(l);
  502 + }
  503 +
  504 + private void notifyListener(CalibrationEvent e) {
  505 + WiimoteWhiteboard.getLogger().info("Calibration Event: " + e);
  506 + for (CalibrationEventListener l : listener) {
  507 + l.calibrationEvent(e);
  508 + }
  509 + }
  510 +
  511 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/WiimoteCalibration.java~ 0 → 100644
... ... @@ -0,0 +1,511 @@
  1 +package org.mote.wiimote.whiteboard.calibration;
  2 +import java.awt.Color;
  3 +import java.awt.Graphics;
  4 +import java.awt.Graphics2D;
  5 +import java.awt.GraphicsDevice;
  6 +import java.awt.GraphicsEnvironment;
  7 +import java.awt.Image;
  8 +import java.awt.Point;
  9 +import java.awt.Rectangle;
  10 +import java.awt.RenderingHints;
  11 +import java.awt.event.KeyAdapter;
  12 +import java.awt.event.KeyEvent;
  13 +import java.awt.geom.Point2D;
  14 +import java.io.BufferedReader;
  15 +import java.io.IOException;
  16 +import java.io.InputStream;
  17 +import java.io.InputStreamReader;
  18 +import java.io.OutputStream;
  19 +import java.io.PrintStream;
  20 +import java.util.Arrays;
  21 +import java.util.Collection;
  22 +import java.util.HashMap;
  23 +import java.util.HashSet;
  24 +import java.util.LinkedHashMap;
  25 +import java.util.LinkedHashSet;
  26 +import java.util.Locale;
  27 +import java.util.Map;
  28 +import java.util.Set;
  29 +
  30 +import javax.media.jai.PerspectiveTransform;
  31 +import javax.swing.Icon;
  32 +import javax.swing.ImageIcon;
  33 +import javax.swing.JFrame;
  34 +import javax.swing.JLabel;
  35 +import javax.swing.JOptionPane;
  36 +import javax.swing.JPanel;
  37 +import javax.swing.SwingConstants;
  38 +
  39 +import org.mote.wiimote.whiteboard.WiimoteWhiteboard;
  40 +import org.mote.wiimote.whiteboard.ds.IRDot;
  41 +import org.mote.wiimote.whiteboard.ds.Wiimote;
  42 +import org.mote.wiimote.whiteboard.util.Util;
  43 +
  44 +public class WiimoteCalibration {
  45 +
  46 + // list of all "rectangles" of the 3x3 calibration grid, larger to smaller
  47 + private static final CalibrationState[][] VALID_STATES = {
  48 + {CalibrationState.UPPER_LEFT, CalibrationState.UPPER_RIGHT, CalibrationState.LOWER_RIGHT, CalibrationState.LOWER_LEFT},
  49 + {CalibrationState.UPPER_LEFT, CalibrationState.TOP_MIDDLE, CalibrationState.BOTTOM_MIDDLE, CalibrationState.LOWER_LEFT},
  50 + {CalibrationState.TOP_MIDDLE, CalibrationState.UPPER_RIGHT, CalibrationState.LOWER_RIGHT, CalibrationState.BOTTOM_MIDDLE},
  51 + {CalibrationState.UPPER_LEFT, CalibrationState.UPPER_RIGHT, CalibrationState.EAST_MIDDLE, CalibrationState.WEST_MIDDLE},
  52 + {CalibrationState.WEST_MIDDLE, CalibrationState.EAST_MIDDLE, CalibrationState.LOWER_RIGHT, CalibrationState.LOWER_LEFT},
  53 + {CalibrationState.WEST_MIDDLE, CalibrationState.CENTER, CalibrationState.BOTTOM_MIDDLE, CalibrationState.LOWER_LEFT},
  54 + {CalibrationState.UPPER_LEFT, CalibrationState.TOP_MIDDLE, CalibrationState.CENTER, CalibrationState.WEST_MIDDLE},
  55 + {CalibrationState.TOP_MIDDLE, CalibrationState.UPPER_RIGHT, CalibrationState.EAST_MIDDLE, CalibrationState.CENTER},
  56 + {CalibrationState.CENTER, CalibrationState.EAST_MIDDLE, CalibrationState.LOWER_RIGHT, CalibrationState.BOTTOM_MIDDLE},
  57 + };
  58 +
  59 + public static final GraphicsDevice DEFAULT_SCREEN = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
  60 +
  61 + public static enum CalibrationEvent {
  62 + SCREEN_CHANGED, STARTED, FINISHED, ABORTED, LOADED, SAVED;
  63 + };
  64 +
  65 + public static interface CalibrationEventListener {
  66 + public void calibrationEvent(CalibrationEvent e);
  67 + }
  68 +
  69 + public static enum CalibrationState {
  70 + DONE(0, 0, null), CENTER(.5, .5, DONE), EAST_MIDDLE(.9, .5, CENTER), WEST_MIDDLE(.1, .5, EAST_MIDDLE), TOP_MIDDLE(.5, .1, WEST_MIDDLE), BOTTOM_MIDDLE(.5, .9, TOP_MIDDLE), LOWER_LEFT(.1, .9, BOTTOM_MIDDLE), LOWER_RIGHT(.9, .9, LOWER_LEFT), UPPER_RIGHT(.9, .1, LOWER_RIGHT), UPPER_LEFT(.1, .1, UPPER_RIGHT), PENDING(0, 0, UPPER_LEFT);
  71 +
  72 + public static final CalibrationState REGULAR_END = LOWER_LEFT;
  73 + private final double xMargin, yMargin;
  74 + private final CalibrationState next;
  75 +
  76 + private CalibrationState(double xMargin, double yMargin, CalibrationState next) {
  77 + this.xMargin = xMargin;
  78 + this.yMargin = yMargin;
  79 + this.next = next;
  80 + }
  81 +
  82 + public int getX(Rectangle bounds) {
  83 + return bounds.x + (int) Math.round(bounds.width * xMargin);
  84 + }
  85 +
  86 + public int getY(Rectangle bounds) {
  87 + return bounds.y + (int) Math.round(bounds.height * yMargin);
  88 + }
  89 +
  90 + public CalibrationState getNext() {
  91 + return next;
  92 + }
  93 + };
  94 +
  95 + private static final double EPS = .05;
  96 +
  97 + private final CalibrationFrame calibrationFrame;
  98 + private final Set<CalibrationEventListener> listener = new LinkedHashSet<CalibrationEventListener>();
  99 +
  100 +
  101 + private GraphicsDevice screen = null;
  102 + private int screenNumber = -1;
  103 + private Rectangle bounds;
  104 + private int sc = 0;
  105 + private boolean stepChange = false;
  106 + private boolean checkPoints = false;
  107 + private Collection<Wiimote> wiimotes;
  108 + private CalibrationState state = CalibrationState.PENDING;
  109 +
  110 + // last calibration point for a wiimote, always non-null
  111 + private Map<Wiimote, Point2D> last = new HashMap<Wiimote, Point2D>();
  112 + // transformer for wiimote
  113 + private Map<String, PerspectiveTransform> transformer = new LinkedHashMap<String, PerspectiveTransform>();
  114 + // all visible calibration points for each wiimote (can be more than 4)
  115 + private Map<Wiimote, Map<CalibrationState, Point2D>> points = new LinkedHashMap<Wiimote, Map<CalibrationState,Point2D>>();
  116 + // final 16 value double array (4<->4 mapping) for each wiimote, used to create transformer
  117 + private Map<String, Double[]> finals = new LinkedHashMap<String, Double[]>();
  118 +
  119 +
  120 +
  121 + public WiimoteCalibration() {
  122 + calibrationFrame = new CalibrationFrame();
  123 + }
  124 +
  125 + public boolean setScreen(GraphicsDevice screen) {
  126 + if (!inProgress()) {
  127 + this.screen = screen;
  128 + bounds = screen.getDefaultConfiguration().getBounds();
  129 + calibrationFrame.setBounds(bounds);
  130 +
  131 + // get "screen number"
  132 + GraphicsDevice[] gds = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices();
  133 + for (int i = 0; i < gds.length; i++) {
  134 + if (gds[i] == screen) {
  135 + screenNumber = i + 1;
  136 + break;
  137 + }
  138 + }
  139 +
  140 + state = CalibrationState.PENDING;
  141 + transformer.clear();
  142 + notifyListener(CalibrationEvent.SCREEN_CHANGED);
  143 + return true;
  144 + } else {
  145 + System.err.println("Calibration in Progress.");
  146 + return false;
  147 + }
  148 + }
  149 +
  150 + public GraphicsDevice getScreen() {
  151 + return screen;
  152 + }
  153 +
  154 + public int getScreenNumber() {
  155 + return screenNumber;
  156 + }
  157 +
  158 + @SuppressWarnings("serial")
  159 + private class CalibrationFrame extends JFrame {
  160 + private final ImageIcon VISIBLE = new ImageIcon(WiimoteCalibration.class.getResource("resources/icons/francisco-ok.png"));
  161 + private final ImageIcon NOT_VISIBLE = new ImageIcon(WiimoteCalibration.class.getResource("resources/icons/francisco-warning.png"));
  162 + private final Image CROSS_HAIR = new ImageIcon(WiimoteCalibration.class.getResource("resources/icons/francisco-crosshair.png")).getImage();
  163 +
  164 + public CalibrationFrame() {
  165 + super("Calibration");
  166 + setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
  167 + setBackground(Color.WHITE);
  168 + ((JPanel)getContentPane()).setOpaque(true);
  169 + setLayout(null);
  170 + setUndecorated(true);
  171 + setAlwaysOnTop(true);
  172 + addKeyListener(new KeyAdapter() {
  173 + @Override
  174 + public void keyPressed(KeyEvent e) {
  175 + if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
  176 + state = isAnyCalibrated(wiimotes) ? CalibrationState.DONE : CalibrationState.PENDING;
  177 + if (screen.getFullScreenWindow() == calibrationFrame)
  178 + screen.setFullScreenWindow(null);
  179 + setVisible(false);
  180 + notifyListener(CalibrationEvent.ABORTED);
  181 + }
  182 + }
  183 + });
  184 + }
  185 +
  186 + private JLabel statusLabel(Icon icon, int id, int x, int y) {
  187 + JLabel l = new JLabel(icon, SwingConstants.LEFT);
  188 + if (wiimotes.size() > 1) l.setText(String.valueOf(id));
  189 + int w = 100;
  190 + int h = icon.getIconHeight();
  191 + x = x - icon.getIconWidth()/2;
  192 + y = y - wiimotes.size()*h/2;
  193 + l.setBounds(x, y + (id-1)*h, w, h);
  194 + return l;
  195 + }
  196 +
  197 + public void finished(CalibrationState s) {
  198 + int x = s.getX(bounds) - bounds.x;
  199 + int y = s.getY(bounds) - bounds.y;
  200 +
  201 + for (Wiimote wiimote : points.keySet()) {
  202 + add(statusLabel(points.get(wiimote).get(s) != null ? VISIBLE : NOT_VISIBLE, wiimote.getId(), x, y));
  203 + }
  204 +
  205 + repaint();
  206 + }
  207 +
  208 + public void reset() {
  209 + getContentPane().removeAll();
  210 + JLabel info = Util.newComponent(JLabel.class, "infoLabel");
  211 + info.setFont(info.getFont().deriveFont(20f));
  212 + info.setHorizontalAlignment(SwingConstants.CENTER);
  213 + int w = bounds.width;
  214 + int h = 200;
  215 + info.setBounds(bounds.width/2 - w/2, bounds.height/3 - h/2, w, h);
  216 + add(info);
  217 + Util.getResourceMap(WiimoteCalibration.class).injectComponents(this);
  218 + }
  219 +
  220 + @Override
  221 + public void paint(Graphics g) {
  222 + super.paint(g);
  223 + ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
  224 +
  225 + if (state != CalibrationState.DONE && state != CalibrationState.PENDING) {
  226 + int x = state.getX(bounds) - bounds.x;
  227 + int y = state.getY(bounds) - bounds.y;
  228 + g.drawImage(CROSS_HAIR, x - CROSS_HAIR.getWidth(null)/2 + 1, y - CROSS_HAIR.getHeight(null)/2 + 1, null);
  229 + }
  230 + }
  231 +
  232 + }
  233 +
  234 + public void start(Collection<Wiimote> wiimotes) {
  235 + last.clear();
  236 + points.clear();
  237 + finals.clear();
  238 + calibrationFrame.reset();
  239 + stepChange = false;
  240 + sc = 0;
  241 + checkPoints = false;
  242 + state = CalibrationState.PENDING.getNext();
  243 +
  244 + this.wiimotes = wiimotes;
  245 + for (Wiimote wiimote : wiimotes) {
  246 + points.put(wiimote, new LinkedHashMap<CalibrationState, Point2D>());
  247 + last.put(wiimote, new Point2D.Double(-1,-1));
  248 + }
  249 +
  250 + if (screen == null)
  251 + setScreen(DEFAULT_SCREEN);
  252 +
  253 + if (Util.MAC_OS_X && screen == DEFAULT_SCREEN)
  254 + screen.setFullScreenWindow(calibrationFrame);
  255 +
  256 + calibrationFrame.repaint();
  257 + calibrationFrame.setVisible(true);
  258 + notifyListener(CalibrationEvent.STARTED);
  259 + }
  260 +
  261 + public boolean inProgress() {
  262 + return !isPending() && !isDone();
  263 + }
  264 +
  265 + public boolean isPending() {
  266 + return state == CalibrationState.PENDING;
  267 + }
  268 +
  269 + public boolean isDone() {
  270 + return state == CalibrationState.DONE;
  271 + }
  272 +
  273 + public Map<String, Double[]> getFinals() {
  274 + return finals;
  275 + }
  276 +
  277 + public boolean isCalibrated(Wiimote wiimote) {
  278 + return transformer.containsKey(wiimote.getAddress());
  279 + }
  280 +
  281 + public boolean isAnyCalibrated(Collection<Wiimote> wiimotes) {
  282 + for (Wiimote wiimote : wiimotes) {
  283 + if (isCalibrated(wiimote))
  284 + return true;
  285 + }
  286 + return false;
  287 + }
  288 +
  289 + public boolean process(Map<Wiimote, IRDot[]> data) {
  290 +
  291 + if (inProgress()) {
  292 +
  293 + for (Wiimote wiimote : points.keySet()) {
  294 + Point2D lastP = last.get(wiimote);
  295 + Point2D currentP = data.get(wiimote)[0];
  296 +
  297 + if (currentP != null && lastP.distance(currentP) > EPS) {
  298 +
  299 + points.get(wiimote).put(state, currentP);
  300 + last.put(wiimote, currentP);
  301 + stepChange = true;
  302 + }
  303 + }
  304 +
  305 + // process at least 5 points to not miss a signal
  306 + if (stepChange && ++sc > 5) {
  307 + sc = 0;
  308 + stepChange = false;
  309 + CalibrationState current = state;
  310 + state = state.getNext();
  311 + calibrationFrame.finished(current);
  312 +
  313 + if (checkPoints || current == CalibrationState.REGULAR_END) {
  314 + checkPoints = true;
  315 + if (calculateQuadsForWiimotes()) {
  316 + // OK, calibration finished
  317 + state = CalibrationState.DONE;
  318 + calculateTransformation();
  319 + if (screen.getFullScreenWindow() == calibrationFrame)
  320 + screen.setFullScreenWindow(null);
  321 + calibrationFrame.setVisible(false);
  322 + notifyListener(CalibrationEvent.FINISHED);
  323 + return true;
  324 + } else {
  325 + // Go on
  326 + }
  327 + }
  328 + }
  329 +
  330 + if (state == CalibrationState.DONE) {
  331 + // PROBLEM, no solution found
  332 + state = CalibrationState.PENDING;
  333 + if (screen.getFullScreenWindow() == calibrationFrame)
  334 + screen.setFullScreenWindow(null);
  335 + calibrationFrame.setVisible(false);
  336 + notifyListener(CalibrationEvent.ABORTED);
  337 + new Thread(new Runnable() {
  338 + public void run() {
  339 + JOptionPane.showMessageDialog(null, Util.getResourceMap(WiimoteCalibration.class).getString("coverageError"), Util.getResourceMap(WiimoteCalibration.class).getString("calibrationFailed"), JOptionPane.ERROR_MESSAGE);
  340 + }
  341 + }).start();
  342 + }
  343 +
  344 + return true;
  345 + }
  346 +
  347 + return false;
  348 + }
  349 +
  350 + private static boolean checkExist(Map<CalibrationState, Point2D> p, CalibrationState... states) {
  351 + for (CalibrationState s : states) {
  352 + if (p.get(s) == null)
  353 + return false;
  354 + }
  355 + return true;
  356 + }
  357 +
  358 + private boolean calculateQuadsForWiimotes() {
  359 + boolean success = true;
  360 + Set<CalibrationState> check = new HashSet<CalibrationState>();
  361 +
  362 + for (Wiimote wiimote : points.keySet()) {
  363 + boolean ok = false;
  364 +
  365 + for (int i = 0; i < VALID_STATES.length; i++) {
  366 + if (checkExist(points.get(wiimote), VALID_STATES[i])) {
  367 + Map<CalibrationState, Point2D> calibrated = points.get(wiimote);
  368 + CalibrationState[] states = VALID_STATES[i];
  369 + check.addAll(Arrays.asList(states));
  370 + finals.put(wiimote.getAddress(), new Double[] {
  371 + calibrated.get(states[0]).getX(), calibrated.get(states[0]).getY(),
  372 + calibrated.get(states[1]).getX(), calibrated.get(states[1]).getY(),
  373 + calibrated.get(states[2]).getX(), calibrated.get(states[2]).getY(),
  374 + calibrated.get(states[3]).getX(), calibrated.get(states[3]).getY(),
  375 + (double)states[0].getX(bounds), (double)states[0].getY(bounds),
  376 + (double)states[1].getX(bounds), (double)states[1].getY(bounds),
  377 + (double)states[2].getX(bounds), (double)states[2].getY(bounds),
  378 + (double)states[3].getX(bounds), (double)states[3].getY(bounds)
  379 + });
  380 + ok = true;
  381 + break;
  382 + }
  383 + }
  384 +
  385 + success = success && ok;
  386 + }
  387 + // check also if the whole screen is covered
  388 + return success && check.containsAll(Arrays.asList(VALID_STATES[0]));
  389 + }
  390 +
  391 + private void calculateTransformation() {
  392 + transformer.clear();
  393 + for (String address : finals.keySet()) {
  394 + Double[] d = finals.get(address);
  395 + transformer.put(address, PerspectiveTransform.getQuadToQuad(d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]));
  396 + }
  397 + }
  398 +
  399 + public Map<String, PerspectiveTransform> getTransformer() {
  400 + return transformer;
  401 + }
  402 +
  403 + public IRDot warp(int i, Wiimote wiimote, Map<Wiimote, IRDot[]> data) {
  404 + final PerspectiveTransform transform = transformer.get(wiimote.getAddress());
  405 + if (transform == null || data.get(wiimote)[i] == null) return null;
  406 + else {
  407 + return (IRDot) transform.transform(data.get(wiimote)[i], new IRDot(data.get(wiimote)[i]));
  408 + }
  409 + }
  410 +
  411 + private Map<Wiimote, IRDot[]> warpIndividually(Map<Wiimote, IRDot[]> data) {
  412 + Map<Wiimote, IRDot[]> warped = new LinkedHashMap<Wiimote, IRDot[]>();
  413 + IRDot[] p;
  414 + for (Wiimote wiimote : data.keySet()) {
  415 + warped.put(wiimote, p = new IRDot[4]);
  416 + for (int i = 0; i < 4; i++) {
  417 + p[i] = warp(i, wiimote, data);
  418 + }
  419 + }
  420 + return warped;
  421 + }
  422 +
  423 + public Point[] warp(Map<Wiimote, IRDot[]> data) {
  424 + Point[] warped = new Point[4];
  425 + if (isDone() && isAnyCalibrated(data.keySet())) {
  426 + IRDot[][] cluster = PointClusterer.cluster(warpIndividually(data));
  427 +
  428 + for (int i = 0; i < cluster.length; i++) {
  429 + if (cluster[i] == null) break;
  430 + double x = 0, y = 0;
  431 + int c = 0;
  432 + for (IRDot p : cluster[i]) {
  433 + x += p.getX();
  434 + y += p.getY();
  435 + c++;
  436 + break;
  437 + }
  438 + warped[i] = new Point((int) Math.round(x / c), (int) Math.round(y / c));
  439 + }
  440 + } else {
  441 + System.err.println("Not calibrated.");
  442 + }
  443 + return warped;
  444 + }
  445 +
  446 +
  447 + public boolean load(InputStream is) throws IOException {
  448 + try {
  449 + BufferedReader in = new BufferedReader(new InputStreamReader(is));
  450 + String address = null;
  451 +
  452 + while ((address = in.readLine()) != null) {
  453 + Double[] d = new Double[16];
  454 + finals.put(address, d);
  455 + for (int i = 0; i < 4; i++) {
  456 + String[] p = in.readLine().split(" ");
  457 + for (int j = 0; j < 2; j++) {
  458 + d[i*2+j+0] = Double.valueOf(p[j+0]);
  459 + d[i*2+j+8] = Double.valueOf(p[j+2]);
  460 + }
  461 + }
  462 + }
  463 +
  464 + calculateTransformation();
  465 + state = CalibrationState.DONE;
  466 + notifyListener(CalibrationEvent.LOADED);
  467 + return true;
  468 +
  469 + } catch (Exception e) {
  470 + e.printStackTrace();
  471 + return false;
  472 + }
  473 + }
  474 +
  475 + public void save(OutputStream os) throws IOException {
  476 + PrintStream out = new PrintStream(os);
  477 +
  478 + for (String address : finals.keySet()) {
  479 + out.print(address);
  480 + Double[] d = finals.get(address);
  481 + for (int i = 0; i < 4; i++) {
  482 + out.printf(Locale.ENGLISH, "\n%f %f %.0f %.0f", d[i*2+0+0], d[i*2+1+0], d[i*2+0+8], d[i*2+1+8]);
  483 + }
  484 + out.println();
  485 + }
  486 + out.close();
  487 +
  488 + notifyListener(CalibrationEvent.SAVED);
  489 + }
  490 +
  491 +
  492 + /*
  493 + * LISTENER STUFF
  494 + */
  495 +
  496 + public void addCalibrationEventListener(CalibrationEventListener l) {
  497 + listener.add(l);
  498 + }
  499 +
  500 + public void removeCalibrationEventListener(CalibrationEventListener l) {
  501 + listener.remove(l);
  502 + }
  503 +
  504 + private void notifyListener(CalibrationEvent e) {
  505 + WiimoteWhiteboard.getLogger().info("Calibration Event: " + e);
  506 + for (CalibrationEventListener l : listener) {
  507 + l.calibrationEvent(e);
  508 + }
  509 + }
  510 +
  511 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/resources/WiimoteCalibration.properties 0 → 100644
... ... @@ -0,0 +1,4 @@
  1 +infoLabel.text = <html><center>Press ESC to abort calibration.<br><br>Make sure all connected Wiimotes can see the screen.</center></html>
  2 +
  3 +calibrationFailed = Calibration failed
  4 +coverageError = The Wiimotes don't seem to cover the whole screen.${nl}Try to reposition them and start again.
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/resources/WiimoteCalibration_de.properties 0 → 100644
... ... @@ -0,0 +1,8 @@
  1 +#:1265226421,Uwe
  2 +
  3 +infoLabel.text=<html><center>Dr\u00fccke ESC um die Kalibrierung abzubrechen.<br><br>Achte darauf dass alle Wiimotes den Bildschirm gut sehen k\u00f6nnen.</center></html>
  4 +
  5 +calibrationFailed=Kalibrierung fehlgeschlagen
  6 +
  7 +coverageError=Die Wiimotes scheinen nicht den gesamten Bildschirm abzudecken.${nl}Versuche sie neu zu positionieren und starte dann nochmal.
  8 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/resources/WiimoteCalibration_es.properties 0 → 100644
... ... @@ -0,0 +1,8 @@
  1 +#:1224248803,Uwe
  2 +
  3 +infoLabel.text=<html><center>Oprime ESC para cancelar calibraci\u00f3n.<br><br>Aseg\u00farese de que todos los Wiimotes puedan ver la pantalla.</center></html>
  4 +
  5 +calibrationFailed=La calibraci\u00f3n fallo
  6 +
  7 +coverageError=Los Wiimotes no parecen cubrir la pantalla entera.${nl}Cambien la posici\u00f3n de los Wiimotes y reinicie la calibraci\u00f3n.
  8 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/resources/WiimoteCalibration_et.properties 0 → 100644
... ... @@ -0,0 +1,8 @@
  1 +#:1248454359,Marko
  2 +
  3 +infoLabel.text=<html><center>Vajuta ESC klahvi kui soovid kalibreerimist katkestada.<br><br>Veendu, et k\u00f5ik Wii puldid n\u00e4evad kogu ekraani.</center></html>
  4 +
  5 +calibrationFailed=Kalibreerimine eba\u00f5nnestus
  6 +
  7 +coverageError=K\u00f5ik Wii puldid ei n\u00e4e kogu ekraani.${nl}Proovi pultide asendit korrigeerida ning alusta kalibreerimist uuesti.
  8 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/resources/WiimoteCalibration_fr.properties 0 → 100644
... ... @@ -0,0 +1,8 @@
  1 +#:1265226429,Uwe
  2 +
  3 +infoLabel.text=<html><center>Presser ESC pour annuler la calibration.<br><br>V\u00e9rifier que toutes les Wiimotes connect\u00e9s peuvent capter l'\u00e9cran.</center></html>
  4 +
  5 +calibrationFailed=La calibration a \u00e9chou\u00e9
  6 +
  7 +coverageError=Les Wiimotes ne semblent pas capter la totalit\u00e9 de l'\u00e9cran.${nl}Essayer de les placer mieux et red\u00e9marrer la calibration.
  8 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/resources/WiimoteCalibration_in.properties 0 → 100644
... ... @@ -0,0 +1,8 @@
  1 +#:1274618479,Bobby
  2 +
  3 +infoLabel.text=<html><center>Tekan ESC untuk membatalkan Kalibrasi.<br><br>Pastikan semua Wiimotes yang terhubung dapat melihat layar.</center></html>
  4 +
  5 +calibrationFailed=Kalibrasi gagal
  6 +
  7 +coverageError=Wiimotes nampaknya tidak dapat melihat keseluruhan layar.${nl}Coba ubah posisinya dan mulai lagi dari awal.
  8 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/resources/WiimoteCalibration_it.properties 0 → 100644
... ... @@ -0,0 +1,8 @@
  1 +#:1240167662,Uwe
  2 +
  3 +infoLabel.text=<html><center>Premi ESC per interrompere la calibrazione.<br><br>Assicurati che tutti i Wiimote connessi possano "vedere" lo schermo.</center></html>
  4 +
  5 +calibrationFailed=Calibrazione fallita
  6 +
  7 +coverageError=Il Wiimote non sembra coprire l'intero schermo.${nl}Prova a riposizionarlo, e ritenta.
  8 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/resources/WiimoteCalibration_pl.properties 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +#:1253207960,Grzegorz
  2 +
  3 +# Wiimote = Wiilot in Polish
  4 +infoLabel.text=<html><center>Naci\u015bnij ESC aby przerwa\u0107 kalibracj\u0119.<br><br>Sprawd\u017a czy wszystkie pod\u0142\u0105czone Wiiloty widz\u0105 ekran.</center></html>
  5 +
  6 +calibrationFailed=Kalibracja nie powiod\u0142a si\u0119
  7 +
  8 +coverageError=Wiiloty nie obejmuj\u0105 ca\u0142ego ekranu. Zmie\u0144 ich pozycj\u0119 i spr\u00f3buj ponownie.
  9 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/resources/WiimoteCalibration_pt.properties 0 → 100644
... ... @@ -0,0 +1,8 @@
  1 +#:1224248742,Uwe
  2 +
  3 +infoLabel.text=<html><center>Pressione ESC para abortar a calibra\u00e7\u00e3o.<br><br>Certifique-se que todos os Wiimotes conseguem ver o ecr\u00e3.</center></html>
  4 +
  5 +calibrationFailed=Calibra\u00e7\u00e3o n\u00e3o efectuada
  6 +
  7 +coverageError=Os Wiimotes parecem n\u00e3o abranger toda a \u00e1rea do ecr\u00e3.${nl}Tente outra posi\u00e7\u00e3o e recomece.
  8 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/resources/WiimoteCalibration_ru.properties 0 → 100644
... ... @@ -0,0 +1,8 @@
  1 +#:1265227045,Uwe
  2 +
  3 +infoLabel.text=<html><center>\u041d\u0430\u0436\u043c\u0438\u0442\u0435 ESC \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0435\u0440\u0432\u0430\u0442\u044c \u043a\u0430\u043b\u0438\u0431\u0440\u043e\u0432\u043a\u0443.<br><br>\u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0432\u0441\u0435 \u043f\u0440\u0438\u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u043d\u044b\u0435 Wiimot'\u044b \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u044b \u043d\u0430 \u044d\u043a\u0440\u0430\u043d.</center></html>
  4 +
  5 +calibrationFailed=\u041a\u0430\u043b\u0438\u0431\u0440\u043e\u0432\u043a\u0430 \u043d\u0435 \u0443\u0434\u0430\u043b\u0430\u0441\u044c
  6 +
  7 +coverageError=Wiimote \u043d\u0435 \u0432\u0438\u0434\u0438\u0442 \u0432\u0435\u0441\u044c \u044d\u043a\u0440\u0430\u043d \u0446\u0435\u043b\u0438\u043a\u043e\u043c.${nl}\u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u0435\u0433\u043e \u0438 \u043d\u0430\u0447\u043d\u0438\u0442\u0435 \u043a\u0430\u043b\u0438\u0431\u0440\u043e\u0432\u043a\u0443 \u0441\u043d\u043e\u0432\u0430.
  8 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/resources/WiimoteCalibration_sl.properties 0 → 100644
... ... @@ -0,0 +1,8 @@
  1 +#:1238601406,Samo
  2 +
  3 +infoLabel.text=<html><center>\u010ce \u017eelite prekiniti kalibracijo, pritisnite tipko ESC.<br><br>Poskrbite, da bodo vsi priklu\u010deni Wiimoti videli ekran ali projekcijsko povr\u0161ino.</center></html>
  4 +
  5 +calibrationFailed=Povezava ni uspela
  6 +
  7 +coverageError=Senzorji Wiimotov ne zaznavajo celotnega ekrana ali projekcijske povr\u0161ine. ${nl}Postavite jih druga\u010de in poskusite znova.
  8 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/resources/icons/francisco-crosshair.png 0 → 100644

3.54 KB

WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/resources/icons/francisco-ok.png 0 → 100644

4.32 KB

WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/resources/icons/francisco-warning.png 0 → 100644

3.66 KB

WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/resources/icons/ok.png 0 → 100644

1019 Bytes

WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/calibration/resources/icons/warning.png 0 → 100644

1.19 KB

WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/ds/IRDot.java 0 → 100644
... ... @@ -0,0 +1,47 @@
  1 +package org.mote.wiimote.whiteboard.ds;
  2 +
  3 +import java.awt.geom.Point2D;
  4 +
  5 +import wiiremotej.IRLight;
  6 +
  7 +public class IRDot extends Point2D.Double {
  8 +
  9 + private final int id;
  10 + private double size;
  11 +
  12 + public IRDot(int id, double x, double y, double size) {
  13 + super(x, y);
  14 + this.id = id;
  15 + this.size = size;
  16 + }
  17 +
  18 + public IRDot(IRDot dot) {
  19 + this(dot.getId(), dot.getX(), dot.getY(), dot.getSize());
  20 + }
  21 +
  22 + public IRDot(int id, IRLight light) {
  23 + this(id, light.getX(), light.getY(), light.getSize());
  24 + }
  25 +
  26 + @Override
  27 + public String toString() {
  28 + return String.format("[Dot%d: x = %.2f, y = %.2f, s = %.2f]", id, x, y, size);
  29 + }
  30 +
  31 + public double getSize() {
  32 + return size;
  33 + }
  34 +
  35 + public int getId() {
  36 + return id;
  37 + }
  38 +
  39 + public static IRDot[] getIRDots(IRLight[] lights) {
  40 + IRDot[] dots = new IRDot[lights.length];
  41 + for (int i = 0; i < lights.length; i++) {
  42 + dots[i] = lights[i] == null ? null : new IRDot(i, lights[i]);
  43 + }
  44 + return dots;
  45 + }
  46 +
  47 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/ds/IRDot.java~ 0 → 100644
... ... @@ -0,0 +1,72 @@
  1 +/*
  2 + * Copyright (C) 2008-2009, Uwe Schmidt
  3 + *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a
  5 + * copy of this software and associated documentation files (the "Software"),
  6 + * to deal in the Software without restriction, including without limitation
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8 + * and/or sell copies of the Software, and to permit persons to whom the
  9 + * Software is furnished to do so, subject to the following conditions:
  10 + *
  11 + * The above copyright notice and this permission notice shall be included in
  12 + * all copies or substantial portions of the Software.
  13 + *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20 + * DEALINGS IN THE SOFTWARE.
  21 + *
  22 + * The Software uses a third-party library (WiiRemoteJ) which is not part of
  23 + * the Software and is subject to its own license.
  24 + */
  25 +
  26 +package org.uweschmidt.wiimote.whiteboard.ds;
  27 +
  28 +import java.awt.geom.Point2D;
  29 +
  30 +import wiiremotej.IRLight;
  31 +
  32 +public class IRDot extends Point2D.Double {
  33 +
  34 + private final int id;
  35 + private double size;
  36 +
  37 + public IRDot(int id, double x, double y, double size) {
  38 + super(x, y);
  39 + this.id = id;
  40 + this.size = size;
  41 + }
  42 +
  43 + public IRDot(IRDot dot) {
  44 + this(dot.getId(), dot.getX(), dot.getY(), dot.getSize());
  45 + }
  46 +
  47 + public IRDot(int id, IRLight light) {
  48 + this(id, light.getX(), light.getY(), light.getSize());
  49 + }
  50 +
  51 + @Override
  52 + public String toString() {
  53 + return String.format("[Dot%d: x = %.2f, y = %.2f, s = %.2f]", id, x, y, size);
  54 + }
  55 +
  56 + public double getSize() {
  57 + return size;
  58 + }
  59 +
  60 + public int getId() {
  61 + return id;
  62 + }
  63 +
  64 + public static IRDot[] getIRDots(IRLight[] lights) {
  65 + IRDot[] dots = new IRDot[lights.length];
  66 + for (int i = 0; i < lights.length; i++) {
  67 + dots[i] = lights[i] == null ? null : new IRDot(i, lights[i]);
  68 + }
  69 + return dots;
  70 + }
  71 +
  72 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/ds/Wiimote.java 0 → 100644
... ... @@ -0,0 +1,23 @@
  1 +package org.mote.wiimote.whiteboard.ds;
  2 +
  3 +import wiiremotej.WiiRemote;
  4 +
  5 +public class Wiimote {
  6 + private final WiiRemote wiiremote;
  7 + private final String address;
  8 + private final int id;
  9 + public Wiimote(WiiRemote wiiremote, String address, int id) {
  10 + this.wiiremote = wiiremote;
  11 + this.address = address;
  12 + this.id = id;
  13 + }
  14 + public WiiRemote getWiiRemote() {
  15 + return wiiremote;
  16 + }
  17 + public String getAddress() {
  18 + return address;
  19 + }
  20 + public int getId() {
  21 + return id;
  22 + }
  23 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/ds/Wiimote.java~ 0 → 100644
... ... @@ -0,0 +1,48 @@
  1 +/*
  2 + * Copyright (C) 2008-2009, Uwe Schmidt
  3 + *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a
  5 + * copy of this software and associated documentation files (the "Software"),
  6 + * to deal in the Software without restriction, including without limitation
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8 + * and/or sell copies of the Software, and to permit persons to whom the
  9 + * Software is furnished to do so, subject to the following conditions:
  10 + *
  11 + * The above copyright notice and this permission notice shall be included in
  12 + * all copies or substantial portions of the Software.
  13 + *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20 + * DEALINGS IN THE SOFTWARE.
  21 + *
  22 + * The Software uses a third-party library (WiiRemoteJ) which is not part of
  23 + * the Software and is subject to its own license.
  24 + */
  25 +
  26 +package org.uweschmidt.wiimote.whiteboard.ds;
  27 +
  28 +import wiiremotej.WiiRemote;
  29 +
  30 +public class Wiimote {
  31 + private final WiiRemote wiiremote;
  32 + private final String address;
  33 + private final int id;
  34 + public Wiimote(WiiRemote wiiremote, String address, int id) {
  35 + this.wiiremote = wiiremote;
  36 + this.address = address;
  37 + this.id = id;
  38 + }
  39 + public WiiRemote getWiiRemote() {
  40 + return wiiremote;
  41 + }
  42 + public String getAddress() {
  43 + return address;
  44 + }
  45 + public int getId() {
  46 + return id;
  47 + }
  48 +}
0 49 \ No newline at end of file
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/AboutWindow.java 0 → 100644
... ... @@ -0,0 +1,72 @@
  1 +package org.mote.wiimote.whiteboard.gui;
  2 +
  3 +import java.awt.BorderLayout;
  4 +import java.awt.Font;
  5 +import java.net.URL;
  6 +
  7 +import javax.swing.JDialog;
  8 +import javax.swing.JEditorPane;
  9 +import javax.swing.JLabel;
  10 +import javax.swing.JPanel;
  11 +import javax.swing.JScrollPane;
  12 +import javax.swing.event.HyperlinkEvent;
  13 +import javax.swing.event.HyperlinkListener;
  14 +
  15 +import net.miginfocom.swing.MigLayout;
  16 +
  17 +import org.jdesktop.application.Action;
  18 +import org.jdesktop.application.Application;
  19 +import org.mote.wiimote.whiteboard.WiimoteWhiteboard;
  20 +import org.mote.wiimote.whiteboard.util.BareBonesBrowserLaunch;
  21 +import org.mote.wiimote.whiteboard.util.Util;
  22 +
  23 +@SuppressWarnings("serial")
  24 +public class AboutWindow extends JDialog implements HyperlinkListener {
  25 +
  26 + public AboutWindow() {
  27 + super(Application.getInstance(WiimoteWhiteboard.class).getMainFrame());
  28 + if (!Util.INSIDE_APP_BUNDLE) {
  29 + setName("aboutWindow");
  30 + setLayout(new BorderLayout());
  31 + final JPanel appPane = Util.newComponent(JPanel.class, "appPane");
  32 + add(appPane, BorderLayout.NORTH);
  33 + appPane.setLayout(new MigLayout("insets i", "[center|center]"));
  34 +
  35 + JLabel appLabel = new JLabel(String.format("%s %s", WiimoteWhiteboard.getProperty("id"), WiimoteWhiteboard.getProperty("version")));
  36 + appLabel.setFont(appLabel.getFont().deriveFont(Font.BOLD, 14f));
  37 + JLabel crLabel = new JLabel(Util.getResourceMap(AboutWindow.class).getString("copyRight", WiimoteWhiteboard.getProperty("year"), WiimoteWhiteboard.getProperty("author")));
  38 + crLabel.setFont(appLabel.getFont().deriveFont(10f));
  39 +
  40 + appPane.add(appLabel, "flowy, split 2");
  41 + appPane.add(crLabel, "");
  42 + appPane.add(new JLabel(Util.getResourceMap(WiimoteWhiteboard.class).getImageIcon("icon")), "flowx, wrap");
  43 +
  44 + try {
  45 +
  46 + JEditorPane tp = Util.newComponent(JEditorPane.class, "infoPane");
  47 + tp.addHyperlinkListener(this);
  48 +
  49 + add(new JScrollPane(tp), BorderLayout.CENTER);
  50 +
  51 + Util.getResourceMap(AboutWindow.class).injectComponents(this);
  52 +
  53 + setResizable(false);
  54 + Util.placeDialogWindow(this, 295, 348);
  55 + } catch (Exception e) {
  56 + e.printStackTrace();
  57 + }
  58 + }
  59 + }
  60 +
  61 + public void hyperlinkUpdate(HyperlinkEvent e) {
  62 + if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
  63 +
  64 + }
  65 + }
  66 +
  67 + @Action
  68 + public void about() {
  69 + setVisible(true);
  70 + }
  71 +
  72 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/AboutWindow.java~ 0 → 100644
... ... @@ -0,0 +1,72 @@
  1 +package org.mote.wiimote.whiteboard.gui;
  2 +
  3 +import java.awt.BorderLayout;
  4 +import java.awt.Font;
  5 +import java.net.URL;
  6 +
  7 +import javax.swing.JDialog;
  8 +import javax.swing.JEditorPane;
  9 +import javax.swing.JLabel;
  10 +import javax.swing.JPanel;
  11 +import javax.swing.JScrollPane;
  12 +import javax.swing.event.HyperlinkEvent;
  13 +import javax.swing.event.HyperlinkListener;
  14 +
  15 +import net.miginfocom.swing.MigLayout;
  16 +
  17 +import org.jdesktop.application.Action;
  18 +import org.jdesktop.application.Application;
  19 +import org.mote.wiimote.whiteboard.WiimoteWhiteboard;
  20 +import org.mote.wiimote.whiteboard.util.BareBonesBrowserLaunch;
  21 +import org.mote.wiimote.whiteboard.util.Util;
  22 +
  23 +@SuppressWarnings("serial")
  24 +public class AboutWindow extends JDialog implements HyperlinkListener {
  25 +
  26 + public AboutWindow() {
  27 + super(Application.getInstance(WiimoteWhiteboard.class).getMainFrame());
  28 + if (!Util.INSIDE_APP_BUNDLE) {
  29 + setName("aboutWindow");
  30 + setLayout(new BorderLayout());
  31 + final JPanel appPane = Util.newComponent(JPanel.class, "appPane");
  32 + add(appPane, BorderLayout.NORTH);
  33 + appPane.setLayout(new MigLayout("insets i", "[center|center]"));
  34 +
  35 + JLabel appLabel = new JLabel(String.format("%s %s", WiimoteWhiteboard.getProperty("id"), WiimoteWhiteboard.getProperty("version")));
  36 + appLabel.setFont(appLabel.getFont().deriveFont(Font.BOLD, 14f));
  37 + JLabel crLabel = new JLabel(Util.getResourceMap(AboutWindow.class).getString("copyRight", WiimoteWhiteboard.getProperty("year"), WiimoteWhiteboard.getProperty("author")));
  38 + crLabel.setFont(appLabel.getFont().deriveFont(10f));
  39 +
  40 + appPane.add(appLabel, "flowy, split 2");
  41 + appPane.add(crLabel, "");
  42 + appPane.add(new JLabel(Util.getResourceMap(WiimoteWhiteboard.class).getImageIcon("icon")), "flowx, wrap");
  43 +
  44 + try {
  45 + URL url = AboutWindow.class.getResource("resources/Credits.html");
  46 + JEditorPane tp = Util.newComponent(JEditorPane.class, "infoPane");
  47 + tp.addHyperlinkListener(this);
  48 + tp.setPage(url);
  49 + add(new JScrollPane(tp), BorderLayout.CENTER);
  50 +
  51 + Util.getResourceMap(AboutWindow.class).injectComponents(this);
  52 +
  53 + setResizable(false);
  54 + Util.placeDialogWindow(this, 295, 348);
  55 + } catch (Exception e) {
  56 + e.printStackTrace();
  57 + }
  58 + }
  59 + }
  60 +
  61 + public void hyperlinkUpdate(HyperlinkEvent e) {
  62 + if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
  63 + BareBonesBrowserLaunch.openURL(e.getURL().toString());
  64 + }
  65 + }
  66 +
  67 + @Action
  68 + public void about() {
  69 + setVisible(true);
  70 + }
  71 +
  72 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/CalibrationInfoWindow.java 0 → 100644
... ... @@ -0,0 +1,267 @@
  1 +package org.mote.wiimote.whiteboard.gui;
  2 +
  3 +import java.awt.Color;
  4 +import java.awt.Graphics;
  5 +import java.awt.Graphics2D;
  6 +import java.awt.Point;
  7 +import java.awt.RenderingHints;
  8 +import java.awt.SystemColor;
  9 +import java.awt.event.ComponentAdapter;
  10 +import java.awt.event.ComponentEvent;
  11 +import java.awt.event.KeyAdapter;
  12 +import java.awt.event.KeyEvent;
  13 +import java.util.Map;
  14 +import java.util.Timer;
  15 +import java.util.TimerTask;
  16 +
  17 +import javax.swing.BorderFactory;
  18 +import javax.swing.JDialog;
  19 +import javax.swing.JLabel;
  20 +import javax.swing.JPanel;
  21 +import javax.swing.JProgressBar;
  22 +
  23 +import net.miginfocom.swing.MigLayout;
  24 +
  25 +import org.jdesktop.application.Action;
  26 +import org.jdesktop.application.Application;
  27 +import org.mote.wiimote.whiteboard.WiimoteDataHandler;
  28 +import org.mote.wiimote.whiteboard.WiimoteWhiteboard;
  29 +import org.mote.wiimote.whiteboard.WiimoteDataHandler.WiimoteDataListener;
  30 +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration;
  31 +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration.CalibrationEvent;
  32 +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration.CalibrationEventListener;
  33 +import org.mote.wiimote.whiteboard.ds.IRDot;
  34 +import org.mote.wiimote.whiteboard.ds.Wiimote;
  35 +import org.mote.wiimote.whiteboard.preferences.WWPreferences;
  36 +import org.mote.wiimote.whiteboard.util.Util;
  37 +
  38 +@SuppressWarnings("serial")
  39 +public class CalibrationInfoWindow extends JDialog implements CalibrationEventListener, WiimoteDataListener {
  40 +
  41 + private static class WiimoteWrapper {
  42 + @SuppressWarnings("unused")
  43 + private int idx;
  44 + private JPanel panel;
  45 + private WiimoteIcon icon;
  46 + private JProgressBar trackingUtility;
  47 + private Double d[];
  48 + private IRDot[] lights = new IRDot[4];
  49 + private void setVisible(boolean visible) {
  50 + panel.setVisible(visible);
  51 + icon.setVisible(visible);
  52 + trackingUtility.setVisible(visible);
  53 + }
  54 + }
  55 +
  56 + private static final long REPAINT_FREQ = 1000 / 25;
  57 +
  58 + private static final Color CALIBRATED_COLOR = SystemColor.textHighlight;
  59 + private static final Color TRACKING_COLOR = SystemColor.text;
  60 +
  61 + private static final Color COLORS[] = {Color.blue, Color.red, Color.green, Color.orange, Color.black, Color.cyan, Color.magenta, Color.pink};
  62 +
  63 + private WiimoteWrapper ww[] = new WiimoteWrapper[WWPreferences.WIIMOTES];
  64 + private WiimoteCalibration calibration;
  65 + private WiimoteDataHandler dh;
  66 + private boolean calibrated = false;
  67 +
  68 +// private Matrix F;
  69 +
  70 +
  71 + public CalibrationInfoWindow(WiimoteCalibration calibration, WiimoteDataHandler dh) {
  72 + super(Application.getInstance(WiimoteWhiteboard.class).getMainFrame(), Util.getResourceMap(CalibrationInfoWindow.class).getString("info.Action.text"));
  73 + getRootPane().putClientProperty("Window.style", "small");
  74 + this.calibration = calibration;
  75 + this.dh = dh;
  76 + calibration.addCalibrationEventListener(this);
  77 + dh.addWiimoteDataListener(this);
  78 + setLayout(new MigLayout("hidemode 3"));
  79 + // info labels
  80 + final JLabel taLabel = Util.newComponent(JLabel.class, "trackingAreaLabel");
  81 + final JLabel csLabel = Util.newComponent(JLabel.class, "calibratedScreenLabel");
  82 + taLabel.setBorder(BorderFactory.createLineBorder(Color.lightGray));
  83 + csLabel.setBorder(BorderFactory.createLineBorder(Color.lightGray));
  84 + taLabel.setBackground(TRACKING_COLOR);
  85 + csLabel.setBackground(CALIBRATED_COLOR);
  86 + taLabel.setForeground(SystemColor.textText);
  87 + csLabel.setForeground(SystemColor.textHighlightText);
  88 + add(taLabel, "sg 1, split, span, growx, pushx");
  89 + add(csLabel, "sg 1, gapbefore 0, growx, pushx, wrap");
  90 +
  91 + for (int i = 0; i < ww.length; i++) {
  92 + ww[i] = new WiimoteWrapper();
  93 + ww[i].idx = i;
  94 + ww[i].icon = new WiimoteIcon(i+1);
  95 + ww[i].icon.displayConnected(true);
  96 + add(ww[i].panel = new InfoPanel(ww[i]), "flowy, w 400, h 300, grow, push");
  97 + add(ww[i].icon, "cell "+i+" 1, growx, pushx");
  98 + add(ww[i].trackingUtility = Util.newComponent(JProgressBar.class, "trackingUtility"), "cell "+i+" 1, growx, pushx");
  99 + ww[i].setVisible(i == 0);
  100 + }
  101 +
  102 + addKeyListener(new KeyAdapter() {
  103 + @Override
  104 + public void keyPressed(KeyEvent e) {
  105 + if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
  106 + setVisible(false);
  107 + }
  108 + }
  109 + });
  110 +
  111 + addComponentListener(new ComponentAdapter() {
  112 + @Override
  113 + public void componentMoved(ComponentEvent e) {
  114 + componentResized(null);
  115 + }
  116 + @Override
  117 + public void componentResized(ComponentEvent e) {
  118 + repaintPanels();
  119 + }
  120 + });
  121 +
  122 +
  123 + Util.getResourceMap(CalibrationInfoWindow.class).injectComponents(this);
  124 + pack();
  125 + Util.placeDialogWindow(this, getWidth(), getHeight());
  126 + new Timer(true).schedule(new UpdateTask(), 0, REPAINT_FREQ);
  127 + }
  128 +
  129 + private class UpdateTask extends TimerTask {
  130 + @Override
  131 + public void run() {
  132 + if (isVisible()) {
  133 + repaintPanels();
  134 + }
  135 + }
  136 + }
  137 +
  138 + private void repaintPanels() {
  139 + for (WiimoteWrapper wrapper : ww) {
  140 + if (wrapper.panel.isVisible())
  141 + wrapper.panel.repaint();
  142 + }
  143 + }
  144 +
  145 + @Action(enabledProperty="calibrated")
  146 + public void info() {
  147 + setVisible(true);
  148 + }
  149 +
  150 + public boolean isCalibrated() {
  151 + return calibrated;
  152 + }
  153 +
  154 + private void updateCalibrated() {
  155 + final boolean old = calibrated;
  156 + calibrated = dh.isConnected() && calibration.isDone() && calibration.isAnyCalibrated(dh.getConnectedWiimotes());
  157 + firePropertyChange("calibrated", old, calibrated);
  158 + }
  159 +
  160 + public void calibrationEvent(CalibrationEvent e) {
  161 + switch (e) {
  162 + case LOADED:
  163 + update();
  164 + case FINISHED:
  165 + update();
  166 + break;
  167 + case SCREEN_CHANGED:
  168 + case STARTED:
  169 + case ABORTED:
  170 + case SAVED:
  171 + }
  172 + updateCalibrated();
  173 + if (!isCalibrated())
  174 + setVisible(false);
  175 + }
  176 +
  177 + public void batteryLevel(Wiimote wiimote, double level) {}
  178 + public void irLights(Wiimote wiimote, IRDot[] lights) {
  179 + ww[wiimote.getId()-1].lights = lights;
  180 + }
  181 + public void irWarped(Map<Wiimote, IRDot[]> data, Point[] warped) {}
  182 + public void wiimoteConnected(Wiimote wiimote) {
  183 + update();
  184 + updateCalibrated();
  185 + }
  186 + public void wiimoteDisconnected(Wiimote wiimote) {}
  187 +
  188 + private int r(double d) {
  189 + return (int)Math.round(d);
  190 + }
  191 +
  192 + private void update() {
  193 + Map<String, Double[]> finals = calibration.getFinals();
  194 +
  195 +
  196 +
  197 + for (Wiimote wiimote : dh.getConnectedWiimotes()) {
  198 + WiimoteWrapper w = ww[wiimote.getId()-1];
  199 + if (!calibration.isCalibrated(wiimote)) continue;
  200 +
  201 + w.d = finals.get(wiimote.getAddress());
  202 +
  203 + double x0 = w.d[0]*1024, y0 = w.d[1]*768;
  204 + double x1 = w.d[2]*1024, y1 = w.d[3]*768;
  205 + double x3 = w.d[4]*1024, y3 = w.d[5]*768;
  206 + double x2 = w.d[6]*1024, y2 = w.d[7]*768;
  207 + double idealArea = 0.8 * 1024 * 0.8 * 768;
  208 + double calibratedArea = 0.5 * (Math.abs(
  209 + (x1 - x2) * (y0 - y3) - (x0 - x3) * (y1 - y2)
  210 + ));
  211 +
  212 + w.trackingUtility.setValue(r(calibratedArea));
  213 + w.trackingUtility.setString(Util.getResourceMap(CalibrationInfoWindow.class).getString("trackingUtilString", 100 * (calibratedArea / idealArea)));
  214 +
  215 + if (!w.panel.isVisible()) {
  216 + w.setVisible(true);
  217 + pack();
  218 + Util.placeDialogWindow(this, getWidth(), getHeight());
  219 + }
  220 + }
  221 + repaintPanels();
  222 + }
  223 +
  224 + private class InfoPanel extends JPanel {
  225 + private static final int DIAMETER = 6;
  226 + private WiimoteWrapper wrapper;
  227 + public InfoPanel(WiimoteWrapper wrapper) {
  228 + this.wrapper = wrapper;
  229 + setLayout(null);
  230 + setOpaque(true);
  231 + setBackground(TRACKING_COLOR);
  232 + setBorder(BorderFactory.createLineBorder(SystemColor.lightGray));
  233 + }
  234 + @Override
  235 + protected void paintComponent(Graphics g) {
  236 + super.paintComponent(g);
  237 + if (wrapper.d != null) {
  238 + Graphics2D g2d = (Graphics2D)g;
  239 + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
  240 + final int w = getWidth();
  241 + final int h = getHeight();
  242 + int x[] = new int[5], y[] = new int[5];
  243 + for (int i = 0; i < 4; i++) {
  244 + x[i] = r(wrapper.d[2*i]*w);
  245 + y[i] = r(h-wrapper.d[2*i+1]*h);
  246 + }
  247 + x[4] = x[0]; y[4] = y[0];
  248 +
  249 + g2d.setColor(CALIBRATED_COLOR);
  250 + g2d.fillPolygon(x, y, 5);
  251 +
  252 +
  253 + for (int i = 0; i < 4; i++) {
  254 + IRDot dot = wrapper.lights[i];
  255 + if (dot != null) {
  256 + g2d.setColor(COLORS[i]);
  257 +
  258 + g2d.fillOval(r(w*dot.x)-DIAMETER/2, r(h-h*dot.y)-DIAMETER/2, DIAMETER, DIAMETER);
  259 +
  260 + }
  261 + }
  262 + }
  263 + }
  264 + }
  265 +
  266 +
  267 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/CalibrationInfoWindow.java~ 0 → 100644
... ... @@ -0,0 +1,267 @@
  1 +package org.mote.wiimote.whiteboard.gui;
  2 +
  3 +import java.awt.Color;
  4 +import java.awt.Graphics;
  5 +import java.awt.Graphics2D;
  6 +import java.awt.Point;
  7 +import java.awt.RenderingHints;
  8 +import java.awt.SystemColor;
  9 +import java.awt.event.ComponentAdapter;
  10 +import java.awt.event.ComponentEvent;
  11 +import java.awt.event.KeyAdapter;
  12 +import java.awt.event.KeyEvent;
  13 +import java.util.Map;
  14 +import java.util.Timer;
  15 +import java.util.TimerTask;
  16 +
  17 +import javax.swing.BorderFactory;
  18 +import javax.swing.JDialog;
  19 +import javax.swing.JLabel;
  20 +import javax.swing.JPanel;
  21 +import javax.swing.JProgressBar;
  22 +
  23 +import net.miginfocom.swing.MigLayout;
  24 +
  25 +import org.jdesktop.application.Action;
  26 +import org.jdesktop.application.Application;
  27 +import org.mote.wiimote.whiteboard.WiimoteDataHandler;
  28 +import org.mote.wiimote.whiteboard.WiimoteWhiteboard;
  29 +import org.mote.wiimote.whiteboard.WiimoteDataHandler.WiimoteDataListener;
  30 +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration;
  31 +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration.CalibrationEvent;
  32 +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration.CalibrationEventListener;
  33 +import org.mote.wiimote.whiteboard.ds.IRDot;
  34 +import org.mote.wiimote.whiteboard.ds.Wiimote;
  35 +import org.mote.wiimote.whiteboard.preferences.WWPreferences;
  36 +import org.mote.wiimote.whiteboard.util.Util;
  37 +
  38 +@SuppressWarnings("serial")
  39 +public class CalibrationInfoWindow extends JDialog implements CalibrationEventListener, WiimoteDataListener {
  40 +
  41 + private static class WiimoteWrapper {
  42 + @SuppressWarnings("unused")
  43 + private int idx;
  44 + private JPanel panel;
  45 + private WiimoteIcon icon;
  46 + private JProgressBar trackingUtility;
  47 + private Double d[];
  48 + private IRDot[] lights = new IRDot[4];
  49 + private void setVisible(boolean visible) {
  50 + panel.setVisible(visible);
  51 + icon.setVisible(visible);
  52 + trackingUtility.setVisible(visible);
  53 + }
  54 + }
  55 +
  56 + private static final long REPAINT_FREQ = 1000 / 25;
  57 +
  58 + private static final Color CALIBRATED_COLOR = SystemColor.textHighlight;
  59 + private static final Color TRACKING_COLOR = SystemColor.text;
  60 +
  61 + private static final Color COLORS[] = {Color.blue, Color.red, Color.green, Color.orange, Color.black, Color.cyan, Color.magenta, Color.pink};
  62 +
  63 + private WiimoteWrapper ww[] = new WiimoteWrapper[WWPreferences.WIIMOTES];
  64 + private WiimoteCalibration calibration;
  65 + private WiimoteDataHandler dh;
  66 + private boolean calibrated = false;
  67 +
  68 +// private Matrix F;
  69 +
  70 +
  71 + public CalibrationInfoWindow(WiimoteCalibration calibration, WiimoteDataHandler dh) {
  72 + super(Application.getInstance(WiimoteWhiteboard.class).getMainFrame(), Util.getResourceMap(CalibrationInfoWindow.class).getString("info.Action.text"));
  73 + getRootPane().putClientProperty("Window.style", "small");
  74 + this.calibration = calibration;
  75 + this.dh = dh;
  76 + calibration.addCalibrationEventListener(this);
  77 + dh.addWiimoteDataListener(this);
  78 + setLayout(new MigLayout("hidemode 3"));
  79 + // info labels
  80 + final JLabel taLabel = Util.newComponent(JLabel.class, "trackingAreaLabel");
  81 + final JLabel csLabel = Util.newComponent(JLabel.class, "calibratedScreenLabel");
  82 + taLabel.setBorder(BorderFactory.createLineBorder(Color.lightGray));
  83 + csLabel.setBorder(BorderFactory.createLineBorder(Color.lightGray));
  84 + taLabel.setBackground(TRACKING_COLOR);
  85 + csLabel.setBackground(CALIBRATED_COLOR);
  86 + taLabel.setForeground(SystemColor.textText);
  87 + csLabel.setForeground(SystemColor.textHighlightText);
  88 + add(taLabel, "sg 1, split, span, growx, pushx");
  89 + add(csLabel, "sg 1, gapbefore 0, growx, pushx, wrap");
  90 +
  91 + for (int i = 0; i < ww.length; i++) {
  92 + ww[i] = new WiimoteWrapper();
  93 + ww[i].idx = i;
  94 + ww[i].icon = new WiimoteIcon(i+1);
  95 + ww[i].icon.displayConnected(true);
  96 + add(ww[i].panel = new InfoPanel(ww[i]), "flowy, w 400, h 300, grow, push");
  97 + add(ww[i].icon, "cell "+i+" 1, growx, pushx");
  98 + add(ww[i].trackingUtility = Util.newComponent(JProgressBar.class, "trackingUtility"), "cell "+i+" 1, growx, pushx");
  99 + ww[i].setVisible(i == 0);
  100 + }
  101 +
  102 + addKeyListener(new KeyAdapter() {
  103 + @Override
  104 + public void keyPressed(KeyEvent e) {
  105 + if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
  106 + setVisible(false);
  107 + }
  108 + }
  109 + });
  110 +
  111 + addComponentListener(new ComponentAdapter() {
  112 + @Override
  113 + public void componentMoved(ComponentEvent e) {
  114 + componentResized(null);
  115 + }
  116 + @Override
  117 + public void componentResized(ComponentEvent e) {
  118 + repaintPanels();
  119 + }
  120 + });
  121 +
  122 +
  123 + Util.getResourceMap(CalibrationInfoWindow.class).injectComponents(this);
  124 + pack();
  125 + Util.placeDialogWindow(this, getWidth(), getHeight());
  126 + new Timer(true).schedule(new UpdateTask(), 0, REPAINT_FREQ);
  127 + }
  128 +
  129 + private class UpdateTask extends TimerTask {
  130 + @Override
  131 + public void run() {
  132 + if (isVisible()) {
  133 + repaintPanels();
  134 + }
  135 + }
  136 + }
  137 +
  138 + private void repaintPanels() {
  139 + for (WiimoteWrapper wrapper : ww) {
  140 + if (wrapper.panel.isVisible())
  141 + wrapper.panel.repaint();
  142 + }
  143 + }
  144 +
  145 + @Action(enabledProperty="calibrated")
  146 + public void info() {
  147 + setVisible(true);
  148 + }
  149 +
  150 + public boolean isCalibrated() {
  151 + return calibrated;
  152 + }
  153 +
  154 + private void updateCalibrated() {
  155 + final boolean old = calibrated;
  156 + calibrated = dh.isConnected() && calibration.isDone() && calibration.isAnyCalibrated(dh.getConnectedWiimotes());
  157 + firePropertyChange("calibrated", old, calibrated);
  158 + }
  159 +
  160 + public void calibrationEvent(CalibrationEvent e) {
  161 + switch (e) {
  162 + case LOADED:
  163 + update();
  164 + case FINISHED:
  165 + update();
  166 + break;
  167 + case SCREEN_CHANGED:
  168 + case STARTED:
  169 + case ABORTED:
  170 + case SAVED:
  171 + }
  172 + updateCalibrated();
  173 + if (!isCalibrated())
  174 + setVisible(false);
  175 + }
  176 +
  177 + public void batteryLevel(Wiimote wiimote, double level) {}
  178 + public void irLights(Wiimote wiimote, IRDot[] lights) {
  179 + ww[wiimote.getId()-1].lights = lights;
  180 + }
  181 + public void irWarped(Map<Wiimote, IRDot[]> data, Point[] warped) {}
  182 + public void wiimoteConnected(Wiimote wiimote) {
  183 + update();
  184 + updateCalibrated();
  185 + }
  186 + public void wiimoteDisconnected(Wiimote wiimote) {}
  187 +
  188 + private int r(double d) {
  189 + return (int)Math.round(d);
  190 + }
  191 +
  192 + private void update() {
  193 + Map<String, Double[]> finals = calibration.getFinals();
  194 +
  195 +
  196 +
  197 + for (Wiimote wiimote : dh.getConnectedWiimotes()) {
  198 + WiimoteWrapper w = ww[wiimote.getId()-1];
  199 + if (!calibration.isCalibrated(wiimote)) continue;
  200 +
  201 + w.d = finals.get(wiimote.getAddress());
  202 +
  203 + double x0 = w.d[0]*1024, y0 = w.d[1]*768;
  204 + double x1 = w.d[2]*1024, y1 = w.d[3]*768;
  205 + double x3 = w.d[4]*1024, y3 = w.d[5]*768;
  206 + double x2 = w.d[6]*1024, y2 = w.d[7]*768;
  207 + double idealArea = 0.8 * 1024 * 0.8 * 768;
  208 + double calibratedArea = 0.5 * (Math.abs(
  209 + (x1 - x2) * (y0 - y3) - (x0 - x3) * (y1 - y2)
  210 + ));
  211 +
  212 + w.trackingUtility.setValue(r(calibratedArea));
  213 + w.trackingUtility.setString(Util.getResourceMap(CalibrationInfoWindow.class).getString("trackingUtilString", 100 * (calibratedArea / idealArea)));
  214 +
  215 + if (!w.panel.isVisible()) {
  216 + w.setVisible(true);
  217 + pack();
  218 + Util.placeDialogWindow(this, getWidth(), getHeight());
  219 + }
  220 + }
  221 + repaintPanels();
  222 + }
  223 +
  224 + private class InfoPanel extends JPanel {
  225 + private static final int DIAMETER = 6;
  226 + private WiimoteWrapper wrapper;
  227 + public InfoPanel(WiimoteWrapper wrapper) {
  228 + this.wrapper = wrapper;
  229 + setLayout(null);
  230 + setOpaque(true);
  231 + setBackground(TRACKING_COLOR);
  232 + setBorder(BorderFactory.createLineBorder(SystemColor.lightGray));
  233 + }
  234 + @Override
  235 + protected void paintComponent(Graphics g) {
  236 + super.paintComponent(g);
  237 + if (wrapper.d != null) {
  238 + Graphics2D g2d = (Graphics2D)g;
  239 + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
  240 + final int w = getWidth();
  241 + final int h = getHeight();
  242 + int x[] = new int[5], y[] = new int[5];
  243 + for (int i = 0; i < 4; i++) {
  244 + x[i] = r(wrapper.d[2*i]*w);
  245 + y[i] = r(h-wrapper.d[2*i+1]*h);
  246 + }
  247 + x[4] = x[0]; y[4] = y[0];
  248 +
  249 + g2d.setColor(CALIBRATED_COLOR);
  250 + g2d.fillPolygon(x, y, 5);
  251 +
  252 +
  253 + for (int i = 0; i < 4; i++) {
  254 + IRDot dot = wrapper.lights[i];
  255 + if (dot != null) {
  256 + g2d.setColor(COLORS[i]);
  257 +
  258 + g2d.fillOval(r(w*dot.x)-DIAMETER/2, r(h-h*dot.y)-DIAMETER/2, DIAMETER, DIAMETER);
  259 +
  260 + }
  261 + }
  262 + }
  263 + }
  264 + }
  265 +
  266 +
  267 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/CameraMonitor.java 0 → 100644
... ... @@ -0,0 +1,103 @@
  1 +package org.mote.wiimote.whiteboard.gui;
  2 +
  3 +import java.awt.Point;
  4 +import java.awt.SystemColor;
  5 +import java.awt.event.KeyAdapter;
  6 +import java.awt.event.KeyEvent;
  7 +import java.util.Map;
  8 +import java.util.Timer;
  9 +import java.util.TimerTask;
  10 +
  11 +import javax.swing.BorderFactory;
  12 +import javax.swing.JDialog;
  13 +import javax.swing.JPanel;
  14 +
  15 +import net.miginfocom.swing.MigLayout;
  16 +
  17 +import org.jdesktop.application.Action;
  18 +import org.jdesktop.application.Application;
  19 +import org.mote.wiimote.whiteboard.WiimoteDataHandler;
  20 +import org.mote.wiimote.whiteboard.WiimoteWhiteboard;
  21 +import org.mote.wiimote.whiteboard.WiimoteDataHandler.WiimoteDataListener;
  22 +import org.mote.wiimote.whiteboard.ds.IRDot;
  23 +import org.mote.wiimote.whiteboard.ds.Wiimote;
  24 +import org.mote.wiimote.whiteboard.preferences.WWPreferences;
  25 +import org.mote.wiimote.whiteboard.util.Util;
  26 +
  27 +@SuppressWarnings("serial")
  28 +public class CameraMonitor extends JDialog implements WiimoteDataListener {
  29 +
  30 + private static final long REPAINT_FREQ = 1000 / 25;
  31 +
  32 + private JPanel canvas;
  33 + private IRDot[][] lights = new IRDot[WWPreferences.WIIMOTES+1][4];
  34 + private LightLabel[][] labels = new LightLabel[WWPreferences.WIIMOTES+1][4];
  35 +
  36 + public CameraMonitor(WiimoteDataHandler dh) {
  37 + super(Application.getInstance(WiimoteWhiteboard.class).getMainFrame(), Util.getResourceMap(CameraMonitor.class).getString("monitor.Action.text"));
  38 + getRootPane().putClientProperty("Window.style", "small");
  39 + setLayout(new MigLayout());
  40 +
  41 + dh.addWiimoteDataListener(this);
  42 +
  43 + canvas = new JPanel(null, true);
  44 + canvas.setOpaque(true);
  45 + canvas.setBorder(BorderFactory.createLineBorder(SystemColor.inactiveCaptionBorder));
  46 + add(canvas, "w 50sp, h 50sp, grow, push");
  47 +
  48 + addKeyListener(new KeyAdapter() {
  49 + @Override
  50 + public void keyPressed(KeyEvent e) {
  51 + if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
  52 + setVisible(false);
  53 + }
  54 + }
  55 + });
  56 +
  57 + pack();
  58 + setLocationRelativeTo(null);
  59 +
  60 + new Timer(true).schedule(new UpdateTask(), 0, REPAINT_FREQ);
  61 + }
  62 +
  63 + @Action
  64 + public void monitor() {
  65 + setVisible(true);
  66 + }
  67 +
  68 + private class UpdateTask extends TimerTask {
  69 + @Override
  70 + public void run() {
  71 + if (isVisible()) {
  72 + for (int i = 1; i <= WWPreferences.WIIMOTES; i++)
  73 + for (int j = 0; j < 4; j++) {
  74 + if (labels[i][j] != null)
  75 + labels[i][j].update();
  76 + }
  77 + }
  78 + }
  79 + }
  80 +
  81 + public void irLights(Wiimote wiimote, IRDot[] lights) {
  82 + this.lights[wiimote.getId()] = lights;
  83 + }
  84 +
  85 + public void irWarped(Map<Wiimote, IRDot[]> data, Point[] warped) {
  86 + }
  87 +
  88 + public void batteryLevel(Wiimote wiimote, double level) {
  89 + }
  90 +
  91 + public void wiimoteConnected(Wiimote wiimote) {
  92 + for (int i = 0; i < 4; i++)
  93 + canvas.add(labels[wiimote.getId()][i] = new LightLabel(canvas, lights, wiimote.getId(), i + 1));
  94 + }
  95 +
  96 + public void wiimoteDisconnected(Wiimote wiimote) {
  97 + for (int i = 0; i < 4; i++) {
  98 + canvas.remove(labels[wiimote.getId()][i]);
  99 + labels[wiimote.getId()][i] = null;
  100 + }
  101 + }
  102 +
  103 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/CameraMonitor.java~ 0 → 100644
... ... @@ -0,0 +1,128 @@
  1 +/*
  2 + * Copyright (C) 2008-2009, Uwe Schmidt
  3 + *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a
  5 + * copy of this software and associated documentation files (the "Software"),
  6 + * to deal in the Software without restriction, including without limitation
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8 + * and/or sell copies of the Software, and to permit persons to whom the
  9 + * Software is furnished to do so, subject to the following conditions:
  10 + *
  11 + * The above copyright notice and this permission notice shall be included in
  12 + * all copies or substantial portions of the Software.
  13 + *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20 + * DEALINGS IN THE SOFTWARE.
  21 + *
  22 + * The Software uses a third-party library (WiiRemoteJ) which is not part of
  23 + * the Software and is subject to its own license.
  24 + */
  25 +
  26 +package org.uweschmidt.wiimote.whiteboard.gui;
  27 +
  28 +import java.awt.Point;
  29 +import java.awt.SystemColor;
  30 +import java.awt.event.KeyAdapter;
  31 +import java.awt.event.KeyEvent;
  32 +import java.util.Map;
  33 +import java.util.Timer;
  34 +import java.util.TimerTask;
  35 +
  36 +import javax.swing.BorderFactory;
  37 +import javax.swing.JDialog;
  38 +import javax.swing.JPanel;
  39 +
  40 +import net.miginfocom.swing.MigLayout;
  41 +
  42 +import org.jdesktop.application.Action;
  43 +import org.jdesktop.application.Application;
  44 +import org.uweschmidt.wiimote.whiteboard.WiimoteDataHandler;
  45 +import org.uweschmidt.wiimote.whiteboard.WiimoteWhiteboard;
  46 +import org.uweschmidt.wiimote.whiteboard.WiimoteDataHandler.WiimoteDataListener;
  47 +import org.uweschmidt.wiimote.whiteboard.ds.IRDot;
  48 +import org.uweschmidt.wiimote.whiteboard.ds.Wiimote;
  49 +import org.uweschmidt.wiimote.whiteboard.preferences.WWPreferences;
  50 +import org.uweschmidt.wiimote.whiteboard.util.Util;
  51 +
  52 +@SuppressWarnings("serial")
  53 +public class CameraMonitor extends JDialog implements WiimoteDataListener {
  54 +
  55 + private static final long REPAINT_FREQ = 1000 / 25;
  56 +
  57 + private JPanel canvas;
  58 + private IRDot[][] lights = new IRDot[WWPreferences.WIIMOTES+1][4];
  59 + private LightLabel[][] labels = new LightLabel[WWPreferences.WIIMOTES+1][4];
  60 +
  61 + public CameraMonitor(WiimoteDataHandler dh) {
  62 + super(Application.getInstance(WiimoteWhiteboard.class).getMainFrame(), Util.getResourceMap(CameraMonitor.class).getString("monitor.Action.text"));
  63 + getRootPane().putClientProperty("Window.style", "small");
  64 + setLayout(new MigLayout());
  65 +
  66 + dh.addWiimoteDataListener(this);
  67 +
  68 + canvas = new JPanel(null, true);
  69 + canvas.setOpaque(true);
  70 + canvas.setBorder(BorderFactory.createLineBorder(SystemColor.inactiveCaptionBorder));
  71 + add(canvas, "w 50sp, h 50sp, grow, push");
  72 +
  73 + addKeyListener(new KeyAdapter() {
  74 + @Override
  75 + public void keyPressed(KeyEvent e) {
  76 + if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
  77 + setVisible(false);
  78 + }
  79 + }
  80 + });
  81 +
  82 + pack();
  83 + setLocationRelativeTo(null);
  84 +
  85 + new Timer(true).schedule(new UpdateTask(), 0, REPAINT_FREQ);
  86 + }
  87 +
  88 + @Action
  89 + public void monitor() {
  90 + setVisible(true);
  91 + }
  92 +
  93 + private class UpdateTask extends TimerTask {
  94 + @Override
  95 + public void run() {
  96 + if (isVisible()) {
  97 + for (int i = 1; i <= WWPreferences.WIIMOTES; i++)
  98 + for (int j = 0; j < 4; j++) {
  99 + if (labels[i][j] != null)
  100 + labels[i][j].update();
  101 + }
  102 + }
  103 + }
  104 + }
  105 +
  106 + public void irLights(Wiimote wiimote, IRDot[] lights) {
  107 + this.lights[wiimote.getId()] = lights;
  108 + }
  109 +
  110 + public void irWarped(Map<Wiimote, IRDot[]> data, Point[] warped) {
  111 + }
  112 +
  113 + public void batteryLevel(Wiimote wiimote, double level) {
  114 + }
  115 +
  116 + public void wiimoteConnected(Wiimote wiimote) {
  117 + for (int i = 0; i < 4; i++)
  118 + canvas.add(labels[wiimote.getId()][i] = new LightLabel(canvas, lights, wiimote.getId(), i + 1));
  119 + }
  120 +
  121 + public void wiimoteDisconnected(Wiimote wiimote) {
  122 + for (int i = 0; i < 4; i++) {
  123 + canvas.remove(labels[wiimote.getId()][i]);
  124 + labels[wiimote.getId()][i] = null;
  125 + }
  126 + }
  127 +
  128 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/HelpBook.java 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +package org.mote.wiimote.whiteboard.gui;
  2 +
  3 +public class HelpBook {
  4 + static {
  5 + System.loadLibrary("HelpBookJNI");
  6 + }
  7 +
  8 + public static native void launchHelpViewer();
  9 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/HelpBook.java~ 0 → 100644
... ... @@ -0,0 +1,34 @@
  1 +/*
  2 + * Copyright (C) 2008-2009, Uwe Schmidt
  3 + *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a
  5 + * copy of this software and associated documentation files (the "Software"),
  6 + * to deal in the Software without restriction, including without limitation
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8 + * and/or sell copies of the Software, and to permit persons to whom the
  9 + * Software is furnished to do so, subject to the following conditions:
  10 + *
  11 + * The above copyright notice and this permission notice shall be included in
  12 + * all copies or substantial portions of the Software.
  13 + *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20 + * DEALINGS IN THE SOFTWARE.
  21 + *
  22 + * The Software uses a third-party library (WiiRemoteJ) which is not part of
  23 + * the Software and is subject to its own license.
  24 + */
  25 +
  26 +package org.uweschmidt.wiimote.whiteboard.gui;
  27 +
  28 +public class HelpBook {
  29 + static {
  30 + System.loadLibrary("HelpBookJNI");
  31 + }
  32 +
  33 + public static native void launchHelpViewer();
  34 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/HelpHandler.java 0 → 100644
... ... @@ -0,0 +1,24 @@
  1 +package org.mote.wiimote.whiteboard.gui;
  2 +
  3 +import javax.swing.JOptionPane;
  4 +
  5 +import org.jdesktop.application.Action;
  6 +import org.mote.wiimote.whiteboard.WiimoteWhiteboard;
  7 +import org.mote.wiimote.whiteboard.util.BareBonesBrowserLaunch;
  8 +import org.mote.wiimote.whiteboard.util.Util;
  9 +
  10 +@SuppressWarnings("serial")
  11 +public class HelpHandler {
  12 +
  13 + @Action
  14 + public void help() {
  15 + if (Util.INSIDE_APP_BUNDLE) {
  16 + HelpBook.launchHelpViewer();
  17 + } else {
  18 + if (JOptionPane.showConfirmDialog(null, Util.getResourceMap(HelpHandler.class).getString("helpQuestion"), Util.getResourceMap(HelpHandler.class).getString("help.Action.text"), JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
  19 + BareBonesBrowserLaunch.openURL(WiimoteWhiteboard.getProperty("onlineHelp"));
  20 + }
  21 + }
  22 + }
  23 +
  24 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/HelpHandler.java~ 0 → 100644
... ... @@ -0,0 +1,49 @@
  1 +/*
  2 + * Copyright (C) 2008-2009, Uwe Schmidt
  3 + *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a
  5 + * copy of this software and associated documentation files (the "Software"),
  6 + * to deal in the Software without restriction, including without limitation
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8 + * and/or sell copies of the Software, and to permit persons to whom the
  9 + * Software is furnished to do so, subject to the following conditions:
  10 + *
  11 + * The above copyright notice and this permission notice shall be included in
  12 + * all copies or substantial portions of the Software.
  13 + *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20 + * DEALINGS IN THE SOFTWARE.
  21 + *
  22 + * The Software uses a third-party library (WiiRemoteJ) which is not part of
  23 + * the Software and is subject to its own license.
  24 + */
  25 +
  26 +package org.uweschmidt.wiimote.whiteboard.gui;
  27 +
  28 +import javax.swing.JOptionPane;
  29 +
  30 +import org.jdesktop.application.Action;
  31 +import org.uweschmidt.wiimote.whiteboard.WiimoteWhiteboard;
  32 +import org.uweschmidt.wiimote.whiteboard.util.BareBonesBrowserLaunch;
  33 +import org.uweschmidt.wiimote.whiteboard.util.Util;
  34 +
  35 +@SuppressWarnings("serial")
  36 +public class HelpHandler {
  37 +
  38 + @Action
  39 + public void help() {
  40 + if (Util.INSIDE_APP_BUNDLE) {
  41 + HelpBook.launchHelpViewer();
  42 + } else {
  43 + if (JOptionPane.showConfirmDialog(null, Util.getResourceMap(HelpHandler.class).getString("helpQuestion"), Util.getResourceMap(HelpHandler.class).getString("help.Action.text"), JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
  44 + BareBonesBrowserLaunch.openURL(WiimoteWhiteboard.getProperty("onlineHelp"));
  45 + }
  46 + }
  47 + }
  48 +
  49 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/LightLabel.java 0 → 100644
... ... @@ -0,0 +1,70 @@
  1 +package org.mote.wiimote.whiteboard.gui;
  2 +
  3 +import java.awt.Color;
  4 +import java.awt.Graphics;
  5 +import java.awt.Graphics2D;
  6 +import java.awt.RenderingHints;
  7 +import java.awt.geom.Point2D;
  8 +
  9 +import javax.swing.JLabel;
  10 +import javax.swing.JPanel;
  11 +import javax.swing.SwingConstants;
  12 +
  13 +import org.uweschmidt.wiimote.whiteboard.ds.IRDot;
  14 +
  15 +@SuppressWarnings("serial")
  16 +public class LightLabel extends JLabel {
  17 +
  18 + private static final int RADIUS = 10;
  19 +
  20 + private final int id, number;
  21 + private Point2D[][] lights;
  22 + private JPanel canvas;
  23 +
  24 + public LightLabel(JPanel canvas, Point2D[][] lights, int id, int number) {
  25 + this(canvas, lights, id, number, WiimoteIcon.COLORS[id - 1]);
  26 + }
  27 +
  28 + public LightLabel(JPanel canvas, Point2D[][] lights, int id, int number, Color bg) {
  29 + super(String.valueOf(number));
  30 + this.id = id;
  31 + this.number = number;
  32 + this.lights = lights;
  33 + this.canvas = canvas;
  34 + setHorizontalAlignment(SwingConstants.CENTER);
  35 + setForeground(Color.black);
  36 + setBackground(bg);
  37 + }
  38 +
  39 + public void update() {
  40 + Point2D l = lights[id][number - 1];
  41 + if (l != null) {
  42 + int x = (int) Math.round(l.getX() * canvas.getWidth());
  43 + int y = canvas.getHeight() - (int) Math.round(l.getY() * canvas.getHeight());
  44 + this.setBounds(x - RADIUS, y - RADIUS, RADIUS * 2, RADIUS * 2);
  45 + setVisible(true);
  46 + } else {
  47 + setVisible(false);
  48 + }
  49 + }
  50 +
  51 + @Override
  52 + protected void paintComponent(Graphics g) {
  53 + Graphics2D g2d = (Graphics2D) g;
  54 + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
  55 + if (lights[id][number - 1] != null) {
  56 + g2d.setColor(this.getBackground());
  57 + g2d.fillOval(1, 1, RADIUS * 2 - 2, RADIUS * 2 - 2);
  58 + g2d.setColor(this.getForeground());
  59 + g2d.drawOval(1, 1, RADIUS * 2 - 2, RADIUS * 2 - 2);
  60 +
  61 + double scale = lights[id][number - 1] instanceof IRDot ? ((IRDot)lights[id][number - 1]).getSize() : -1;
  62 + if (scale != -1) {
  63 + g2d.setColor(Color.cyan);
  64 + final int d = (int)Math.round(RADIUS * scale * 10);
  65 + g2d.fillOval(RADIUS - d/2, RADIUS - d/2, d, d);
  66 + }
  67 + }
  68 + super.paintComponent(g);
  69 + }
  70 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/LightLabel.java~ 0 → 100644
... ... @@ -0,0 +1,98 @@
  1 +/*
  2 + * Copyright (C) 2008-2009, Uwe Schmidt
  3 + *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a
  5 + * copy of this software and associated documentation files (the "Software"),
  6 + * to deal in the Software without restriction, including without limitation
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8 + * and/or sell copies of the Software, and to permit persons to whom the
  9 + * Software is furnished to do so, subject to the following conditions:
  10 + *
  11 + * The above copyright notice and this permission notice shall be included in
  12 + * all copies or substantial portions of the Software.
  13 + *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20 + * DEALINGS IN THE SOFTWARE.
  21 + *
  22 + * The Software uses a third-party library (WiiRemoteJ) which is not part of
  23 + * the Software and is subject to its own license.
  24 + */
  25 +
  26 +package org.uweschmidt.wiimote.whiteboard.gui;
  27 +
  28 +import java.awt.Color;
  29 +import java.awt.Graphics;
  30 +import java.awt.Graphics2D;
  31 +import java.awt.RenderingHints;
  32 +import java.awt.geom.Point2D;
  33 +
  34 +import javax.swing.JLabel;
  35 +import javax.swing.JPanel;
  36 +import javax.swing.SwingConstants;
  37 +
  38 +import org.uweschmidt.wiimote.whiteboard.ds.IRDot;
  39 +
  40 +@SuppressWarnings("serial")
  41 +public class LightLabel extends JLabel {
  42 +
  43 + private static final int RADIUS = 10;
  44 +
  45 + private final int id, number;
  46 + private Point2D[][] lights;
  47 + private JPanel canvas;
  48 +
  49 + public LightLabel(JPanel canvas, Point2D[][] lights, int id, int number) {
  50 + this(canvas, lights, id, number, WiimoteIcon.COLORS[id - 1]);
  51 + }
  52 +
  53 + public LightLabel(JPanel canvas, Point2D[][] lights, int id, int number, Color bg) {
  54 + super(String.valueOf(number));
  55 + this.id = id;
  56 + this.number = number;
  57 + this.lights = lights;
  58 + this.canvas = canvas;
  59 + // setOpaque(true);
  60 + setHorizontalAlignment(SwingConstants.CENTER);
  61 + // setBorder(BorderFactory.createLineBorder(Color.black));
  62 + setForeground(Color.black);
  63 + setBackground(bg);
  64 + }
  65 +
  66 + public void update() {
  67 + Point2D l = lights[id][number - 1];
  68 + if (l != null) {
  69 + int x = (int) Math.round(l.getX() * canvas.getWidth());
  70 + int y = canvas.getHeight() - (int) Math.round(l.getY() * canvas.getHeight());
  71 + this.setBounds(x - RADIUS, y - RADIUS, RADIUS * 2, RADIUS * 2);
  72 + setVisible(true);
  73 + } else {
  74 + setVisible(false);
  75 + }
  76 + }
  77 +
  78 + @Override
  79 + protected void paintComponent(Graphics g) {
  80 + Graphics2D g2d = (Graphics2D) g;
  81 + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
  82 + if (lights[id][number - 1] != null) {
  83 + g2d.setColor(this.getBackground());
  84 + g2d.fillOval(1, 1, RADIUS * 2 - 2, RADIUS * 2 - 2);
  85 + g2d.setColor(this.getForeground());
  86 + g2d.drawOval(1, 1, RADIUS * 2 - 2, RADIUS * 2 - 2);
  87 +
  88 + // XXX explain cyan oval for size
  89 + double scale = lights[id][number - 1] instanceof IRDot ? ((IRDot)lights[id][number - 1]).getSize() : -1;
  90 + if (scale != -1) {
  91 + g2d.setColor(Color.cyan);
  92 + final int d = (int)Math.round(RADIUS * scale * 10);
  93 + g2d.fillOval(RADIUS - d/2, RADIUS - d/2, d, d);
  94 + }
  95 + }
  96 + super.paintComponent(g);
  97 + }
  98 +}
0 99 \ No newline at end of file
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/LogWindow.java 0 → 100644
... ... @@ -0,0 +1,134 @@
  1 +package org.mote.wiimote.whiteboard.gui;
  2 +
  3 +import java.awt.BorderLayout;
  4 +import java.awt.event.KeyAdapter;
  5 +import java.awt.event.KeyEvent;
  6 +import java.io.PrintWriter;
  7 +import java.io.StringWriter;
  8 +import java.io.Writer;
  9 +import java.util.Calendar;
  10 +import java.util.logging.Handler;
  11 +import java.util.logging.Level;
  12 +import java.util.logging.LogRecord;
  13 +import java.util.logging.Logger;
  14 +
  15 +import javax.swing.JDialog;
  16 +import javax.swing.JLabel;
  17 +import javax.swing.JScrollPane;
  18 +import javax.swing.JTextArea;
  19 +
  20 +import net.miginfocom.swing.MigLayout;
  21 +
  22 +import org.jdesktop.application.Action;
  23 +import org.jdesktop.application.Application;
  24 +import org.mote.wiimote.whiteboard.WiimoteWhiteboard;
  25 +import org.mote.wiimote.whiteboard.preferences.WWPreferences;
  26 +import org.mote.wiimote.whiteboard.util.Util;
  27 +
  28 +@SuppressWarnings("serial")
  29 +public class LogWindow extends JDialog {
  30 +
  31 + private JTextArea log;
  32 + private JDialog failedDialog;
  33 +
  34 + public LogWindow() {
  35 + super(Application.getInstance(WiimoteWhiteboard.class).getMainFrame(), WiimoteWhiteboard.getProperty("id") + " " + Util.getResourceMap(LogWindow.class).getString("log.Action.text"));
  36 + getRootPane().putClientProperty("Window.style", "small");
  37 + setLayout(new MigLayout());
  38 +
  39 + log = Util.newComponent(JTextArea.class, "log");
  40 + add(new JScrollPane(log), "w 66sp, h 33sp, grow, push");
  41 +
  42 + Logger.getLogger("wiiremotej").addHandler(new LogHandler("WiiRemoteJ: "));
  43 + WiimoteWhiteboard.getLogger().addHandler(new LogHandler(""));
  44 +
  45 + log.addKeyListener(new KeyAdapter() {
  46 + @Override
  47 + public void keyPressed(KeyEvent e) {
  48 + if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
  49 + setVisible(false);
  50 + }
  51 + }
  52 + });
  53 +
  54 + Util.getResourceMap(LogWindow.class).injectComponents(this);
  55 + pack();
  56 + Util.placeDialogWindow(this, getWidth(), getHeight());
  57 +
  58 + failedDialog = Util.newComponent(JDialog.class, "failedDialog");
  59 + failedDialog.addKeyListener(new KeyAdapter() {
  60 + @Override
  61 + public void keyPressed(KeyEvent e) {
  62 + if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
  63 + failedDialog.setVisible(false);
  64 + }
  65 + }
  66 + });
  67 + failedDialog.setAlwaysOnTop(true);
  68 + failedDialog.getRootPane().putClientProperty("Window.style", "small");
  69 + failedDialog.getRootPane().putClientProperty("Window.alpha", new Float(0.90));
  70 + failedDialog.setLayout(new BorderLayout());
  71 + failedDialog.add(Util.newComponent(JLabel.class, "failedLabel"), BorderLayout.CENTER);
  72 + Util.getResourceMap(LogWindow.class).injectComponents(failedDialog);
  73 + failedDialog.pack();
  74 + failedDialog.setBounds(getX()+getWidth()/2-(failedDialog.getWidth()+20)/2, getY()+getHeight()+10, failedDialog.getWidth()+20, failedDialog.getHeight()+20);
  75 + }
  76 +
  77 + @Action
  78 + public void log() {
  79 + setVisible(!isVisible());
  80 + }
  81 +
  82 + private class LogHandler extends Handler {
  83 + private static final String DIRECT_CONNECTION_TIMEOUT = "Failed to open baseband connection";
  84 + private static final String CONNECTION_FAILED = "WiiRemote failed to connect!";
  85 + private static final String CONNECTION_SUCCEEDED = "Initial connection complete.";
  86 + private final String name;
  87 + public LogHandler(String name) {
  88 + this.name = name;
  89 + setLevel(Level.ALL);
  90 + }
  91 + @Override
  92 + public void close() throws SecurityException {}
  93 + @Override
  94 + public void flush() {}
  95 +
  96 + @Override
  97 + public void publish(LogRecord record) {
  98 + Level level = record.getLevel();
  99 + String msg = record.getMessage();
  100 + Throwable e = record.getThrown();
  101 + boolean failed = false;
  102 +
  103 + if (!WWPreferences.WIIMOTE_BT_ADDRESSES.isEmpty() && e != null && e.getCause() != null && e.getCause().getMessage().startsWith(DIRECT_CONNECTION_TIMEOUT))
  104 + return;
  105 +
  106 + log.append(String.format("%7s %tT %s%s\n", level.getName(), Calendar.getInstance(), name, msg));
  107 + if (e != null) {
  108 + log.append(getStackTrace(e));
  109 + failed = CONNECTION_FAILED.equals(e.getMessage());
  110 + }
  111 + log.setCaretPosition(log.getText().length()-1);
  112 +
  113 + if (!failed && level == Level.SEVERE) {
  114 + if (!LogWindow.this.isVisible()) {
  115 + LogWindow.this.setVisible(true);
  116 + }
  117 + }
  118 +
  119 + if (CONNECTION_SUCCEEDED.equals(msg)) {
  120 + failedDialog.setVisible(false);
  121 + } else if (failed) {
  122 + failedDialog.setVisible(true);
  123 + }
  124 + }
  125 + }
  126 +
  127 + private static String getStackTrace(Throwable e) {
  128 + final Writer result = new StringWriter();
  129 + final PrintWriter printWriter = new PrintWriter(result);
  130 + e.printStackTrace(printWriter);
  131 + return result.toString();
  132 + }
  133 +
  134 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/LogWindow.java~ 0 → 100644
... ... @@ -0,0 +1,171 @@
  1 +/*
  2 + * Copyright (C) 2008-2009, Uwe Schmidt
  3 + *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a
  5 + * copy of this software and associated documentation files (the "Software"),
  6 + * to deal in the Software without restriction, including without limitation
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8 + * and/or sell copies of the Software, and to permit persons to whom the
  9 + * Software is furnished to do so, subject to the following conditions:
  10 + *
  11 + * The above copyright notice and this permission notice shall be included in
  12 + * all copies or substantial portions of the Software.
  13 + *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20 + * DEALINGS IN THE SOFTWARE.
  21 + *
  22 + * The Software uses a third-party library (WiiRemoteJ) which is not part of
  23 + * the Software and is subject to its own license.
  24 + */
  25 +
  26 +package org.uweschmidt.wiimote.whiteboard.gui;
  27 +
  28 +import java.awt.BorderLayout;
  29 +import java.awt.event.KeyAdapter;
  30 +import java.awt.event.KeyEvent;
  31 +import java.io.PrintWriter;
  32 +import java.io.StringWriter;
  33 +import java.io.Writer;
  34 +import java.util.Calendar;
  35 +import java.util.logging.Handler;
  36 +import java.util.logging.Level;
  37 +import java.util.logging.LogRecord;
  38 +import java.util.logging.Logger;
  39 +
  40 +import javax.swing.JDialog;
  41 +import javax.swing.JLabel;
  42 +import javax.swing.JScrollPane;
  43 +import javax.swing.JTextArea;
  44 +
  45 +import net.miginfocom.swing.MigLayout;
  46 +
  47 +import org.jdesktop.application.Action;
  48 +import org.jdesktop.application.Application;
  49 +import org.uweschmidt.wiimote.whiteboard.WiimoteWhiteboard;
  50 +import org.uweschmidt.wiimote.whiteboard.preferences.WWPreferences;
  51 +import org.uweschmidt.wiimote.whiteboard.util.Util;
  52 +
  53 +@SuppressWarnings("serial")
  54 +public class LogWindow extends JDialog {
  55 +
  56 + private JTextArea log;
  57 + private JDialog failedDialog;
  58 +
  59 + public LogWindow() {
  60 + super(Application.getInstance(WiimoteWhiteboard.class).getMainFrame(), WiimoteWhiteboard.getProperty("id") + " " + Util.getResourceMap(LogWindow.class).getString("log.Action.text"));
  61 + getRootPane().putClientProperty("Window.style", "small");
  62 +// setLayout(new BorderLayout());
  63 + setLayout(new MigLayout());
  64 +// if (getContentPane() instanceof JPanel) {
  65 +// ((JPanel)getContentPane()).setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
  66 +// }
  67 +
  68 + log = Util.newComponent(JTextArea.class, "log");
  69 +// add(new JScrollPane(log), BorderLayout.CENTER);
  70 + add(new JScrollPane(log), "w 66sp, h 33sp, grow, push");
  71 +
  72 + Logger.getLogger("wiiremotej").addHandler(new LogHandler("WiiRemoteJ: "));
  73 + WiimoteWhiteboard.getLogger().addHandler(new LogHandler(""));
  74 +
  75 + log.addKeyListener(new KeyAdapter() {
  76 + @Override
  77 + public void keyPressed(KeyEvent e) {
  78 + if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
  79 + setVisible(false);
  80 + }
  81 + }
  82 + });
  83 +
  84 + Util.getResourceMap(LogWindow.class).injectComponents(this);
  85 + pack();
  86 +// Util.placeDialogWindow(this, 500, 300);
  87 + Util.placeDialogWindow(this, getWidth(), getHeight());
  88 +
  89 + failedDialog = Util.newComponent(JDialog.class, "failedDialog");
  90 + failedDialog.addKeyListener(new KeyAdapter() {
  91 + @Override
  92 + public void keyPressed(KeyEvent e) {
  93 + if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
  94 + failedDialog.setVisible(false);
  95 + }
  96 + }
  97 + });
  98 + failedDialog.setAlwaysOnTop(true);
  99 + failedDialog.getRootPane().putClientProperty("Window.style", "small");
  100 + failedDialog.getRootPane().putClientProperty("Window.alpha", new Float(0.90));
  101 + failedDialog.setLayout(new BorderLayout());
  102 + failedDialog.add(Util.newComponent(JLabel.class, "failedLabel"), BorderLayout.CENTER);
  103 + Util.getResourceMap(LogWindow.class).injectComponents(failedDialog);
  104 + failedDialog.pack();
  105 +// failedDialog.setBounds(getX(), getY()+getHeight()+10, getWidth(), failedDialog.getHeight()+20);
  106 + failedDialog.setBounds(getX()+getWidth()/2-(failedDialog.getWidth()+20)/2, getY()+getHeight()+10, failedDialog.getWidth()+20, failedDialog.getHeight()+20);
  107 +// failedDialog.setVisible(true);
  108 + }
  109 +
  110 + @Action
  111 + public void log() {
  112 + setVisible(!isVisible());
  113 + }
  114 +
  115 + private class LogHandler extends Handler {
  116 + private static final String DIRECT_CONNECTION_TIMEOUT = "Failed to open baseband connection";
  117 + private static final String CONNECTION_FAILED = "WiiRemote failed to connect!";
  118 + private static final String CONNECTION_SUCCEEDED = "Initial connection complete.";
  119 + private final String name;
  120 + public LogHandler(String name) {
  121 + this.name = name;
  122 + setLevel(Level.ALL);
  123 + }
  124 + @Override
  125 + public void close() throws SecurityException {}
  126 + @Override
  127 + public void flush() {}
  128 +
  129 + @Override
  130 + public void publish(LogRecord record) {
  131 + Level level = record.getLevel();
  132 + String msg = record.getMessage();
  133 + Throwable e = record.getThrown();
  134 + boolean failed = false;
  135 +
  136 + // skip that error (apparently timeout on direct connection attempts)
  137 + if (!WWPreferences.WIIMOTE_BT_ADDRESSES.isEmpty() && e != null && e.getCause() != null && e.getCause().getMessage().startsWith(DIRECT_CONNECTION_TIMEOUT))
  138 + return;
  139 +
  140 + log.append(String.format("%7s %tT %s%s\n", level.getName(), Calendar.getInstance(), name, msg));
  141 + if (e != null) {
  142 + log.append(getStackTrace(e));
  143 + failed = CONNECTION_FAILED.equals(e.getMessage());
  144 + }
  145 + log.setCaretPosition(log.getText().length()-1);
  146 +
  147 + if (!failed && level == Level.SEVERE) {
  148 + if (!LogWindow.this.isVisible()) {
  149 +// LogWindow.this.pack();
  150 +// Util.placeDialogWindow(LogWindow.this, LogWindow.this.getWidth(), LogWindow.this.getHeight());
  151 + LogWindow.this.setVisible(true);
  152 + }
  153 + }
  154 +
  155 + if (CONNECTION_SUCCEEDED.equals(msg)) {
  156 +// LogWindow.this.setVisible(false);
  157 + failedDialog.setVisible(false);
  158 + } else if (failed) {
  159 + failedDialog.setVisible(true);
  160 + }
  161 + }
  162 + }
  163 +
  164 + private static String getStackTrace(Throwable e) {
  165 + final Writer result = new StringWriter();
  166 + final PrintWriter printWriter = new PrintWriter(result);
  167 + e.printStackTrace(printWriter);
  168 + return result.toString();
  169 + }
  170 +
  171 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/MainPanel.java 0 → 100644
... ... @@ -0,0 +1,332 @@
  1 +package org.mote.wiimote.whiteboard.gui;
  2 +
  3 +import java.awt.Color;
  4 +import java.awt.Font;
  5 +import java.awt.Graphics;
  6 +import java.awt.Point;
  7 +import java.awt.SystemColor;
  8 +import java.awt.event.ActionEvent;
  9 +import java.awt.event.ActionListener;
  10 +import java.awt.event.WindowEvent;
  11 +import java.awt.event.WindowFocusListener;
  12 +import java.util.Map;
  13 +import java.util.logging.Level;
  14 +
  15 +import javax.swing.BorderFactory;
  16 +import javax.swing.ButtonGroup;
  17 +import javax.swing.ImageIcon;
  18 +import javax.swing.JButton;
  19 +import javax.swing.JCheckBox;
  20 +import javax.swing.JLabel;
  21 +import javax.swing.JOptionPane;
  22 +import javax.swing.JPanel;
  23 +import javax.swing.JProgressBar;
  24 +import javax.swing.JRadioButton;
  25 +import javax.swing.JSeparator;
  26 +import javax.swing.SwingConstants;
  27 +
  28 +import net.miginfocom.swing.MigLayout;
  29 +
  30 +import org.jdesktop.application.Action;
  31 +import org.jdesktop.application.Application;
  32 +import org.jdesktop.application.ResourceMap;
  33 +import org.mote.wiimote.whiteboard.WiimoteDataHandler;
  34 +import org.mote.wiimote.whiteboard.WiimoteWhiteboard;
  35 +import org.mote.wiimote.whiteboard.WiimoteDataHandler.WiimoteDataListener;
  36 +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration;
  37 +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration.CalibrationEvent;
  38 +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration.CalibrationEventListener;
  39 +import org.mote.wiimote.whiteboard.ds.IRDot;
  40 +import org.mote.wiimote.whiteboard.ds.Wiimote;
  41 +import org.mote.wiimote.whiteboard.preferences.WWPreferences;
  42 +import org.mote.wiimote.whiteboard.util.Util;
  43 +
  44 +@SuppressWarnings("serial")
  45 +public class MainPanel extends JPanel implements WiimoteDataListener, CalibrationEventListener {
  46 +
  47 + private static final ImageIcon CALIBRATED = new ImageIcon(MainPanel.class.getResource("resources/icons/ok.png"));
  48 + private static final ImageIcon NOT_CALIBRATED = new ImageIcon(MainPanel.class.getResource("resources/icons/warning.png"));
  49 +
  50 + private static final WWPreferences prefs = WWPreferences.getPreferences();
  51 +
  52 + private DotLabel[] dotLabel = new DotLabel[4];
  53 + private JProgressBar[] batteryLevel = new JProgressBar[WWPreferences.WIIMOTES];
  54 + private JButton[] resetButton = new JButton[WWPreferences.WIIMOTES];
  55 + private WiimoteIcon[] wiimoteIcon = new WiimoteIcon[WWPreferences.WIIMOTES];
  56 + private JLabel[] statusLabel = new JLabel[WWPreferences.WIIMOTES];
  57 + private JCheckBox cursorControl;
  58 + private JRadioButton moveMouse, leftClick;
  59 + private JButton calibrationButton, cameraButton
  60 + private ScreenSelector screenSelector;
  61 +
  62 + private boolean notifiedLowBattery = false;
  63 +
  64 + private Wiimote[] wiimotes = new Wiimote[WWPreferences.WIIMOTES];
  65 +
  66 + private WiimoteDataHandler dh;
  67 + private WiimoteCalibration calibration;
  68 + private ResourceMap r = Util.getResourceMap(MainPanel.class);
  69 +
  70 + public MainPanel(WiimoteDataHandler dh, WiimoteCalibration calibration) {
  71 + this.dh = dh;
  72 + this.calibration = calibration;
  73 +
  74 + dh.addWiimoteDataListener(this);
  75 + calibration.addCalibrationEventListener(this);
  76 +
  77 + createComponents();
  78 +
  79 + getValues();
  80 + update();
  81 + }
  82 +
  83 + public void getValues() {
  84 + cursorControl.setSelected(dh.isCursorControl());
  85 + leftClick.setSelected(prefs.isLeftClick());
  86 + moveMouse.setSelected(!prefs.isLeftClick());
  87 + }
  88 +
  89 + public void calibrationEvent(CalibrationEvent e) {
  90 + switch (e) {
  91 + case FINISHED:
  92 + case LOADED:
  93 + cursorControl.setSelected(WWPreferences.MOUSE_CONTROL_AFTER_CALIBRATION);
  94 + case STARTED:
  95 + case SCREEN_CHANGED:
  96 + case ABORTED:
  97 + update();
  98 + break;
  99 + }
  100 + }
  101 +
  102 + public void batteryLevel(Wiimote wiimote, double level) {
  103 + batteryLevel[wiimote.getId()-1].setValue((int) Math.round(level * 100));
  104 + batteryLevel[wiimote.getId()-1].setString(r.getString("batteryLevel", level * 100));
  105 +
  106 + if (!notifiedLowBattery && prefs.isLowBatteryWarning() && dh.isConnected(wiimote) && level <= .05) {
  107 + notifiedLowBattery = true;
  108 + WiimoteWhiteboard.getLogger().log(Level.WARNING, r.getString("lowBattery"));
  109 + new Thread(new Runnable() {
  110 + public void run() {
  111 + JOptionPane.showMessageDialog(null, r.getString("lowBattery"), WiimoteWhiteboard.getProperty("id"), JOptionPane.WARNING_MESSAGE);
  112 + }
  113 + }).start();
  114 + }
  115 + }
  116 +
  117 + public void irLights(Wiimote wiimote, IRDot[] lights) {
  118 + for (int i = 0; i < lights.length; i++) {
  119 + dotLabel[i].update(wiimote, lights[i] != null);
  120 + }
  121 + }
  122 +
  123 + public void irWarped(Map<Wiimote, IRDot[]> data, Point[] warped) {
  124 + }
  125 +
  126 + public void wiimoteConnected(Wiimote wiimote) {
  127 + wiimotes[wiimote.getId()-1] = wiimote;
  128 +
  129 + if (wiimote.getId() > 1) {
  130 + for (int i = 0; i < wiimote.getId(); i++) {
  131 + wiimoteIcon[i].setVisible(true);
  132 + }
  133 + }
  134 + statusLabel[wiimote.getId()-1].setVisible(true);
  135 +
  136 + batteryLevel[wiimote.getId()-1].setVisible(true);
  137 + resetButton[wiimote.getId()-1].setVisible(true);
  138 + cursorControl.setSelected(WWPreferences.MOUSE_CONTROL_AFTER_CALIBRATION);
  139 + update();
  140 + }
  141 +
  142 + public void wiimoteDisconnected(Wiimote wiimote) {
  143 + if (wiimote.getId() != 1) batteryLevel[wiimote.getId()-1].setVisible(false);
  144 + if (wiimote.getId() != 1) wiimoteIcon[wiimote.getId()-1].setVisible(false);
  145 + if (wiimote.getId() != 1) resetButton[wiimote.getId()-1].setVisible(false);
  146 + if (wiimote.getId() != 1) statusLabel[wiimote.getId()-1].setVisible(false);
  147 + update();
  148 + JOptionPane.showMessageDialog(null, r.getString("disconnected", wiimote.getId()), WiimoteWhiteboard.getProperty("id"), JOptionPane.ERROR_MESSAGE);
  149 + Application.getInstance(WiimoteWhiteboard.class).exit();
  150 + }
  151 +
  152 +
  153 + /*
  154 + * UPDATE UI WIDGETS
  155 + */
  156 +
  157 + @Action
  158 + public void update() {
  159 + calibrationButton.setEnabled(dh.isConnected());
  160 + for (int i = 0; i < WWPreferences.WIIMOTES; i++) {
  161 + resetButton[i].setEnabled(dh.isConnected(wiimotes[i]));
  162 + wiimoteIcon[i].displayConnected(dh.isConnected(wiimotes[i]));
  163 + if (dh.isConnected(wiimotes[i])) {
  164 + boolean calibrated = calibration.isCalibrated(wiimotes[i]);
  165 + statusLabel[i].setText(r.getString(calibrated ? "calibrated" : "notCalibrated"));
  166 + statusLabel[i].setIcon(calibrated ? CALIBRATED : NOT_CALIBRATED);
  167 + }
  168 + }
  169 + cameraButton.setEnabled(dh.isConnected());
  170 + screenSelector.setEnabled(dh.isConnected() && !calibration.inProgress());
  171 +
  172 + if (!dh.isConnected()) {
  173 + batteryLevel[0].setString(r.getString("searching"));
  174 + batteryLevel[0].setValue(0);
  175 + batteryLevel[0].setToolTipText(Util.getResourceMap(MainPanel.class).getString("batteryLevelBar.toolTipText"));
  176 + } else {
  177 + batteryLevel[0].setToolTipText(null);
  178 + }
  179 +
  180 + cursorControl.setEnabled(dh.isConnected() && calibration.isDone() && calibration.isAnyCalibrated(dh.getConnectedWiimotes()));
  181 + if (!cursorControl.isEnabled())
  182 + cursorControl.setSelected(false);
  183 +
  184 + moveMouse.setEnabled(cursorControl.isSelected());
  185 + leftClick.setEnabled(cursorControl.isSelected());
  186 +
  187 + dh.setCursorControl(cursorControl.isSelected());
  188 + prefs.setLeftClick(leftClick.isSelected());
  189 + }
  190 +
  191 + /*
  192 + * MAIN PANEL
  193 + */
  194 +
  195 + private void createComponents() {
  196 + setLayout(new MigLayout("nocache, hidemode 3, gap 0", "[fill]"));
  197 +
  198 + addHeadline(r.getString("wiimoteHeadline"), false);
  199 +
  200 + for (int i = 0; i < WWPreferences.WIIMOTES; i++) {
  201 + add(wiimoteIcon[i] = new WiimoteIcon(i+1), "split");
  202 + if (i > 0) wiimoteIcon[i].setVisible(false);
  203 + }
  204 +
  205 + for (int i = 0; i < WWPreferences.WIIMOTES; i++) {
  206 + add(batteryLevel[i] = Util.newComponent(JProgressBar.class, "batteryLevelBar"), (i == 0 ? "newline related/2, " : "") + "split");
  207 + if (i > 0) batteryLevel[i].setVisible(false);
  208 + }
  209 +
  210 + for (int i = 0; i < WWPreferences.WIIMOTES; i++) {
  211 + add(statusLabel[i] = Util.newComponent(JLabel.class, "statusLabel"), (i == 0 ? "newline related/2, split, " : "") + "sg, h 16!, center");
  212 + statusLabel[i].setFont(statusLabel[i].getFont().deriveFont(10f));
  213 + if (i > 0) statusLabel[i].setVisible(false);
  214 + }
  215 +
  216 + String gap = Util.MAC_OS_X_LEOPARD_OR_HIGHER ? "0" : "related/2";
  217 + for (int i = 0; i < WWPreferences.WIIMOTES; i++) {
  218 + final int j = i;
  219 + add(resetButton[i] = Util.newComponent(JButton.class, "resetCameraButton"), (i == 0 ? "newline "+gap+", split, " : "") + "");
  220 + resetButton[i].putClientProperty("JButton.buttonType", "textured");
  221 + resetButton[i].putClientProperty("JComponent.sizeVariant", "small");
  222 + resetButton[i].addActionListener(new ActionListener() {
  223 + public void actionPerformed(ActionEvent e) {
  224 + try {
  225 + dh.enableIR(wiimotes[j]);
  226 + } catch (Exception e1) {
  227 + e1.printStackTrace();
  228 + }
  229 + }
  230 + });
  231 + if (i > 0) resetButton[i].setVisible(false);
  232 + }
  233 +
  234 + add(new JSeparator(), String.format("newline %s, span, growx, wrap related", Util.MAC_OS_X_LEOPARD_OR_HIGHER ? "related/3" : "related"));
  235 +
  236 + add(Util.newComponent(JLabel.class, "visibleDotsLabel"), "split" + (Util.MAC_OS_X ? ", gapleft 4" : ""));
  237 + add(dotLabel[0] = new DotLabel("1"), "w 18, h 18");
  238 + add(dotLabel[1] = new DotLabel("2"), "w 18, h 18");
  239 + add(dotLabel[2] = new DotLabel("3"), "w 18, h 18");
  240 + add(dotLabel[3] = new DotLabel("4"), "w 18, h 18, wrap related" + (Util.MAC_OS_X ? ", gapright 4" : ""));
  241 +
  242 + add(cameraButton = new JButton(Util.getAction(new CameraMonitor(dh), "monitor")), "");
  243 + cameraButton.putClientProperty("JButton.buttonType", "textured");
  244 +
  245 + // CALIBRATION
  246 +
  247 + addHeadline(r.getString("calibrationHeadline"));
  248 +
  249 +
  250 + final JButton infoButton = new JButton(Util.getAction(new CalibrationInfoWindow(calibration, dh), "info"));
  251 + infoButton.putClientProperty("JButton.buttonType", "textured");
  252 + infoButton.putClientProperty("JComponent.sizeVariant", "small");
  253 + add(infoButton, "wrap related");
  254 +
  255 +
  256 + add(screenSelector = new ScreenSelector(calibration, dh), "align center, grow 0, wrap related");
  257 +
  258 + add(calibrationButton = Util.newComponent(JButton.class, "calibrationButton"), "");
  259 + calibrationButton.putClientProperty("JButton.buttonType", "textured");
  260 + calibrationButton.addActionListener(new ActionListener() {
  261 + public void actionPerformed(ActionEvent e) {
  262 + calibration.start(dh.getConnectedWiimotes());
  263 + }
  264 + });
  265 +
  266 + // MOUSE CONTROL
  267 +
  268 + addHeadline(r.getString("mouseControlHeadline"));
  269 +
  270 + add(cursorControl = Util.newComponent(JCheckBox.class, "cursorControl"), "wrap related");
  271 + add(moveMouse = Util.newComponent(JRadioButton.class, "moveMouse"), "pad 0 20 0 0, wmin pref+20, wrap related");
  272 + add(leftClick = Util.newComponent(JRadioButton.class, "leftClick"), "pad 0 20 0 0, wmin pref+20, wrap");
  273 +
  274 + ButtonGroup group = new ButtonGroup();
  275 + group.add(moveMouse);
  276 + group.add(leftClick);
  277 +
  278 + cursorControl.addActionListener(Util.getAction(this, "update"));
  279 + moveMouse.addActionListener(Util.getAction(this, "update"));
  280 + leftClick.addActionListener(Util.getAction(this, "update"));
  281 +
  282 + Application.getInstance(WiimoteWhiteboard.class).getMainFrame().addWindowFocusListener(new WindowFocusListener() {
  283 + public void windowGainedFocus(WindowEvent e) {
  284 + updateUI();
  285 + }
  286 + public void windowLostFocus(WindowEvent e) {}
  287 + });
  288 +
  289 + Util.getResourceMap(MainPanel.class).injectComponents(this);
  290 + }
  291 +
  292 + private JLabel addHeadline(String name) {
  293 + return addHeadline(name, true);
  294 + }
  295 +
  296 + private JLabel addHeadline(String name, boolean newline) {
  297 + final JLabel label = new JLabel(name);
  298 + label.setFont(label.getFont().deriveFont(Font.BOLD, 18f));
  299 + add(label, (newline ? "newline unrelated, " : "") + "split, span");
  300 + add(new JSeparator(), "growx, wrap related");
  301 + return label;
  302 + }
  303 +
  304 + private class DotLabel extends JLabel {
  305 +
  306 + private boolean[] state = new boolean[WWPreferences.WIIMOTES];
  307 +
  308 + public DotLabel(String name) {
  309 + setText(name);
  310 + setHorizontalAlignment(SwingConstants.CENTER);
  311 + setBorder(BorderFactory.createLineBorder(Color.lightGray));
  312 + }
  313 +
  314 + public void update(Wiimote wiimote, boolean state) {
  315 + if (this.state[wiimote.getId() - 1] != state) {
  316 + this.state[wiimote.getId() - 1] = state;
  317 + repaint();
  318 + }
  319 + }
  320 +
  321 + @Override
  322 + protected void paintComponent(Graphics g) {
  323 + final int n = Math.max(1, dh.getNumberOfConnectedWiimotes());
  324 + for (int i = 1; i <= n; i++) {
  325 + g.setColor(state[i-1] ? WiimoteIcon.COLORS[i-1] : SystemColor.textInactiveText);
  326 + g.fillRect(0, (i-1)*this.getHeight()/n, this.getWidth(), this.getHeight()/n);
  327 + }
  328 + super.paintComponent(g);
  329 + }
  330 +
  331 + }
  332 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/MainPanel.java~ 0 → 100644
... ... @@ -0,0 +1,384 @@
  1 +/*
  2 + * Copyright (C) 2008-2009, Uwe Schmidt
  3 + *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a
  5 + * copy of this software and associated documentation files (the "Software"),
  6 + * to deal in the Software without restriction, including without limitation
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8 + * and/or sell copies of the Software, and to permit persons to whom the
  9 + * Software is furnished to do so, subject to the following conditions:
  10 + *
  11 + * The above copyright notice and this permission notice shall be included in
  12 + * all copies or substantial portions of the Software.
  13 + *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20 + * DEALINGS IN THE SOFTWARE.
  21 + *
  22 + * The Software uses a third-party library (WiiRemoteJ) which is not part of
  23 + * the Software and is subject to its own license.
  24 + */
  25 +
  26 +package org.uweschmidt.wiimote.whiteboard.gui;
  27 +
  28 +import java.awt.Color;
  29 +import java.awt.Font;
  30 +import java.awt.Graphics;
  31 +import java.awt.Point;
  32 +import java.awt.SystemColor;
  33 +import java.awt.event.ActionEvent;
  34 +import java.awt.event.ActionListener;
  35 +import java.awt.event.WindowEvent;
  36 +import java.awt.event.WindowFocusListener;
  37 +import java.util.Map;
  38 +import java.util.logging.Level;
  39 +
  40 +import javax.swing.BorderFactory;
  41 +import javax.swing.ButtonGroup;
  42 +import javax.swing.ImageIcon;
  43 +import javax.swing.JButton;
  44 +import javax.swing.JCheckBox;
  45 +import javax.swing.JLabel;
  46 +import javax.swing.JOptionPane;
  47 +import javax.swing.JPanel;
  48 +import javax.swing.JProgressBar;
  49 +import javax.swing.JRadioButton;
  50 +import javax.swing.JSeparator;
  51 +import javax.swing.SwingConstants;
  52 +
  53 +import net.miginfocom.swing.MigLayout;
  54 +
  55 +import org.jdesktop.application.Action;
  56 +import org.jdesktop.application.Application;
  57 +import org.jdesktop.application.ResourceMap;
  58 +import org.uweschmidt.wiimote.whiteboard.WiimoteDataHandler;
  59 +import org.uweschmidt.wiimote.whiteboard.WiimoteWhiteboard;
  60 +import org.uweschmidt.wiimote.whiteboard.WiimoteDataHandler.WiimoteDataListener;
  61 +import org.uweschmidt.wiimote.whiteboard.calibration.WiimoteCalibration;
  62 +import org.uweschmidt.wiimote.whiteboard.calibration.WiimoteCalibration.CalibrationEvent;
  63 +import org.uweschmidt.wiimote.whiteboard.calibration.WiimoteCalibration.CalibrationEventListener;
  64 +import org.uweschmidt.wiimote.whiteboard.ds.IRDot;
  65 +import org.uweschmidt.wiimote.whiteboard.ds.Wiimote;
  66 +import org.uweschmidt.wiimote.whiteboard.preferences.WWPreferences;
  67 +import org.uweschmidt.wiimote.whiteboard.util.Util;
  68 +
  69 +@SuppressWarnings("serial")
  70 +public class MainPanel extends JPanel implements WiimoteDataListener, CalibrationEventListener {
  71 +
  72 + private static final ImageIcon CALIBRATED = new ImageIcon(MainPanel.class.getResource("resources/icons/ok.png"));
  73 + private static final ImageIcon NOT_CALIBRATED = new ImageIcon(MainPanel.class.getResource("resources/icons/warning.png"));
  74 +
  75 + private static final WWPreferences prefs = WWPreferences.getPreferences();
  76 +
  77 + private DotLabel[] dotLabel = new DotLabel[4];
  78 + private JProgressBar[] batteryLevel = new JProgressBar[WWPreferences.WIIMOTES];
  79 + private JButton[] resetButton = new JButton[WWPreferences.WIIMOTES];
  80 + private WiimoteIcon[] wiimoteIcon = new WiimoteIcon[WWPreferences.WIIMOTES];
  81 + private JLabel[] statusLabel = new JLabel[WWPreferences.WIIMOTES];
  82 + private JCheckBox cursorControl;
  83 + private JRadioButton moveMouse, leftClick;
  84 + private JButton calibrationButton, cameraButton /*,warpedButton, calibrationInfoButton*/;
  85 + private ScreenSelector screenSelector;
  86 +
  87 + private boolean notifiedLowBattery = false;
  88 +// private boolean donePack = false;
  89 +
  90 + private Wiimote[] wiimotes = new Wiimote[WWPreferences.WIIMOTES];
  91 +
  92 + private WiimoteDataHandler dh;
  93 + private WiimoteCalibration calibration;
  94 + private ResourceMap r = Util.getResourceMap(MainPanel.class);
  95 +
  96 + public MainPanel(WiimoteDataHandler dh, WiimoteCalibration calibration) {
  97 + this.dh = dh;
  98 + this.calibration = calibration;
  99 +
  100 + dh.addWiimoteDataListener(this);
  101 + calibration.addCalibrationEventListener(this);
  102 +
  103 + createComponents();
  104 +
  105 + getValues();
  106 + update();
  107 + }
  108 +
  109 + public void getValues() {
  110 + cursorControl.setSelected(dh.isCursorControl());
  111 +// rightClick.setSelected(prefs.isRightClick());
  112 + leftClick.setSelected(prefs.isLeftClick());
  113 + moveMouse.setSelected(!prefs.isLeftClick());
  114 + }
  115 +
  116 + public void calibrationEvent(CalibrationEvent e) {
  117 + switch (e) {
  118 + case FINISHED:
  119 + case LOADED:
  120 + cursorControl.setSelected(WWPreferences.MOUSE_CONTROL_AFTER_CALIBRATION);
  121 + case STARTED:
  122 + case SCREEN_CHANGED:
  123 + case ABORTED:
  124 + update();
  125 + break;
  126 + }
  127 + }
  128 +
  129 + public void batteryLevel(Wiimote wiimote, double level) {
  130 + batteryLevel[wiimote.getId()-1].setValue((int) Math.round(level * 100));
  131 + batteryLevel[wiimote.getId()-1].setString(r.getString("batteryLevel", level * 100));
  132 +
  133 + if (!notifiedLowBattery && prefs.isLowBatteryWarning() && dh.isConnected(wiimote) && level <= .05) {
  134 + notifiedLowBattery = true;
  135 + WiimoteWhiteboard.getLogger().log(Level.WARNING, r.getString("lowBattery"));
  136 + new Thread(new Runnable() {
  137 + public void run() {
  138 + JOptionPane.showMessageDialog(null, r.getString("lowBattery"), WiimoteWhiteboard.getProperty("id"), JOptionPane.WARNING_MESSAGE);
  139 + }
  140 + }).start();
  141 + }
  142 + }
  143 +
  144 + public void irLights(Wiimote wiimote, IRDot[] lights) {
  145 + for (int i = 0; i < lights.length; i++) {
  146 + dotLabel[i].update(wiimote, lights[i] != null);
  147 + }
  148 + }
  149 +
  150 + public void irWarped(Map<Wiimote, IRDot[]> data, Point[] warped) {
  151 + }
  152 +
  153 + public void wiimoteConnected(Wiimote wiimote) {
  154 + wiimotes[wiimote.getId()-1] = wiimote;
  155 +
  156 + if (wiimote.getId() > 1) {
  157 + for (int i = 0; i < wiimote.getId(); i++) {
  158 + wiimoteIcon[i].setVisible(true);
  159 + }
  160 + }
  161 + statusLabel[wiimote.getId()-1].setVisible(true);
  162 +
  163 +// Application.getInstance(WiimoteWhiteboard.class).getMainFrame().pack();
  164 +
  165 + batteryLevel[wiimote.getId()-1].setVisible(true);
  166 + resetButton[wiimote.getId()-1].setVisible(true);
  167 + cursorControl.setSelected(WWPreferences.MOUSE_CONTROL_AFTER_CALIBRATION);
  168 + update();
  169 + }
  170 +
  171 + public void wiimoteDisconnected(Wiimote wiimote) {
  172 + if (wiimote.getId() != 1) batteryLevel[wiimote.getId()-1].setVisible(false);
  173 + if (wiimote.getId() != 1) wiimoteIcon[wiimote.getId()-1].setVisible(false);
  174 + if (wiimote.getId() != 1) resetButton[wiimote.getId()-1].setVisible(false);
  175 + if (wiimote.getId() != 1) statusLabel[wiimote.getId()-1].setVisible(false);
  176 + update();
  177 +// Application.getInstance(WiimoteWhiteboard.class).getMainFrame().pack();
  178 +// WiimoteWhiteboard.getLogger().log(Level.SEVERE, r.getString("disconnected", id));
  179 + JOptionPane.showMessageDialog(null, r.getString("disconnected", wiimote.getId()), WiimoteWhiteboard.getProperty("id"), JOptionPane.ERROR_MESSAGE);
  180 + Application.getInstance(WiimoteWhiteboard.class).exit();
  181 + }
  182 +
  183 +
  184 + /*
  185 + * UPDATE UI WIDGETS
  186 + */
  187 +
  188 + @Action
  189 + public void update() {
  190 + calibrationButton.setEnabled(dh.isConnected());
  191 + for (int i = 0; i < WWPreferences.WIIMOTES; i++) {
  192 + resetButton[i].setEnabled(dh.isConnected(wiimotes[i]));
  193 + wiimoteIcon[i].displayConnected(dh.isConnected(wiimotes[i]));
  194 + if (dh.isConnected(wiimotes[i])) {
  195 + boolean calibrated = calibration.isCalibrated(wiimotes[i]);
  196 + statusLabel[i].setText(r.getString(calibrated ? "calibrated" : "notCalibrated"));
  197 + statusLabel[i].setIcon(calibrated ? CALIBRATED : NOT_CALIBRATED);
  198 + }
  199 + }
  200 + cameraButton.setEnabled(dh.isConnected());
  201 +// warpedButton.setEnabled(dh.isConnected() && calibration.isDone() && calibration.isAnyCalibrated(dh.getConnectedWiimotes()));
  202 + screenSelector.setEnabled(dh.isConnected() && !calibration.inProgress());
  203 +
  204 + if (!dh.isConnected()) {
  205 + batteryLevel[0].setString(r.getString("searching"));
  206 + batteryLevel[0].setValue(0);
  207 + batteryLevel[0].setToolTipText(Util.getResourceMap(MainPanel.class).getString("batteryLevelBar.toolTipText"));
  208 + } else {
  209 + batteryLevel[0].setToolTipText(null);
  210 + }
  211 +
  212 + cursorControl.setEnabled(dh.isConnected() && calibration.isDone() && calibration.isAnyCalibrated(dh.getConnectedWiimotes()));
  213 + if (!cursorControl.isEnabled())
  214 + cursorControl.setSelected(false);
  215 +
  216 + moveMouse.setEnabled(cursorControl.isSelected());
  217 + leftClick.setEnabled(cursorControl.isSelected());
  218 +// rightClick.setEnabled(cursorControl.isSelected() && leftClick.isSelected());
  219 +
  220 + dh.setCursorControl(cursorControl.isSelected());
  221 + prefs.setLeftClick(leftClick.isSelected());
  222 +// prefs.setRightClick(/*rightClick.isEnabled() && */rightClick.isSelected());
  223 + }
  224 +
  225 + /*
  226 + * MAIN PANEL
  227 + */
  228 +
  229 + private void createComponents() {
  230 + setLayout(new MigLayout("nocache, hidemode 3, gap 0", "[fill]"));
  231 +
  232 + addHeadline(r.getString("wiimoteHeadline"), false);
  233 +
  234 + for (int i = 0; i < WWPreferences.WIIMOTES; i++) {
  235 + add(wiimoteIcon[i] = new WiimoteIcon(i+1), "split");
  236 + if (i > 0) wiimoteIcon[i].setVisible(false);
  237 + }
  238 +
  239 + for (int i = 0; i < WWPreferences.WIIMOTES; i++) {
  240 + add(batteryLevel[i] = Util.newComponent(JProgressBar.class, "batteryLevelBar"), (i == 0 ? "newline related/2, " : "") + "split");
  241 + if (i > 0) batteryLevel[i].setVisible(false);
  242 + }
  243 +
  244 + for (int i = 0; i < WWPreferences.WIIMOTES; i++) {
  245 + add(statusLabel[i] = Util.newComponent(JLabel.class, "statusLabel"), (i == 0 ? "newline related/2, split, " : "") + "sg, h 16!, center");
  246 + statusLabel[i].setFont(statusLabel[i].getFont().deriveFont(10f));
  247 + if (i > 0) statusLabel[i].setVisible(false);
  248 + }
  249 +
  250 + String gap = Util.MAC_OS_X_LEOPARD_OR_HIGHER ? "0" : "related/2";
  251 + for (int i = 0; i < WWPreferences.WIIMOTES; i++) {
  252 + final int j = i;
  253 + add(resetButton[i] = Util.newComponent(JButton.class, "resetCameraButton"), (i == 0 ? "newline "+gap+", split, " : "") + "");
  254 + resetButton[i].putClientProperty("JButton.buttonType", "textured");
  255 + resetButton[i].putClientProperty("JComponent.sizeVariant", "small");
  256 + resetButton[i].addActionListener(new ActionListener() {
  257 + public void actionPerformed(ActionEvent e) {
  258 + try {
  259 + dh.enableIR(wiimotes[j]);
  260 + } catch (Exception e1) {
  261 + e1.printStackTrace();
  262 + }
  263 + }
  264 + });
  265 + if (i > 0) resetButton[i].setVisible(false);
  266 + }
  267 +
  268 + add(new JSeparator(), String.format("newline %s, span, growx, wrap related", Util.MAC_OS_X_LEOPARD_OR_HIGHER ? "related/3" : "related"));
  269 +
  270 + add(Util.newComponent(JLabel.class, "visibleDotsLabel"), "split" + (Util.MAC_OS_X ? ", gapleft 4" : ""));
  271 + add(dotLabel[0] = new DotLabel("1"), "w 18, h 18");
  272 + add(dotLabel[1] = new DotLabel("2"), "w 18, h 18");
  273 + add(dotLabel[2] = new DotLabel("3"), "w 18, h 18");
  274 + add(dotLabel[3] = new DotLabel("4"), "w 18, h 18, wrap related" + (Util.MAC_OS_X ? ", gapright 4" : ""));
  275 +
  276 + add(cameraButton = new JButton(Util.getAction(new CameraMonitor(dh), "monitor")), "");
  277 + cameraButton.putClientProperty("JButton.buttonType", "textured");
  278 +
  279 + // CALIBRATION
  280 +
  281 + addHeadline(r.getString("calibrationHeadline"));
  282 +
  283 +// add(warpedButton = new JButton(SC.getAction(new WarpedMonitor(dh, calibration), "monitor")), "wrap");
  284 +
  285 + final JButton infoButton = new JButton(Util.getAction(new CalibrationInfoWindow(calibration, dh), "info"));
  286 +// final JToggleButton infoButton = new JToggleButton(Util.getAction(new CalibrationInfoWindow(calibration, dh), "info"));
  287 + infoButton.putClientProperty("JButton.buttonType", "textured");
  288 + infoButton.putClientProperty("JComponent.sizeVariant", "small");
  289 + add(infoButton, "wrap related");
  290 +// add(new JSeparator(), "span, growx, wrap");
  291 +
  292 +
  293 + add(screenSelector = new ScreenSelector(calibration, dh), "align center, grow 0, wrap related");
  294 +
  295 + add(calibrationButton = Util.newComponent(JButton.class, "calibrationButton"), "");
  296 + calibrationButton.putClientProperty("JButton.buttonType", "textured");
  297 + calibrationButton.addActionListener(new ActionListener() {
  298 + public void actionPerformed(ActionEvent e) {
  299 + calibration.start(dh.getConnectedWiimotes());
  300 + }
  301 + });
  302 +
  303 + // MOUSE CONTROL
  304 +
  305 + addHeadline(r.getString("mouseControlHeadline"));
  306 +
  307 + add(cursorControl = Util.newComponent(JCheckBox.class, "cursorControl"), "wrap related");
  308 + add(moveMouse = Util.newComponent(JRadioButton.class, "moveMouse"), "pad 0 20 0 0, wmin pref+20, wrap related");
  309 + add(leftClick = Util.newComponent(JRadioButton.class, "leftClick"), "pad 0 20 0 0, wmin pref+20, wrap");
  310 +// add(rightClick = SC.newComponent(JCheckBox.class, "rightClick"), "pad 0 20 0 0, wrap");
  311 +
  312 +// add(new JSeparator(), "wrap");
  313 +// final JButton exitButton = new JButton(SC.getAction(Application.getInstance(), "quitApp"));
  314 +// add(exitButton, "wrap");
  315 +
  316 + ButtonGroup group = new ButtonGroup();
  317 + group.add(moveMouse);
  318 + group.add(leftClick);
  319 +
  320 + cursorControl.addActionListener(Util.getAction(this, "update"));
  321 + moveMouse.addActionListener(Util.getAction(this, "update"));
  322 + leftClick.addActionListener(Util.getAction(this, "update"));
  323 +// rightClick.addActionListener(SC.getAction(this, "update"));
  324 +
  325 + // fixes issue that components stay grayed out although they're enabled
  326 + // (mac os x), only happens when mainFrame doesn't have focus on connect
  327 + // workaround for windows: pack() once frame gains focus, due to
  328 + // incorrect height apparently caused by non-resizability
  329 + Application.getInstance(WiimoteWhiteboard.class).getMainFrame().addWindowFocusListener(new WindowFocusListener() {
  330 + public void windowGainedFocus(WindowEvent e) {
  331 + updateUI();
  332 +// if (!Util.MAC_OS_X && !donePack) {
  333 +// donePack = true;
  334 +// Application.getInstance(WiimoteWhiteboard.class).getMainFrame().pack();
  335 +// }
  336 + }
  337 + public void windowLostFocus(WindowEvent e) {}
  338 + });
  339 +
  340 + Util.getResourceMap(MainPanel.class).injectComponents(this);
  341 + }
  342 +
  343 + private JLabel addHeadline(String name) {
  344 + return addHeadline(name, true);
  345 + }
  346 +
  347 + private JLabel addHeadline(String name, boolean newline) {
  348 + final JLabel label = new JLabel(name);
  349 + label.setFont(label.getFont().deriveFont(Font.BOLD, 18f));
  350 + add(label, (newline ? "newline unrelated, " : "") + "split, span");
  351 + add(new JSeparator(), "growx, wrap related");
  352 + return label;
  353 + }
  354 +
  355 + private class DotLabel extends JLabel {
  356 +
  357 + private boolean[] state = new boolean[WWPreferences.WIIMOTES];
  358 +
  359 + public DotLabel(String name) {
  360 + setText(name);
  361 + setHorizontalAlignment(SwingConstants.CENTER);
  362 + setBorder(BorderFactory.createLineBorder(Color.lightGray));
  363 + }
  364 +
  365 + public void update(Wiimote wiimote, boolean state) {
  366 + if (this.state[wiimote.getId() - 1] != state) {
  367 + this.state[wiimote.getId() - 1] = state;
  368 + repaint();
  369 + }
  370 + }
  371 +
  372 + @Override
  373 + protected void paintComponent(Graphics g) {
  374 + final int n = Math.max(1, dh.getNumberOfConnectedWiimotes());
  375 + for (int i = 1; i <= n; i++) {
  376 + g.setColor(state[i-1] ? WiimoteIcon.COLORS[i-1] : SystemColor.textInactiveText);
  377 + g.fillRect(0, (i-1)*this.getHeight()/n, this.getWidth(), this.getHeight()/n);
  378 +// g.fillRect((i-1)*this.getWidth()/n, 0, this.getWidth()/n, this.getHeight());
  379 + }
  380 + super.paintComponent(g);
  381 + }
  382 +
  383 + }
  384 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/MenuBar.java 0 → 100644
... ... @@ -0,0 +1,48 @@
  1 +package org.mote.wiimote.whiteboard.gui;
  2 +
  3 +import java.awt.Toolkit;
  4 +import java.awt.event.KeyEvent;
  5 +
  6 +import javax.swing.JMenu;
  7 +import javax.swing.JMenuBar;
  8 +import javax.swing.JMenuItem;
  9 +import javax.swing.KeyStroke;
  10 +
  11 +import org.jdesktop.application.Application;
  12 +import org.mote.wiimote.whiteboard.WiimoteWhiteboard;
  13 +import org.mote.wiimote.whiteboard.util.Util;
  14 +
  15 +@SuppressWarnings("serial")
  16 +public class MenuBar extends JMenuBar {
  17 +
  18 + public MenuBar(PreferencesWindow pf, AboutWindow af, /*HelpHandler hh*/, LogWindow lw) {
  19 + JMenu menu;
  20 + JMenuItem item;
  21 +
  22 + if (!Util.MAC_OS_X) {
  23 + menu = new JMenu(Util.getResourceMap(MenuBar.class).getString("editMenu"));
  24 + menu.add(new JMenuItem(Util.getAction(pf, "preferences")));
  25 + add(menu);
  26 + }
  27 +
  28 + //menu = new JMenu(Util.getResourceMap(HelpHandler.class).getString("help"));
  29 +
  30 + //menu.add(item = new JMenuItem(Util.getAction(hh, "help")));
  31 + if (Util.MAC_OS_X)
  32 + item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_SLASH, KeyEvent.SHIFT_MASK | Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
  33 +
  34 + //menu.addSeparator();
  35 +
  36 + //if (!Util.MAC_OS_X)
  37 + // menu.add(new JMenuItem(Util.getAction(af, "about")));
  38 +
  39 + //menu.add(new JMenuItem(Util.getAction(lw, "log")));
  40 +
  41 + //menu.addSeparator();
  42 +
  43 + //menu.add(new JMenuItem(Util.getAction(Application.getInstance(WiimoteWhiteboard.class), "donate")));
  44 +
  45 + add(menu);
  46 + }
  47 +
  48 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/MenuBar.java~ 0 → 100644
... ... @@ -0,0 +1,48 @@
  1 +package org.mote.wiimote.whiteboard.gui;
  2 +
  3 +import java.awt.Toolkit;
  4 +import java.awt.event.KeyEvent;
  5 +
  6 +import javax.swing.JMenu;
  7 +import javax.swing.JMenuBar;
  8 +import javax.swing.JMenuItem;
  9 +import javax.swing.KeyStroke;
  10 +
  11 +import org.jdesktop.application.Application;
  12 +import org.mote.wiimote.whiteboard.WiimoteWhiteboard;
  13 +import org.mote.wiimote.whiteboard.util.Util;
  14 +
  15 +@SuppressWarnings("serial")
  16 +public class MenuBar extends JMenuBar {
  17 +
  18 + public MenuBar(PreferencesWindow pf, AboutWindow af, /*HelpHandler hh*/, LogWindow lw) {
  19 + JMenu menu;
  20 + JMenuItem item;
  21 +
  22 + if (!Util.MAC_OS_X) {
  23 + menu = new JMenu(Util.getResourceMap(MenuBar.class).getString("editMenu"));
  24 + menu.add(new JMenuItem(Util.getAction(pf, "preferences")));
  25 + add(menu);
  26 + }
  27 +
  28 + //menu = new JMenu(Util.getResourceMap(HelpHandler.class).getString("help"));
  29 +
  30 + //menu.add(item = new JMenuItem(Util.getAction(hh, "help")));
  31 + if (Util.MAC_OS_X)
  32 + item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_SLASH, KeyEvent.SHIFT_MASK | Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
  33 +
  34 + //menu.addSeparator();
  35 +
  36 + //if (!Util.MAC_OS_X)
  37 + // menu.add(new JMenuItem(Util.getAction(af, "about")));
  38 +
  39 + //menu.add(new JMenuItem(Util.getAction(lw, "log")));
  40 +
  41 + //menu.addSeparator();
  42 +
  43 + //menu.add(new JMenuItem(Util.getAction(Application.getInstance(WiimoteWhiteboard.class), "donate")));
  44 +
  45 + add(menu);
  46 + }
  47 +
  48 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/PreferencesWindow.java 0 → 100644
... ... @@ -0,0 +1,342 @@
  1 +package org.mote.wiimote.whiteboard.gui;
  2 +import java.awt.BorderLayout;
  3 +import java.awt.FlowLayout;
  4 +import java.awt.Insets;
  5 +import java.awt.event.ActionEvent;
  6 +import java.awt.event.ActionListener;
  7 +import java.awt.event.ItemEvent;
  8 +import java.awt.event.ItemListener;
  9 +import java.awt.event.WindowEvent;
  10 +import java.awt.event.WindowFocusListener;
  11 +import java.net.InetAddress;
  12 +import java.net.UnknownHostException;
  13 +import java.util.Dictionary;
  14 +import java.util.Hashtable;
  15 +
  16 +import javax.swing.BorderFactory;
  17 +import javax.swing.ButtonGroup;
  18 +import javax.swing.DefaultComboBoxModel;
  19 +import javax.swing.JButton;
  20 +import javax.swing.JCheckBox;
  21 +import javax.swing.JComboBox;
  22 +import javax.swing.JDialog;
  23 +import javax.swing.JLabel;
  24 +import javax.swing.JOptionPane;
  25 +import javax.swing.JPanel;
  26 +import javax.swing.JRadioButton;
  27 +import javax.swing.JSeparator;
  28 +import javax.swing.JSlider;
  29 +import javax.swing.JTabbedPane;
  30 +import javax.swing.JTextField;
  31 +import javax.swing.UIManager;
  32 +import javax.swing.border.Border;
  33 +import javax.swing.border.TitledBorder;
  34 +import javax.swing.event.ChangeEvent;
  35 +import javax.swing.event.ChangeListener;
  36 +
  37 +import net.miginfocom.swing.MigLayout;
  38 +
  39 +import org.jdesktop.application.Action;
  40 +import org.jdesktop.application.Application;
  41 +import org.jdesktop.application.ResourceMap;
  42 +import org.mote.wiimote.whiteboard.WiimoteWhiteboard;
  43 +import org.mote.wiimote.whiteboard.mouse.DefaultControlStrategy;
  44 +import org.mote.wiimote.whiteboard.mouse.TouchpadControlStrategy;
  45 +import org.mote.wiimote.whiteboard.mouse.smoothing.AdaptiveExponentialSmoothing;
  46 +import org.mote.wiimote.whiteboard.mouse.smoothing.NoSmoothing;
  47 +import org.mote.wiimote.whiteboard.mouse.smoothing.SimpleMovingAverage;
  48 +import org.mote.wiimote.whiteboard.preferences.WWPreferences;
  49 +import org.mote.wiimote.whiteboard.preferences.WWPreferences.LocaleWrapper;
  50 +import org.mote.wiimote.whiteboard.util.Util;
  51 +
  52 +@SuppressWarnings("serial")
  53 +public class PreferencesWindow extends JDialog {
  54 +
  55 + private final static WWPreferences prefs = WWPreferences.getPreferences();
  56 + private final static ResourceMap r = Util.getResourceMap(PreferencesWindow.class);
  57 +
  58 + private JSlider delaySlider;
  59 + private JTextField tuioHost;
  60 + private JButton defaultsButton;
  61 + private JCheckBox batteryWarning, checkForUpdates, tuioEnable, mouseSmoothing, touchpadMode, rightClicks, assistDoubleClicks;
  62 + private JRadioButton staticSmoothing, adaptiveSmoothing;
  63 + private JComboBox languages;
  64 + private JTabbedPane tabbedPane;
  65 + private boolean donePack = false;
  66 +
  67 + public PreferencesWindow(final MainPanel mp, final HelpHandler hh) {
  68 + super(Application.getInstance(WiimoteWhiteboard.class).getMainFrame(), r.getString("preferences.Action.text"));
  69 +
  70 + Border aquaBorder = UIManager.getBorder("TitledBorder.aquaVariant");
  71 + if (aquaBorder != null) UIManager.put("TitledBorder.border", aquaBorder);
  72 +
  73 + // create panels
  74 + tabbedPane = new JTabbedPane();
  75 + JPanel generalPanel = new JPanel(new MigLayout(Util.MAC_OS_X ? "insets para-10 para para para" : ""));
  76 + JPanel mousePanel = new JPanel(new MigLayout(Util.MAC_OS_X ? String.format("insets para-10 para %s para", Util.MAC_OS_X_LEOPARD_OR_HIGHER ? "para-10" : "para") : ""));
  77 + JPanel tuioPanel = new JPanel(new MigLayout(Util.MAC_OS_X ? "insets para-10 para para para" : ""));
  78 + generalPanel.setOpaque(false);
  79 + mousePanel.setOpaque(false);
  80 + tuioPanel.setOpaque(false);
  81 + tabbedPane.addTab(r.getString("generalTab"), generalPanel);
  82 + tabbedPane.addTab(r.getString("mouseTab"), mousePanel);
  83 + tabbedPane.addTab(r.getString("tuioTab"), tuioPanel);
  84 +
  85 + ((JPanel)getContentPane()).setBorder(BorderFactory.createEmptyBorder(8, 10, 10, 10));
  86 + add(tabbedPane, BorderLayout.CENTER);
  87 +
  88 + /*
  89 + * GENERAL PANEL
  90 + */
  91 +
  92 + // check for updates
  93 + generalPanel.add(checkForUpdates = Util.newComponent(JCheckBox.class, "checkForUpdates"), "wrap");
  94 + checkForUpdates.addActionListener(new ActionListener() {
  95 + public void actionPerformed(ActionEvent arg0) {
  96 + prefs.setCheckForUpdates(checkForUpdates.isSelected());
  97 + }
  98 + });
  99 +
  100 + // low battery warning
  101 + generalPanel.add(batteryWarning = Util.newComponent(JCheckBox.class, "batteryWarning"), "wrap");
  102 + batteryWarning.addActionListener(new ActionListener() {
  103 + public void actionPerformed(ActionEvent arg0) {
  104 + prefs.setLowBatteryWarning(batteryWarning.isSelected());
  105 + }
  106 + });
  107 +
  108 + generalPanel.add(new JSeparator(), "split, span, pushx, growx, wrap");
  109 +
  110 + generalPanel.add(Util.newComponent(JLabel.class, "language"), "split, gapbottom 3, gapleft 6");
  111 + generalPanel.add(languages = Util.newComponent(JComboBox.class, "languageBox"), "wrap");
  112 + languages.setModel(new DefaultComboBoxModel(WWPreferences.LANGUAGES));
  113 + languages.addItemListener(new ItemListener() {
  114 + public void itemStateChanged(ItemEvent e) {
  115 + if (e.getStateChange() == ItemEvent.SELECTED) {
  116 + prefs.setLanguage(((LocaleWrapper)languages.getSelectedItem()).getLocaleString());
  117 + }
  118 + }
  119 + });
  120 + generalPanel.add(Util.newComponent(JLabel.class, "languageRestartLabel"), "split, span, w 225, gapleft 6");
  121 +
  122 + /*
  123 + * MOUSE CONTROL PANEL
  124 + */
  125 +
  126 + // touchpad mode
  127 + mousePanel.add(touchpadMode = Util.newComponent(JCheckBox.class, "touchpadMode"), "wrap");
  128 + touchpadMode.addActionListener(new ActionListener() {
  129 + public void actionPerformed(ActionEvent arg0) {
  130 + prefs.setCursorControl(touchpadMode.isSelected() ? TouchpadControlStrategy.class.getName() : DefaultControlStrategy.class.getName());
  131 + }
  132 + });
  133 +
  134 + mousePanel.add(assistDoubleClicks = Util.newComponent(JCheckBox.class, "assistDoubleClicks"), "wrap");
  135 + assistDoubleClicks.addActionListener(new ActionListener() {
  136 + public void actionPerformed(ActionEvent arg0) {
  137 + prefs.setAssistDoubleClicks(assistDoubleClicks.isSelected());
  138 + }
  139 + });
  140 +
  141 + // mouse smoothing
  142 + final ButtonGroup smoothingGroup = new ButtonGroup();
  143 + mousePanel.add(mouseSmoothing = Util.newComponent(JCheckBox.class, "mouseSmoothing"), "split");
  144 + mouseSmoothing.addActionListener(new ActionListener() {
  145 + public void actionPerformed(ActionEvent arg0) {
  146 + staticSmoothing.setEnabled(mouseSmoothing.isSelected());
  147 + adaptiveSmoothing.setEnabled(mouseSmoothing.isSelected());
  148 + if (mouseSmoothing.isSelected()) {
  149 + if (smoothingGroup.getSelection() == null)
  150 + adaptiveSmoothing.doClick();
  151 + else {
  152 + if (adaptiveSmoothing.isSelected()) adaptiveSmoothing.doClick();
  153 + if (staticSmoothing.isSelected()) staticSmoothing.doClick();
  154 + }
  155 + } else {
  156 + prefs.setMouseSmoothing(NoSmoothing.class.getName());
  157 + }
  158 + }
  159 + });
  160 +
  161 + mousePanel.add(staticSmoothing = Util.newComponent(JRadioButton.class, "staticSmoothing"));
  162 + staticSmoothing.addActionListener(new ActionListener() {
  163 + public void actionPerformed(ActionEvent e) {
  164 + prefs.setMouseSmoothing(SimpleMovingAverage.class.getName());
  165 + }
  166 + });
  167 + smoothingGroup.add(staticSmoothing);
  168 +
  169 + mousePanel.add(adaptiveSmoothing = Util.newComponent(JRadioButton.class, "adaptiveSmoothing"));
  170 + adaptiveSmoothing.addActionListener(new ActionListener() {
  171 + public void actionPerformed(ActionEvent e) {
  172 + prefs.setMouseSmoothing(AdaptiveExponentialSmoothing.class.getName());
  173 + }
  174 + });
  175 + smoothingGroup.add(adaptiveSmoothing);
  176 +
  177 +
  178 +
  179 + mousePanel.add(new JSeparator(), "newline, split, span, pushx, growx, wrap");
  180 +
  181 + // right clicks
  182 + mousePanel.add(rightClicks = Util.newComponent(JCheckBox.class, "rightClicks"), "wrap");
  183 + rightClicks.addActionListener(new ActionListener() {
  184 + public void actionPerformed(ActionEvent arg0) {
  185 + prefs.setRightClick(rightClicks.isSelected());
  186 + }
  187 + });
  188 +
  189 + // right click activation delay
  190 + JPanel wrapper = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
  191 + wrapper.setOpaque(false);
  192 + final TitledBorder tb = BorderFactory.createTitledBorder(null, r.getString("rightClickDelay"), TitledBorder.CENTER, TitledBorder.DEFAULT_POSITION, new JLabel().getFont().deriveFont(11f));
  193 + wrapper.setBorder(tb);
  194 + delaySlider = Util.newComponent(JSlider.class, "delaySlider");
  195 + Dictionary<Integer, JLabel> labelTable = new Hashtable<Integer, JLabel>();
  196 + labelTable.put(500, new JLabel("\u00bd"));
  197 + labelTable.put(1000, new JLabel("1"));
  198 + labelTable.put(2000, new JLabel("2"));
  199 + labelTable.put(3000, new JLabel("3"));
  200 + delaySlider.setLabelTable(labelTable);
  201 + delaySlider.addChangeListener(new ChangeListener() {
  202 + public void stateChanged(ChangeEvent e) {
  203 + if (!delaySlider.getValueIsAdjusting() && isVisible()) {
  204 + prefs.setRightClickDelay(delaySlider.getValue());
  205 + }
  206 + }
  207 + });
  208 + Insets tbInsets = tb.getBorderInsets(wrapper);
  209 + int tbWidth = tb.getMinimumSize(wrapper).width-tbInsets.left-tbInsets.right+(Util.MAC_OS_X_LEOPARD_OR_HIGHER ? 0 : 20);
  210 + wrapper.add(delaySlider);
  211 + mousePanel.add(wrapper, "center, growx, w " +tbWidth);
  212 +
  213 + /*
  214 + * TUIO/OSC PANEL
  215 + */
  216 +
  217 + // enable tuio
  218 + tuioPanel.add(tuioEnable = Util.newComponent(JCheckBox.class, "tuioEnable"), "wrap");
  219 + tuioEnable.addActionListener(new ActionListener() {
  220 + public void actionPerformed(ActionEvent arg0) {
  221 + if (tuioEnable.isSelected()) {
  222 + String[] s = tuioHost.getText().split(":");
  223 + String errorTitle = null;
  224 + if ((s.length == 1 && s[0].length() == 0) || s.length > 2) {
  225 + errorTitle = r.getString("tuioInvalidFormat");
  226 + } else {
  227 + try {
  228 + int port = 3333;
  229 + if (s.length == 2) {
  230 + port = Integer.valueOf(s[1]);
  231 + if (port < 0 || port > 0xFFFF) {
  232 + throw new NumberFormatException();
  233 + }
  234 + }
  235 + InetAddress.getByName(s[0]);
  236 +
  237 + prefs.setTuioPort(port);
  238 + prefs.setTuioHost(s[0]);
  239 + prefs.setTuioEnabled(true);
  240 + } catch (NumberFormatException e) {
  241 + errorTitle = r.getString("tuioInvalidPort", s[1]);
  242 + } catch (UnknownHostException e) {
  243 + errorTitle = r.getString("tuioInvalidHost", s[0]);
  244 + }
  245 + }
  246 +
  247 + if (errorTitle != null) {
  248 + JOptionPane.showMessageDialog(PreferencesWindow.this, r.getString("tuioErrorMessage"), errorTitle, JOptionPane.ERROR_MESSAGE);
  249 + }
  250 +
  251 + } else {
  252 + prefs.setTuioEnabled(false);
  253 + }
  254 + update();
  255 + }
  256 + });
  257 +
  258 + // tuio host
  259 + tuioPanel.add(tuioHost = Util.newComponent(JTextField.class, "tuioHost"), "growx, pushx, wrap");
  260 +
  261 +
  262 + JPanel bottomPanel = new JPanel(new MigLayout(Util.MAC_OS_X ? "insets 0 2 0 2, gap 0" : "insets i 0 0 0, gap 0"));
  263 + add(bottomPanel, BorderLayout.SOUTH);
  264 +
  265 + bottomPanel.add(defaultsButton = Util.newComponent(JButton.class, "resetButton"));
  266 + defaultsButton.addActionListener(new ActionListener() {
  267 + public void actionPerformed(ActionEvent e) {
  268 + prefs.reset();
  269 + mp.update();
  270 + update();
  271 + }
  272 + });
  273 +
  274 + JButton helpButton = new JButton(Util.getAction(hh, "help"));
  275 + bottomPanel.add(helpButton, "push, right");
  276 + if (Util.MAC_OS_X_LEOPARD_OR_HIGHER) {
  277 + helpButton.setText("");
  278 + helpButton.putClientProperty("JButton.buttonType", "help");
  279 + } else {
  280 + helpButton.setText(Util.getResourceMap(HelpHandler.class).getString("help"));
  281 + }
  282 +
  283 + Util.getResourceMap(PreferencesWindow.class).injectComponents(this);
  284 +
  285 + pack();
  286 + setResizable(false);
  287 +
  288 + if (Util.WINDOWS) {
  289 + addWindowFocusListener(new WindowFocusListener() {
  290 + public void windowGainedFocus(WindowEvent e) {
  291 + if (!donePack) {
  292 + donePack = true;
  293 + pack();
  294 + Util.placeDialogWindow(PreferencesWindow.this, getWidth(), getHeight());
  295 + }
  296 + }
  297 + public void windowLostFocus(WindowEvent e) {}
  298 + });
  299 + }
  300 + }
  301 +
  302 + private void update() {
  303 + checkForUpdates.setSelected(prefs.checkForUpdates());
  304 + batteryWarning.setSelected(prefs.isLowBatteryWarning());
  305 + rightClicks.setSelected(prefs.isRightClick());
  306 + assistDoubleClicks.setSelected(prefs.assistDoubleClicks());
  307 + delaySlider.setValue((int)prefs.getRightClickDelay());
  308 + tuioEnable.setSelected(prefs.isTuioEnabled());
  309 + tuioHost.setText(String.format("%s:%d", prefs.getTuioHost(), prefs.getTuioPort()));
  310 + tuioHost.setEnabled(!tuioEnable.isSelected());
  311 + tuioHost.setToolTipText(tuioHost.isEnabled() ? Util.getResourceMap(PreferencesWindow.class).getString("tuioHost.toolTipText") : r.getString("tuioDisableToEdit"));
  312 +
  313 + touchpadMode.setSelected(TouchpadControlStrategy.class.getName().equals(prefs.getCursorControl()));
  314 +
  315 + mouseSmoothing.setSelected(!NoSmoothing.class.getName().equals(prefs.getMouseSmoothing()));
  316 + adaptiveSmoothing.setSelected(true);
  317 + staticSmoothing.setSelected(SimpleMovingAverage.class.getName().equals(prefs.getMouseSmoothing()));
  318 + adaptiveSmoothing.setEnabled(mouseSmoothing.isSelected());
  319 + staticSmoothing.setEnabled(mouseSmoothing.isSelected());
  320 +
  321 + String lang = prefs.getLanguage();
  322 + for (int i = 0; i < languages.getItemCount(); i++) {
  323 + LocaleWrapper lw = (LocaleWrapper)languages.getItemAt(i);
  324 + if (lang.equals(lw.getLocaleString())) {
  325 + languages.setSelectedIndex(i);
  326 + break;
  327 + }
  328 + }
  329 + }
  330 +
  331 + @Action
  332 + public void preferences() {
  333 + if (!isVisible()) {
  334 + update();
  335 + pack();
  336 +
  337 + Util.placeDialogWindow(this, getWidth(), getHeight());
  338 + }
  339 + setVisible(true);
  340 + }
  341 +
  342 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/PreferencesWindow.java~ 0 → 100644
... ... @@ -0,0 +1,396 @@
  1 +/*
  2 + * Copyright (C) 2008-2009, Uwe Schmidt
  3 + *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a
  5 + * copy of this software and associated documentation files (the "Software"),
  6 + * to deal in the Software without restriction, including without limitation
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8 + * and/or sell copies of the Software, and to permit persons to whom the
  9 + * Software is furnished to do so, subject to the following conditions:
  10 + *
  11 + * The above copyright notice and this permission notice shall be included in
  12 + * all copies or substantial portions of the Software.
  13 + *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20 + * DEALINGS IN THE SOFTWARE.
  21 + *
  22 + * The Software uses a third-party library (WiiRemoteJ) which is not part of
  23 + * the Software and is subject to its own license.
  24 + */
  25 +
  26 +package org.uweschmidt.wiimote.whiteboard.gui;
  27 +import java.awt.BorderLayout;
  28 +import java.awt.FlowLayout;
  29 +import java.awt.Insets;
  30 +import java.awt.event.ActionEvent;
  31 +import java.awt.event.ActionListener;
  32 +import java.awt.event.ItemEvent;
  33 +import java.awt.event.ItemListener;
  34 +import java.awt.event.WindowEvent;
  35 +import java.awt.event.WindowFocusListener;
  36 +import java.net.InetAddress;
  37 +import java.net.UnknownHostException;
  38 +import java.util.Dictionary;
  39 +import java.util.Hashtable;
  40 +
  41 +import javax.swing.BorderFactory;
  42 +import javax.swing.ButtonGroup;
  43 +import javax.swing.DefaultComboBoxModel;
  44 +import javax.swing.JButton;
  45 +import javax.swing.JCheckBox;
  46 +import javax.swing.JComboBox;
  47 +import javax.swing.JDialog;
  48 +import javax.swing.JLabel;
  49 +import javax.swing.JOptionPane;
  50 +import javax.swing.JPanel;
  51 +import javax.swing.JRadioButton;
  52 +import javax.swing.JSeparator;
  53 +import javax.swing.JSlider;
  54 +import javax.swing.JTabbedPane;
  55 +import javax.swing.JTextField;
  56 +import javax.swing.UIManager;
  57 +import javax.swing.border.Border;
  58 +import javax.swing.border.TitledBorder;
  59 +import javax.swing.event.ChangeEvent;
  60 +import javax.swing.event.ChangeListener;
  61 +
  62 +import net.miginfocom.swing.MigLayout;
  63 +
  64 +import org.jdesktop.application.Action;
  65 +import org.jdesktop.application.Application;
  66 +import org.jdesktop.application.ResourceMap;
  67 +import org.uweschmidt.wiimote.whiteboard.WiimoteWhiteboard;
  68 +import org.uweschmidt.wiimote.whiteboard.mouse.DefaultControlStrategy;
  69 +import org.uweschmidt.wiimote.whiteboard.mouse.TouchpadControlStrategy;
  70 +import org.uweschmidt.wiimote.whiteboard.mouse.smoothing.AdaptiveExponentialSmoothing;
  71 +import org.uweschmidt.wiimote.whiteboard.mouse.smoothing.NoSmoothing;
  72 +import org.uweschmidt.wiimote.whiteboard.mouse.smoothing.SimpleMovingAverage;
  73 +import org.uweschmidt.wiimote.whiteboard.preferences.WWPreferences;
  74 +import org.uweschmidt.wiimote.whiteboard.preferences.WWPreferences.LocaleWrapper;
  75 +import org.uweschmidt.wiimote.whiteboard.util.Util;
  76 +
  77 +@SuppressWarnings("serial")
  78 +public class PreferencesWindow extends JDialog {
  79 +
  80 + private final static WWPreferences prefs = WWPreferences.getPreferences();
  81 + private final static ResourceMap r = Util.getResourceMap(PreferencesWindow.class);
  82 +
  83 + private JSlider delaySlider;
  84 + private JTextField tuioHost;
  85 + private JButton defaultsButton;
  86 + private JCheckBox batteryWarning, checkForUpdates, tuioEnable, mouseSmoothing, touchpadMode, rightClicks, assistDoubleClicks;
  87 + private JRadioButton staticSmoothing, adaptiveSmoothing;
  88 +// private JRadioButton[] wiimoteNumberButtons = new JRadioButton[WWPreferences.WIIMOTES];
  89 + private JComboBox languages;
  90 + private JTabbedPane tabbedPane;
  91 + private boolean donePack = false;
  92 +
  93 + public PreferencesWindow(final MainPanel mp, final HelpHandler hh) {
  94 + super(Application.getInstance(WiimoteWhiteboard.class).getMainFrame(), r.getString("preferences.Action.text"));
  95 +
  96 + // use NSBox-like TitledBorder if available (Leopard)
  97 + Border aquaBorder = UIManager.getBorder("TitledBorder.aquaVariant");
  98 + if (aquaBorder != null) UIManager.put("TitledBorder.border", aquaBorder);
  99 +
  100 + // create panels
  101 + tabbedPane = new JTabbedPane();
  102 + JPanel generalPanel = new JPanel(new MigLayout(Util.MAC_OS_X ? "insets para-10 para para para" : ""));
  103 + // FIXME bottom insets too large, but only in French on Leopard?!
  104 + JPanel mousePanel = new JPanel(new MigLayout(Util.MAC_OS_X ? String.format("insets para-10 para %s para", Util.MAC_OS_X_LEOPARD_OR_HIGHER ? "para-10" : "para") : ""));
  105 + JPanel tuioPanel = new JPanel(new MigLayout(Util.MAC_OS_X ? "insets para-10 para para para" : ""));
  106 + generalPanel.setOpaque(false);
  107 + mousePanel.setOpaque(false);
  108 + tuioPanel.setOpaque(false);
  109 + tabbedPane.addTab(r.getString("generalTab"), generalPanel);
  110 + tabbedPane.addTab(r.getString("mouseTab"), mousePanel);
  111 + tabbedPane.addTab(r.getString("tuioTab"), tuioPanel);
  112 +
  113 + ((JPanel)getContentPane()).setBorder(BorderFactory.createEmptyBorder(8, 10, 10, 10));
  114 + add(tabbedPane, BorderLayout.CENTER);
  115 +
  116 + /*
  117 + * GENERAL PANEL
  118 + */
  119 +
  120 + // check for updates
  121 + generalPanel.add(checkForUpdates = Util.newComponent(JCheckBox.class, "checkForUpdates"), "wrap");
  122 + checkForUpdates.addActionListener(new ActionListener() {
  123 + public void actionPerformed(ActionEvent arg0) {
  124 + prefs.setCheckForUpdates(checkForUpdates.isSelected());
  125 + }
  126 + });
  127 +
  128 + // low battery warning
  129 + generalPanel.add(batteryWarning = Util.newComponent(JCheckBox.class, "batteryWarning"), "wrap");
  130 + batteryWarning.addActionListener(new ActionListener() {
  131 + public void actionPerformed(ActionEvent arg0) {
  132 + prefs.setLowBatteryWarning(batteryWarning.isSelected());
  133 + }
  134 + });
  135 +
  136 + generalPanel.add(new JSeparator(), "split, span, pushx, growx, wrap");
  137 +
  138 + generalPanel.add(Util.newComponent(JLabel.class, "language"), "split, gapbottom 3, gapleft 6");
  139 + generalPanel.add(languages = Util.newComponent(JComboBox.class, "languageBox"), "wrap");
  140 +// languages.putClientProperty("JComboBox.isSquare", Boolean.TRUE);
  141 +// languages.putClientProperty("JComboBox.isPopDown", Boolean.TRUE);
  142 + languages.setModel(new DefaultComboBoxModel(WWPreferences.LANGUAGES));
  143 + languages.addItemListener(new ItemListener() {
  144 + public void itemStateChanged(ItemEvent e) {
  145 + if (e.getStateChange() == ItemEvent.SELECTED) {
  146 + prefs.setLanguage(((LocaleWrapper)languages.getSelectedItem()).getLocaleString());
  147 + }
  148 + }
  149 + });
  150 + generalPanel.add(Util.newComponent(JLabel.class, "languageRestartLabel"), "split, span, w 225, gapleft 6");
  151 +
  152 +// // number of wiimotes
  153 +// generalPanel.add(Util.newComponent(JLabel.class, "numberOfWiimotesLabel"));
  154 +// ButtonGroup bg = new ButtonGroup();
  155 +// for (int i = 1; i <= WWPreferences.WIIMOTES; i++) {
  156 +// final int j = i-1;
  157 +// bg.add(wiimoteNumberButtons[j] = new JRadioButton(String.valueOf(i)));
  158 +// wiimoteNumberButtons[j].setOpaque(false);
  159 +// wiimoteNumberButtons[j].addActionListener(new ActionListener() {
  160 +// public void actionPerformed(ActionEvent e) {
  161 +// prefs.setNumberOfWiimotes(j+1);
  162 +// }
  163 +// });
  164 +// generalPanel.add(wiimoteNumberButtons[j], i == 1 ? "split" : "");
  165 +// }
  166 +// generalPanel.add(Util.newComponent(JLabel.class, "numberOfWiimotesExplLabel"), "newline, split, span, center, w 290");
  167 +
  168 + /*
  169 + * MOUSE CONTROL PANEL
  170 + */
  171 +
  172 + // touchpad mode
  173 + mousePanel.add(touchpadMode = Util.newComponent(JCheckBox.class, "touchpadMode"), "wrap");
  174 + touchpadMode.addActionListener(new ActionListener() {
  175 + public void actionPerformed(ActionEvent arg0) {
  176 + prefs.setCursorControl(touchpadMode.isSelected() ? TouchpadControlStrategy.class.getName() : DefaultControlStrategy.class.getName());
  177 + }
  178 + });
  179 +
  180 + // assist double clicks
  181 + mousePanel.add(assistDoubleClicks = Util.newComponent(JCheckBox.class, "assistDoubleClicks"), "wrap");
  182 + assistDoubleClicks.addActionListener(new ActionListener() {
  183 + public void actionPerformed(ActionEvent arg0) {
  184 + prefs.setAssistDoubleClicks(assistDoubleClicks.isSelected());
  185 + }
  186 + });
  187 +
  188 + // mouse smoothing
  189 + final ButtonGroup smoothingGroup = new ButtonGroup();
  190 + mousePanel.add(mouseSmoothing = Util.newComponent(JCheckBox.class, "mouseSmoothing"), "split");
  191 + mouseSmoothing.addActionListener(new ActionListener() {
  192 + public void actionPerformed(ActionEvent arg0) {
  193 + staticSmoothing.setEnabled(mouseSmoothing.isSelected());
  194 + adaptiveSmoothing.setEnabled(mouseSmoothing.isSelected());
  195 + if (mouseSmoothing.isSelected()) {
  196 + if (smoothingGroup.getSelection() == null)
  197 + adaptiveSmoothing.doClick();
  198 + else {
  199 + // trigger actionlistener
  200 + if (adaptiveSmoothing.isSelected()) adaptiveSmoothing.doClick();
  201 + if (staticSmoothing.isSelected()) staticSmoothing.doClick();
  202 + }
  203 + } else {
  204 + prefs.setMouseSmoothing(NoSmoothing.class.getName());
  205 + }
  206 + }
  207 + });
  208 +
  209 + mousePanel.add(staticSmoothing = Util.newComponent(JRadioButton.class, "staticSmoothing"));
  210 + staticSmoothing.addActionListener(new ActionListener() {
  211 + public void actionPerformed(ActionEvent e) {
  212 + prefs.setMouseSmoothing(SimpleMovingAverage.class.getName());
  213 + }
  214 + });
  215 + smoothingGroup.add(staticSmoothing);
  216 +
  217 + mousePanel.add(adaptiveSmoothing = Util.newComponent(JRadioButton.class, "adaptiveSmoothing"));
  218 + adaptiveSmoothing.addActionListener(new ActionListener() {
  219 + public void actionPerformed(ActionEvent e) {
  220 + prefs.setMouseSmoothing(AdaptiveExponentialSmoothing.class.getName());
  221 + }
  222 + });
  223 + smoothingGroup.add(adaptiveSmoothing);
  224 +
  225 +
  226 +
  227 + mousePanel.add(new JSeparator(), "newline, split, span, pushx, growx, wrap");
  228 +
  229 + // right clicks
  230 + mousePanel.add(rightClicks = Util.newComponent(JCheckBox.class, "rightClicks"), "wrap");
  231 + rightClicks.addActionListener(new ActionListener() {
  232 + public void actionPerformed(ActionEvent arg0) {
  233 + prefs.setRightClick(rightClicks.isSelected());
  234 + }
  235 + });
  236 +
  237 + // right click activation delay
  238 + JPanel wrapper = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
  239 + wrapper.setOpaque(false);
  240 + final TitledBorder tb = BorderFactory.createTitledBorder(null, r.getString("rightClickDelay"), TitledBorder.CENTER, TitledBorder.DEFAULT_POSITION, new JLabel().getFont().deriveFont(11f));
  241 + wrapper.setBorder(tb);
  242 + delaySlider = Util.newComponent(JSlider.class, "delaySlider");
  243 + Dictionary<Integer, JLabel> labelTable = new Hashtable<Integer, JLabel>();
  244 + labelTable.put(500, new JLabel("\u00bd"));
  245 + labelTable.put(1000, new JLabel("1"));
  246 + labelTable.put(2000, new JLabel("2"));
  247 + labelTable.put(3000, new JLabel("3"));
  248 + delaySlider.setLabelTable(labelTable);
  249 + delaySlider.addChangeListener(new ChangeListener() {
  250 + public void stateChanged(ChangeEvent e) {
  251 + if (!delaySlider.getValueIsAdjusting() && isVisible()) {
  252 + prefs.setRightClickDelay(delaySlider.getValue());
  253 + }
  254 + }
  255 + });
  256 + Insets tbInsets = tb.getBorderInsets(wrapper);
  257 + int tbWidth = tb.getMinimumSize(wrapper).width-tbInsets.left-tbInsets.right+(Util.MAC_OS_X_LEOPARD_OR_HIGHER ? 0 : 20);
  258 + wrapper.add(delaySlider);
  259 + mousePanel.add(wrapper, "center, growx, w " +tbWidth);
  260 +
  261 + /*
  262 + * TUIO/OSC PANEL
  263 + */
  264 +
  265 + // enable tuio
  266 + tuioPanel.add(tuioEnable = Util.newComponent(JCheckBox.class, "tuioEnable"), "wrap");
  267 + tuioEnable.addActionListener(new ActionListener() {
  268 + public void actionPerformed(ActionEvent arg0) {
  269 + if (tuioEnable.isSelected()) {
  270 + String[] s = tuioHost.getText().split(":");
  271 + String errorTitle = null;
  272 + if ((s.length == 1 && s[0].length() == 0) || s.length > 2) {
  273 + errorTitle = r.getString("tuioInvalidFormat");
  274 + } else {
  275 + try {
  276 + int port = 3333;
  277 + if (s.length == 2) {
  278 + port = Integer.valueOf(s[1]);
  279 + if (port < 0 || port > 0xFFFF) {
  280 + throw new NumberFormatException();
  281 + }
  282 + }
  283 + InetAddress.getByName(s[0]);
  284 +
  285 + prefs.setTuioPort(port);
  286 + prefs.setTuioHost(s[0]);
  287 + prefs.setTuioEnabled(true);
  288 + } catch (NumberFormatException e) {
  289 + errorTitle = r.getString("tuioInvalidPort", s[1]);
  290 + } catch (UnknownHostException e) {
  291 + errorTitle = r.getString("tuioInvalidHost", s[0]);
  292 + }
  293 + }
  294 +
  295 + if (errorTitle != null) {
  296 + JOptionPane.showMessageDialog(PreferencesWindow.this, r.getString("tuioErrorMessage"), errorTitle, JOptionPane.ERROR_MESSAGE);
  297 + }
  298 +
  299 + } else {
  300 + prefs.setTuioEnabled(false);
  301 + }
  302 + update();
  303 + }
  304 + });
  305 +
  306 + // tuio host
  307 + tuioPanel.add(tuioHost = Util.newComponent(JTextField.class, "tuioHost"), "growx, pushx, wrap");
  308 +
  309 +
  310 + JPanel bottomPanel = new JPanel(new MigLayout(Util.MAC_OS_X ? "insets 0 2 0 2, gap 0" : "insets i 0 0 0, gap 0"));
  311 + add(bottomPanel, BorderLayout.SOUTH);
  312 +
  313 + bottomPanel.add(defaultsButton = Util.newComponent(JButton.class, "resetButton"));
  314 +// defaultsButton.putClientProperty("JButton.buttonType", "textured");
  315 + defaultsButton.addActionListener(new ActionListener() {
  316 + public void actionPerformed(ActionEvent e) {
  317 + prefs.reset();
  318 + // re-set currently chosen mouse control settings
  319 + // (probably not perceived as persistent preferences by user)
  320 + mp.update();
  321 + update();
  322 + }
  323 + });
  324 +
  325 + JButton helpButton = new JButton(Util.getAction(hh, "help"));
  326 + bottomPanel.add(helpButton, "push, right");
  327 + if (Util.MAC_OS_X_LEOPARD_OR_HIGHER) {
  328 + helpButton.setText("");
  329 + helpButton.putClientProperty("JButton.buttonType", "help");
  330 + } else {
  331 + helpButton.setText(Util.getResourceMap(HelpHandler.class).getString("help"));
  332 + }
  333 +
  334 + Util.getResourceMap(PreferencesWindow.class).injectComponents(this);
  335 +
  336 + pack();
  337 + setResizable(false);
  338 +
  339 + if (Util.WINDOWS) {
  340 + addWindowFocusListener(new WindowFocusListener() {
  341 + public void windowGainedFocus(WindowEvent e) {
  342 + if (!donePack) {
  343 + donePack = true;
  344 + pack();
  345 + Util.placeDialogWindow(PreferencesWindow.this, getWidth(), getHeight());
  346 + }
  347 + }
  348 + public void windowLostFocus(WindowEvent e) {}
  349 + });
  350 + }
  351 + }
  352 +
  353 + private void update() {
  354 + checkForUpdates.setSelected(prefs.checkForUpdates());
  355 + batteryWarning.setSelected(prefs.isLowBatteryWarning());
  356 + rightClicks.setSelected(prefs.isRightClick());
  357 + assistDoubleClicks.setSelected(prefs.assistDoubleClicks());
  358 + delaySlider.setValue((int)prefs.getRightClickDelay());
  359 + tuioEnable.setSelected(prefs.isTuioEnabled());
  360 + tuioHost.setText(String.format("%s:%d", prefs.getTuioHost(), prefs.getTuioPort()));
  361 + tuioHost.setEnabled(!tuioEnable.isSelected());
  362 + tuioHost.setToolTipText(tuioHost.isEnabled() ? Util.getResourceMap(PreferencesWindow.class).getString("tuioHost.toolTipText") : r.getString("tuioDisableToEdit"));
  363 +// wiimoteNumberButtons[prefs.getNumberOfWiimotes()-1].setSelected(true);
  364 +
  365 + touchpadMode.setSelected(TouchpadControlStrategy.class.getName().equals(prefs.getCursorControl()));
  366 +
  367 + mouseSmoothing.setSelected(!NoSmoothing.class.getName().equals(prefs.getMouseSmoothing()));
  368 + adaptiveSmoothing.setSelected(true);
  369 + staticSmoothing.setSelected(SimpleMovingAverage.class.getName().equals(prefs.getMouseSmoothing()));
  370 + adaptiveSmoothing.setEnabled(mouseSmoothing.isSelected());
  371 + staticSmoothing.setEnabled(mouseSmoothing.isSelected());
  372 +
  373 + String lang = prefs.getLanguage();
  374 + for (int i = 0; i < languages.getItemCount(); i++) {
  375 + LocaleWrapper lw = (LocaleWrapper)languages.getItemAt(i);
  376 + if (lang.equals(lw.getLocaleString())) {
  377 + languages.setSelectedIndex(i);
  378 + break;
  379 + }
  380 + }
  381 + }
  382 +
  383 + @Action
  384 + public void preferences() {
  385 + if (!isVisible()) {
  386 + update();
  387 + pack();
  388 +// if (Util.WINDOWS && !donePack) {
  389 +// setSize(getWidth(), 300);
  390 +// }
  391 + Util.placeDialogWindow(this, getWidth(), getHeight());
  392 + }
  393 + setVisible(true);
  394 + }
  395 +
  396 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/ScreenSelector.java 0 → 100644
... ... @@ -0,0 +1,206 @@
  1 +package org.mote.wiimote.whiteboard.gui;
  2 +
  3 +import java.awt.BasicStroke;
  4 +import java.awt.Color;
  5 +import java.awt.Dimension;
  6 +import java.awt.Graphics;
  7 +import java.awt.Graphics2D;
  8 +import java.awt.GraphicsDevice;
  9 +import java.awt.GraphicsEnvironment;
  10 +import java.awt.Point;
  11 +import java.awt.Rectangle;
  12 +import java.awt.RenderingHints;
  13 +import java.awt.event.ItemEvent;
  14 +import java.awt.event.ItemListener;
  15 +import java.awt.geom.Point2D;
  16 +import java.awt.geom.Rectangle2D;
  17 +import java.util.Iterator;
  18 +import java.util.LinkedList;
  19 +import java.util.List;
  20 +import java.util.Map;
  21 +import java.util.Timer;
  22 +import java.util.TimerTask;
  23 +
  24 +import javax.media.jai.PerspectiveTransform;
  25 +import javax.swing.BorderFactory;
  26 +import javax.swing.ButtonGroup;
  27 +import javax.swing.JPanel;
  28 +import javax.swing.JRadioButton;
  29 +import javax.swing.SwingConstants;
  30 +
  31 +import org.mote.wiimote.whiteboard.WiimoteDataHandler;
  32 +import org.mote.wiimote.whiteboard.WiimoteDataHandler.WiimoteDataListener;
  33 +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration;
  34 +import org.mote.wiimote.whiteboard.ds.IRDot;
  35 +import org.mote.wiimote.whiteboard.ds.Wiimote;
  36 +import org.mote.wiimote.whiteboard.util.Util;
  37 +
  38 +@SuppressWarnings("serial")
  39 +public class ScreenSelector extends JPanel implements WiimoteDataListener {
  40 +
  41 + private static final GraphicsDevice DEFAULT_SCREEN = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
  42 + private static final int MAX_H = 130;
  43 + private static final int MAX_W = 185;
  44 +
  45 + private static final long REPAINT_FREQ = 1000 / 20;
  46 +
  47 + private WiimoteCalibration calibration;
  48 + private List<ScreenBox> screenBoxes = new LinkedList<ScreenBox>();
  49 + private Point lastCursor = null, cursor = null;
  50 +
  51 + public ScreenSelector(WiimoteCalibration calibration, WiimoteDataHandler dh) {
  52 + super(null);
  53 + this.calibration = calibration;
  54 + dh.addWiimoteDataListener(this);
  55 +
  56 + final GraphicsDevice[] screens = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices();
  57 +
  58 + Rectangle r = new Rectangle();
  59 + for (GraphicsDevice s : screens) {
  60 + r = r.union(s.getDefaultConfiguration().getBounds());
  61 + }
  62 +
  63 + final int maxH = MAX_H - (screens.length == 1 ? 30 : 0);
  64 + int w = MAX_W;
  65 + int h = (int) Math.round((w * r.getHeight()) / r.getWidth());
  66 + // if too high
  67 + if (h > maxH) {
  68 + h = maxH;
  69 + w = (int) Math.round((h * r.getWidth()) / r.getHeight());
  70 + }
  71 + setPreferredSize(new Dimension(w, h));
  72 +
  73 + PerspectiveTransform t = PerspectiveTransform.getQuadToQuad(
  74 + r.getMinX(), r.getMinY(), r.getMaxX(), r.getMinY(),
  75 + r.getMaxX(), r.getMaxY(), r.getMinX(), r.getMaxY(),
  76 + 0, 0, w, 0, w, h, 0, h);
  77 +
  78 + ButtonGroup bg = new ButtonGroup();
  79 + for (int i = 0; i < screens.length; i++) {
  80 + Rectangle b = screens[i].getDefaultConfiguration().getBounds();
  81 + final ScreenBox sb = new ScreenBox(screens[i], i, transformBounds(t, b), screens[i].equals(DEFAULT_SCREEN));
  82 + bg.add(sb);
  83 + screenBoxes.add(sb);
  84 + add(sb);
  85 + }
  86 +
  87 + new Timer(true).schedule(new UpdateTask(), 0, REPAINT_FREQ);
  88 + }
  89 +
  90 + private class UpdateTask extends TimerTask {
  91 + @Override
  92 + public void run() {
  93 + if (cursor != lastCursor) {
  94 + for (ScreenBox sb : screenBoxes) {
  95 + if (sb.isSelected() && sb.isEnabled()) {
  96 + lastCursor = cursor;
  97 + sb.repaint();
  98 + }
  99 + }
  100 + }
  101 + }
  102 + }
  103 +
  104 + private Rectangle transformBounds(PerspectiveTransform t, Rectangle b) {
  105 + Point2D ul = t.transform(new Point2D.Double(b.getMinX(), b.getMinY()), null);
  106 + Point2D ur = t.transform(new Point2D.Double(b.getMaxX(), b.getMinY()), null);
  107 + Point2D ll = t.transform(new Point2D.Double(b.getMinX(), b.getMaxY()), null);
  108 + return new Rectangle2D.Double(ul.getX(), ul.getY(), ul.distance(ur), ul.distance(ll)).getBounds();
  109 + }
  110 +
  111 + @Override
  112 + public void setEnabled(boolean enabled) {
  113 + super.setEnabled(enabled);
  114 + enableScreenBoxes(enabled);
  115 + }
  116 +
  117 + private class ScreenBox extends JRadioButton {
  118 + private final BasicStroke STROKE = new BasicStroke(2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER);
  119 + private static final int DIAMETER = 4;
  120 + private static final int MAX_TRACE = 1000 / (int)REPAINT_FREQ;
  121 + private LinkedList<Point> trace = new LinkedList<Point>();
  122 + private GraphicsDevice screen;
  123 + private final Rectangle bounds;
  124 + public ScreenBox(GraphicsDevice screen, int i, Rectangle b, boolean selected) {
  125 + super(Util.getResourceMap(ScreenSelector.class).getString("screenText", i+1, (int)screen.getDefaultConfiguration().getBounds().getWidth(), (int)screen.getDefaultConfiguration().getBounds().getHeight()));
  126 + this.screen = screen;
  127 + bounds = screen.getDefaultConfiguration().getBounds();
  128 +
  129 + setBounds(b);
  130 + setSelected(selected);
  131 +
  132 + setFocusable(false);
  133 + setHorizontalAlignment(SwingConstants.CENTER);
  134 +
  135 + if (!Util.MAC_OS_X) setBorder(BorderFactory.createEtchedBorder());
  136 + setBorderPainted(true);
  137 +
  138 + addItemListener(new ItemListener() {
  139 + public void itemStateChanged(ItemEvent e) {
  140 + if (e.getStateChange() == ItemEvent.SELECTED) {
  141 + calibration.setScreen(ScreenBox.this.screen);
  142 + }
  143 + }
  144 + });
  145 + }
  146 +
  147 + @Override
  148 + protected void paintComponent(Graphics g) {
  149 + super.paintComponent(g);
  150 + if (isSelected() && cursor != null) {
  151 + Graphics2D g2d = (Graphics2D)g;
  152 + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
  153 + try {
  154 +
  155 + int x = Math.max(0, Math.min(getWidth(), (int)Math.round(((cursor.x - bounds.x) / bounds.getWidth()) * getWidth())));
  156 + int y = Math.max(0, Math.min(getHeight(), (int)Math.round(((cursor.y - bounds.y) / bounds.getHeight()) * getHeight())));
  157 +
  158 + if (trace.size() > MAX_TRACE)
  159 + trace.removeFirst();
  160 +
  161 + if (!trace.isEmpty()) {
  162 + g2d.setStroke(STROKE);
  163 + int inc = 255/MAX_TRACE, alpha = (MAX_TRACE - trace.size()) * inc;
  164 + Iterator<Point> it = trace.iterator();
  165 + Point lp = it.next();
  166 + while (it.hasNext()) {
  167 + Point p = it.next();
  168 + g2d.setColor(new Color(0,0,255,alpha));
  169 + g2d.drawLine(lp.x, lp.y, p.x, p.y);
  170 + lp = p;
  171 + alpha += inc;
  172 + }
  173 + g2d.setColor(Color.blue);
  174 + g2d.drawLine(lp.x, lp.y, x, y);
  175 + }
  176 +
  177 + g2d.setColor(Color.blue);
  178 + g2d.fillOval(x-DIAMETER/2, y-DIAMETER/2, DIAMETER, DIAMETER);
  179 +
  180 + trace.addLast(new Point(x,y));
  181 + } catch (NullPointerException e) {
  182 + trace.clear();
  183 + }
  184 + } else {
  185 + trace.clear();
  186 + }
  187 + }
  188 + }
  189 +
  190 + private void enableScreenBoxes(boolean enabled) {
  191 +
  192 + for (ScreenBox b : screenBoxes)
  193 + b.setEnabled(enabled);
  194 + }
  195 +
  196 + public void irWarped(Map<Wiimote, IRDot[]> data, Point[] warped) {
  197 + cursor = warped[0];
  198 + }
  199 + public void batteryLevel(Wiimote wiimote, double level) {}
  200 + public void irLights(Wiimote wiimote, IRDot[] lights) {}
  201 + public void wiimoteConnected(Wiimote wiimote) {}
  202 + public void wiimoteDisconnected(Wiimote wiimote) {}
  203 +
  204 +
  205 +
  206 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/ScreenSelector.java~ 0 → 100644
... ... @@ -0,0 +1,311 @@
  1 +/*
  2 + * Copyright (C) 2008-2009, Uwe Schmidt
  3 + *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a
  5 + * copy of this software and associated documentation files (the "Software"),
  6 + * to deal in the Software without restriction, including without limitation
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8 + * and/or sell copies of the Software, and to permit persons to whom the
  9 + * Software is furnished to do so, subject to the following conditions:
  10 + *
  11 + * The above copyright notice and this permission notice shall be included in
  12 + * all copies or substantial portions of the Software.
  13 + *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20 + * DEALINGS IN THE SOFTWARE.
  21 + *
  22 + * The Software uses a third-party library (WiiRemoteJ) which is not part of
  23 + * the Software and is subject to its own license.
  24 + */
  25 +
  26 +package org.uweschmidt.wiimote.whiteboard.gui;
  27 +
  28 +import java.awt.BasicStroke;
  29 +import java.awt.Color;
  30 +import java.awt.Dimension;
  31 +import java.awt.Graphics;
  32 +import java.awt.Graphics2D;
  33 +import java.awt.GraphicsDevice;
  34 +import java.awt.GraphicsEnvironment;
  35 +import java.awt.Point;
  36 +import java.awt.Rectangle;
  37 +import java.awt.RenderingHints;
  38 +import java.awt.event.ItemEvent;
  39 +import java.awt.event.ItemListener;
  40 +import java.awt.geom.Point2D;
  41 +import java.awt.geom.Rectangle2D;
  42 +import java.util.Iterator;
  43 +import java.util.LinkedList;
  44 +import java.util.List;
  45 +import java.util.Map;
  46 +import java.util.Timer;
  47 +import java.util.TimerTask;
  48 +
  49 +import javax.media.jai.PerspectiveTransform;
  50 +import javax.swing.BorderFactory;
  51 +import javax.swing.ButtonGroup;
  52 +import javax.swing.JPanel;
  53 +import javax.swing.JRadioButton;
  54 +import javax.swing.SwingConstants;
  55 +
  56 +import org.uweschmidt.wiimote.whiteboard.WiimoteDataHandler;
  57 +import org.uweschmidt.wiimote.whiteboard.WiimoteDataHandler.WiimoteDataListener;
  58 +import org.uweschmidt.wiimote.whiteboard.calibration.WiimoteCalibration;
  59 +import org.uweschmidt.wiimote.whiteboard.ds.IRDot;
  60 +import org.uweschmidt.wiimote.whiteboard.ds.Wiimote;
  61 +import org.uweschmidt.wiimote.whiteboard.util.Util;
  62 +
  63 +@SuppressWarnings("serial")
  64 +public class ScreenSelector extends JPanel implements WiimoteDataListener {
  65 +
  66 + private static final GraphicsDevice DEFAULT_SCREEN = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
  67 + private static final int MAX_H = 130;
  68 + private static final int MAX_W = 185;
  69 +
  70 + private static final long REPAINT_FREQ = 1000 / 20;
  71 +
  72 + private WiimoteCalibration calibration;
  73 +// private WiimoteDataHandler dh;
  74 + private List<ScreenBox> screenBoxes = new LinkedList<ScreenBox>();
  75 + private Point lastCursor = null, cursor = null;
  76 +
  77 + public ScreenSelector(WiimoteCalibration calibration, WiimoteDataHandler dh) {
  78 + super(null);
  79 + this.calibration = calibration;
  80 +// this.dh = dh;
  81 + dh.addWiimoteDataListener(this);
  82 +
  83 + final GraphicsDevice[] screens = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices();
  84 +
  85 + // calculate maximum screen bounds (virtual device)
  86 + Rectangle r = new Rectangle();
  87 + for (GraphicsDevice s : screens) {
  88 + r = r.union(s.getDefaultConfiguration().getBounds());
  89 + }
  90 +
  91 + final int maxH = MAX_H - (screens.length == 1 ? 30 : 0);
  92 + // proportional bounds of panel
  93 + int w = MAX_W;
  94 + int h = (int) Math.round((w * r.getHeight()) / r.getWidth());
  95 + // if too high
  96 + if (h > maxH) {
  97 + h = maxH;
  98 + w = (int) Math.round((h * r.getWidth()) / r.getHeight());
  99 + }
  100 + setPreferredSize(new Dimension(w, h));
  101 +
  102 + // map screen bounds to panel bounds
  103 + PerspectiveTransform t = PerspectiveTransform.getQuadToQuad(
  104 + r.getMinX(), r.getMinY(), r.getMaxX(), r.getMinY(),
  105 + r.getMaxX(), r.getMaxY(), r.getMinX(), r.getMaxY(),
  106 + 0, 0, w, 0, w, h, 0, h);
  107 +
  108 + // TODO temporary until multiple screens are allowed
  109 + ButtonGroup bg = new ButtonGroup();
  110 + for (int i = 0; i < screens.length; i++) {
  111 + Rectangle b = screens[i].getDefaultConfiguration().getBounds();
  112 + final ScreenBox sb = new ScreenBox(screens[i], i, transformBounds(t, b), screens[i].equals(DEFAULT_SCREEN));
  113 + bg.add(sb);
  114 + screenBoxes.add(sb);
  115 + add(sb);
  116 + }
  117 +
  118 + new Timer(true).schedule(new UpdateTask(), 0, REPAINT_FREQ);
  119 + }
  120 +
  121 + private class UpdateTask extends TimerTask {
  122 + @Override
  123 + public void run() {
  124 + if (cursor != lastCursor) {
  125 + for (ScreenBox sb : screenBoxes) {
  126 + if (sb.isSelected() && sb.isEnabled()) {
  127 + lastCursor = cursor;
  128 + sb.repaint();
  129 + }
  130 + }
  131 + }
  132 + }
  133 + }
  134 +
  135 + private Rectangle transformBounds(PerspectiveTransform t, Rectangle b) {
  136 + Point2D ul = t.transform(new Point2D.Double(b.getMinX(), b.getMinY()), null);
  137 + Point2D ur = t.transform(new Point2D.Double(b.getMaxX(), b.getMinY()), null);
  138 + Point2D ll = t.transform(new Point2D.Double(b.getMinX(), b.getMaxY()), null);
  139 + return new Rectangle2D.Double(ul.getX(), ul.getY(), ul.distance(ur), ul.distance(ll)).getBounds();
  140 + }
  141 +
  142 + @Override
  143 + public void setEnabled(boolean enabled) {
  144 + super.setEnabled(enabled);
  145 + enableScreenBoxes(enabled);
  146 + }
  147 +
  148 + // TODO use JToggleButton instead of JRadioButton or JCheckBox
  149 + private class ScreenBox extends JRadioButton {
  150 + private final BasicStroke STROKE = new BasicStroke(2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER);
  151 + private static final int DIAMETER = 4;
  152 + private static final int MAX_TRACE = 1000 / (int)REPAINT_FREQ;
  153 + private LinkedList<Point> trace = new LinkedList<Point>();
  154 + private GraphicsDevice screen;
  155 + private final Rectangle bounds;
  156 +// private final int screenWidth, screenHeight;
  157 + public ScreenBox(GraphicsDevice screen, int i, Rectangle b, boolean selected) {
  158 + super(Util.getResourceMap(ScreenSelector.class).getString("screenText", i+1, (int)screen.getDefaultConfiguration().getBounds().getWidth(), (int)screen.getDefaultConfiguration().getBounds().getHeight()));
  159 + this.screen = screen;
  160 + bounds = screen.getDefaultConfiguration().getBounds();
  161 +// screenWidth = (int)screen.getDefaultConfiguration().getBounds().getWidth();
  162 +// screenHeight = (int)screen.getDefaultConfiguration().getBounds().getHeight();
  163 +
  164 + setBounds(b);
  165 + setSelected(selected);
  166 +
  167 + setFocusable(false);
  168 + setHorizontalAlignment(SwingConstants.CENTER);
  169 +
  170 + if (!Util.MAC_OS_X) setBorder(BorderFactory.createEtchedBorder());
  171 + setBorderPainted(true);
  172 +
  173 + addItemListener(new ItemListener() {
  174 + public void itemStateChanged(ItemEvent e) {
  175 + if (e.getStateChange() == ItemEvent.SELECTED) {
  176 + calibration.setScreen(ScreenBox.this.screen);
  177 + }
  178 +// enableScreenBoxes(true);
  179 + }
  180 + });
  181 + }
  182 +
  183 + @Override
  184 + protected void paintComponent(Graphics g) {
  185 + super.paintComponent(g);
  186 + if (isSelected() && cursor != null) {
  187 + Graphics2D g2d = (Graphics2D)g;
  188 + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
  189 + try {
  190 +// g.setColor(new Color(255,255,255,75));
  191 +// g.fillRect(0, 0, getWidth(), getHeight());
  192 +
  193 + int x = Math.max(0, Math.min(getWidth(), (int)Math.round(((cursor.x - bounds.x) / bounds.getWidth()) * getWidth())));
  194 + int y = Math.max(0, Math.min(getHeight(), (int)Math.round(((cursor.y - bounds.y) / bounds.getHeight()) * getHeight())));
  195 +
  196 + if (trace.size() > MAX_TRACE)
  197 + trace.removeFirst();
  198 +
  199 + if (!trace.isEmpty()) {
  200 + g2d.setStroke(STROKE);
  201 + int inc = 255/MAX_TRACE, alpha = (MAX_TRACE - trace.size()) * inc;
  202 + Iterator<Point> it = trace.iterator();
  203 + Point lp = it.next();
  204 + while (it.hasNext()) {
  205 + Point p = it.next();
  206 + g2d.setColor(new Color(0,0,255,alpha));
  207 + g2d.drawLine(lp.x, lp.y, p.x, p.y);
  208 + lp = p;
  209 + alpha += inc;
  210 + }
  211 + g2d.setColor(Color.blue);
  212 + g2d.drawLine(lp.x, lp.y, x, y);
  213 + }
  214 +
  215 + g2d.setColor(Color.blue);
  216 + g2d.fillOval(x-DIAMETER/2, y-DIAMETER/2, DIAMETER, DIAMETER);
  217 +
  218 + trace.addLast(new Point(x,y));
  219 + } catch (NullPointerException e) {
  220 + // cursor can be null because of UpdateTask, no problem
  221 + trace.clear();
  222 + }
  223 + } else {
  224 + trace.clear();
  225 + }
  226 + }
  227 + }
  228 +
  229 + private void enableScreenBoxes(boolean enabled) {
  230 +
  231 + for (ScreenBox b : screenBoxes)
  232 + b.setEnabled(enabled);
  233 +
  234 +// if (!enabled) {
  235 +// for (ScreenBox b : screenBoxes)
  236 +// b.setEnabled(false);
  237 +// } else {
  238 +// LinkedList<ScreenBox> list = new LinkedList<ScreenBox>();
  239 +//
  240 +// // enable all screens
  241 +// for (ScreenBox sb : screenBoxes) {
  242 +// sb.setEnabled(true);
  243 +// if (sb.isSelected()) list.add(sb);
  244 +// }
  245 +//
  246 +// // disallow deselection if only screen left
  247 +// if (list.size() == 1)
  248 +// list.getFirst().setEnabled(false);
  249 +// }
  250 + }
  251 +
  252 + public void irWarped(Map<Wiimote, IRDot[]> data, Point[] warped) {
  253 + cursor = warped[0];
  254 + }
  255 + public void batteryLevel(Wiimote wiimote, double level) {}
  256 + public void irLights(Wiimote wiimote, IRDot[] lights) {}
  257 + public void wiimoteConnected(Wiimote wiimote) {}
  258 + public void wiimoteDisconnected(Wiimote wiimote) {}
  259 +
  260 +
  261 +// private class ScreenLabel extends JLabel {
  262 +//
  263 +// private boolean selected;
  264 +// private GraphicsDevice screen;
  265 +//
  266 +// public ScreenLabel(GraphicsDevice screen, int i, Rectangle b, boolean selected) {
  267 +// super(String.format("<html><center>Screen %d<br><small>%d x %d</small></center></html>", i+1, (int)screen.getDefaultConfiguration().getBounds().getWidth(), (int)screen.getDefaultConfiguration().getBounds().getHeight()));
  268 +// this.screen = screen;
  269 +// setSelected(selected);
  270 +// setBounds(b);
  271 +// setOpaque(true);
  272 +// setBorder(BorderFactory.createLineBorder(SystemColor.windowBorder));
  273 +// setHorizontalAlignment(SwingConstants.CENTER);
  274 +//
  275 +// final ScreenLabel thisLabel = this;
  276 +// addMouseListener(new MouseAdapter() {
  277 +// @Override
  278 +// public void mousePressed(MouseEvent e) {
  279 +// if (thisLabel.isEnabled() && !thisLabel.isSelected()) {
  280 +// calibration.setScreen(thisLabel.screen);
  281 +// thisLabel.setSelected(true);
  282 +// repaint();
  283 +// for (ScreenLabel l : screenLabels) {
  284 +// if (thisLabel != l) {
  285 +// l.setSelected(false);
  286 +// l.repaint();
  287 +// }
  288 +// }
  289 +// }
  290 +// }
  291 +// });
  292 +// }
  293 +//
  294 +// @Override
  295 +// public void setEnabled(boolean enabled) {
  296 +// super.setEnabled(enabled);
  297 +// setForeground(enabled ? SystemColor.textText : SystemColor.textInactiveText);
  298 +// }
  299 +//
  300 +// public void setSelected(boolean selected) {
  301 +// this.selected = selected;
  302 +// setBackground(selected ? SystemColor.textHighlight : SystemColor.window);
  303 +// }
  304 +//
  305 +// public boolean isSelected() {
  306 +// return selected;
  307 +// }
  308 +//
  309 +// }
  310 +
  311 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/WarpedMonitor.java 0 → 100644
... ... @@ -0,0 +1,137 @@
  1 +package org.mote.wiimote.whiteboard.gui;
  2 +
  3 +import java.awt.BorderLayout;
  4 +import java.awt.Color;
  5 +import java.awt.GraphicsDevice;
  6 +import java.awt.Point;
  7 +import java.awt.Rectangle;
  8 +import java.awt.event.KeyAdapter;
  9 +import java.awt.event.KeyEvent;
  10 +import java.awt.geom.Point2D;
  11 +import java.util.Map;
  12 +import java.util.Timer;
  13 +import java.util.TimerTask;
  14 +
  15 +import javax.swing.BorderFactory;
  16 +import javax.swing.JDialog;
  17 +import javax.swing.JPanel;
  18 +
  19 +import org.jdesktop.application.Action;
  20 +import org.jdesktop.application.Application;
  21 +import org.mote.wiimote.whiteboard.WiimoteDataHandler;
  22 +import org.mote.wiimote.whiteboard.WiimoteWhiteboard;
  23 +import org.mote.wiimote.whiteboard.WiimoteDataHandler.WiimoteDataListener;
  24 +import org.mote.wiimote.whiteboard.calibration.WiimoteCalibration;
  25 +import org.mote.wiimote.whiteboard.ds.IRDot;
  26 +import org.mote.wiimote.whiteboard.ds.Wiimote;
  27 +import org.mote.wiimote.whiteboard.preferences.WWPreferences;
  28 +import org.mote.wiimote.whiteboard.util.Util;
  29 +
  30 +@SuppressWarnings("serial")
  31 +public class WarpedMonitor extends JDialog implements WiimoteDataListener {
  32 +
  33 + private static final int REPAINT_FREQ = 1000 / 50;
  34 + static final int RADIUS = 10;
  35 +
  36 + private JPanel canvas;
  37 + private Point2D[][] lights = new Point2D[WWPreferences.WIIMOTES+1][4];
  38 + private LightLabel[][] labels = new LightLabel[WWPreferences.WIIMOTES+1][4];
  39 + private WiimoteCalibration calibration;
  40 + private WiimoteDataHandler dh;
  41 +
  42 + public WarpedMonitor(WiimoteDataHandler dh, final WiimoteCalibration calibration) {
  43 + super(Application.getInstance(WiimoteWhiteboard.class).getMainFrame(), "Warped Point Monitor");
  44 + setLayout(new BorderLayout());
  45 + dh.addWiimoteDataListener(this);
  46 + this.calibration = calibration;
  47 + this.dh = dh;
  48 + ((JPanel) getContentPane()).setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
  49 +
  50 + canvas = new JPanel(null, true);
  51 + canvas.setBorder(BorderFactory.createLineBorder(Color.black));
  52 + add(canvas, BorderLayout.CENTER);
  53 +
  54 + setUndecorated(true);
  55 + addKeyListener(new KeyAdapter() {
  56 + @Override
  57 + public void keyPressed(KeyEvent e) {
  58 + if (e.getKeyCode() == KeyEvent.VK_F || e.getKeyCode() == KeyEvent.VK_ESCAPE) {
  59 + GraphicsDevice screen = calibration.getScreen();
  60 + if (screen != null) {
  61 + if (screen.getFullScreenWindow() == WarpedMonitor.this) {
  62 + ((JPanel) getContentPane()).setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
  63 + screen.setFullScreenWindow(null);
  64 + Util.placeDialogWindow(WarpedMonitor.this, 640, 480);
  65 + } else {
  66 + if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
  67 + WarpedMonitor.this.setVisible(false);
  68 + else {
  69 + ((JPanel) getContentPane()).setBorder(BorderFactory.createEmptyBorder());
  70 + screen.setFullScreenWindow(WarpedMonitor.this);
  71 + }
  72 + }
  73 + }
  74 + }
  75 + }
  76 + });
  77 +
  78 + Util.placeDialogWindow(this, 640, 480);
  79 + new Timer(true).schedule(new UpdateTask(), 0, REPAINT_FREQ);
  80 + }
  81 +
  82 + @Action
  83 + public void monitor() {
  84 + setVisible(true);
  85 + }
  86 +
  87 + private class UpdateTask extends TimerTask {
  88 + @Override
  89 + public void run() {
  90 + if (isVisible()) {
  91 + for (int i = WWPreferences.WIIMOTES; i >= 0; i--)
  92 + for (int j = 0; j < 4; j++) {
  93 + if (labels[i][j] != null)
  94 + labels[i][j].update();
  95 + }
  96 + }
  97 + }
  98 + }
  99 +
  100 + public void irLights(Wiimote wiimote, IRDot[] lights) {
  101 + }
  102 +
  103 + public void irWarped(Map<Wiimote, IRDot[]> data, Point[] warped) {
  104 + if (isVisible()) {
  105 + Rectangle bounds = calibration.getScreen().getDefaultConfiguration().getBounds();
  106 + for (int i = 0; i < 4; i++) {
  107 + final Point w = warped[i];
  108 + this.lights[0][i] = w == null ? null : new Point2D.Double(w.getX() / bounds.getWidth(), 1 - w.getY() / bounds.getHeight());
  109 + }
  110 + for (Wiimote wiimote : dh.getConnectedWiimotes()) {
  111 + for (int i = 0; i < 4; i++) {
  112 + final Point2D w = calibration.warp(i, wiimote, data);
  113 + this.lights[wiimote.getId()][i] = w == null ? null : new Point2D.Double(w.getX() / bounds.getWidth(), 1 - w.getY() / bounds.getHeight());
  114 + }
  115 + }
  116 + }
  117 + }
  118 +
  119 + public void batteryLevel(Wiimote wiimote, double level) {
  120 + }
  121 +
  122 + public void wiimoteConnected(Wiimote wiimote) {
  123 + if (wiimote.getId() == 1)
  124 + for (int i = 0; i < 4; i++)
  125 + canvas.add(labels[0][i] = new LightLabel(canvas, lights, 0, i + 1, Color.red));
  126 + for (int i = 0; i < 4; i++)
  127 + canvas.add(labels[wiimote.getId()][i] = new LightLabel(canvas, lights, wiimote.getId(), i + 1));
  128 + }
  129 +
  130 + public void wiimoteDisconnected(Wiimote wiimote) {
  131 + for (int i = 0; i < 4; i++) {
  132 + canvas.remove(labels[wiimote.getId()][i]);
  133 + labels[wiimote.getId()][i] = null;
  134 + }
  135 + }
  136 +
  137 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/WarpedMonitor.java~ 0 → 100644
... ... @@ -0,0 +1,183 @@
  1 +/*
  2 + * Copyright (C) 2008-2009, Uwe Schmidt
  3 + *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a
  5 + * copy of this software and associated documentation files (the "Software"),
  6 + * to deal in the Software without restriction, including without limitation
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8 + * and/or sell copies of the Software, and to permit persons to whom the
  9 + * Software is furnished to do so, subject to the following conditions:
  10 + *
  11 + * The above copyright notice and this permission notice shall be included in
  12 + * all copies or substantial portions of the Software.
  13 + *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20 + * DEALINGS IN THE SOFTWARE.
  21 + *
  22 + * The Software uses a third-party library (WiiRemoteJ) which is not part of
  23 + * the Software and is subject to its own license.
  24 + */
  25 +
  26 +package org.uweschmidt.wiimote.whiteboard.gui;
  27 +
  28 +import java.awt.BorderLayout;
  29 +import java.awt.Color;
  30 +import java.awt.GraphicsDevice;
  31 +import java.awt.Point;
  32 +import java.awt.Rectangle;
  33 +import java.awt.event.KeyAdapter;
  34 +import java.awt.event.KeyEvent;
  35 +import java.awt.geom.Point2D;
  36 +import java.util.Map;
  37 +import java.util.Timer;
  38 +import java.util.TimerTask;
  39 +
  40 +import javax.swing.BorderFactory;
  41 +import javax.swing.JDialog;
  42 +import javax.swing.JPanel;
  43 +
  44 +import org.jdesktop.application.Action;
  45 +import org.jdesktop.application.Application;
  46 +import org.uweschmidt.wiimote.whiteboard.WiimoteDataHandler;
  47 +import org.uweschmidt.wiimote.whiteboard.WiimoteWhiteboard;
  48 +import org.uweschmidt.wiimote.whiteboard.WiimoteDataHandler.WiimoteDataListener;
  49 +import org.uweschmidt.wiimote.whiteboard.calibration.WiimoteCalibration;
  50 +import org.uweschmidt.wiimote.whiteboard.ds.IRDot;
  51 +import org.uweschmidt.wiimote.whiteboard.ds.Wiimote;
  52 +import org.uweschmidt.wiimote.whiteboard.preferences.WWPreferences;
  53 +import org.uweschmidt.wiimote.whiteboard.util.Util;
  54 +
  55 +@SuppressWarnings("serial")
  56 +public class WarpedMonitor extends JDialog implements WiimoteDataListener {
  57 +
  58 + private static final int REPAINT_FREQ = 1000 / 50;
  59 + static final int RADIUS = 10;
  60 +
  61 + private JPanel canvas;
  62 + private Point2D[][] lights = new Point2D[WWPreferences.WIIMOTES+1][4];
  63 + private LightLabel[][] labels = new LightLabel[WWPreferences.WIIMOTES+1][4];
  64 + private WiimoteCalibration calibration;
  65 + private WiimoteDataHandler dh;
  66 +
  67 + public WarpedMonitor(WiimoteDataHandler dh, final WiimoteCalibration calibration) {
  68 + super(Application.getInstance(WiimoteWhiteboard.class).getMainFrame(), "Warped Point Monitor");
  69 + setLayout(new BorderLayout());
  70 + dh.addWiimoteDataListener(this);
  71 + this.calibration = calibration;
  72 + this.dh = dh;
  73 + ((JPanel) getContentPane()).setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
  74 +
  75 + canvas = new JPanel(null, true);
  76 + canvas.setBorder(BorderFactory.createLineBorder(Color.black));
  77 + add(canvas, BorderLayout.CENTER);
  78 +
  79 + setUndecorated(true);
  80 + addKeyListener(new KeyAdapter() {
  81 + @Override
  82 + public void keyPressed(KeyEvent e) {
  83 + if (e.getKeyCode() == KeyEvent.VK_F || e.getKeyCode() == KeyEvent.VK_ESCAPE) {
  84 + GraphicsDevice screen = calibration.getScreen();
  85 + if (screen != null) {
  86 + if (screen.getFullScreenWindow() == WarpedMonitor.this) {
  87 + ((JPanel) getContentPane()).setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
  88 + screen.setFullScreenWindow(null);
  89 + Util.placeDialogWindow(WarpedMonitor.this, 640, 480);
  90 + } else {
  91 + if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
  92 + WarpedMonitor.this.setVisible(false);
  93 + else {
  94 + ((JPanel) getContentPane()).setBorder(BorderFactory.createEmptyBorder());
  95 + screen.setFullScreenWindow(WarpedMonitor.this);
  96 + }
  97 + }
  98 + }
  99 + }
  100 + }
  101 + });
  102 +
  103 + Util.placeDialogWindow(this, 640, 480);
  104 + new Timer(true).schedule(new UpdateTask(), 0, REPAINT_FREQ);
  105 + }
  106 +
  107 + @Action
  108 + public void monitor() {
  109 + setVisible(true);
  110 + }
  111 +
  112 + private class UpdateTask extends TimerTask {
  113 + @Override
  114 + public void run() {
  115 + if (isVisible()) {
  116 + for (int i = WWPreferences.WIIMOTES; i >= 0; i--)
  117 + for (int j = 0; j < 4; j++) {
  118 + if (labels[i][j] != null)
  119 + labels[i][j].update();
  120 + }
  121 + }
  122 + }
  123 + }
  124 +
  125 + public void irLights(Wiimote wiimote, IRDot[] lights) {
  126 + }
  127 +
  128 + public void irWarped(Map<Wiimote, IRDot[]> data, Point[] warped) {
  129 + if (isVisible()) {
  130 + Rectangle bounds = calibration.getScreen().getDefaultConfiguration().getBounds();
  131 + for (int i = 0; i < 4; i++) {
  132 + final Point w = warped[i];
  133 + this.lights[0][i] = w == null ? null : new Point2D.Double(w.getX() / bounds.getWidth(), 1 - w.getY() / bounds.getHeight());
  134 + }
  135 +// Map<String, Point[]> warpedData = new LinkedHashMap<String, Point[]>();
  136 + for (Wiimote wiimote : dh.getConnectedWiimotes()) {
  137 +// Point[] pArr = new Point[4];
  138 + for (int i = 0; i < 4; i++) {
  139 + final Point2D w = calibration.warp(i, wiimote, data);
  140 +// pArr[i] = w;
  141 + this.lights[wiimote.getId()][i] = w == null ? null : new Point2D.Double(w.getX() / bounds.getWidth(), 1 - w.getY() / bounds.getHeight());
  142 + }
  143 +// warpedData.put(address, pArr);
  144 + }
  145 +//
  146 +// Point[][] cluster = PointClusterer.cluster(warpedData);
  147 +// for (int i = 0; i < cluster.length; i++) {
  148 +// Point[] c = cluster[i];
  149 +// double x = 0, y = 0;
  150 +// for (Point d : c) {
  151 +// x += d.getX();
  152 +// y += d.getY();
  153 +// }
  154 +// final Point2D w = new Point2D.Double(x/c.length, y/c.length);
  155 +// this.lights[0][i] = new Point2D.Double(w.getX() / bounds.getWidth(), 1 - w.getY() / bounds.getHeight());
  156 +//// System.out.println(this.lights[0][i]);
  157 +// }
  158 +// for (int i = cluster.length; i < 4; i++)
  159 +// this.lights[0][i] = null;
  160 +
  161 +
  162 + }
  163 + }
  164 +
  165 + public void batteryLevel(Wiimote wiimote, double level) {
  166 + }
  167 +
  168 + public void wiimoteConnected(Wiimote wiimote) {
  169 + if (wiimote.getId() == 1)
  170 + for (int i = 0; i < 4; i++)
  171 + canvas.add(labels[0][i] = new LightLabel(canvas, lights, 0, i + 1, Color.red));
  172 + for (int i = 0; i < 4; i++)
  173 + canvas.add(labels[wiimote.getId()][i] = new LightLabel(canvas, lights, wiimote.getId(), i + 1));
  174 + }
  175 +
  176 + public void wiimoteDisconnected(Wiimote wiimote) {
  177 + for (int i = 0; i < 4; i++) {
  178 + canvas.remove(labels[wiimote.getId()][i]);
  179 + labels[wiimote.getId()][i] = null;
  180 + }
  181 + }
  182 +
  183 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/WiimoteIcon.java 0 → 100644
... ... @@ -0,0 +1,35 @@
  1 +package org.mote.wiimote.whiteboard.gui;
  2 +
  3 +import java.awt.Color;
  4 +import java.awt.SystemColor;
  5 +
  6 +import javax.swing.BorderFactory;
  7 +import javax.swing.JLabel;
  8 +import javax.swing.JPanel;
  9 +
  10 +import net.miginfocom.swing.MigLayout;
  11 +
  12 +@SuppressWarnings("serial")
  13 +public class WiimoteIcon extends JPanel {
  14 +
  15 + public static final Color[] COLORS = { Color.white, Color.pink, Color.orange, Color.green };
  16 + private JLabel idLabel;
  17 +
  18 + public WiimoteIcon(int id) {
  19 + setBackground(COLORS[id - 1]);
  20 + setBorder(BorderFactory.createLineBorder(Color.lightGray));
  21 + setLayout(new MigLayout("insets 3, center"));
  22 + for (int i = 1; i <= 4; i++) {
  23 + JLabel l = new JLabel();
  24 + l.setOpaque(true);
  25 + l.setBackground(SystemColor.textInactiveText);
  26 + add(l, "w 6!, h 6!");
  27 + if (i == id) idLabel = l;
  28 + }
  29 + }
  30 +
  31 + public void displayConnected(boolean connected) {
  32 + idLabel.setBackground(connected ? Color.blue : SystemColor.textInactiveText);
  33 + }
  34 +
  35 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/WiimoteIcon.java~ 0 → 100644
... ... @@ -0,0 +1,60 @@
  1 +/*
  2 + * Copyright (C) 2008-2009, Uwe Schmidt
  3 + *
  4 + * Permission is hereby granted, free of charge, to any person obtaining a
  5 + * copy of this software and associated documentation files (the "Software"),
  6 + * to deal in the Software without restriction, including without limitation
  7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8 + * and/or sell copies of the Software, and to permit persons to whom the
  9 + * Software is furnished to do so, subject to the following conditions:
  10 + *
  11 + * The above copyright notice and this permission notice shall be included in
  12 + * all copies or substantial portions of the Software.
  13 + *
  14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  17 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20 + * DEALINGS IN THE SOFTWARE.
  21 + *
  22 + * The Software uses a third-party library (WiiRemoteJ) which is not part of
  23 + * the Software and is subject to its own license.
  24 + */
  25 +
  26 +package org.uweschmidt.wiimote.whiteboard.gui;
  27 +
  28 +import java.awt.Color;
  29 +import java.awt.SystemColor;
  30 +
  31 +import javax.swing.BorderFactory;
  32 +import javax.swing.JLabel;
  33 +import javax.swing.JPanel;
  34 +
  35 +import net.miginfocom.swing.MigLayout;
  36 +
  37 +@SuppressWarnings("serial")
  38 +public class WiimoteIcon extends JPanel {
  39 +
  40 + public static final Color[] COLORS = { Color.white, Color.pink, Color.orange, Color.green };
  41 + private JLabel idLabel;
  42 +
  43 + public WiimoteIcon(int id) {
  44 + setBackground(COLORS[id - 1]);
  45 + setBorder(BorderFactory.createLineBorder(Color.lightGray));
  46 + setLayout(new MigLayout("insets 3, center"));
  47 + for (int i = 1; i <= 4; i++) {
  48 + JLabel l = new JLabel();
  49 + l.setOpaque(true);
  50 + l.setBackground(SystemColor.textInactiveText);
  51 + add(l, "w 6!, h 6!");
  52 + if (i == id) idLabel = l;
  53 + }
  54 + }
  55 +
  56 + public void displayConnected(boolean connected) {
  57 + idLabel.setBackground(connected ? Color.blue : SystemColor.textInactiveText);
  58 + }
  59 +
  60 +}
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/AboutWindow.properties 0 → 100644
... ... @@ -0,0 +1,13 @@
  1 +about.Action.text = About
  2 +# no
  3 +aboutWindow.title =
  4 +
  5 +# no
  6 +appPane.opaque = false
  7 +
  8 +# no
  9 +infoPane.editable = false
  10 +# no
  11 +infoPane.contentType = text/html
  12 +# no
  13 +copyRight = Copyright \u00a9 %s %s
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/AboutWindow_de.properties 0 → 100644
... ... @@ -0,0 +1,4 @@
  1 +#:1223319130,Uwe
  2 +
  3 +about.Action.text=\u00dcber
  4 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/AboutWindow_es.properties 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +#:1224611470,Descalzo
  2 +
  3 +# fuzzy
  4 +about.Action.text=Informaci\u00f3n
  5 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/AboutWindow_et.properties 0 → 100644
... ... @@ -0,0 +1,4 @@
  1 +#:1248461469,Marko
  2 +
  3 +about.Action.text=Programmist
  4 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/AboutWindow_fr.properties 0 → 100644
... ... @@ -0,0 +1,4 @@
  1 +#:1223394792,Francois
  2 +
  3 +about.Action.text=A propos
  4 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/AboutWindow_in.properties 0 → 100644
... ... @@ -0,0 +1,4 @@
  1 +#:1274618503,Bobby
  2 +
  3 +about.Action.text=Tentang
  4 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/AboutWindow_it.properties 0 → 100644
... ... @@ -0,0 +1,4 @@
  1 +#:1225965549,Francesco
  2 +
  3 +about.Action.text=Informazioni
  4 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/AboutWindow_pl.properties 0 → 100644
... ... @@ -0,0 +1,4 @@
  1 +#:1253206914,Grzegorz
  2 +
  3 +about.Action.text=Info
  4 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/AboutWindow_pt.properties 0 → 100644
... ... @@ -0,0 +1,4 @@
  1 +#:1223492237,Francisco
  2 +
  3 +about.Action.text=Acerca
  4 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/AboutWindow_ru.properties 0 → 100644
... ... @@ -0,0 +1,4 @@
  1 +#:1265226935,Uwe
  2 +
  3 +about.Action.text=\u041e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0435
  4 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/AboutWindow_ru_bak.properties 0 → 100644
... ... @@ -0,0 +1,4 @@
  1 +#Translated by Dmitry Pupinin (dlnsk@mail.ru)
  2 +#Mon Jan 25 00:31:50 NOVT 2010
  3 +about.Action.text=\u041e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0435
  4 +copyRight=\u0410\u0432\u0442\u043e\u0440\u0441\u043a\u043e\u0435 \u043f\u0440\u0430\u0432\u043e \u00a9 %s %s
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/AboutWindow_sl.properties 0 → 100644
... ... @@ -0,0 +1,4 @@
  1 +#:1238597107,Samo
  2 +
  3 +about.Action.text=O programu
  4 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CalibrationInfoWindow.properties 0 → 100644
... ... @@ -0,0 +1,24 @@
  1 +info.Action.text = Calibration Details
  2 +info.Action.shortDescription = Shows details about the current calibration settings.
  3 +
  4 +# no
  5 +trackingUtility.minimum = 0
  6 +# no
  7 +trackingUtility.maximum = 503316
  8 +# no
  9 +trackingUtility.stringPainted = true
  10 +# no
  11 +trackingUtility.toolTipText =
  12 +
  13 +# no
  14 +trackingAreaLabel.horizontalAlignment = 0
  15 +# no
  16 +calibratedScreenLabel.horizontalAlignment = 0
  17 +# no
  18 +trackingAreaLabel.opaque = true
  19 +# no
  20 +calibratedScreenLabel.opaque = true
  21 +
  22 +trackingAreaLabel.text = Wiimote Tracking Area
  23 +calibratedScreenLabel.text = Calibrated Screen Area
  24 +trackingUtilString = Tracking Utilization: %.0f%%
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CalibrationInfoWindow_de.properties 0 → 100644
... ... @@ -0,0 +1,12 @@
  1 +#:1223760565,Uwe
  2 +
  3 +info.Action.text=Kalibrierungs-Details
  4 +
  5 +info.Action.shortDescription=Zeigt Details \u00fcber die aktuelle Kalibrierung.
  6 +
  7 +trackingAreaLabel.text=Tracking-Bereich der Wiimote
  8 +
  9 +calibratedScreenLabel.text=Kalibrierter Bildschirm-Bereich
  10 +
  11 +trackingUtilString=Tracking-Nutzung: %.0f%%
  12 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CalibrationInfoWindow_es.properties 0 → 100644
... ... @@ -0,0 +1,12 @@
  1 +#:1224611921,Descalzo
  2 +
  3 +info.Action.text=Detalles de Calibraci\u00f3n
  4 +
  5 +info.Action.shortDescription=Las detalles de las posici\u00f3nes de la calibraci\u00f3n corriente.
  6 +
  7 +trackingAreaLabel.text=\u00c1rea de Rastreo del Wiimote
  8 +
  9 +calibratedScreenLabel.text=\u00c1rea de la Pantalla Calibrada
  10 +
  11 +trackingUtilString=Utilizaci\u00f3n de Rastreo: %.0f%%
  12 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CalibrationInfoWindow_et.properties 0 → 100644
... ... @@ -0,0 +1,12 @@
  1 +#:1248457890,Marko
  2 +
  3 +info.Action.text=Kalibreerimise \u00fcksikasjad
  4 +
  5 +info.Action.shortDescription=N\u00e4itab hetkel kehtiva kalibreeringu \u00fcksikasju.
  6 +
  7 +trackingAreaLabel.text=Wii puldi poolt j\u00e4lgitav ala
  8 +
  9 +calibratedScreenLabel.text=Kalibreeritud ekraani ala
  10 +
  11 +trackingUtilString=J\u00e4lgitava ala h\u00f5ivatus: %.0f%%
  12 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CalibrationInfoWindow_fr.properties 0 → 100644
... ... @@ -0,0 +1,12 @@
  1 +#:1223892916,Francois
  2 +
  3 +info.Action.text=D\u00e9tails de la calibration
  4 +
  5 +info.Action.shortDescription=Pr\u00e9sente en d\u00e9tail les param\u00e8tres de la calibration en cours.
  6 +
  7 +trackingAreaLabel.text=Aire suivie par la Wiimote
  8 +
  9 +calibratedScreenLabel.text=Aire d'\u00e9cran calibr\u00e9
  10 +
  11 +trackingUtilString=Utilisation du suivi: %.0f%%
  12 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CalibrationInfoWindow_in.properties 0 → 100644
... ... @@ -0,0 +1,12 @@
  1 +#:1274618605,Bobby
  2 +
  3 +info.Action.text=Detail Kalibrasi
  4 +
  5 +info.Action.shortDescription=Menunjukkan informasi detail mengenai setting Kalibrasi yang digunakan.
  6 +
  7 +trackingAreaLabel.text=Area Tracking Wiimote
  8 +
  9 +calibratedScreenLabel.text=Area layar yang terkalibrasi
  10 +
  11 +trackingUtilString=Penggunaan Tracking: %.0f%%
  12 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CalibrationInfoWindow_it.properties 0 → 100644
... ... @@ -0,0 +1,12 @@
  1 +#:1225964626,Francesco
  2 +
  3 +info.Action.text=Dettagli della calibrazione
  4 +
  5 +info.Action.shortDescription=Mostra i dettagli della calibrazione corrente.
  6 +
  7 +trackingAreaLabel.text=Area di tracciamento del Wiimote
  8 +
  9 +calibratedScreenLabel.text=Area di calibrazione schermo
  10 +
  11 +trackingUtilString=Utilizzo del tracciamento: %.0f%%
  12 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CalibrationInfoWindow_pl.properties 0 → 100644
... ... @@ -0,0 +1,12 @@
  1 +#:1253207905,Grzegorz
  2 +
  3 +info.Action.text=Szczeg\u00f3\u0142y kalibracji
  4 +
  5 +info.Action.shortDescription=Pokazuje szczeg\u00f3\u0142owe obszary wykonanej kalibracji.
  6 +
  7 +trackingAreaLabel.text=Pole widzenia Wiilot\u00f3w
  8 +
  9 +calibratedScreenLabel.text=Skalibrowane pole ekranu
  10 +
  11 +trackingUtilString=Optymalne wykorzystanie: %.0f%%
  12 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CalibrationInfoWindow_pt.properties 0 → 100644
... ... @@ -0,0 +1,12 @@
  1 +#:1223913940,Francisco
  2 +
  3 +info.Action.text=Detalhes da Calibra\u00e7\u00e3o
  4 +
  5 +info.Action.shortDescription=Apresenta os detalhes da presente calibra\u00e7\u00e3o.
  6 +
  7 +trackingAreaLabel.text=\u00c1rea de Visualiza\u00e7\u00e3o do Wiimote
  8 +
  9 +calibratedScreenLabel.text=\u00c1rea de Calibra\u00e7\u00e3o do Ecr\u00e3
  10 +
  11 +trackingUtilString=Utiliza\u00e7\u00e3o da \u00c1rea de Visualiza\u00e7\u00e3o: %.0f%%
  12 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CalibrationInfoWindow_ru.properties 0 → 100644
... ... @@ -0,0 +1,7 @@
  1 +#Translated by Dmitry Pupinin (dlnsk@mail.ru)
  2 +#Mon Jan 25 00:14:24 NOVT 2010
  3 +calibratedScreenLabel.text=\u041e\u0442\u043a\u0430\u043b\u0438\u0431\u0440\u043e\u0432\u0430\u043d\u043d\u0430\u044f \u043e\u0431\u043b\u0430\u0441\u0442\u044c \u044d\u043a\u0440\u0430\u043d\u0430
  4 +trackingAreaLabel.text=\u041e\u0431\u043b\u0430\u0441\u0442\u044c \u0441\u043b\u0435\u0436\u0435\u043d\u0438\u044f Wiimote
  5 +trackingUtilString=\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0430\u044f \u043e\u0431\u043b\u0430\u0441\u0442\u044c: %.0f%%
  6 +info.Action.text=\u041f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u0438 \u043a\u0430\u043b\u0438\u0431\u0440\u043e\u0432\u043a\u0438
  7 +info.Action.shortDescription=\u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u0438 \u043e \u0442\u0435\u043a\u0443\u0449\u0438\u0445 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u0445 \u043a\u0430\u043b\u0438\u0431\u0440\u043e\u0432\u043a\u0438.
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CalibrationInfoWindow_sl.properties 0 → 100644
... ... @@ -0,0 +1,12 @@
  1 +#:1238601491,Samo
  2 +
  3 +info.Action.text=Podrobnosti kalibracije
  4 +
  5 +info.Action.shortDescription=Prika\u017ee podrobnosti veljavne kalibracije.
  6 +
  7 +trackingAreaLabel.text=Obmo\u010dje zaznavanja
  8 +
  9 +calibratedScreenLabel.text=Kalibrirano obmo\u010dje
  10 +
  11 +trackingUtilString=Izkoristek obmo\u010dja zaznavanja: %.0f%%
  12 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CameraMonitor.properties 0 → 100644
... ... @@ -0,0 +1,2 @@
  1 +monitor.Action.text = IR Camera Monitor
  2 +monitor.Action.shortDescription = Shows what the Wiimote's IR camera sees. Can assist you in finding a good position for the Wiimote.
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CameraMonitor_de.properties 0 → 100644
... ... @@ -0,0 +1,6 @@
  1 +#:1224191972,Uwe
  2 +
  3 +monitor.Action.text=IR Kamera Monitor
  4 +
  5 +monitor.Action.shortDescription=Zeigt was die Infrarot-Kamera der Wiimote sieht. Kann dabei helfen eine gute Position f\u00fcr die Wiimote zu finden.
  6 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CameraMonitor_es.properties 0 → 100644
... ... @@ -0,0 +1,6 @@
  1 +#:1224192458,Uwe
  2 +
  3 +monitor.Action.text=Monitor de la C\u00e1mara de IR
  4 +
  5 +monitor.Action.shortDescription=Monitor de lo que ve la c\u00e1mara de infrarroja del Wiimote. Para asistir en encontrar la mejor posici\u00f3n del Wiimote.
  6 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CameraMonitor_et.properties 0 → 100644
... ... @@ -0,0 +1,6 @@
  1 +#:1248457491,Marko
  2 +
  3 +monitor.Action.text=Infrapunakaamera monitor
  4 +
  5 +monitor.Action.shortDescription=N\u00e4itab mida Wii puldi infrapunakaamera n\u00e4eb. Aitab leida hea asetuse Wii puldile/pultidele.
  6 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CameraMonitor_fr.properties 0 → 100644
... ... @@ -0,0 +1,7 @@
  1 +#:1224197209,Francois
  2 +
  3 +# 'Moniteur de la cam\u00e9ra IR' also OK? (need to save some space)
  4 +monitor.Action.text=Moniteur de la cam\u00e9ra IR
  5 +
  6 +monitor.Action.shortDescription=Vous indique ce que les cam\u00e9ras IR des Wiimotes enregistrent. Peut vous aider \u00e0 trouver la meilleure position pour les Wiimotes.
  7 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CameraMonitor_in.properties 0 → 100644
... ... @@ -0,0 +1,6 @@
  1 +#:1275569889,Bobby
  2 +
  3 +monitor.Action.text=Monitor IR Camera
  4 +
  5 +monitor.Action.shortDescription=Menampikan apa yang dilihat oleh Kamera IR Wiimote. Dapat membantu anda dalam menemukan posisi yang bagus untuk Wiimote.
  6 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CameraMonitor_it.properties 0 → 100644
... ... @@ -0,0 +1,6 @@
  1 +#:1240346802,Uwe
  2 +
  3 +monitor.Action.text=Monitor videocamera a IR
  4 +
  5 +monitor.Action.shortDescription=Mostra cosa vede la videocamera a infrarossi del Wiimote. Pu\u00f2 aiutarti a trovare una buona posizione per il Wiimote.
  6 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CameraMonitor_pl.properties 0 → 100644
... ... @@ -0,0 +1,6 @@
  1 +#:1253209074,Grzegorz
  2 +
  3 +monitor.Action.text=Monitor czujnika IR
  4 +
  5 +monitor.Action.shortDescription=Pokazuje punkty rejestrowane przez czujnik. U\u0142atwia ustawienie Wiilot\u00f3w w optymalnej pozycji.
  6 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CameraMonitor_pt.properties 0 → 100644
... ... @@ -0,0 +1,7 @@
  1 +#:1224239416,Francisco
  2 +
  3 +# 'Monitoriza\u00e7\u00e3o da C\u00e2mera de IV' also ok?
  4 +monitor.Action.text=Monitoriza\u00e7\u00e3o da C\u00e2mera de IV
  5 +
  6 +monitor.Action.shortDescription=Apresenta o que a c\u00e2mera de infravermelhos do Wiimote v\u00ea. Pode ajudar na escolha duma boa localiza\u00e7\u00e3o para o Wiimote.
  7 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CameraMonitor_ru.properties 0 → 100644
... ... @@ -0,0 +1,4 @@
  1 +#Translated by Dmitry Pupinin (dlnsk@mail.ru)
  2 +#Mon Jan 25 00:14:24 NOVT 2010
  3 +monitor.Action.shortDescription=\u041f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u0442\u043e, \u0447\u0442\u043e \u0432\u0438\u0434\u0438\u0442 \u0418\u041a-\u043a\u0430\u043c\u0435\u0440\u0430. \u041c\u043e\u0436\u0435\u0442 \u043f\u043e\u043c\u043e\u0447\u044c \u0432\u0430\u043c \u043d\u0430\u0439\u0442\u0438 \u0445\u043e\u0440\u043e\u0448\u0443\u044e \u043f\u043e\u0437\u0438\u0446\u0438\u044e \u0434\u043b\u044f Wiimote.
  4 +monitor.Action.text=\u041c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433 \u0418\u041a-\u043a\u0430\u043c\u0435\u0440\u044b
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/CameraMonitor_sl.properties 0 → 100644
... ... @@ -0,0 +1,6 @@
  1 +#:1238649529,Samo
  2 +
  3 +monitor.Action.text=Pogled IR kamere
  4 +
  5 +monitor.Action.shortDescription=Prika\u017ee vidno polje IR kamere. S tem pogledom in IR pisalom si lahko pomagate pri nastavitvi optimalnega polo\u017eaja Wiimotea.
  6 +
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/Credits.html 0 → 100644
... ... @@ -0,0 +1,86 @@
  1 +<html>
  2 +<body>
  3 +
  4 +<div style="text-align: center; font-family: Lucida Grande, Lucida Sans, Verdana; font-size: 11pt;">
  5 +
  6 +<p>
  7 +<b>Website</b><br>
  8 +<a href="http://www.uweschmidt.org/wiimote-whiteboard">uweschmidt.org/wiimote-whiteboard</a>
  9 +</p>
  10 +
  11 +<p>
  12 +<b>Developer</b><br>
  13 +Uwe Schmidt
  14 +</p>
  15 +
  16 +<p>
  17 +<b>Based on</b><br>
  18 +WiimoteWhiteboard by <a href="http://johnnylee.net/projects/wii/">Johnny Lee</a>
  19 +</p>
  20 +
  21 +<p>
  22 +<b>Translators</b><br>
  23 +<a href="http://estmarx.pri.ee">Marko Puusaar<a> (Estonian)<br>
  24 +<a href="http://perso.univ-lyon2.fr/~fbocquet/">Francois Bocquet<a> (French)<br>
  25 +<a href="http://www.uweschmidt.org">Uwe Schmidt</a> (German)<br>
  26 +<a href="http://bobbyprabowo.wordpress.com">Bobby Adi Prabowo</a> (Indonesian)<br>
  27 +<a href="http://fradelpra.altervista.org">Francesco Del Prato</a>, <a href="http://nilocram.altervista.org/spip/index.php3">Roberto Marcolin</a> (Italian)<br>
  28 +<a href="http://edukom.sytes.net/">Grzegorz Ciaglo</a> (Polish)<br>
  29 +<a href="http://clinik.net/wiimote/">Francisco Cardoso Lima</a> (Portuguese)<br>
  30 +Dmitry Pupinin (Russian)<br>
  31 +Samo Vesel (Slovene)<br>
  32 +Peter Skouson (Spanish)<br>
  33 +</p>
  34 +
  35 +<p>
  36 +<b>Third Party Software</b><br>
  37 +<a href="http://www.centerkey.com/java/browser/">Bare Bones Browser Launch<a><br>
  38 +<a href="http://www.bluecove.org/">BlueCove</a><br>
  39 +<a href="https://jai-core.dev.java.net/">Java Advanced Imaging</a><br>
  40 +<a href="http://www.miglayout.com/">MiGLayout</a><br>
  41 +<a href="http://www.sciss.de/netutil/">NetUtil</a><br>
  42 +<a href="http://developer.apple.com/samplecode/OSXAdapter/listing3.html">OSXAdapter</a><br>
  43 +<a href="https://appframework.dev.java.net/">Swing Application Framework</a><br>
  44 +<a href="https://swingworker.dev.java.net/">Swing Worker</a><br>
  45 +<a href="http://www.world-of-cha0s.hostrocket.com/WiiRemoteJ/">WiiRemoteJ</a><br>
  46 +</p>
  47 +
  48 +<p>
  49 +<b>Icons</b><br>
  50 +<a href="http://www.everaldo.com/crystal/">Crystal Project<a><br>
  51 +<a href="http://clinik.net/wiimote/">Francisco Cardoso Lima</a> - Application Icon, Calibration Icons
  52 +</p>
  53 +
  54 +<p>
  55 +<b>Warranty Information</b><br>
  56 +This software is licensed<br>
  57 +under a modified MIT License:
  58 +</p>
  59 +
  60 +<div style="color: gray; padding: 5px; text-align: justify;">
  61 +Permission is hereby granted, free of charge, to any person obtaining a
  62 +copy of this software and associated documentation files (the "Software"),
  63 +to deal in the Software without restriction, including without limitation
  64 +the rights to use, copy, modify, merge, publish, distribute, sublicense,
  65 +and/or sell copies of the Software, and to permit persons to whom the
  66 +Software is furnished to do so, subject to the following conditions: <br><br>
  67 +
  68 +The above copyright notice and this permission notice shall be included in
  69 +all copies or substantial portions of the Software. <br><br>
  70 +
  71 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  72 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  73 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  74 +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  75 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  76 +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  77 +DEALINGS IN THE SOFTWARE. <br><br>
  78 +
  79 +The Software uses a third-party library (WiiRemoteJ) which is not part of
  80 +the Software and is subject to its own license.
  81 +</div>
  82 +</div>
  83 +
  84 +
  85 +</body>
  86 +</html>
0 87 \ No newline at end of file
... ...
WiimoteWhiteboard/src/org/mote/wiimote/whiteboard/gui/resources/HelpHandler.properties 0 → 100644
... ... @@ -0,0 +1,3 @@
  1 +help = Help
  2 +help.Action.text = ${Application.id} ${help}
  3 +helpQuestion = Basic help was shipped with the application in form of HTML-files.${nl}Do you want to go to the website?
... ...