Initial import tactile pictures and Immersion touchscreen demo
authorThomas Pietrzak <thomas.pietrzak@gmail.com>
Fri, 15 Feb 2013 14:01:57 +0000 (14:01 +0000)
committerThomas Pietrzak <thomas.pietrzak@gmail.com>
Fri, 15 Feb 2013 14:01:57 +0000 (14:01 +0000)
git-svn-id: svn+ssh://thomaspietrzak.com/var/svn/rep@104 47cf9a05-e0a8-4ed5-9e9b-101a649bc004

60 files changed:
DwellCursor/GeneratedFiles/qrc_dwellcursor.cpp
DwellCursor/GeneratedFiles/ui_ExperimentSetup.h
DwellCursor/GeneratedFiles/ui_dwellcursor.h
PushButtons/KinectInput.cpp
PushButtons/KinectInput.h
PushButtons/OneEuroFilter.cpp [new file with mode: 0644]
PushButtons/OneEuroFilter.h [new file with mode: 0644]
TactileButtons.sln
TactileButtons.suo
TactileFluids/KinectInput.cpp
TactileFluids/KinectInput.h
TactileFluids/OneEuroFilter.cpp
TactileFluids/OneEuroFilter.h
TactileFluids/TactileFluids.vcxproj
TactileFluids/tactilefluids.ui
TactilePictures/Canvas.cpp [new file with mode: 0644]
TactilePictures/Canvas.h [new file with mode: 0644]
TactilePictures/Canvas.ui [new file with mode: 0644]
TactilePictures/ImageDemo.cpp [new file with mode: 0644]
TactilePictures/ImageDemo.h [new file with mode: 0644]
TactilePictures/ImageDemo.ui [new file with mode: 0644]
TactilePictures/KinectInput.cpp [new file with mode: 0644]
TactilePictures/KinectInput.h [new file with mode: 0644]
TactilePictures/OneEuroFilter.cpp [new file with mode: 0644]
TactilePictures/OneEuroFilter.h [new file with mode: 0644]
TactilePictures/PictureView.cpp [new file with mode: 0644]
TactilePictures/PictureView.h [new file with mode: 0644]
TactilePictures/TactilePictures.vcxproj [new file with mode: 0644]
TactilePictures/images/00-VH07.PNG [new file with mode: 0644]
TactilePictures/images/00-VS07.PNG [new file with mode: 0644]
TactilePictures/images/01-VH03.PNG [new file with mode: 0644]
TactilePictures/images/01-VS03.PNG [new file with mode: 0644]
TactilePictures/images/02-VH01.PNG [new file with mode: 0644]
TactilePictures/images/02-VS01.PNG [new file with mode: 0644]
TactilePictures/images/03-OH07.PNG [new file with mode: 0644]
TactilePictures/images/03-OS07.PNG [new file with mode: 0644]
TactilePictures/images/10-BW-eiffel.png [new file with mode: 0644]
TactilePictures/images/11-BW-patterns.png [new file with mode: 0644]
TactilePictures/images/20-BW-teapot.png [new file with mode: 0644]
TactilePictures/images/21-BW-teapot.png [new file with mode: 0644]
TactilePictures/images/22-BW-teapot.png [new file with mode: 0644]
TactilePictures/images/23-BW-teapot.data.png [new file with mode: 0644]
TactilePictures/images/23-BW-teapot.png [new file with mode: 0644]
TactilePictures/images/30-BW-map.png [new file with mode: 0644]
TactilePictures/images/31-BW-map.data.png [new file with mode: 0644]
TactilePictures/images/31-BW-map.png [new file with mode: 0644]
TactilePictures/main.cpp [new file with mode: 0644]
TactilePictures/pixelbased.cpp [new file with mode: 0644]
TactilePictures/tactilepictures.cpp [new file with mode: 0644]
TactilePictures/tactilepictures.h [new file with mode: 0644]
TactilePictures/tactilepictures.ui [new file with mode: 0644]
TouchscreenButton/TouchscreenButton.cpp [new file with mode: 0644]
TouchscreenButton/TouchscreenButton.h [new file with mode: 0644]
TouchscreenButton/TouchscreenButton.vcxproj [new file with mode: 0644]
TouchscreenButton/USBHIDImmersionTouchscreen.cpp [new file with mode: 0644]
TouchscreenButton/USBHIDImmersionTouchscreen.h [new file with mode: 0644]
TouchscreenButton/Wristband.cpp [new file with mode: 0644]
TouchscreenButton/Wristband.h [new file with mode: 0644]
TouchscreenButton/main.cpp [new file with mode: 0644]
TouchscreenButton/touchscreenbutton.ui [new file with mode: 0644]

index 913cbe3fb53d08ebaf6f3b078ac109a6991936ec..e5cc9d124db28c2e26adaf2441856f38ba341d53 100644 (file)
@@ -1,7 +1,7 @@
 /****************************************************************************\r
 ** Resource object code\r
 **\r
-** Created: Wed 1. Aug 17:16:43 2012\r
+** Created: Mon 28. Jan 16:21:26 2013\r
 **      by: The Resource Compiler for Qt version 4.8.2\r
 **\r
 ** WARNING! All changes made in this file will be lost!\r
index 8513b8310c88bedb0846147e984518cabdb8f6da..cbc427dbde84e3adafc99390de06b30195abcad9 100644 (file)
@@ -1,7 +1,7 @@
 /********************************************************************************\r
 ** Form generated from reading UI file 'ExperimentSetup.ui'\r
 **\r
-** Created: Wed 1. Aug 17:16:43 2012\r
+** Created: Mon 28. Jan 16:21:26 2013\r
 **      by: Qt User Interface Compiler version 4.8.2\r
 **\r
 ** WARNING! All changes made in this file will be lost when recompiling UI file!\r
index 5f9f9ffa00351b9fefd01089edfc49afa28f0395..79bbb94b93886746af57d12dc0e0a20749a68785 100644 (file)
@@ -1,7 +1,7 @@
 /********************************************************************************\r
 ** Form generated from reading UI file 'dwellcursor.ui'\r
 **\r
-** Created: Wed 1. Aug 17:16:42 2012\r
+** Created: Mon 28. Jan 16:21:22 2013\r
 **      by: Qt User Interface Compiler version 4.8.2\r
 **\r
 ** WARNING! All changes made in this file will be lost when recompiling UI file!\r
index 15bcd9d45f7b87ecb845c4fffd1cbb9e6cd0ae2f..9fc8f372fc85c2065c7da39f76c61ec04ea4872a 100644 (file)
@@ -1,11 +1,12 @@
 #include "KinectInput.h"\r
 \r
 #include <QDebug>\r
+#include <QDateTime>\r
 \r
 #define TIMEOUT 100\r
 \r
 KinectInput::KinectInput()\r
-:_running(false), _skeletonid(-1)\r
+:_running(false), _skeletonid(-1), _skeletonEvent(NULL), _xfilter(50, 0.05), _yfilter(50, 0.05), _zfilter(50, 0.01)\r
 {\r
        //creates the kinect sensor (id 0)\r
        if(FAILED(NuiCreateSensorByIndex(0, &_kinect)))\r
@@ -76,8 +77,9 @@ void KinectInput::run()
 /*             if (data.eTrackingState != NUI_SKELETON_TRACKED)\r
                        continue;*/\r
 \r
+               //Let's use the 1 euro instead, see below\r
                //smooth out the skeleton data\r
-               _kinect->NuiTransformSmooth(&SkeletonFrame, NULL);\r
+               //_kinect->NuiTransformSmooth(&SkeletonFrame, NULL);\r
 \r
 \r
                if (data.eSkeletonPositionTrackingState[NUI_SKELETON_POSITION_HAND_RIGHT] == NUI_SKELETON_NOT_TRACKED)\r
@@ -88,7 +90,14 @@ void KinectInput::run()
                        NuiTransformSkeletonToDepthImageF(data.SkeletonPositions[NUI_SKELETON_POSITION_HAND_RIGHT], &posx, &posy);\r
                        emit rightHandMove(posx, posy,0);*/\r
                        Vector4 &skelpos = data.SkeletonPositions[NUI_SKELETON_POSITION_HAND_RIGHT];\r
-                       emit rightHandMove(skelpos.x, skelpos.y, skelpos.z);\r
+\r
+                       //Filter\r
+                       int timestamp = QDateTime::currentMSecsSinceEpoch();\r
+                       float fx = _xfilter.filter(skelpos.x, timestamp);\r
+                       float fy = _yfilter.filter(skelpos.y, timestamp);\r
+                       float fz = _zfilter.filter(skelpos.z, timestamp);\r
+\r
+                       emit rightHandMove(fx, fy, fz);\r
         }\r
        }\r
 }\r
index b4bf077c2872a993119aa631f3956b43b1089ea6..855fb7b544dd219160dbe2d57f60eb478c813206 100644 (file)
@@ -6,6 +6,8 @@
 #include <Windows.h>\r
 #include <NuiAPI.h>\r
 \r
+#include "OneEuroFilter.h"\r
+\r
 class KinectInput: public QThread\r
 {\r
        Q_OBJECT\r
@@ -22,6 +24,8 @@ class KinectInput: public QThread
                bool _running;\r
                int _skeletonid;\r
 \r
+               OneEuroFilter _xfilter, _yfilter, _zfilter;\r
+\r
        signals:\r
                void rightHandMove(float x, float y, float z);\r
 };\r
diff --git a/PushButtons/OneEuroFilter.cpp b/PushButtons/OneEuroFilter.cpp
new file mode 100644 (file)
index 0000000..ee1754c
--- /dev/null
@@ -0,0 +1,118 @@
+#include "OneEuroFilter.h"\r
+\r
+#define _USE_MATH_DEFINES \r
+#include <cmath>\r
+#include <stdexcept>\r
+\r
+LowPassFilter::LowPassFilter(double alpha, double initval) \r
+:_y(initval), _s(initval), _initialized(false)\r
+{\r
+       setAlpha(alpha);\r
+}\r
+\r
+double LowPassFilter::filter(double value) \r
+{\r
+       double result;\r
+       if (_initialized)\r
+               result = _a * value + (1.0 - _a) * _s;\r
+       else \r
+       {\r
+               result = value;\r
+               _initialized = true;\r
+       }\r
+       _y = value;\r
+       _s = result;\r
+       return result;\r
+}\r
+\r
+double LowPassFilter::filterWithAlpha(double value, double alpha) \r
+{\r
+       setAlpha(alpha);\r
+       return filter(value);\r
+}\r
+\r
+bool LowPassFilter::hasLastRawValue(void) \r
+{\r
+       return _initialized;\r
+}\r
+\r
+double LowPassFilter::lastRawValue(void) \r
+{\r
+       return _y ;\r
+}\r
+\r
+void LowPassFilter::setAlpha(double alpha) \r
+{\r
+       if (alpha <= 0.0 || alpha > 1.0) \r
+               throw std::range_error("alpha should be in ]0.0., 1.0]");\r
+       _a = alpha;\r
+}\r
+\r
+\r
+OneEuroFilter::OneEuroFilter(double freq, double mincutoff, double beta, double dcutoff)\r
+:_lasttime(UndefinedTime)\r
+{\r
+               setFrequency(freq);\r
+\r
+               //don't do this earlier, frequency is required to compute alpha\r
+               _x = new LowPassFilter(alpha(mincutoff));\r
+               _dx = new LowPassFilter(alpha(dcutoff));\r
+\r
+               setMinCutoff(mincutoff);\r
+               setBeta(beta);\r
+               setDerivateCutoff(dcutoff);\r
+}\r
+\r
+OneEuroFilter::~OneEuroFilter(void) \r
+{\r
+       delete _x;\r
+       delete _dx;\r
+}\r
+\r
+double OneEuroFilter::filter(double value, TimeStamp timestamp) \r
+{\r
+       // update the sampling frequency based on timestamps\r
+       if (_lasttime != UndefinedTime && timestamp != UndefinedTime)\r
+               _freq = 1.0 / (timestamp - _lasttime);\r
+       _lasttime = timestamp;\r
+       // estimate the current variation per second \r
+       double dvalue = _x->hasLastRawValue() ? (value - _x->lastRawValue()) * _freq : 0.0; // FIXME: 0.0 or value?\r
+       double edvalue = _dx->filterWithAlpha(dvalue, alpha(_dcutoff));\r
+       // use it to update the cutoff frequency\r
+       double cutoff = _mincutoff + _beta * fabs(edvalue);\r
+       // filter the given value\r
+       return _x->filterWithAlpha(value, alpha(cutoff));\r
+}\r
+\r
+double OneEuroFilter::alpha(double cutoff) \r
+{\r
+       double te = 1.0 / _freq;\r
+       double tau = 1.0 / (2 * M_PI * cutoff);\r
+       return 1.0 / (1.0 + tau/te);\r
+}\r
+\r
+void OneEuroFilter::setFrequency(double f) \r
+{\r
+       if (f <= 0) \r
+               throw std::range_error("freq should be >0");\r
+       _freq = f;\r
+}\r
+\r
+void OneEuroFilter::setMinCutoff(double mc) \r
+{\r
+       if (mc <= 0) \r
+               throw std::range_error("mincutoff should be >0");\r
+       _mincutoff = mc;\r
+}\r
+\r
+void OneEuroFilter::setBeta(double b) \r
+{\r
+       _beta = b;\r
+}\r
+\r
+void OneEuroFilter::setDerivateCutoff(double dc) \r
+{\r
+       if (dc <= 0) \r
+               throw std::range_error("dcutoff should be >0");\r
+       _dcutoff = dc;\r
+}\r
diff --git a/PushButtons/OneEuroFilter.h b/PushButtons/OneEuroFilter.h
new file mode 100644 (file)
index 0000000..7d24ffa
--- /dev/null
@@ -0,0 +1,62 @@
+/*\r
+ * OneEuroFilter.h/.cpp -\r
+ *\r
+ * Author: Thomas Pietrzak (thomas.pietrzak@lifl.fr)\r
+ * based on code from\r
+ * Nicolas Roussel (nicolas.roussel@inria.fr)\r
+ *\r
+ */\r
+\r
+\r
+#ifndef __ONEEURO__\r
+#define __ONEEURO__\r
+\r
+\r
+typedef double TimeStamp ; // in seconds\r
+\r
+static const TimeStamp UndefinedTime = -1.0 ;\r
+\r
+\r
+class LowPassFilter \r
+{\r
+       public:\r
+               LowPassFilter(double alpha, double initval=0.0);\r
+\r
+               double filterWithAlpha(double value, double alpha);\r
+               inline bool hasLastRawValue(void);\r
+               inline double lastRawValue(void);\r
+\r
+       private:\r
+               double _y, _a, _s;\r
+               bool _initialized;\r
+\r
+               void setAlpha(double alpha);\r
+               double filter(double value);\r
+} ;\r
+\r
+class OneEuroFilter \r
+{\r
+       public:\r
+               OneEuroFilter(\r
+                       double freq, \r
+                       double mincutoff=1.0, \r
+                       double beta_=0.0, \r
+                       double dcutoff=1.0);\r
+       \r
+               ~OneEuroFilter();\r
+\r
+               double filter(double value, TimeStamp timestamp=UndefinedTime);\r
+\r
+       private:\r
+               double _freq, _mincutoff, _beta, _dcutoff;\r
+               LowPassFilter *_x, *_dx;\r
+               TimeStamp _lasttime;\r
+\r
+               double alpha(double cutoff);\r
+               inline void setFrequency(double f);\r
+               inline void setMinCutoff(double mc);\r
+               inline void setBeta(double b);\r
+               inline void setDerivateCutoff(double dc);\r
+} ;\r
+\r
+#endif\r
index b12eb95e5c92e496a30df74c7f46c3e50cd46d30..4ac90463a43117393dbfd140e95844f58a6e445b 100644 (file)
@@ -7,6 +7,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DwellCursor", "DwellCursor\
 EndProject\r
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TactileFluids", "TactileFluids\TactileFluids.vcxproj", "{014A41B9-3E4D-48F0-B5D7-8C6FE42A142E}"\r
 EndProject\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TactilePictures", "TactilePictures\TactilePictures.vcxproj", "{B219D272-E4C1-46D8-9263-3B4462606CC6}"\r
+EndProject\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TouchscreenButton", "TouchscreenButton\TouchscreenButton.vcxproj", "{3484A961-9B00-4197-85ED-99303909089C}"\r
+EndProject\r
 Global\r
        GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
                Debug|Win32 = Debug|Win32\r
@@ -25,6 +29,14 @@ Global
                {014A41B9-3E4D-48F0-B5D7-8C6FE42A142E}.Debug|Win32.Build.0 = Debug|Win32\r
                {014A41B9-3E4D-48F0-B5D7-8C6FE42A142E}.Release|Win32.ActiveCfg = Release|Win32\r
                {014A41B9-3E4D-48F0-B5D7-8C6FE42A142E}.Release|Win32.Build.0 = Release|Win32\r
+               {B219D272-E4C1-46D8-9263-3B4462606CC6}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {B219D272-E4C1-46D8-9263-3B4462606CC6}.Debug|Win32.Build.0 = Debug|Win32\r
+               {B219D272-E4C1-46D8-9263-3B4462606CC6}.Release|Win32.ActiveCfg = Release|Win32\r
+               {B219D272-E4C1-46D8-9263-3B4462606CC6}.Release|Win32.Build.0 = Release|Win32\r
+               {3484A961-9B00-4197-85ED-99303909089C}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {3484A961-9B00-4197-85ED-99303909089C}.Debug|Win32.Build.0 = Debug|Win32\r
+               {3484A961-9B00-4197-85ED-99303909089C}.Release|Win32.ActiveCfg = Release|Win32\r
+               {3484A961-9B00-4197-85ED-99303909089C}.Release|Win32.Build.0 = Release|Win32\r
        EndGlobalSection\r
        GlobalSection(SolutionProperties) = preSolution\r
                HideSolutionNode = FALSE\r
index 95b9ff68fbc8d38f0706f6ca0cdbbc6fcc708875..8297b586913b330b8f590b4a3898eb5f2c91dbe5 100644 (file)
Binary files a/TactileButtons.suo and b/TactileButtons.suo differ
index e908518807a5ffbfc65c4583103bcd452645313d..cc9512fe614598adf1e50bdf04e407c8bcf4ba29 100644 (file)
@@ -1,11 +1,12 @@
 #include "KinectInput.h"\r
 \r
 #include <QDebug>\r
+#include <QDateTime>\r
 \r
 #define TIMEOUT 100\r
 \r
 KinectInput::KinectInput()\r
-:_running(false), _skeletonid(-1), _skeletonEvent(NULL)\r
+:_running(false), _skeletonid(-1), _skeletonEvent(NULL), _xfilter(50, 1.0), _yfilter(50, 1.0), _zfilter(50, 1.0)\r
 {\r
        //creates the kinect sensor (id 0)\r
        if(FAILED(NuiCreateSensorByIndex(0, &_kinect)))\r
@@ -76,8 +77,9 @@ void KinectInput::run()
 /*             if (data.eTrackingState != NUI_SKELETON_TRACKED)\r
                        continue;*/\r
 \r
+               //Let's use the 1 euro instead, see below\r
                //smooth out the skeleton data\r
-               _kinect->NuiTransformSmooth(&SkeletonFrame, NULL);\r
+               //_kinect->NuiTransformSmooth(&SkeletonFrame, NULL);\r
 \r
 \r
                if (data.eSkeletonPositionTrackingState[NUI_SKELETON_POSITION_HAND_RIGHT] == NUI_SKELETON_NOT_TRACKED)\r
@@ -88,7 +90,14 @@ void KinectInput::run()
                        NuiTransformSkeletonToDepthImageF(data.SkeletonPositions[NUI_SKELETON_POSITION_HAND_RIGHT], &posx, &posy);\r
                        emit rightHandMove(posx, posy,0);*/\r
                        Vector4 &skelpos = data.SkeletonPositions[NUI_SKELETON_POSITION_HAND_RIGHT];\r
-                       emit rightHandMove(skelpos.x, skelpos.y, skelpos.z);\r
+\r
+                       //Filter\r
+                       int timestamp = QDateTime::currentMSecsSinceEpoch();\r
+                       float fx = _xfilter.filter(skelpos.x, timestamp);\r
+                       float fy = _yfilter.filter(skelpos.y, timestamp);\r
+                       float fz = _zfilter.filter(skelpos.z, timestamp);\r
+\r
+                       emit rightHandMove(fx, fy, fz);\r
         }\r
        }\r
 }\r
index b4bf077c2872a993119aa631f3956b43b1089ea6..855fb7b544dd219160dbe2d57f60eb478c813206 100644 (file)
@@ -6,6 +6,8 @@
 #include <Windows.h>\r
 #include <NuiAPI.h>\r
 \r
+#include "OneEuroFilter.h"\r
+\r
 class KinectInput: public QThread\r
 {\r
        Q_OBJECT\r
@@ -22,6 +24,8 @@ class KinectInput: public QThread
                bool _running;\r
                int _skeletonid;\r
 \r
+               OneEuroFilter _xfilter, _yfilter, _zfilter;\r
+\r
        signals:\r
                void rightHandMove(float x, float y, float z);\r
 };\r
index 02377c44b31d2309acfbea3b2b362302e662f7d1..ee1754c8de5c570c3f0edd32aae6b7f03b8e5aa9 100644 (file)
@@ -50,9 +50,14 @@ void LowPassFilter::setAlpha(double alpha)
 \r
 \r
 OneEuroFilter::OneEuroFilter(double freq, double mincutoff, double beta, double dcutoff)\r
-:_x(new LowPassFilter(alpha(mincutoff))), _dx(new LowPassFilter(alpha(dcutoff))), _lasttime(UndefinedTime)\r
+:_lasttime(UndefinedTime)\r
 {\r
                setFrequency(freq);\r
+\r
+               //don't do this earlier, frequency is required to compute alpha\r
+               _x = new LowPassFilter(alpha(mincutoff));\r
+               _dx = new LowPassFilter(alpha(dcutoff));\r
+\r
                setMinCutoff(mincutoff);\r
                setBeta(beta);\r
                setDerivateCutoff(dcutoff);\r
index 100a5ae5d772d7e819f7c2641c5ee6f16b8f4933..7d24ffa26bfda9c12f1cd9467b04d42d63bdcfc2 100644 (file)
@@ -48,7 +48,7 @@ class OneEuroFilter
                double filter(double value, TimeStamp timestamp=UndefinedTime);\r
 \r
        private:\r
-               double _freq, _mincutoff, _beta;, _dcutoff;\r
+               double _freq, _mincutoff, _beta, _dcutoff;\r
                LowPassFilter *_x, *_dx;\r
                TimeStamp _lasttime;\r
 \r
index 1ba5787992dfea9918b06ac780b6d9be463661b0..15b4a3ee2c3daf5f16407de79e8e54a52ec8fb5b 100644 (file)
@@ -54,7 +54,7 @@
     <Link>\r
       <SubSystem>Windows</SubSystem>\r
       <OutputFile>$(OutDir)\$(ProjectName).exe</OutputFile>\r
-      <AdditionalLibraryDirectories>$(KINECTSDK10_DIR)\lib\x86;;$(QTDIR)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
+      <AdditionalLibraryDirectories>$(KINECTSDK10_DIR)\lib\x86;$(QTDIR)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
       <GenerateDebugInformation>true</GenerateDebugInformation>\r
       <AdditionalDependencies>TactonPlayerd.lib;Kinect10.lib;qtmaind.lib;QtCored4.lib;QtGuid4.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
     </Link>\r
index 22abb0189110074e23d10b8c41b97daa59ba4a24..c91f830229791f4d2f2c2814b92099ce86226de7 100644 (file)
@@ -67,7 +67,7 @@
          <number>10</number>\r
         </property>\r
         <property name="value">\r
-         <number>100</number>\r
+         <number>500</number>\r
         </property>\r
        </widget>\r
       </item>\r
diff --git a/TactilePictures/Canvas.cpp b/TactilePictures/Canvas.cpp
new file mode 100644 (file)
index 0000000..903d908
--- /dev/null
@@ -0,0 +1,286 @@
+/*\r
+ *\r
+ * Adapted from Pixel based by Nicolas Roussel and Paolo Olivo\r
+ * Authors: Thomas Pietrzak\r
+ * Copyright © Inria\r
+ *\r
+ */\r
+\r
+#include "Canvas.h"\r
+\r
+#include <QPainter>\r
+#include <QPaintEvent>\r
+#include <QDebug>\r
+#include <QPixmap>\r
+\r
+#include <iostream>\r
+#include <cstdio>\r
+\r
+const float Canvas::KinectWidth = 1.6;\r
+const float Canvas::KinectHeight = 1.0;\r
+const float Canvas::CursorSize = 10;\r
+\r
+\r
+// ############################### CLASS Canvas ################################\r
+Canvas::Canvas(QWidget *parent) \r
+: QGraphicsView(parent), _tactonplayer(NULL), _image(new QGraphicsPixmapItem), data(new QImage) , _cursor(new QGraphicsEllipseItem(0, 0, CursorSize, CursorSize))\r
+{\r
+  setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);\r
+  ui.setupUi(this) ;\r
+  ui.infoWidget->setVisible(false);\r
+\r
+  //feedback = NULL ;\r
+  //this->_image = new QGraphicsPixmapItem ;\r
+  setScene(&_scene);\r
+  _scene.addItem(_image);\r
+  _scene.addItem(_cursor);\r
+  _cursor->setPen(QPen(QBrush(Qt::black), 5));\r
+\r
+  //this->data = new QImage ;\r
+\r
+  showData = false ;\r
+  invFeedback = false ;\r
+  paintUpFeedback = true ;\r
+\r
+  connect(&_kinectinput, SIGNAL(rightHandMove(float,float,float)), \r
+               this, SLOT(updateFeedback(float,float,float)));\r
+\r
+    _kinectinput.start();\r
+}\r
+\r
+Canvas::~Canvas() {\r
+  delete data;\r
+  delete _image;\r
+\r
+  _kinectinput.stop();\r
+  if(_tactonplayer)\r
+  {\r
+         unsigned char amp[] = {0, 0, 0, 0};\r
+         _tactonplayer->setAmplitudes(4, amp);\r
+         //May be dangerous, new in main\r
+         delete _tactonplayer;\r
+  }\r
+}\r
+/*\r
+void \r
+Canvas::setFeedback(Feedback *feedback) {\r
+  this->feedback = feedback ;\r
+}*/\r
+void \r
+Canvas::setTactonPlayer(TactonPlayer *player) {\r
+  this->_tactonplayer = player;\r
+  if (_tactonplayer)\r
+         _tactonplayer->setFrequency(250);\r
+}\r
+\r
+int\r
+Canvas::setImage(const char *imagePath, const char *dataPath) {\r
+//  if (image->load(imagePath)) {\r
+       QPixmap im;\r
+       if (im.load(imagePath))\r
+       {\r
+               //pixels copied?\r
+               _image->setPixmap(im);\r
+           ui.imagePath->setText(QString(imagePath)) ;\r
+               if (!data->load(dataPath)) {\r
+                       // If the data image cannot be found, delete the old data image\r
+                       // and use image as data.\r
+                       delete data;\r
+                       QPixmap greydata(imagePath, 0, Qt::MonoOnly);\r
+                       data = new QImage(greydata.toImage());\r
+                       qDebug("No tactile map. Using %s", imagePath) ;\r
+                       ui.dataPath->setText(QString("No tactile map")) ;\r
+               } else {\r
+                       QPixmap greydata;\r
+                       greydata.convertFromImage(*data, Qt::MonoOnly);\r
+                       delete data;\r
+                       data = new QImage(greydata.toImage());\r
+                       ui.dataPath->setText(QString(dataPath)) ;\r
+               }\r
+               // check if the file requires to invert the feedback\r
+               std::string imageStr(imagePath) ;\r
+               if (imageStr.find("-BW-") < imageStr.length() ) {\r
+                       // BW means "black on white", i.e. dark areas are the one with the strongest feedback\r
+                       data->invertPixels() ;\r
+               }\r
+               // check if the user has required to invert the feedback\r
+               if (invFeedback) \r
+                       data->invertPixels() ;\r
+\r
+               setMinimumSize(_image->pixmap().size());\r
+               fitInView(_scene.sceneRect(), Qt::KeepAspectRatio);\r
+               this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);\r
+               this->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);\r
+\r
+               //adjustSize() ; \r
+               /*setFixedSize(sizeHint()) ;\r
+               update() ;\r
+               updateGeometry() ;*/\r
+\r
+               qDebug() << "Image w=" << _image->pixmap().width() << " h=" << _image->pixmap().height();\r
+               qDebug() << "Widget w=" << width() << " h=" << height();\r
+\r
+               paintUpFeedback = true;\r
+               // Cut the string manually at beginning since is the end part the most\r
+               // important one.\r
+               QFontMetrics metrics(ui.imagePath->font());\r
+               int width = metrics.width(ui.imagePath->text());\r
+               if (width > sizeHint().width() - 28) {\r
+                       ui.imagePath->setText(metrics.elidedText(ui.imagePath->text(), Qt::ElideLeft, sizeHint().width() - 28)) ;\r
+                       ui.imagePath->setAlignment(Qt::AlignRight) ;\r
+               } else {\r
+                       ui.imagePath->setAlignment(Qt::AlignLeft) ;\r
+               }\r
+               // Same thing for the dataPath\r
+               width = metrics.width(ui.dataPath->text());\r
+               if (width > sizeHint().width() - 28) {\r
+                       ui.dataPath->setText(metrics.elidedText(ui.dataPath->text(), Qt::ElideLeft, sizeHint().width() - 28)) ;\r
+                       ui.dataPath->setAlignment(Qt::AlignRight) ;\r
+               } else {\r
+                       ui.dataPath->setAlignment(Qt::AlignLeft) ;\r
+               }\r
+               return 0 ;\r
+       } else {\r
+               qDebug("Image %s cannot be loaded.", imagePath) ;\r
+               return 1;\r
+       }\r
+}\r
+\r
+void\r
+Canvas::updateFeedback() {\r
+  QPoint pos = mapFromGlobal(QCursor::pos()) ;\r
+  updateFeedback(_currentpos.x(), _currentpos.y(), 0.0) ;\r
+}\r
+\r
+void\r
+Canvas::updateFeedback(float x, float y, float z) {\r
+  qDebug() << "Hand at x=" << x << " y=" << y << " z=" << z;\r
+\r
+  if (!_tactonplayer) return ;\r
+\r
+  //map Kinect Coordinates to image\r
+  int px = (x / KinectWidth + 0.5) * data->width();\r
+  int py = (0.5 - y / KinectHeight) * data->height();\r
+  if (px < 0)\r
+         px = 0;\r
+  else if (px > data->width())\r
+         px = data->width();\r
+  if (py < 0)\r
+         py = 0;\r
+  else if (py > data->width())\r
+         py = data->width();\r
+\r
+  _currentpos = QPoint(px, py);\r
+  _cursor->setPos(px - CursorSize / 2, py - CursorSize / 2);\r
+  qDebug() << "Screen  x=" << px << " y=" << py << "\n";\r
+\r
+\r
+  if (data->valid(px, py)) { \r
+    int gray = qGray(data->pixel(px, py)) ;\r
+       //TODO: try 4 pixels around\r
+       unsigned char amp[] = {gray, gray, gray, gray};\r
+       _tactonplayer->setAmplitudes(4, amp);\r
+  } else {\r
+    unsigned char amp[] = {0, 0, 0, 0};\r
+       _tactonplayer->setAmplitudes(4, amp);\r
+  }\r
+}\r
+\r
+// <<<<<<<<<<<<<<<<<<<<<<<<<<<< OVERRIDDEN METHODS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>\r
+/*QSize\r
+Canvas::minimumSizeHint() const {\r
+  return QSize(_image->pixmap().width(), _image->pixmap().height()) ;\r
+}\r
+\r
+QSize\r
+Canvas::sizeHint() const {\r
+  return QSize(_image->pixmap().width(), _image->pixmap().height()) ;\r
+}*/\r
+/*\r
+void\r
+Canvas::paintEvent(QPaintEvent * event) {\r
+  QRect dirtyRect = event->rect();\r
+\r
+  QPainter painter(this) ;\r
+  painter.setRenderHint(QPainter::Antialiasing, true) ;\r
+  if (showData)  \r
+    painter.drawImage(dirtyRect, *data, dirtyRect) ;\r
+  else\r
+    painter.drawImage(dirtyRect, *image, dirtyRect) ;\r
+  painter.end() ;\r
+\r
+  if (paintUpFeedback) {\r
+    updateFeedback() ;\r
+    paintUpFeedback = false ;\r
+  }\r
+\r
+  //draw Kinect cursor\r
+  painter.drawLine(_currentpos - QPoint(-5, 0), _currentpos - QPoint(+5, 0));\r
+  painter.drawLine(_currentpos - QPoint(0, -5), _currentpos - QPoint(0, +5));\r
+}*/\r
+/*\r
+void\r
+Canvas::mouseMoveEvent(QMouseEvent * event) {\r
+  updateFeedback(event->pos()) ;\r
+}\r
+\r
+void\r
+Canvas::leaveEvent(QEvent * event) {\r
+  if (feedback) feedback->setModalities(Feedback::NONE) ;\r
+}*/\r
+\r
+// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< SLOTS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\r
+void \r
+Canvas::showFeedback(bool value) {\r
+  showData = value ;\r
+  if (!showData) ui.imageShown->setText("Visible image") ;\r
+  else ui.imageShown->setText("Friction map") ;\r
+  update() ;\r
+}\r
+\r
+void\r
+Canvas::invertFeedback(bool value) {\r
+  invFeedback = value ;\r
+  data->invertPixels() ;\r
+  if (invFeedback) ui.feedbackInfo->setText("Inverted") ; \r
+  else ui.feedbackInfo->setText("Normal") ; \r
+  if (showData)\r
+    update() ;\r
+  updateFeedback() ;\r
+}\r
+\r
+void \r
+Canvas::showInfo(bool value) {\r
+  ui.infoWidget->setVisible(value) ;\r
+}\r
+\r
+void \r
+Canvas::notifyImageNum(int id, int num) {\r
+  char label[64];\r
+  sprintf(label,"%d/%d", id, num);\r
+  ui.imageNum->setText(label) ;\r
+}\r
+\r
+/*\r
+QImage *\r
+Canvas::toGrayscale(QImage *image) {\r
+  // Initialize color table\r
+  QVector<QRgb> colorTable(256);\r
+  for (int i = 0; i<256; ++i) \r
+    colorTable[i] = qRgb(i, i, i) ;\r
+\r
+  QSize size = image->size() ;\r
+  QImage * grayImage = new QImage(size, QImage::Format_Indexed8) ;\r
+  grayImage->setColorTable(colorTable) ;\r
+  for (int i = 0; i<size.height(); ++i)\r
+    for(int j = 0; j<size.width(); ++j)\r
+      grayImage->setPixel(j, i, qGray(image->pixel(j,i))) ;\r
+  return grayImage ; \r
+}*/\r
+/*\r
+void\r
+Canvas::touchEvent(STIMTAC_input_200::TouchEvent event) {\r
+  if (event.activecount==0 && feedback) feedback->setModalities(Feedback::NONE) ;\r
+}\r
+\r
+*/
\ No newline at end of file
diff --git a/TactilePictures/Canvas.h b/TactilePictures/Canvas.h
new file mode 100644 (file)
index 0000000..f3579be
--- /dev/null
@@ -0,0 +1,79 @@
+/*\r
+ *\r
+ * Adapted from Pixel based by Nicolas Roussel and Paolo Olivo\r
+ * Authors: Thomas Pietrzak\r
+ * Copyright © Inria\r
+ *\r
+ */\r
+\r
+#ifndef CANVAS_H\r
+#define CANVAS_H\r
+\r
+#include "ui_Canvas.h"\r
+\r
+#include<QGraphicsPixmapItem>\r
+#include <QGraphicsEllipseItem>\r
+#include <QGraphicsScene>\r
+#include <QGraphicsView>\r
+\r
+#include "KinectInput.h"\r
+#include <TactonPlayer\TactonPlayer.hpp>\r
+\r
+class Canvas : public QGraphicsView {\r
+\r
+  Q_OBJECT ;\r
+  \r
+  Ui::Canvas ui;\r
+  /** When showdata is true that it will be shown the data image and not\r
+   *  the front image. */\r
+  bool showData;\r
+  bool invFeedback ;\r
+  /** If true then the feedback must be updated at the end of next paint event.\r
+   *  This is necessary when the image is changed since the new\r
+   *  image get place only at the end of the paint method. */\r
+  bool paintUpFeedback ;\r
+\r
+protected:\r
+//  Feedback *feedback ;\r
+  TactonPlayer *_tactonplayer;\r
+  //QImage *image;\r
+  QImage *data;\r
+  QGraphicsScene _scene;\r
+  QGraphicsPixmapItem *_image;\r
+  QGraphicsEllipseItem *_cursor;\r
+  static const float CursorSize;\r
+\r
+  KinectInput _kinectinput;\r
+  QPoint _currentpos;\r
+  static const float KinectWidth, KinectHeight;\r
+\r
+public:\r
+  Canvas(QWidget *parent=0) ;\r
+  virtual ~Canvas() ;\r
+\r
+//  void setFeedback(Feedback *feedback) ;\r
+  void setTactonPlayer(TactonPlayer *player) ;\r
+  virtual int setImage(const char *img, const char *data = 0) ;\r
+\r
+  void showFeedback(bool value) ;\r
+  void invertFeedback(bool value) ;\r
+  void showInfo(bool value) ;\r
+  void notifyImageNum(int id, int num) ;\r
+\r
+protected:\r
+//  QSize minimumSizeHint() const ;\r
+//  QSize sizeHint() const ;\r
+  //virtual void paintEvent(QPaintEvent *event) ;\r
+  //virtual void mouseMoveEvent(QMouseEvent *event) ;\r
+  //void leaveEvent(QEvent *event) ;\r
+  \r
+  virtual void updateFeedback() ;\r
+\r
+  QImage * toGrayscale(QImage *image) ;\r
\r
+public slots:\r
+//  void touchEvent(STIMTAC_input_200::TouchEvent event) ;\r
+       virtual void updateFeedback(float x, float y, float z) ;\r
+} ;\r
+\r
+#endif\r
diff --git a/TactilePictures/Canvas.ui b/TactilePictures/Canvas.ui
new file mode 100644 (file)
index 0000000..89e784b
--- /dev/null
@@ -0,0 +1,326 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Canvas</class>
+ <widget class="QWidget" name="Canvas">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>300</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="maximumSize">
+   <size>
+    <width>300</width>
+    <height>300</height>
+   </size>
+  </property>
+  <property name="mouseTracking">
+   <bool>true</bool>
+  </property>
+  <property name="windowTitle">
+   <string>Canvas</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="spacing">
+    <number>0</number>
+   </property>
+   <property name="margin">
+    <number>0</number>
+   </property>
+   <item>
+    <widget class="QWidget" name="infoWidget" native="true">
+     <property name="mouseTracking">
+      <bool>true</bool>
+     </property>
+     <property name="styleSheet">
+      <string notr="true">color: rgb(255, 0, 0);</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout_2">
+      <item>
+       <layout class="QVBoxLayout" name="pathForm">
+        <property name="spacing">
+         <number>0</number>
+        </property>
+        <item>
+         <widget class="QLabel" name="imageLabel">
+          <property name="font">
+           <font>
+            <weight>75</weight>
+            <bold>true</bold>
+           </font>
+          </property>
+          <property name="mouseTracking">
+           <bool>true</bool>
+          </property>
+          <property name="layoutDirection">
+           <enum>Qt::LeftToRight</enum>
+          </property>
+          <property name="styleSheet">
+           <string notr="true"/>
+          </property>
+          <property name="text">
+           <string>Image:</string>
+          </property>
+          <property name="alignment">
+           <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QLabel" name="imagePath">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="mouseTracking">
+           <bool>true</bool>
+          </property>
+          <property name="styleSheet">
+           <string notr="true"/>
+          </property>
+          <property name="text">
+           <string>TextLabel</string>
+          </property>
+          <property name="scaledContents">
+           <bool>false</bool>
+          </property>
+          <property name="alignment">
+           <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+          </property>
+          <property name="wordWrap">
+           <bool>false</bool>
+          </property>
+          <property name="margin">
+           <number>5</number>
+          </property>
+          <property name="indent">
+           <number>0</number>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QLabel" name="dataLabel">
+          <property name="font">
+           <font>
+            <weight>75</weight>
+            <bold>true</bold>
+           </font>
+          </property>
+          <property name="mouseTracking">
+           <bool>true</bool>
+          </property>
+          <property name="styleSheet">
+           <string notr="true"/>
+          </property>
+          <property name="text">
+           <string>Friction map</string>
+          </property>
+          <property name="alignment">
+           <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QLabel" name="dataPath">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="mouseTracking">
+           <bool>true</bool>
+          </property>
+          <property name="styleSheet">
+           <string notr="true"/>
+          </property>
+          <property name="text">
+           <string>TextLabel</string>
+          </property>
+          <property name="alignment">
+           <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+          </property>
+          <property name="wordWrap">
+           <bool>false</bool>
+          </property>
+          <property name="margin">
+           <number>5</number>
+          </property>
+          <property name="indent">
+           <number>0</number>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </item>
+      <item>
+       <spacer name="infoVSpacer">
+        <property name="orientation">
+         <enum>Qt::Vertical</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>279</width>
+          <height>208</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <layout class="QHBoxLayout" name="infoLayout">
+        <item>
+         <layout class="QVBoxLayout" name="propertiesLayout">
+          <item>
+           <spacer name="propertiesVSpacer">
+            <property name="orientation">
+             <enum>Qt::Vertical</enum>
+            </property>
+            <property name="sizeHint" stdset="0">
+             <size>
+              <width>20</width>
+              <height>40</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+          <item>
+           <widget class="QLabel" name="ImageShownLabel">
+            <property name="font">
+             <font>
+              <weight>75</weight>
+              <bold>true</bold>
+             </font>
+            </property>
+            <property name="mouseTracking">
+             <bool>true</bool>
+            </property>
+            <property name="styleSheet">
+             <string notr="true"/>
+            </property>
+            <property name="text">
+             <string>Image shown:</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QLabel" name="imageShown">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="mouseTracking">
+             <bool>true</bool>
+            </property>
+            <property name="styleSheet">
+             <string notr="true"/>
+            </property>
+            <property name="text">
+             <string>Visible image</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QLabel" name="feedbackLabel">
+            <property name="font">
+             <font>
+              <weight>75</weight>
+              <bold>true</bold>
+             </font>
+            </property>
+            <property name="mouseTracking">
+             <bool>true</bool>
+            </property>
+            <property name="styleSheet">
+             <string notr="true"/>
+            </property>
+            <property name="text">
+             <string>Feedback:</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QLabel" name="feedbackInfo">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="mouseTracking">
+             <bool>true</bool>
+            </property>
+            <property name="styleSheet">
+             <string notr="true"/>
+            </property>
+            <property name="text">
+             <string>Normal</string>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </item>
+        <item>
+         <spacer name="infoHSpacer">
+          <property name="orientation">
+           <enum>Qt::Horizontal</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>40</width>
+            <height>20</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+        <item>
+         <layout class="QVBoxLayout" name="imageNumLayout">
+          <item>
+           <spacer name="imageNumVSpacer">
+            <property name="mouseTracking">
+             <bool>true</bool>
+            </property>
+            <property name="orientation">
+             <enum>Qt::Vertical</enum>
+            </property>
+            <property name="sizeHint" stdset="0">
+             <size>
+              <width>20</width>
+              <height>40</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+          <item>
+           <widget class="QLabel" name="imageNum">
+            <property name="mouseTracking">
+             <bool>true</bool>
+            </property>
+            <property name="text">
+             <string>1/1</string>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </item>
+       </layout>
+      </item>
+     </layout>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/TactilePictures/ImageDemo.cpp b/TactilePictures/ImageDemo.cpp
new file mode 100644 (file)
index 0000000..72288d7
--- /dev/null
@@ -0,0 +1,300 @@
+/* -*- mode: c++ -*-
+ *
+ * Adapted from Pixel based by Paolo Olivo
+ * Authors: Thomas Pietrzak
+ * Copyright © Inria
+ *
+ */
+
+#include <QtGui>
+
+#include "ImageDemo.h"
+
+// ############################### CLASS ImageRef ##############################
+ImageRef::ImageRef(const char *img, const char *data) :
+  _img(img), _data(data) {
+}
+
+ImageRef::ImageRef(const ImageRef &copy) :
+  _img(copy.img()), _data(copy.data()) {
+}
+
+// ############################## CLASS ImageDemo ##############################
+ImageDemo::ImageDemo(/*Feedback *feedback*/ TactonPlayer *player, const char *path, QWidget *parent) : QMainWindow(parent) {
+  ui.setupUi(this);
+//  ui.canvas->setFeedback(feedback) ;
+  ui.canvas->setTactonPlayer(player) ;
+  showRepository(false);
+  showMenuBar(true) ;
+  showCursor(true) ;
+  QString sPath ;
+  if (path) sPath = path ;
+  else sPath = ":/images/" ;
+  QFileInfo pathInfo(sPath) ;
+  if (pathInfo.isDir()) {
+    addDir(sPath.toLocal8Bit().data()) ;
+  } else if (pathInfo.isFile()) {
+    QListWidgetItem *item = addImage(sPath.toLocal8Bit().data()) ;
+    if (item) {
+      QVariant var = item->data(Qt::UserRole) ;
+      ImageRef ref = var.value<ImageRef>() ;  
+      showImage(item) ;
+    }
+  }
+  connect(ui.repository, SIGNAL(itemClicked(QListWidgetItem *)), 
+         SLOT(showImage(QListWidgetItem *))) ;
+  connect(ui.openImage, SIGNAL(triggered(void)), SLOT(loadImagesDialog(void))) ;
+  connect(ui.openDir, SIGNAL(triggered(void)), SLOT(loadDirectoryDialog(void))) ;
+  connect(ui.showRepository, SIGNAL(triggered(bool)), SLOT(showRepository(bool))) ;
+  connect(ui.showMenuBar, SIGNAL(triggered(bool)), SLOT(showMenuBar(bool))) ;
+  connect(ui.showCursor, SIGNAL(triggered(bool)), SLOT(showCursor(bool))) ;
+  connect(ui.showOverlay, SIGNAL(triggered(bool)), SLOT(showOverlay(bool))) ;
+  connect(ui.showFeedback, SIGNAL(triggered(bool)), SLOT(showFeedback(bool))) ;
+  connect(ui.invertFeedback, SIGNAL(triggered(bool)), SLOT(invertFeedback(bool))) ;
+  connect(ui.showInfo, SIGNAL(triggered(bool)), SLOT(showInfo(bool))) ;
+}
+
+// <<<<<<<<<<<<<<<<<<<<<<<<<<<< OVERRIDDEN METHODS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+void
+ImageDemo::enterEvent(QEvent *) {
+  activateWindow() ;
+}
+
+void
+ImageDemo::dragEnterEvent(QDragEnterEvent *event) {
+  if (event->mimeData()->hasUrls()) {
+    event->setDropAction(Qt::CopyAction) ;
+    event->accept() ;
+  }
+}
+
+void
+ImageDemo::dragMoveEvent(QDragMoveEvent *event) {
+  if (event->mimeData()->hasUrls()) {
+    event->setDropAction(Qt::CopyAction) ;
+    event->accept() ;
+  }
+}
+
+void
+ImageDemo::dropEvent(QDropEvent *event) {
+  if (event->mimeData()->hasUrls()) {
+    QList<QUrl> urls = event->mimeData()->urls() ;    
+    QStringList files ;
+    for (int i = 0; i < urls.size(); ++i) {
+      files.append(urls[i].toLocalFile()) ;
+    }
+    addFiles(files) ;
+  }
+  // Set current window as active
+  activateWindow() ;
+}
+
+void 
+ImageDemo::keyPressEvent(QKeyEvent *event) {
+  bool handled = false;
+  if (!ui.menuBar->isVisible()) {
+    if (event->key() == Qt::Key_O && (event->modifiers() & Qt::CTRL)) {
+      loadImagesDialog() ;
+      handled = true ;
+    } else if (event->key() == Qt::Key_D && (event->modifiers() & Qt::CTRL)) {
+      loadDirectoryDialog() ;
+      handled = true ;
+    } else if (event->key() == Qt::Key_S && (event->modifiers() & Qt::CTRL)) {
+      showInfo(!ui.showInfo->isChecked()) ;
+      handled = true ;
+    } else if (event->key() == Qt::Key_Q && (event->modifiers() & Qt::CTRL)) {
+      close() ;
+      handled = true ;
+    } else if (event->key() == Qt::Key_F && (event->modifiers() & Qt::CTRL)) {
+      showFeedback(!ui.showFeedback->isChecked()) ;
+      handled = true ;
+    } else if (event->key() == Qt::Key_I && (event->modifiers() & Qt::CTRL)) {
+      invertFeedback(!ui.showFeedback->isChecked()) ;
+      handled = true ;
+    } else if (event->key() == Qt::Key_R && (event->modifiers() & Qt::CTRL)) {
+      showRepository(!ui.showRepository->isChecked()) ;
+      handled = true ;
+    } else if (event->key() == Qt::Key_M && (event->modifiers() & Qt::CTRL)) {
+      showMenuBar(!ui.showMenuBar->isChecked()) ;
+      handled = true ;
+    } else if (event->key() == Qt::Key_C && (event->modifiers() & Qt::CTRL)) {
+      showCursor(!ui.showCursor->isChecked()) ;
+      handled = true ;
+    } else if (event->key() == Qt::Key_V && (event->modifiers() & Qt::CTRL)) {
+      showOverlay(!ui.showOverlay->isChecked()) ;
+      handled = true ;
+    }
+  }
+  if (event->key()==Qt::Key_Up) {
+    int row = ui.repository->row(currItem) ;
+    if (row > 0)
+      showImage(ui.repository->item(row-1)) ;
+    handled = true ;
+  } else if (event->key()==Qt::Key_Down) {
+    int row = ui.repository->row(currItem) ;
+    if (row < ui.repository->count())
+      showImage(ui.repository->item(row+1)) ;
+    handled = true ;
+  }
+  if (!handled) QMainWindow::keyPressEvent(event) ;
+}
+
+void
+ImageDemo::addFiles(QStringList &files) {
+  bool set = false ;
+  for (int i = 0; i < files.size(); ++i) { 
+    if (!set) {
+      QListWidgetItem *item = addImage(files[i].toLocal8Bit().data()) ;
+      if (showImage(item) == 0) 
+        set = true;
+    } else {
+        addImage(files[i].toLocal8Bit().data()) ;
+    }
+  }
+}
+
+void
+ImageDemo::addDir(const char *path) {
+  QDir dir(path) ;
+  if (!dir.exists()) {
+     qWarning("Cannot find the example directory");
+  } else {
+    dir.setFilter(QDir::Files | QDir::NoSymLinks);
+    
+    QFileInfoList list = dir.entryInfoList();
+    QStringList files ;
+    for (int i = 0; i < list.size(); ++i) {
+      QFileInfo fileInfo = list.at(i);
+      files.append(fileInfo.absoluteFilePath()) ;
+    }
+    addFiles(files) ;
+  }
+}
+
+QListWidgetItem *
+ImageDemo::addImage(const char * img) {
+  if (img) {
+    std::string file(img) ;
+    std::size_t pos = file.rfind('/') ;
+    file = file.substr(pos + 1) ;
+
+    if (file.find(".data") < file.length() ) {
+      qDebug("%s not added to the list", file.data()) ;
+      return NULL ;
+    }
+
+    std::string dataImg(img) ;
+    pos = dataImg.rfind('.') ;
+    if (pos > 0 && pos < dataImg.length())  {
+      dataImg.insert(pos,".data") ; 
+    }
+    
+    ImageRef imgRef(img, dataImg.data()) ;
+    QListWidgetItem *item = new QListWidgetItem(QString(file.data())) ;
+    item->setData(Qt::UserRole, QVariant::fromValue(imgRef)) ;
+    ui.repository->addItem(item) ;
+
+    ui.canvas->notifyImageNum(ui.repository->row(item) + 1, ui.repository->count()) ;
+    return item ;
+  } else
+    return NULL ;
+}
+    
+// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< SLOTS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+int 
+ImageDemo::showImage(QListWidgetItem *item) {
+  if (item) {
+    QVariant var = item->data(Qt::UserRole) ;
+    ImageRef ref = var.value<ImageRef>() ;  
+    if (ui.canvas->setImage(ref.img(), ref.data())) {
+      return 1 ;
+    }
+    currItem = item ;
+    ui.repository->setCurrentItem(item) ;
+    ui.canvas->notifyImageNum(ui.repository->row(item) + 1, ui.repository->count()) ;
+    return 0 ;
+  } else 
+    return 1 ;
+}  
+
+void 
+ImageDemo::loadImagesDialog(void) {
+  QFileDialog fileDialog ;  
+  fileDialog.setFileMode(QFileDialog::ExistingFiles); 
+  fileDialog.setViewMode(QFileDialog::List);
+  fileDialog.exec() ; 
+  QStringList files = fileDialog.selectedFiles() ;
+  addFiles(files) ;
+  // Set current window as active
+  activateWindow() ;
+}
+
+void 
+ImageDemo::loadDirectoryDialog(void) {
+  QFileDialog fileDialog ;  
+  fileDialog.setFileMode(QFileDialog::Directory); 
+  fileDialog.setViewMode(QFileDialog::List);
+  fileDialog.exec() ; 
+  QStringList files = fileDialog.selectedFiles() ;
+  addDir(files[0].toLocal8Bit().data()) ;
+  // Set current window as active
+  activateWindow() ;
+}
+
+void 
+ImageDemo::showRepository(bool value) {
+  ui.repository->setVisible(value) ; 
+  if (value && isFullScreen())
+  {
+       ui.repositorySpacer->setVisible(true) ;
+       ui.repositorySpacer->setMinimumWidth(250);
+  }
+  else
+  {
+       ui.repositorySpacer->setMinimumWidth(0);
+       ui.repositorySpacer->setVisible(false) ;
+  }
+  ui.showRepository->setChecked(value) ;
+}
+
+void 
+ImageDemo::showMenuBar(bool value) {
+  ui.menuBar->setVisible(value) ;
+  ui.showMenuBar->setChecked(value) ;
+}
+
+void 
+ImageDemo::showCursor(bool value) {
+  if (value)
+    this->setCursor(Qt::ArrowCursor) ;
+  else
+    this->setCursor(Qt::BlankCursor) ;
+  ui.showCursor->setChecked(value) ;
+}
+
+void 
+ImageDemo::showOverlay(bool value) {
+  ui.showOverlay->setChecked(value) ;
+  emit overlayRequest(value) ;
+}
+
+void 
+ImageDemo::showFeedback(bool value) {
+  ui.canvas->showFeedback(value) ;
+  ui.showFeedback->setChecked(value) ;
+}
+
+void 
+ImageDemo::invertFeedback(bool value) {
+  ui.canvas->invertFeedback(value) ;
+  ui.invertFeedback->setChecked(value) ;
+}
+
+void 
+ImageDemo::showInfo(bool value) {
+  ui.canvas->showInfo(value) ;
+  ui.showInfo->setChecked(value) ;
+}
+
+
diff --git a/TactilePictures/ImageDemo.h b/TactilePictures/ImageDemo.h
new file mode 100644 (file)
index 0000000..9a14fe8
--- /dev/null
@@ -0,0 +1,81 @@
+/* -*- mode: c++ -*-
+ *
+ * Adapted from Pixel based by Paolo Olivo
+ * Authors: Thomas Pietrzak
+ * Copyright © Inria
+ *
+ */
+
+#ifndef IMAGEDEMO_H
+#define IMAGEDEMO_H
+
+#include "Canvas.h"
+#include "ui_ImageDemo.h"
+
+#include <TactonPlayer\TactonPlayer.hpp>
+
+class ImageRef {
+
+  std::string _img ;
+  std::string _data ;
+
+public:
+
+  ImageRef() {}
+  ImageRef(const ImageRef &copy) ;
+  ImageRef(const char *img, const char *data) ;
+  ~ImageRef(void) {}
+
+  const char *img() const { return _img.data() ; }
+  const char *data() const { return _data.data() ; }
+
+};
+
+// This MACRO is necessary to use ImageRef as a QVariant.
+Q_DECLARE_METATYPE(ImageRef)
+
+class ImageDemo : public QMainWindow {
+
+  Q_OBJECT ;
+
+  Ui::ImageDemo ui;
+  QListWidgetItem *currItem ;
+
+public:
+  ImageDemo(/*Feedback *feedback*/TactonPlayer *player, const char *path=0, QWidget *parent=0) ;
+  //void setFeedback(Feedback *feedback) { ui.canvas->setFeedback(feedback) ; }
+  void setTactonPlayer(TactonPlayer *player) { ui.canvas->setTactonPlayer(player) ; }
+  QWidget* canvas(void) { return ui.canvas ; }
+
+protected:
+  void enterEvent(QEvent *event) ;
+  void dragEnterEvent(QDragEnterEvent *event) ;
+  void dragMoveEvent(QDragMoveEvent *event) ;
+  void dropEvent(QDropEvent *event) ;
+  void keyPressEvent(QKeyEvent *event) ;
+
+private:
+  void addFiles(QStringList &files) ;
+  void addDir(const char *path) ;
+  QListWidgetItem * addImage(const char * img) ;
+
+public slots:
+  void showMenuBar(bool value) ;
+  void showCursor(bool value) ;
+  void showOverlay(bool value) ;
+
+protected slots:
+  int showImage(QListWidgetItem * item) ;
+  void loadImagesDialog(void) ;
+  void loadDirectoryDialog(void) ;
+  void showRepository(bool value) ;
+  void showFeedback(bool value) ;
+  void invertFeedback(bool value) ;
+  void showInfo(bool value) ;
+
+signals:
+  void overlayRequest(bool value) ;
+
+};
+
+#endif
diff --git a/TactilePictures/ImageDemo.ui b/TactilePictures/ImageDemo.ui
new file mode 100644 (file)
index 0000000..1297ec1
--- /dev/null
@@ -0,0 +1,351 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ImageDemo</class>
+ <widget class="QMainWindow" name="ImageDemo">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>861</width>
+    <height>477</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="acceptDrops">
+   <bool>true</bool>
+  </property>
+  <property name="windowTitle">
+   <string>ImageDemo</string>
+  </property>
+  <widget class="QWidget" name="centralwidget">
+   <property name="acceptDrops">
+    <bool>true</bool>
+   </property>
+   <layout class="QHBoxLayout" name="horizontalLayout">
+    <property name="spacing">
+     <number>0</number>
+    </property>
+    <property name="margin">
+     <number>0</number>
+    </property>
+    <item>
+     <widget class="QWidget" name="repositorySpacer" native="true">
+      <property name="sizePolicy">
+       <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+        <horstretch>0</horstretch>
+        <verstretch>0</verstretch>
+       </sizepolicy>
+      </property>
+      <property name="minimumSize">
+       <size>
+        <width>0</width>
+        <height>0</height>
+       </size>
+      </property>
+      <property name="maximumSize">
+       <size>
+        <width>250</width>
+        <height>16777215</height>
+       </size>
+      </property>
+     </widget>
+    </item>
+    <item>
+     <spacer name="leftSpacer">
+      <property name="orientation">
+       <enum>Qt::Horizontal</enum>
+      </property>
+      <property name="sizeType">
+       <enum>QSizePolicy::Preferred</enum>
+      </property>
+      <property name="sizeHint" stdset="0">
+       <size>
+        <width>0</width>
+        <height>0</height>
+       </size>
+      </property>
+     </spacer>
+    </item>
+    <item>
+     <layout class="QVBoxLayout" name="canvasLayout">
+      <item>
+       <spacer name="topSpacer">
+        <property name="orientation">
+         <enum>Qt::Vertical</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>0</width>
+          <height>0</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <widget class="Canvas" name="canvas" native="true">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <spacer name="bottomSpacer">
+        <property name="orientation">
+         <enum>Qt::Vertical</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>0</width>
+          <height>0</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+     </layout>
+    </item>
+    <item>
+     <spacer name="rightSpacer">
+      <property name="orientation">
+       <enum>Qt::Horizontal</enum>
+      </property>
+      <property name="sizeType">
+       <enum>QSizePolicy::Preferred</enum>
+      </property>
+      <property name="sizeHint" stdset="0">
+       <size>
+        <width>0</width>
+        <height>0</height>
+       </size>
+      </property>
+     </spacer>
+    </item>
+    <item>
+     <widget class="QListWidget" name="repository">
+      <property name="sizePolicy">
+       <sizepolicy hsizetype="MinimumExpanding" vsizetype="Expanding">
+        <horstretch>0</horstretch>
+        <verstretch>0</verstretch>
+       </sizepolicy>
+      </property>
+      <property name="minimumSize">
+       <size>
+        <width>250</width>
+        <height>0</height>
+       </size>
+      </property>
+      <property name="maximumSize">
+       <size>
+        <width>250</width>
+        <height>16777215</height>
+       </size>
+      </property>
+      <property name="focusPolicy">
+       <enum>Qt::NoFocus</enum>
+      </property>
+      <property name="alternatingRowColors">
+       <bool>true</bool>
+      </property>
+      <property name="uniformItemSizes">
+       <bool>true</bool>
+      </property>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QMenuBar" name="menuBar">
+   <property name="geometry">
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>861</width>
+     <height>21</height>
+    </rect>
+   </property>
+   <widget class="QMenu" name="fileMenu">
+    <property name="title">
+     <string>&amp;File</string>
+    </property>
+    <addaction name="openImage"/>
+    <addaction name="openDir"/>
+    <addaction name="separator"/>
+    <addaction name="quit"/>
+   </widget>
+   <widget class="QMenu" name="canvasMenu">
+    <property name="title">
+     <string>&amp;Canvas</string>
+    </property>
+    <addaction name="invertFeedback"/>
+   </widget>
+   <widget class="QMenu" name="menuShow">
+    <property name="title">
+     <string>&amp;Show</string>
+    </property>
+    <addaction name="showRepository"/>
+    <addaction name="showInfo"/>
+    <addaction name="showFeedback"/>
+    <addaction name="separator"/>
+    <addaction name="showMenuBar"/>
+    <addaction name="showCursor"/>
+    <addaction name="showOverlay"/>
+   </widget>
+   <addaction name="fileMenu"/>
+   <addaction name="canvasMenu"/>
+   <addaction name="menuShow"/>
+  </widget>
+  <action name="openImage">
+   <property name="text">
+    <string>&amp;Open Image</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+O</string>
+   </property>
+  </action>
+  <action name="toggleImages">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="text">
+    <string>&amp;Toggle images</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+T</string>
+   </property>
+  </action>
+  <action name="invertFeedback">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="text">
+    <string>&amp;Invert feedback</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+I</string>
+   </property>
+  </action>
+  <action name="showRepository">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="text">
+    <string>&amp;Repository</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+R</string>
+   </property>
+  </action>
+  <action name="showInfo">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="text">
+    <string>&amp;Image Info</string>
+   </property>
+   <property name="toolTip">
+    <string>Show Image Info</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+S</string>
+   </property>
+  </action>
+  <action name="showFeedback">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="text">
+    <string>&amp;Feedback Image</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+F</string>
+   </property>
+  </action>
+  <action name="showMenuBar">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="text">
+    <string>&amp;Menubar</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+M</string>
+   </property>
+  </action>
+  <action name="openDir">
+   <property name="text">
+    <string>Open &amp;Directory</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+D</string>
+   </property>
+  </action>
+  <action name="quit">
+   <property name="text">
+    <string>&amp;Quit</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+Q</string>
+   </property>
+  </action>
+  <action name="showCursor">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="checked">
+    <bool>false</bool>
+   </property>
+   <property name="text">
+    <string>&amp;Cursor</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+C</string>
+   </property>
+  </action>
+  <action name="showOverlay">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="text">
+    <string>O&amp;verlay</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+V</string>
+   </property>
+  </action>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>Canvas</class>
+   <extends>QWidget</extends>
+   <header>Canvas.h</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
+ <resources>
+  <include location="pixelbased.qrc"/>
+ </resources>
+ <connections>
+  <connection>
+   <sender>quit</sender>
+   <signal>triggered()</signal>
+   <receiver>ImageDemo</receiver>
+   <slot>close()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>-1</x>
+     <y>-1</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>283</x>
+     <y>238</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/TactilePictures/KinectInput.cpp b/TactilePictures/KinectInput.cpp
new file mode 100644 (file)
index 0000000..9fc8f37
--- /dev/null
@@ -0,0 +1,108 @@
+#include "KinectInput.h"\r
+\r
+#include <QDebug>\r
+#include <QDateTime>\r
+\r
+#define TIMEOUT 100\r
+\r
+KinectInput::KinectInput()\r
+:_running(false), _skeletonid(-1), _skeletonEvent(NULL), _xfilter(50, 0.05), _yfilter(50, 0.05), _zfilter(50, 0.01)\r
+{\r
+       //creates the kinect sensor (id 0)\r
+       if(FAILED(NuiCreateSensorByIndex(0, &_kinect)))\r
+    {\r
+               qDebug() << "Cannot find a KINECT sensor" << endl;\r
+               //I should do something else, sucha as an exception\r
+        return;\r
+    }\r
+\r
+    if (_kinect->NuiInitialize(NUI_INITIALIZE_FLAG_USES_DEPTH_AND_PLAYER_INDEX | NUI_INITIALIZE_FLAG_USES_SKELETON) == E_NUI_SKELETAL_ENGINE_BUSY)\r
+    {\r
+               qDebug() << "Cannot initialize the KINECT sensor" << endl;\r
+        return;\r
+   }\r
+\r
+       //initialize the skeleton tracking\r
+       _skeletonEvent = CreateEvent(NULL, TRUE, FALSE, NULL);\r
+       if(!HasSkeletalEngine(_kinect) || FAILED(_kinect->NuiSkeletonTrackingEnable(_skeletonEvent, 0)))\r
+    {\r
+               qDebug() << "Cannot Initialize skeleton tracking" << endl;\r
+        return;\r
+    }\r
+}\r
+\r
+KinectInput::~KinectInput()\r
+{\r
+       NuiShutdown();\r
+       if( _skeletonEvent && ( _skeletonEvent != INVALID_HANDLE_VALUE ) )\r
+        CloseHandle( _skeletonEvent );\r
+}\r
+\r
+//thread that manages the kinect events\r
+void KinectInput::run()\r
+{\r
+       _running = true;\r
+       while(_running)\r
+       {\r
+               //wait for an event\r
+               if (WaitForSingleObject(_skeletonEvent, TIMEOUT) != 0)\r
+                       continue;\r
+\r
+               //get skeleton values\r
+               NUI_SKELETON_FRAME SkeletonFrame;\r
+               HRESULT hr = _kinect->NuiSkeletonGetNextFrame( 0, &SkeletonFrame );\r
+//             qDebug() << "Kinect frame " << SkeletonFrame.dwFrameNumber;\r
+\r
+               //if no skeleton already identified or not tracked anymore, search for one\r
+               if (_skeletonid < 0 || SkeletonFrame.SkeletonData[_skeletonid].eTrackingState != NUI_SKELETON_TRACKED)\r
+               {\r
+                       for( int i = 0 ; i < NUI_SKELETON_COUNT ; i++ )\r
+                       {\r
+                               if(SkeletonFrame.SkeletonData[i].eTrackingState == NUI_SKELETON_TRACKED)\r
+                               {\r
+                                       _skeletonid = i;\r
+                                       break;\r
+                               }\r
+                       }\r
+               }\r
+\r
+               //no skeleton found\r
+               if (_skeletonid < 0)\r
+                       continue;\r
+\r
+               //retrieve information on the skeleton\r
+               NUI_SKELETON_DATA &data = SkeletonFrame.SkeletonData[_skeletonid];\r
+\r
+               //checking if we have a skeleton\r
+/*             if (data.eTrackingState != NUI_SKELETON_TRACKED)\r
+                       continue;*/\r
+\r
+               //Let's use the 1 euro instead, see below\r
+               //smooth out the skeleton data\r
+               //_kinect->NuiTransformSmooth(&SkeletonFrame, NULL);\r
+\r
+\r
+               if (data.eSkeletonPositionTrackingState[NUI_SKELETON_POSITION_HAND_RIGHT] == NUI_SKELETON_NOT_TRACKED)\r
+                       continue; //right hand not detected\r
+               else\r
+               {\r
+/*                     float posx, posy;\r
+                       NuiTransformSkeletonToDepthImageF(data.SkeletonPositions[NUI_SKELETON_POSITION_HAND_RIGHT], &posx, &posy);\r
+                       emit rightHandMove(posx, posy,0);*/\r
+                       Vector4 &skelpos = data.SkeletonPositions[NUI_SKELETON_POSITION_HAND_RIGHT];\r
+\r
+                       //Filter\r
+                       int timestamp = QDateTime::currentMSecsSinceEpoch();\r
+                       float fx = _xfilter.filter(skelpos.x, timestamp);\r
+                       float fy = _yfilter.filter(skelpos.y, timestamp);\r
+                       float fz = _zfilter.filter(skelpos.z, timestamp);\r
+\r
+                       emit rightHandMove(fx, fy, fz);\r
+        }\r
+       }\r
+}\r
+\r
+void KinectInput::stop()\r
+{\r
+       _running = false;\r
+}\r
diff --git a/TactilePictures/KinectInput.h b/TactilePictures/KinectInput.h
new file mode 100644 (file)
index 0000000..855fb7b
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef __KINECTINPUT__\r
+#define __KINECTINPUT__\r
+\r
+#include <QObject>\r
+#include <QThread>\r
+#include <Windows.h>\r
+#include <NuiAPI.h>\r
+\r
+#include "OneEuroFilter.h"\r
+\r
+class KinectInput: public QThread\r
+{\r
+       Q_OBJECT\r
+       public:\r
+               KinectInput();\r
+               ~KinectInput();\r
+\r
+               void run();\r
+               void stop();\r
+\r
+       private:\r
+               INuiSensor* _kinect;\r
+               HANDLE _skeletonEvent;\r
+               bool _running;\r
+               int _skeletonid;\r
+\r
+               OneEuroFilter _xfilter, _yfilter, _zfilter;\r
+\r
+       signals:\r
+               void rightHandMove(float x, float y, float z);\r
+};\r
+\r
+#endif\r
diff --git a/TactilePictures/OneEuroFilter.cpp b/TactilePictures/OneEuroFilter.cpp
new file mode 100644 (file)
index 0000000..ee1754c
--- /dev/null
@@ -0,0 +1,118 @@
+#include "OneEuroFilter.h"\r
+\r
+#define _USE_MATH_DEFINES \r
+#include <cmath>\r
+#include <stdexcept>\r
+\r
+LowPassFilter::LowPassFilter(double alpha, double initval) \r
+:_y(initval), _s(initval), _initialized(false)\r
+{\r
+       setAlpha(alpha);\r
+}\r
+\r
+double LowPassFilter::filter(double value) \r
+{\r
+       double result;\r
+       if (_initialized)\r
+               result = _a * value + (1.0 - _a) * _s;\r
+       else \r
+       {\r
+               result = value;\r
+               _initialized = true;\r
+       }\r
+       _y = value;\r
+       _s = result;\r
+       return result;\r
+}\r
+\r
+double LowPassFilter::filterWithAlpha(double value, double alpha) \r
+{\r
+       setAlpha(alpha);\r
+       return filter(value);\r
+}\r
+\r
+bool LowPassFilter::hasLastRawValue(void) \r
+{\r
+       return _initialized;\r
+}\r
+\r
+double LowPassFilter::lastRawValue(void) \r
+{\r
+       return _y ;\r
+}\r
+\r
+void LowPassFilter::setAlpha(double alpha) \r
+{\r
+       if (alpha <= 0.0 || alpha > 1.0) \r
+               throw std::range_error("alpha should be in ]0.0., 1.0]");\r
+       _a = alpha;\r
+}\r
+\r
+\r
+OneEuroFilter::OneEuroFilter(double freq, double mincutoff, double beta, double dcutoff)\r
+:_lasttime(UndefinedTime)\r
+{\r
+               setFrequency(freq);\r
+\r
+               //don't do this earlier, frequency is required to compute alpha\r
+               _x = new LowPassFilter(alpha(mincutoff));\r
+               _dx = new LowPassFilter(alpha(dcutoff));\r
+\r
+               setMinCutoff(mincutoff);\r
+               setBeta(beta);\r
+               setDerivateCutoff(dcutoff);\r
+}\r
+\r
+OneEuroFilter::~OneEuroFilter(void) \r
+{\r
+       delete _x;\r
+       delete _dx;\r
+}\r
+\r
+double OneEuroFilter::filter(double value, TimeStamp timestamp) \r
+{\r
+       // update the sampling frequency based on timestamps\r
+       if (_lasttime != UndefinedTime && timestamp != UndefinedTime)\r
+               _freq = 1.0 / (timestamp - _lasttime);\r
+       _lasttime = timestamp;\r
+       // estimate the current variation per second \r
+       double dvalue = _x->hasLastRawValue() ? (value - _x->lastRawValue()) * _freq : 0.0; // FIXME: 0.0 or value?\r
+       double edvalue = _dx->filterWithAlpha(dvalue, alpha(_dcutoff));\r
+       // use it to update the cutoff frequency\r
+       double cutoff = _mincutoff + _beta * fabs(edvalue);\r
+       // filter the given value\r
+       return _x->filterWithAlpha(value, alpha(cutoff));\r
+}\r
+\r
+double OneEuroFilter::alpha(double cutoff) \r
+{\r
+       double te = 1.0 / _freq;\r
+       double tau = 1.0 / (2 * M_PI * cutoff);\r
+       return 1.0 / (1.0 + tau/te);\r
+}\r
+\r
+void OneEuroFilter::setFrequency(double f) \r
+{\r
+       if (f <= 0) \r
+               throw std::range_error("freq should be >0");\r
+       _freq = f;\r
+}\r
+\r
+void OneEuroFilter::setMinCutoff(double mc) \r
+{\r
+       if (mc <= 0) \r
+               throw std::range_error("mincutoff should be >0");\r
+       _mincutoff = mc;\r
+}\r
+\r
+void OneEuroFilter::setBeta(double b) \r
+{\r
+       _beta = b;\r
+}\r
+\r
+void OneEuroFilter::setDerivateCutoff(double dc) \r
+{\r
+       if (dc <= 0) \r
+               throw std::range_error("dcutoff should be >0");\r
+       _dcutoff = dc;\r
+}\r
diff --git a/TactilePictures/OneEuroFilter.h b/TactilePictures/OneEuroFilter.h
new file mode 100644 (file)
index 0000000..7d24ffa
--- /dev/null
@@ -0,0 +1,62 @@
+/*\r
+ * OneEuroFilter.h/.cpp -\r
+ *\r
+ * Author: Thomas Pietrzak (thomas.pietrzak@lifl.fr)\r
+ * based on code from\r
+ * Nicolas Roussel (nicolas.roussel@inria.fr)\r
+ *\r
+ */\r
+\r
+\r
+#ifndef __ONEEURO__\r
+#define __ONEEURO__\r
+\r
+\r
+typedef double TimeStamp ; // in seconds\r
+\r
+static const TimeStamp UndefinedTime = -1.0 ;\r
+\r
+\r
+class LowPassFilter \r
+{\r
+       public:\r
+               LowPassFilter(double alpha, double initval=0.0);\r
+\r
+               double filterWithAlpha(double value, double alpha);\r
+               inline bool hasLastRawValue(void);\r
+               inline double lastRawValue(void);\r
+\r
+       private:\r
+               double _y, _a, _s;\r
+               bool _initialized;\r
+\r
+               void setAlpha(double alpha);\r
+               double filter(double value);\r
+} ;\r
+\r
+class OneEuroFilter \r
+{\r
+       public:\r
+               OneEuroFilter(\r
+                       double freq, \r
+                       double mincutoff=1.0, \r
+                       double beta_=0.0, \r
+                       double dcutoff=1.0);\r
+       \r
+               ~OneEuroFilter();\r
+\r
+               double filter(double value, TimeStamp timestamp=UndefinedTime);\r
+\r
+       private:\r
+               double _freq, _mincutoff, _beta, _dcutoff;\r
+               LowPassFilter *_x, *_dx;\r
+               TimeStamp _lasttime;\r
+\r
+               double alpha(double cutoff);\r
+               inline void setFrequency(double f);\r
+               inline void setMinCutoff(double mc);\r
+               inline void setBeta(double b);\r
+               inline void setDerivateCutoff(double dc);\r
+} ;\r
+\r
+#endif\r
diff --git a/TactilePictures/PictureView.cpp b/TactilePictures/PictureView.cpp
new file mode 100644 (file)
index 0000000..b6f2e3e
--- /dev/null
@@ -0,0 +1,25 @@
+#include "PictureView.h"\r
+\r
+#include <QSizePolicy>\r
+#include <QDebug>\r
+\r
+PictureView::PictureView(void)\r
+{\r
+       setScene(&_scene);\r
+    _scene.addItem(&_image);\r
+//     this->setMaximumSize(0xffffffff, 0xffffffff);\r
+       //setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);\r
+//     resize(200, 200);\r
+\r
+}\r
+\r
+\r
+PictureView::~PictureView(void)\r
+{\r
+}\r
+\r
+void PictureView::setImage(QString fileName)\r
+{\r
+        _image.setPixmap(QPixmap(fileName));\r
+       fitInView(_scene.sceneRect(),Qt::KeepAspectRatio);\r
+}\r
diff --git a/TactilePictures/PictureView.h b/TactilePictures/PictureView.h
new file mode 100644 (file)
index 0000000..330a6d4
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef __PICTUREVIEW__\r
+#define __PICTUREVIEW__\r
+\r
+#include <QGraphicsScene>\r
+#include <QGraphicsPixmapItem>\r
+#include <QGraphicsView>\r
+#include <QMouseEvent>\r
+\r
+class PictureView :\r
+       public QGraphicsView\r
+{\r
+       Q_OBJECT\r
+\r
+       public:\r
+               PictureView(void);\r
+               ~PictureView(void);\r
+\r
+               void setImage(QString);\r
+\r
+       private:\r
+               QGraphicsScene _scene;\r
+               QGraphicsPixmapItem _image;\r
+};\r
+\r
+#endif\r
diff --git a/TactilePictures/TactilePictures.vcxproj b/TactilePictures/TactilePictures.vcxproj
new file mode 100644 (file)
index 0000000..05e6b03
--- /dev/null
@@ -0,0 +1,242 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <ItemGroup Label="ProjectConfigurations">\r
+    <ProjectConfiguration Include="Debug|Win32">\r
+      <Configuration>Debug</Configuration>\r
+      <Platform>Win32</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="Release|Win32">\r
+      <Configuration>Release</Configuration>\r
+      <Platform>Win32</Platform>\r
+    </ProjectConfiguration>\r
+  </ItemGroup>\r
+  <PropertyGroup Label="Globals">\r
+    <ProjectGuid>{B219D272-E4C1-46D8-9263-3B4462606CC6}</ProjectGuid>\r
+    <Keyword>Qt4VSv1.0</Keyword>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">\r
+    <ConfigurationType>Application</ConfigurationType>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">\r
+    <ConfigurationType>Application</ConfigurationType>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
+  <ImportGroup Label="ExtensionSettings">\r
+  </ImportGroup>\r
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <PropertyGroup Label="UserMacros" />\r
+  <PropertyGroup>\r
+    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\r
+    <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>\r
+    <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />\r
+    <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />\r
+    <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>\r
+    <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />\r
+    <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />\r
+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>\r
+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>\r
+  </PropertyGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
+    <ClCompile>\r
+      <PreprocessorDefinitions>UNICODE;WIN32;QT_LARGEFILE_SUPPORT;QT_DLL;QT_CORE_LIB;QT_GUI_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>$(KINECTSDK10_DIR)\inc;.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <Optimization>Disabled</Optimization>\r
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\r
+      <TreatWChar_tAsBuiltInType>false</TreatWChar_tAsBuiltInType>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Windows</SubSystem>\r
+      <OutputFile>$(OutDir)\$(ProjectName).exe</OutputFile>\r
+      <AdditionalLibraryDirectories>$(KINECTSDK10_DIR)\lib\x86;$(QTDIR)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <AdditionalDependencies>TactonPlayerd.lib;Kinect10.lib;qtmaind.lib;QtCored4.lib;QtGuid4.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
+    <ClCompile>\r
+      <PreprocessorDefinitions>UNICODE;WIN32;QT_LARGEFILE_SUPPORT;QT_DLL;QT_NO_DEBUG;NDEBUG;QT_CORE_LIB;QT_GUI_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>$(KINECTSDK10_DIR)\inc;.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <DebugInformationFormat>\r
+      </DebugInformationFormat>\r
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\r
+      <TreatWChar_tAsBuiltInType>false</TreatWChar_tAsBuiltInType>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Windows</SubSystem>\r
+      <OutputFile>$(OutDir)\$(ProjectName).exe</OutputFile>\r
+      <AdditionalLibraryDirectories>$(KINECTSDK10_DIR)\lib\x86;$(QTDIR)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
+      <GenerateDebugInformation>false</GenerateDebugInformation>\r
+      <AdditionalDependencies>TactonPlayer.lib;Kinect10.lib;qtmain.lib;QtCore4.lib;QtGui4.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemGroup>\r
+    <ClCompile Include="Canvas.cpp" />\r
+    <ClCompile Include="GeneratedFiles\Debug\moc_Canvas.cpp">\r
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>\r
+    </ClCompile>\r
+    <ClCompile Include="GeneratedFiles\Debug\moc_ImageDemo.cpp">\r
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>\r
+    </ClCompile>\r
+    <ClCompile Include="GeneratedFiles\Debug\moc_KinectInput.cpp">\r
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>\r
+    </ClCompile>\r
+    <ClCompile Include="GeneratedFiles\Debug\moc_PictureView.cpp">\r
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>\r
+    </ClCompile>\r
+    <ClCompile Include="GeneratedFiles\Debug\moc_tactilepictures.cpp">\r
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>\r
+    </ClCompile>\r
+    <ClCompile Include="GeneratedFiles\qrc_tactilepictures.cpp">\r
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
+      </PrecompiledHeader>\r
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
+      </PrecompiledHeader>\r
+    </ClCompile>\r
+    <ClCompile Include="GeneratedFiles\Release\moc_Canvas.cpp">\r
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>\r
+    </ClCompile>\r
+    <ClCompile Include="GeneratedFiles\Release\moc_ImageDemo.cpp">\r
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>\r
+    </ClCompile>\r
+    <ClCompile Include="GeneratedFiles\Release\moc_KinectInput.cpp">\r
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>\r
+    </ClCompile>\r
+    <ClCompile Include="GeneratedFiles\Release\moc_PictureView.cpp">\r
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>\r
+    </ClCompile>\r
+    <ClCompile Include="GeneratedFiles\Release\moc_tactilepictures.cpp">\r
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>\r
+    </ClCompile>\r
+    <ClCompile Include="ImageDemo.cpp" />\r
+    <ClCompile Include="KinectInput.cpp" />\r
+    <ClCompile Include="main.cpp" />\r
+    <ClCompile Include="OneEuroFilter.cpp" />\r
+    <ClCompile Include="PictureView.cpp" />\r
+    <ClCompile Include="tactilepictures.cpp" />\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <CustomBuild Include="tactilepictures.h">\r
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>\r
+      <Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Moc%27ing tactilepictures.h...</Message>\r
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>\r
+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe"  "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp"  -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_CORE_LIB -DQT_GUI_LIB  "-I$(KINECTSDK10_DIR)\inc" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui"</Command>\r
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>\r
+      <Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Moc%27ing tactilepictures.h...</Message>\r
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>\r
+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe"  "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp"  -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB  "-I$(KINECTSDK10_DIR)\inc" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui"</Command>\r
+    </CustomBuild>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <CustomBuild Include="tactilepictures.ui">\r
+      <FileType>Document</FileType>\r
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>\r
+      <Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Uic%27ing %(Identity)...</Message>\r
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\ui_%(Filename).h;%(Outputs)</Outputs>\r
+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\uic.exe" -o ".\GeneratedFiles\ui_%(Filename).h" "%(FullPath)"</Command>\r
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>\r
+      <Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Uic%27ing %(Identity)...</Message>\r
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\ui_%(Filename).h;%(Outputs)</Outputs>\r
+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\uic.exe" -o ".\GeneratedFiles\ui_%(Filename).h" "%(FullPath)"</Command>\r
+    </CustomBuild>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <CustomBuild Include="Canvas.h">\r
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>\r
+      <Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Moc%27ing Canvas.h...</Message>\r
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>\r
+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe"  "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp"  -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_CORE_LIB -DQT_GUI_LIB "-I$(KINECTSDK10_DIR)\inc" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui"</Command>\r
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>\r
+      <Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Moc%27ing Canvas.h...</Message>\r
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>\r
+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe"  "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp"  -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB "-I$(KINECTSDK10_DIR)\inc" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui"</Command>\r
+    </CustomBuild>\r
+    <ClInclude Include="GeneratedFiles\ui_Canvas.h" />\r
+    <ClInclude Include="GeneratedFiles\ui_ImageDemo.h" />\r
+    <ClInclude Include="GeneratedFiles\ui_tactilepictures.h" />\r
+    <CustomBuild Include="ImageDemo.h">\r
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>\r
+      <Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Moc%27ing ImageDemo.h...</Message>\r
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>\r
+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe"  "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp"  -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_CORE_LIB -DQT_GUI_LIB "-I$(KINECTSDK10_DIR)\inc" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui"</Command>\r
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>\r
+      <Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Moc%27ing ImageDemo.h...</Message>\r
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>\r
+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe"  "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp"  -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB "-I$(KINECTSDK10_DIR)\inc" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui"</Command>\r
+    </CustomBuild>\r
+    <ClInclude Include="OneEuroFilter.h" />\r
+    <CustomBuild Include="PictureView.h">\r
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>\r
+      <Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Moc%27ing PictureView.h...</Message>\r
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>\r
+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe"  "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp"  -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_CORE_LIB -DQT_GUI_LIB "-I$(KINECTSDK10_DIR)\inc" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui"</Command>\r
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>\r
+      <Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Moc%27ing PictureView.h...</Message>\r
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>\r
+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe"  "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp"  -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB "-I$(KINECTSDK10_DIR)\inc" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui"</Command>\r
+    </CustomBuild>\r
+    <CustomBuild Include="KinectInput.h">\r
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>\r
+      <Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Moc%27ing KinectInput.h...</Message>\r
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>\r
+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe"  "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp"  -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_CORE_LIB -DQT_GUI_LIB  "-I$(KINECTSDK10_DIR)\inc" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui"</Command>\r
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>\r
+      <Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Moc%27ing KinectInput.h...</Message>\r
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>\r
+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe"  "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp"  -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB  "-I$(KINECTSDK10_DIR)\inc" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui"</Command>\r
+    </CustomBuild>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <CustomBuild Include="tactilepictures.qrc">\r
+      <FileType>Document</FileType>\r
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(FullPath);%(AdditionalInputs)</AdditionalInputs>\r
+      <Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Rcc%27ing %(Identity)...</Message>\r
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\qrc_%(Filename).cpp;%(Outputs)</Outputs>\r
+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\rcc.exe" -name "%(Filename)" -no-compress "%(FullPath)" -o .\GeneratedFiles\qrc_%(Filename).cpp</Command>\r
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(FullPath);%(AdditionalInputs)</AdditionalInputs>\r
+      <Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Rcc%27ing %(Identity)...</Message>\r
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\qrc_%(Filename).cpp;%(Outputs)</Outputs>\r
+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\rcc.exe" -name "%(Filename)" -no-compress "%(FullPath)" -o .\GeneratedFiles\qrc_%(Filename).cpp</Command>\r
+    </CustomBuild>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <CustomBuild Include="Canvas.ui">\r
+      <FileType>Document</FileType>\r
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>\r
+      <Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Uic%27ing %(Identity)...</Message>\r
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\ui_%(Filename).h;%(Outputs)</Outputs>\r
+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\uic.exe" -o ".\GeneratedFiles\ui_%(Filename).h" "%(FullPath)"</Command>\r
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>\r
+      <Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Uic%27ing %(Identity)...</Message>\r
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\ui_%(Filename).h;%(Outputs)</Outputs>\r
+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\uic.exe" -o ".\GeneratedFiles\ui_%(Filename).h" "%(FullPath)"</Command>\r
+    </CustomBuild>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <CustomBuild Include="ImageDemo.ui">\r
+      <FileType>Document</FileType>\r
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>\r
+      <Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Uic%27ing %(Identity)...</Message>\r
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\ui_%(Filename).h;%(Outputs)</Outputs>\r
+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\uic.exe" -o ".\GeneratedFiles\ui_%(Filename).h" "%(FullPath)"</Command>\r
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>\r
+      <Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Uic%27ing %(Identity)...</Message>\r
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\ui_%(Filename).h;%(Outputs)</Outputs>\r
+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\uic.exe" -o ".\GeneratedFiles\ui_%(Filename).h" "%(FullPath)"</Command>\r
+    </CustomBuild>\r
+  </ItemGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
+  <ImportGroup Label="ExtensionTargets">\r
+  </ImportGroup>\r
+  <ProjectExtensions>\r
+    <VisualStudio>\r
+      <UserProperties UicDir=".\GeneratedFiles" MocDir=".\GeneratedFiles\$(ConfigurationName)" MocOptions="" RccDir=".\GeneratedFiles" lupdateOnBuild="0" lupdateOptions="" lreleaseOptions="" QtVersion_x0020_Win32="4.8.2" />\r
+    </VisualStudio>\r
+  </ProjectExtensions>\r
+</Project>
\ No newline at end of file
diff --git a/TactilePictures/images/00-VH07.PNG b/TactilePictures/images/00-VH07.PNG
new file mode 100644 (file)
index 0000000..129e219
Binary files /dev/null and b/TactilePictures/images/00-VH07.PNG differ
diff --git a/TactilePictures/images/00-VS07.PNG b/TactilePictures/images/00-VS07.PNG
new file mode 100644 (file)
index 0000000..8424ad9
Binary files /dev/null and b/TactilePictures/images/00-VS07.PNG differ
diff --git a/TactilePictures/images/01-VH03.PNG b/TactilePictures/images/01-VH03.PNG
new file mode 100644 (file)
index 0000000..0fa6176
Binary files /dev/null and b/TactilePictures/images/01-VH03.PNG differ
diff --git a/TactilePictures/images/01-VS03.PNG b/TactilePictures/images/01-VS03.PNG
new file mode 100644 (file)
index 0000000..d556cbd
Binary files /dev/null and b/TactilePictures/images/01-VS03.PNG differ
diff --git a/TactilePictures/images/02-VH01.PNG b/TactilePictures/images/02-VH01.PNG
new file mode 100644 (file)
index 0000000..b71d168
Binary files /dev/null and b/TactilePictures/images/02-VH01.PNG differ
diff --git a/TactilePictures/images/02-VS01.PNG b/TactilePictures/images/02-VS01.PNG
new file mode 100644 (file)
index 0000000..d546ede
Binary files /dev/null and b/TactilePictures/images/02-VS01.PNG differ
diff --git a/TactilePictures/images/03-OH07.PNG b/TactilePictures/images/03-OH07.PNG
new file mode 100644 (file)
index 0000000..5d3ca93
Binary files /dev/null and b/TactilePictures/images/03-OH07.PNG differ
diff --git a/TactilePictures/images/03-OS07.PNG b/TactilePictures/images/03-OS07.PNG
new file mode 100644 (file)
index 0000000..c225248
Binary files /dev/null and b/TactilePictures/images/03-OS07.PNG differ
diff --git a/TactilePictures/images/10-BW-eiffel.png b/TactilePictures/images/10-BW-eiffel.png
new file mode 100644 (file)
index 0000000..a03ba46
Binary files /dev/null and b/TactilePictures/images/10-BW-eiffel.png differ
diff --git a/TactilePictures/images/11-BW-patterns.png b/TactilePictures/images/11-BW-patterns.png
new file mode 100644 (file)
index 0000000..a25f09b
Binary files /dev/null and b/TactilePictures/images/11-BW-patterns.png differ
diff --git a/TactilePictures/images/20-BW-teapot.png b/TactilePictures/images/20-BW-teapot.png
new file mode 100644 (file)
index 0000000..1e77f01
Binary files /dev/null and b/TactilePictures/images/20-BW-teapot.png differ
diff --git a/TactilePictures/images/21-BW-teapot.png b/TactilePictures/images/21-BW-teapot.png
new file mode 100644 (file)
index 0000000..70fe955
Binary files /dev/null and b/TactilePictures/images/21-BW-teapot.png differ
diff --git a/TactilePictures/images/22-BW-teapot.png b/TactilePictures/images/22-BW-teapot.png
new file mode 100644 (file)
index 0000000..b68ece8
Binary files /dev/null and b/TactilePictures/images/22-BW-teapot.png differ
diff --git a/TactilePictures/images/23-BW-teapot.data.png b/TactilePictures/images/23-BW-teapot.data.png
new file mode 100644 (file)
index 0000000..b68ece8
Binary files /dev/null and b/TactilePictures/images/23-BW-teapot.data.png differ
diff --git a/TactilePictures/images/23-BW-teapot.png b/TactilePictures/images/23-BW-teapot.png
new file mode 100644 (file)
index 0000000..70fe955
Binary files /dev/null and b/TactilePictures/images/23-BW-teapot.png differ
diff --git a/TactilePictures/images/30-BW-map.png b/TactilePictures/images/30-BW-map.png
new file mode 100644 (file)
index 0000000..a2b4c18
Binary files /dev/null and b/TactilePictures/images/30-BW-map.png differ
diff --git a/TactilePictures/images/31-BW-map.data.png b/TactilePictures/images/31-BW-map.data.png
new file mode 100644 (file)
index 0000000..afdcbc3
Binary files /dev/null and b/TactilePictures/images/31-BW-map.data.png differ
diff --git a/TactilePictures/images/31-BW-map.png b/TactilePictures/images/31-BW-map.png
new file mode 100644 (file)
index 0000000..a2b4c18
Binary files /dev/null and b/TactilePictures/images/31-BW-map.png differ
diff --git a/TactilePictures/main.cpp b/TactilePictures/main.cpp
new file mode 100644 (file)
index 0000000..5873344
--- /dev/null
@@ -0,0 +1,29 @@
+#include "tactilepictures.h"\r
+#include <QtGui/QApplication>\r
+\r
+#include <TactonPlayer\TactonPlayer.hpp>\r
+#include "ImageDemo.h"\r
+\r
+#include <QDebug>\r
+\r
+int main(int argc, char *argv[])\r
+{\r
+       TactonPlayer *player;\r
+       try\r
+       {\r
+               player = new TactonPlayer("COM8");\r
+       }\r
+       catch (...)\r
+       {\r
+               player = NULL;\r
+               qDebug() << "No wristband found";\r
+               return 0;\r
+       }\r
+\r
+       QApplication a(argc, argv);\r
+       ImageDemo demo(player);\r
+       demo.show();\r
+       //TactilePictures w;\r
+       //w.show();\r
+       return a.exec();\r
+}\r
diff --git a/TactilePictures/pixelbased.cpp b/TactilePictures/pixelbased.cpp
new file mode 100644 (file)
index 0000000..cec056e
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ *
+ * demos/pixelbased/pixelbased.cpp --
+ *
+ * Initial software
+ * Authors: Nicolas Roussel, Paolo Olivo
+ * Copyright © Inria
+ *
+ */
+
+#include <QApplication>
+#include <QDesktopWidget>
+#include <QDebug>
+#include <QMatrix3x3>
+#include <QStyleFactory>
+
+#include <tIO/stimtac/STM32TS60CursorControl.h>
+#include <tIO/stimtac/StandaloneCursorControl.h>
+#include <tIO/stimtac/STIMTAC200CursorControl.h>
+#include <tIO/utils/Overlay.h>
+
+#include "ImageDemo.h"
+
+int
+main(int argc, char* argv[]) {
+  QApplication::setStyle(QStyleFactory::create("plastique")) ;
+  QApplication app(argc, argv) ;
+  // Parse args
+  int ch, overlaysize=-1 ;
+  bool absolute=false, fullscreen=false, hidemenubar=false, showoverlay=false;
+  QString device, rotation, screenstr, calibstr ;
+  while ((ch = getopt(argc, argv, "d:r:f::maho::c:")) != -1) {
+    switch (ch) {
+    case 'f': fullscreen = true ; if (optarg) screenstr = optarg ; break ;
+    case 'r': rotation = optarg ; break ;
+    case 'd': device = optarg ; break ;
+    case 'm': hidemenubar = true ; break ;
+    case 'a': absolute = true ; break ;
+    case 'c': calibstr = optarg ; break ;
+    case 'o': showoverlay = true ; if (optarg) overlaysize = atoi(optarg) ; break ;
+    case 'h': 
+      qDebug() << "Usage:" << argv[0] << "[OPTION]... [DIRECTORY]" ;
+      qDebug();
+      qDebug() << "Options:" ;
+      qDebug() << " -d <DEVICE>        select device between: standalone, stimtac200, stm32ts60" ;
+      qDebug() << "                    (default=standalone)" ;
+      qDebug() << " -c MATRIX          set 3x3 calibration matrix (e.g. -c 0.865,0,0.074,0,1.1,0,0,0,1)" ;
+      qDebug() << "                    (standalone only)" ;
+      qDebug() << " -r <ROTATION>      select rotation between: normal, left, inverted, right" ;
+      qDebug() << "                    (standalone only, default=normal)" ;
+      qDebug() << " -f[SCREEN-NUMBER]  set demo fullscreen and select screen (e.g. -f0)" ;
+      qDebug() << " -m                 hide menubar" ;
+      qDebug() << " -o[SIZE]           show overlay (e.g. -o60)" ;
+      qDebug() << " -a                 set absolute pointing (standalone only)" ;
+      qDebug() << " -h                 display this help and exit" ;
+      return 0 ;
+    default: break ;
+    }
+  }
+  char* path = argc - optind > 0 ? argv[optind] : NULL ;
+  // Init demo and stimtac device
+  Q_INIT_RESOURCE(pixelbased) ;
+  ImageDemo* demo = new ImageDemo(NULL, path) ;
+  Overlay *overlay = new Overlay(demo) ;
+  overlay->setRadius(overlaysize) ;
+  QObject::connect(demo, SIGNAL(overlayRequest(bool)), 
+                  overlay, SLOT(setEnabled(bool))) ;
+  Feedback* feedback = NULL;
+  STM32TS60CursorControl* stm32ts60Cursor = NULL ;
+  StandaloneCursorControl* standaloneCursor = NULL ;
+  STIMTAC200CursorControl* stimtac200Cursor = NULL ;
+  if (device.isEmpty()) {
+    device = "standalone" ;
+    qDebug() << "Using default device:" << device ;
+  }
+  if (device=="standalone") {
+    standaloneCursor = new StandaloneCursorControl(demo) ;
+    feedback = new Feedback(standaloneCursor->standalone()) ;
+    standaloneCursor->setAbsolute(absolute) ;
+    if (!calibstr.isEmpty()) {
+      bool ok ;
+      int i = 0 ;
+      qreal data[] = {0, 0, 0, 0, 0, 0, 0, 0, 0} ;
+      QStringList list = calibstr.remove(QChar(' ')).split(",") ;
+      ok = list.size()==9 ; 
+      while (i<9 && ok) {
+       data[i] = list.at(i).toFloat(&ok) ;
+       ++i ;
+      }
+      if (ok) {
+       QMatrix3x3 matrix(data) ;
+       QMatrix3x3 result = matrix * standaloneCursor->transformationMatrix() ;
+       standaloneCursor->setTransformationMatrix(result) ;
+      } else {
+       qDebug() << "WARNING: invalid calibration matrix" << calibstr ;
+      }
+    }
+    if (!rotation.isEmpty()) {
+      QMatrix3x3 matrix = StandaloneCursorControl::orientationMatrix(rotation) ;
+      QMatrix3x3 result = matrix * standaloneCursor->transformationMatrix() ;
+      standaloneCursor->setTransformationMatrix(result) ;
+    }
+    if (absolute) demo->showCursor(false) ;
+
+  } else if (device=="stimtac200") {
+    stimtac200Cursor = new STIMTAC200CursorControl(demo, 0.0) ;
+    feedback = new Feedback(stimtac200Cursor->stimtac()) ;
+    demo->connect(stimtac200Cursor->stimtac(), 
+                 SIGNAL(touchEvent(STIMTAC_input_200::TouchEvent)), 
+                 demo->canvas(), 
+                 SLOT(touchEvent(STIMTAC_input_200::TouchEvent))) ;
+    if (!calibstr.isEmpty()) qDebug() 
+       << "WARNING: calibration matrix cannot be set for requested device:" 
+       << device ;
+    if (!rotation.isEmpty()) qDebug() 
+       << "WARNING: rotation cannot be set for requested device:" 
+       << device ;
+    if (absolute) qDebug() 
+       << "WARNING: absolute pointing not available for requested device:" 
+       << device ;
+
+  } else if (device=="stm32ts60") {
+    stm32ts60Cursor = new STM32TS60CursorControl(demo, 0.0) ;
+    feedback = new Feedback ;
+    if (!calibstr.isEmpty()) qDebug() 
+       << "WARNING: calibration matrix cannot be set for requested device:" 
+       << device ;
+    if (!rotation.isEmpty()) qDebug() 
+       << "WARNING: rotation cannot be set for requested device:" 
+       << device ;
+    if (absolute) qDebug() 
+       << "WARNING: absolute pointing not available for requested device:" 
+       << device ;
+  } else {
+    qDebug() << "ERROR! Device not recognized: " << device ;
+    return -1 ;
+  }
+  demo->setFeedback(feedback) ;
+  demo->showOverlay(showoverlay) ;
+  demo->showMenuBar(!hidemenubar) ;
+  if (!screenstr.isEmpty()) {
+    // Check fullscreen and screen selection
+    QDesktopWidget* desktop = app.desktop() ;
+    bool ok ;
+    int screennumber = screenstr.toInt(&ok) ;
+    if (ok && screennumber>=0 && screennumber<desktop->screenCount()) {
+      const QRect screen = desktop->screenGeometry(screennumber) ;
+      demo->move(screen.x(), screen.y()) ;
+    } else {
+      qDebug() << "Cannot select screen:" << screenstr ;
+    }
+  }
+  fullscreen ? demo->showFullScreen() : demo->show() ;
+  demo->raise() ;
+  // Run
+  int value = app.exec() ;
+  // Closing
+  if (stm32ts60Cursor) delete stm32ts60Cursor ;
+  if (standaloneCursor) delete standaloneCursor ;
+  if (stimtac200Cursor) delete stimtac200Cursor ;
+  delete feedback ;
+  delete demo ;
+  return value ;
+}
diff --git a/TactilePictures/tactilepictures.cpp b/TactilePictures/tactilepictures.cpp
new file mode 100644 (file)
index 0000000..3bb4f3f
--- /dev/null
@@ -0,0 +1,24 @@
+#include "tactilepictures.h"\r
+\r
+#include <QFileDialog>\r
+\r
+TactilePictures::TactilePictures(QWidget *parent, Qt::WFlags flags)\r
+: QMainWindow(parent, flags)\r
+{\r
+       setupUi(this);\r
+\r
+       _pictureview.setParent(_pictureframe);\r
+\r
+       connect(_load, SIGNAL(pressed()), this, SLOT(pressLoad()));\r
+}\r
+\r
+TactilePictures::~TactilePictures()\r
+{\r
+\r
+}\r
+\r
+void TactilePictures::pressLoad()\r
+{\r
+       QString fileName = QFileDialog::getOpenFileName(this, tr("Open Image"), ".", tr("Image Files (*.png *.jpg *.bmp)"));\r
+       _pictureview.setImage(fileName);\r
+}
\ No newline at end of file
diff --git a/TactilePictures/tactilepictures.h b/TactilePictures/tactilepictures.h
new file mode 100644 (file)
index 0000000..4e0f8ef
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef TACTILEPICTURES_H\r
+#define TACTILEPICTURES_H\r
+\r
+#include <QtGui/QMainWindow>\r
+#include "ui_tactilepictures.h"\r
+\r
+#include <TactonPlayer\TactonPlayer.hpp>\r
+\r
+#include "PictureView.h"\r
+\r
+\r
+class TactilePictures : public QMainWindow, public Ui::TactilePicturesClass\r
+{\r
+       Q_OBJECT\r
+\r
+       public:\r
+               TactilePictures(QWidget *parent = 0, Qt::WFlags flags = 0);\r
+               ~TactilePictures();\r
+\r
+       public slots:\r
+               void pressLoad();\r
+\r
+       private:\r
+               PictureView _pictureview;\r
+};\r
+\r
+#endif // TACTILEPICTURES_H\r
diff --git a/TactilePictures/tactilepictures.ui b/TactilePictures/tactilepictures.ui
new file mode 100644 (file)
index 0000000..ffbb963
--- /dev/null
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<ui version="4.0">\r
+ <class>TactilePicturesClass</class>\r
+ <widget class="QMainWindow" name="TactilePicturesClass">\r
+  <property name="geometry">\r
+   <rect>\r
+    <x>0</x>\r
+    <y>0</y>\r
+    <width>919</width>\r
+    <height>676</height>\r
+   </rect>\r
+  </property>\r
+  <property name="windowTitle">\r
+   <string>TactilePictures</string>\r
+  </property>\r
+  <widget class="QWidget" name="centralWidget">\r
+   <property name="layoutDirection">\r
+    <enum>Qt::LeftToRight</enum>\r
+   </property>\r
+   <layout class="QVBoxLayout">\r
+    <item>\r
+     <widget class="QWidget" name="_pictureframe" native="true">\r
+      <property name="sizePolicy">\r
+       <sizepolicy hsizetype="Expanding" vsizetype="Expanding">\r
+        <horstretch>0</horstretch>\r
+        <verstretch>0</verstretch>\r
+       </sizepolicy>\r
+      </property>\r
+      <layout class="QHBoxLayout" name="horizontalLayout_2"/>\r
+     </widget>\r
+    </item>\r
+    <item>\r
+     <layout class="QHBoxLayout" name="horizontalLayout">\r
+      <property name="sizeConstraint">\r
+       <enum>QLayout::SetMinimumSize</enum>\r
+      </property>\r
+      <item>\r
+       <spacer name="horizontalSpacer">\r
+        <property name="orientation">\r
+         <enum>Qt::Horizontal</enum>\r
+        </property>\r
+        <property name="sizeHint" stdset="0">\r
+         <size>\r
+          <width>40</width>\r
+          <height>20</height>\r
+         </size>\r
+        </property>\r
+       </spacer>\r
+      </item>\r
+      <item>\r
+       <widget class="QPushButton" name="_load">\r
+        <property name="text">\r
+         <string>Load</string>\r
+        </property>\r
+       </widget>\r
+      </item>\r
+      <item>\r
+       <widget class="QWidget" name="_sample" native="true">\r
+        <property name="minimumSize">\r
+         <size>\r
+          <width>20</width>\r
+          <height>20</height>\r
+         </size>\r
+        </property>\r
+       </widget>\r
+      </item>\r
+      <item>\r
+       <spacer name="horizontalSpacer_2">\r
+        <property name="orientation">\r
+         <enum>Qt::Horizontal</enum>\r
+        </property>\r
+        <property name="sizeHint" stdset="0">\r
+         <size>\r
+          <width>40</width>\r
+          <height>20</height>\r
+         </size>\r
+        </property>\r
+       </spacer>\r
+      </item>\r
+     </layout>\r
+    </item>\r
+   </layout>\r
+  </widget>\r
+ </widget>\r
+ <layoutdefault spacing="6" margin="11"/>\r
+ <resources>\r
+  <include location="tactilepictures.qrc"/>\r
+ </resources>\r
+ <connections/>\r
+</ui>\r
diff --git a/TouchscreenButton/TouchscreenButton.cpp b/TouchscreenButton/TouchscreenButton.cpp
new file mode 100644 (file)
index 0000000..5471467
--- /dev/null
@@ -0,0 +1,39 @@
+#include "TouchscreenButton.h"\r
+\r
+#include <QDebug>\r
+\r
+TouchscreenButton::TouchscreenButton(QWidget *parent, Qt::WFlags flags)\r
+: QMainWindow(parent, flags)\r
+{\r
+       setupUi(this);\r
+\r
+       try\r
+       {\r
+               _touchscreen = new USBHIDImmersionTouchscreen();\r
+               _wristband = new TactonPlayer("COM11");\r
+       }\r
+       catch(...)\r
+       {\r
+               qDebug() << "Cannot find the touchscreen or the wristband";\r
+       }\r
+\r
+       connect(_play, SIGNAL(pressed()), this, SLOT(play()));\r
+       connect(_stop, SIGNAL(pressed()), this, SLOT(stop()));\r
+}\r
+\r
+TouchscreenButton::~TouchscreenButton()\r
+{\r
+       if (_touchscreen)\r
+               delete _touchscreen;\r
+       hid_exit();\r
+}\r
+\r
+void TouchscreenButton::play()\r
+{\r
+       _touchscreen->playEffect((unsigned char)(_effect->value()), (unsigned char)(_repeats->value()));\r
+}\r
+\r
+void TouchscreenButton::stop()\r
+{\r
+       _touchscreen->playEffect(0, 1);\r
+}\r
diff --git a/TouchscreenButton/TouchscreenButton.h b/TouchscreenButton/TouchscreenButton.h
new file mode 100644 (file)
index 0000000..79fec7d
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef TOUCHSCREENBUTTON_H\r
+#define TOUCHSCREENBUTTON_H\r
+\r
+#include <QtGui/QMainWindow>\r
+#include "ui_touchscreenbutton.h"\r
+\r
+#include <ArduinoSerial\SerialWindows.hpp>\r
+#include "USBHIDImmersionTouchscreen.h"\r
+\r
+class TouchscreenButton : public QMainWindow, public Ui::TouchscreenButtonClass\r
+{\r
+       Q_OBJECT\r
+\r
+       public:\r
+               TouchscreenButton(QWidget *parent = 0, Qt::WFlags flags = 0);\r
+               ~TouchscreenButton();\r
+\r
+       public slots:\r
+               void play();\r
+               void stop();\r
+\r
+       private:\r
+               USBHIDImmersionTouchscreen *_touchscreen;\r
+               TactonPlayer *_wristband;\r
+};\r
+\r
+#endif // TOUCHSCREENBUTTON_H\r
diff --git a/TouchscreenButton/TouchscreenButton.vcxproj b/TouchscreenButton/TouchscreenButton.vcxproj
new file mode 100644 (file)
index 0000000..55d5fc0
--- /dev/null
@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <ItemGroup Label="ProjectConfigurations">\r
+    <ProjectConfiguration Include="Debug|Win32">\r
+      <Configuration>Debug</Configuration>\r
+      <Platform>Win32</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="Release|Win32">\r
+      <Configuration>Release</Configuration>\r
+      <Platform>Win32</Platform>\r
+    </ProjectConfiguration>\r
+  </ItemGroup>\r
+  <PropertyGroup Label="Globals">\r
+    <ProjectGuid>{3484A961-9B00-4197-85ED-99303909089C}</ProjectGuid>\r
+    <Keyword>Qt4VSv1.0</Keyword>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">\r
+    <ConfigurationType>Application</ConfigurationType>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">\r
+    <ConfigurationType>Application</ConfigurationType>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
+  <ImportGroup Label="ExtensionSettings">\r
+  </ImportGroup>\r
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <PropertyGroup Label="UserMacros" />\r
+  <PropertyGroup>\r
+    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\r
+    <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>\r
+    <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />\r
+    <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />\r
+    <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>\r
+    <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />\r
+    <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />\r
+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>\r
+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>\r
+  </PropertyGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
+    <ClCompile>\r
+      <PreprocessorDefinitions>UNICODE;WIN32;QT_LARGEFILE_SUPPORT;QT_DLL;QT_CORE_LIB;QT_GUI_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>ArduinoSerial;.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <Optimization>Disabled</Optimization>\r
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\r
+      <TreatWChar_tAsBuiltInType>false</TreatWChar_tAsBuiltInType>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Windows</SubSystem>\r
+      <OutputFile>$(OutDir)\$(ProjectName).exe</OutputFile>\r
+      <AdditionalLibraryDirectories>$(QTDIR)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <AdditionalDependencies>hidapid.lib;qtmaind.lib;QtCored4.lib;QtGuid4.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
+    <ClCompile>\r
+      <PreprocessorDefinitions>UNICODE;WIN32;QT_LARGEFILE_SUPPORT;QT_DLL;QT_NO_DEBUG;NDEBUG;QT_CORE_LIB;QT_GUI_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>ArduinoSerial;.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <DebugInformationFormat>\r
+      </DebugInformationFormat>\r
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\r
+      <TreatWChar_tAsBuiltInType>false</TreatWChar_tAsBuiltInType>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Windows</SubSystem>\r
+      <OutputFile>$(OutDir)\$(ProjectName).exe</OutputFile>\r
+      <AdditionalLibraryDirectories>$(QTDIR)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
+      <GenerateDebugInformation>false</GenerateDebugInformation>\r
+      <AdditionalDependencies>hidapi.lib;qtmain.lib;QtCore4.lib;QtGui4.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemGroup>\r
+    <ClCompile Include="GeneratedFiles\Debug\moc_TouchscreenButton.cpp">\r
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>\r
+    </ClCompile>\r
+    <ClCompile Include="GeneratedFiles\qrc_touchscreenbutton.cpp">\r
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
+      </PrecompiledHeader>\r
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
+      </PrecompiledHeader>\r
+    </ClCompile>\r
+    <ClCompile Include="GeneratedFiles\Release\moc_TouchscreenButton.cpp">\r
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>\r
+    </ClCompile>\r
+    <ClCompile Include="main.cpp" />\r
+    <ClCompile Include="TouchscreenButton.cpp" />\r
+    <ClCompile Include="USBHIDImmersionTouchscreen.cpp" />\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <CustomBuild Include="TouchscreenButton.h">\r
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>\r
+      <Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Moc%27ing TouchscreenButton.h...</Message>\r
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>\r
+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe"  "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp"  -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_CORE_LIB -DQT_GUI_LIB  "-I.\ArduinoSerial" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui"</Command>\r
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>\r
+      <Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Moc%27ing TouchscreenButton.h...</Message>\r
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>\r
+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe"  "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp"  -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB  "-I.\ArduinoSerial" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui"</Command>\r
+    </CustomBuild>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <CustomBuild Include="touchscreenbutton.ui">\r
+      <FileType>Document</FileType>\r
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>\r
+      <Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Uic%27ing %(Identity)...</Message>\r
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\ui_%(Filename).h;%(Outputs)</Outputs>\r
+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\uic.exe" -o ".\GeneratedFiles\ui_%(Filename).h" "%(FullPath)"</Command>\r
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>\r
+      <Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Uic%27ing %(Identity)...</Message>\r
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\ui_%(Filename).h;%(Outputs)</Outputs>\r
+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\uic.exe" -o ".\GeneratedFiles\ui_%(Filename).h" "%(FullPath)"</Command>\r
+    </CustomBuild>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClInclude Include="GeneratedFiles\ui_touchscreenbutton.h" />\r
+    <CustomBuild Include="USBHIDImmersionTouchscreen.h">\r
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalInputs)</AdditionalInputs>\r
+      <Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
+      </Message>\r
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
+      </Outputs>\r
+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
+      </Command>\r
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalInputs)</AdditionalInputs>\r
+      <Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
+      </Message>\r
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
+      </Outputs>\r
+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
+      </Command>\r
+    </CustomBuild>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <CustomBuild Include="touchscreenbutton.qrc">\r
+      <FileType>Document</FileType>\r
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(FullPath);%(AdditionalInputs)</AdditionalInputs>\r
+      <Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Rcc%27ing %(Identity)...</Message>\r
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\qrc_%(Filename).cpp;%(Outputs)</Outputs>\r
+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\rcc.exe" -name "%(Filename)" -no-compress "%(FullPath)" -o .\GeneratedFiles\qrc_%(Filename).cpp</Command>\r
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(FullPath);%(AdditionalInputs)</AdditionalInputs>\r
+      <Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Rcc%27ing %(Identity)...</Message>\r
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\qrc_%(Filename).cpp;%(Outputs)</Outputs>\r
+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\rcc.exe" -name "%(Filename)" -no-compress "%(FullPath)" -o .\GeneratedFiles\qrc_%(Filename).cpp</Command>\r
+    </CustomBuild>\r
+  </ItemGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
+  <ImportGroup Label="ExtensionTargets">\r
+  </ImportGroup>\r
+  <ProjectExtensions>\r
+    <VisualStudio>\r
+      <UserProperties UicDir=".\GeneratedFiles" MocDir=".\GeneratedFiles\$(ConfigurationName)" MocOptions="" RccDir=".\GeneratedFiles" lupdateOnBuild="0" lupdateOptions="" lreleaseOptions="" QtVersion_x0020_Win32="4.8.2" />\r
+    </VisualStudio>\r
+  </ProjectExtensions>\r
+</Project>
\ No newline at end of file
diff --git a/TouchscreenButton/USBHIDImmersionTouchscreen.cpp b/TouchscreenButton/USBHIDImmersionTouchscreen.cpp
new file mode 100644 (file)
index 0000000..75d2aa4
--- /dev/null
@@ -0,0 +1,48 @@
+#include "USBHIDImmersionTouchscreen.h"\r
+\r
+\r
+// Vendir ID and Product ID (see lsusb)\r
+int USBHIDImmersionTouchscreen::VID = 0x0563;\r
+int USBHIDImmersionTouchscreen::PID = 0x0423;\r
+\r
+#define TIMEOUT 100\r
+\r
+#define PLAYEFFECTREPREAT_BYTE 90\r
+#define SETNONVOLATILEEFFECTS_BYTE 88\r
+#define STATUS_BYTE 96\r
+#define STRING_BYTE 2\r
+\r
+hid_device *USBHIDImmersionTouchscreen::_devicehandle = NULL;\r
+\r
+USBHIDImmersionTouchscreen::USBHIDImmersionTouchscreen(void)\r
+{\r
+       if ((_devicehandle = hid_open(VID, PID, NULL)) == NULL)\r
+               throw "Cannot claim the device";\r
+}\r
+\r
+\r
+USBHIDImmersionTouchscreen::~USBHIDImmersionTouchscreen(void)\r
+{\r
+       if (_devicehandle)\r
+       {\r
+               hid_close(_devicehandle);\r
+               _devicehandle = NULL;\r
+       }\r
+}\r
+\r
+bool USBHIDImmersionTouchscreen::playEffect(unsigned char effect, unsigned char nbrepeat) const\r
+{\r
+       unsigned char buffer[35];\r
+       buffer[0] = PLAYEFFECTREPREAT_BYTE;\r
+       buffer[1] = effect;\r
+       buffer[2] = nbrepeat;\r
+       if (_devicehandle)\r
+               return hid_write(_devicehandle, buffer, 35);\r
+       else\r
+               return -1;\r
+}\r
+\r
+char * USBHIDImmersionTouchscreen::getStatus() const\r
+{\r
+       return NULL;\r
+}\r
diff --git a/TouchscreenButton/USBHIDImmersionTouchscreen.h b/TouchscreenButton/USBHIDImmersionTouchscreen.h
new file mode 100644 (file)
index 0000000..f40bb6a
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef __USBHIDINNERSIONTOUCHSCREEN__\r
+#define __USBHIDINNERSIONTOUCHSCREEN__\r
+\r
+#include <hidapi.h>\r
+\r
+class USBHIDImmersionTouchscreen\r
+{\r
+       public:\r
+               USBHIDImmersionTouchscreen(void);\r
+               ~USBHIDImmersionTouchscreen(void);\r
+\r
+               /*\r
+                       See documentation for list of effects (0-46), 255 for no effect\r
+                       nbrepeats: 255 for infinite until other effect or no effect\r
+               */\r
+               bool playEffect(unsigned char effect, unsigned char nbrepeat) const;\r
+               char *getStatus() const;\r
+               //bool setNonVolatileEffects() const;\r
+\r
+       private:\r
+               // Vendor ID and Product ID\r
+               static int VID;\r
+               static int PID;\r
+               //handle on the device\r
+               static hid_device *_devicehandle;\r
+};\r
+\r
+#endif\r
+\r
diff --git a/TouchscreenButton/Wristband.cpp b/TouchscreenButton/Wristband.cpp
new file mode 100644 (file)
index 0000000..8e7af34
--- /dev/null
@@ -0,0 +1,37 @@
+#include "Wristband.h"\r
+\r
+#include <QDebug>\r
+\r
+Wristband::Wristband()\r
+{\r
+       try\r
+       {\r
+               _tactonplayer = new TactonPlayer("COM11");\r
+       }\r
+       catch(...)\r
+       {\r
+               qDebug() << "Cannot find the touchscreen or the wristband";\r
+               _tactonplayer = NULL;\r
+       }\r
+\r
+}\r
+\r
+\r
+Wristband::~Wristband()\r
+{\r
+       if (_tactonplayer)\r
+               delete _tactonplayer;\r
+}\r
+\r
+bool Wristband::playEffect(unsigned char effect, unsigned char nbrepeat) const\r
+{\r
+       for (int i = 0 ; i < nbrepeat ; i++)\r
+       {\r
+               _tactonplayer->play(_effects[effect]);\r
+               ///TODO: add a pause\r
+       }\r
+}\r
+\r
+char *Wristband::getStatus() const\r
+{\r
+}\r
diff --git a/TouchscreenButton/Wristband.h b/TouchscreenButton/Wristband.h
new file mode 100644 (file)
index 0000000..aa6f0ce
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef __WRISTBAND__\r
+#define __WRISTBAND__\r
+\r
+#include <TactonPlayer\TactonPlayer.hpp>\r
+\r
+class Wristband :\r
+       public TactonPlayer\r
+{\r
+       public:\r
+               Wristband(void);\r
+               ~Wristband(void);\r
+\r
+               /*\r
+                       Mimics Immersion touchscreen effects (0-46), 255 for no effect\r
+                       nbrepeats: 255 for infinite until other effect or no effect\r
+               */\r
+               bool playEffect(unsigned char effect, unsigned char nbrepeat) const;\r
+               char *getStatus() const;\r
+\r
+       private:\r
+               TactonPlayer *_tactonplayer;\r
+               Tacton _effects[46];\r
+};\r
+\r
+#endif\r
diff --git a/TouchscreenButton/main.cpp b/TouchscreenButton/main.cpp
new file mode 100644 (file)
index 0000000..fcc30a6
--- /dev/null
@@ -0,0 +1,10 @@
+#include "TouchscreenButton.h"\r
+#include <QtGui/QApplication>\r
+\r
+int main(int argc, char *argv[])\r
+{\r
+       QApplication a(argc, argv);\r
+       TouchscreenButton w;\r
+       w.show();\r
+       return a.exec();\r
+}\r
diff --git a/TouchscreenButton/touchscreenbutton.ui b/TouchscreenButton/touchscreenbutton.ui
new file mode 100644 (file)
index 0000000..7dfcac8
--- /dev/null
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<ui version="4.0">\r
+ <class>TouchscreenButtonClass</class>\r
+ <widget class="QMainWindow" name="TouchscreenButtonClass">\r
+  <property name="geometry">\r
+   <rect>\r
+    <x>0</x>\r
+    <y>0</y>\r
+    <width>345</width>\r
+    <height>191</height>\r
+   </rect>\r
+  </property>\r
+  <property name="windowTitle">\r
+   <string>TouchscreenButton</string>\r
+  </property>\r
+  <widget class="QWidget" name="centralWidget">\r
+   <layout class="QVBoxLayout" name="verticalLayout">\r
+    <item>\r
+     <layout class="QGridLayout" name="gridLayout">\r
+      <item row="0" column="1">\r
+       <widget class="QSpinBox" name="_effect">\r
+        <property name="maximum">\r
+         <number>46</number>\r
+        </property>\r
+       </widget>\r
+      </item>\r
+      <item row="0" column="0">\r
+       <widget class="QLabel" name="label">\r
+        <property name="text">\r
+         <string>Effect:</string>\r
+        </property>\r
+       </widget>\r
+      </item>\r
+      <item row="1" column="1">\r
+       <widget class="QSpinBox" name="_repeats">\r
+        <property name="maximum">\r
+         <number>254</number>\r
+        </property>\r
+        <property name="value">\r
+         <number>1</number>\r
+        </property>\r
+       </widget>\r
+      </item>\r
+      <item row="1" column="0">\r
+       <widget class="QLabel" name="label_2">\r
+        <property name="text">\r
+         <string>Repeats</string>\r
+        </property>\r
+       </widget>\r
+      </item>\r
+     </layout>\r
+    </item>\r
+    <item>\r
+     <widget class="QPushButton" name="_play">\r
+      <property name="font">\r
+       <font>\r
+        <pointsize>20</pointsize>\r
+       </font>\r
+      </property>\r
+      <property name="text">\r
+       <string>Play</string>\r
+      </property>\r
+     </widget>\r
+    </item>\r
+    <item>\r
+     <widget class="QPushButton" name="_stop">\r
+      <property name="font">\r
+       <font>\r
+        <pointsize>20</pointsize>\r
+       </font>\r
+      </property>\r
+      <property name="text">\r
+       <string>Stop</string>\r
+      </property>\r
+     </widget>\r
+    </item>\r
+   </layout>\r
+  </widget>\r
+ </widget>\r
+ <layoutdefault spacing="6" margin="11"/>\r
+ <resources>\r
+  <include location="touchscreenbutton.qrc"/>\r
+ </resources>\r
+ <connections/>\r
+</ui>\r