Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

Contacts

Contacts

A contact is a single contiguous surface image (typically fingers) which contains all the relevant position, velocity, and proximity/pseudo-pressure data. After one debouncing the contact is assigned a path_id which is constant across all consecutive frames where the contact is touching the surface. Also the device takes a best guess at which finger the contact is (finger_id). This guess may change as more contacts touch the surface.

See FWHID_Contact.h for struture and function references pertaining to Contacts.

Contacts Example Code

The following Windows example code draws the contacts on the screen using FWHID_Contact::xpos, FWHID_Contact::ypos, FWHID_Contact::proximity, FWHID_Contact::eccentricity, FWHID_Contact::orientation, and FWHID_Contact::finger_id to modify the shape and color of the drawing. It also uses FWHID_getSurfaceDimensions() to scale the coordinates to the screen.

To build the code you need to include the additional following libraries when linking: opengl32.lib and glu32.lib (see also Setting up the Compile and Linking Environment). The following code can be found at sdk_path\FWHID_HandTracking\examples\contacts\contact_example.cpp.

For a Mac example see sdk path\FWHID_HandTracking\examples\ContactPaths.xcode

/**********************************************************************
* A Program that visually illustrates the Contact information from
* the FW Hand Tracking SDK
*
* To compile this code you must include the following libraries:
* fwtrack.lib, setupapi.lib, hid.lib, opengl32.lib, glu32.lib
*
* Press 'q' to quit
*
* File: contact_example.cpp
* Author: James Orr
* Created: Mon. Aug. 23, 2004
* Last Modified: Tues. Aug. 31, 2004
*
***********************************************************************/
/*
 *  Copyright (c) 2004 FingerWorks, Inc. All rights reserved.
 *
This FingerWorks software is supplied to you by FingerWorks, Inc.
("FingerWorks") in consideration of your agreement to the following terms, and your
use, installation, or modification of this FingerWorks software
constitutes acceptance of these terms.  If you do not agree with these terms,
please do not use, install or modify this FingerWorks software.

In consideration of your agreement to abide by the following terms, and subject
to these terms, FingerWorks grants you a personal, non-exclusive license, under FingerWorks's
copyrights in this original FingerWorks software (the "FingerWorks Software"), to use,
reproduce, and modify the FingerWorks Software for personal, academic, research, or artistic purposes.

You may NOT distribute this FingerWorks Software, with or without modifications,
in either source or binary form.

Neither the name, trademarks, service marks or logos of
FingerWorks, Inc. may be used to endorse or promote products derived from the
FingerWorks Software without specific prior written permission from FingerWorks.  Except as
expressly stated in this notice, no other rights or licenses, express or implied,
are granted by FingerWorks herein, including but not limited to any patent rights that
may be infringed by your derivative works or by other works in which the FingerWorks
Software may be incorporated.

Disclaimer:             The FingerWorks Software is provided by FingerWorks on an "AS IS" basis.
                                FINGERWORKS MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT
                                LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY
                                AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE FINGERWORKS SOFTWARE
                                OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.

                                IN NO EVENT SHALL FINGERWORKS BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
                                CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
                                GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                                ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
                                OF THE FINGERWORKS SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
                                (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF FINGERWORKS HAS BEEN
                                ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */
#include <Windows.h>

#include "FWHID_MultiTouchDevice.h"

#include <gl/gl.h>
#include <gl/glu.h>

//Constants
#define kSCREEN_WIDTH 1024
#define kSCREEN_HEIGHT 768
#define kREFRESH_RATE 75
#define kMAX_DEVICES 3
#define kCIRCLE_SIZE .05

//Globals
HGLRC gHrc = NULL;  //Window Rendering Context
HDC gHdc;  // A global handle to the device context
bool gQuit = false;
float gFingerColors[kFWHID_MAX_CONTACTS_PER_HAND][3];

//Globals specific to the SDK
FWMultiTouchDevicePtr gDevices[kMAX_DEVICES];
int gTotalDevices=0;
FWHID_ContactFrame gDeviceFrames[kMAX_DEVICES];


//Prototypes
void glInit(void);
void MyPaint(void);
void SetupPixelFormat(HDC hdc);
void initializeColorLUT();
void drawContact(FWHID_ContactPtr pContact, FWSurfaceRectanglePtr surface_dim);

//Callback prototypes
void DeviceCreationCallback(FWMultiTouchDevicePtr fwdevice, void *targetData);
void DeviceDisposalCallback(FWMultiTouchDevicePtr fwdevice, void *targetData);
void DeviceFrameCompleteCallback(FWMultiTouchDevicePtr fwdevice, void *targetData);


//The Device Creation Callback is called for every FW device found in the system
void DeviceCreationCallback(FWMultiTouchDevicePtr fwdevice, void *targetData){
        if(gTotalDevices < kMAX_DEVICES){
                FWHID_enableStreams(fwdevice,kFW_ContactPathStream);            
                gDevices[gTotalDevices] = fwdevice;
                FWHID_setContactFrameCallback(gDevices[gTotalDevices],DeviceFrameCompleteCallback);
                gTotalDevices++;
        }
}

//This is called after every frame
void DeviceFrameCompleteCallback(FWMultiTouchDevicePtr fwdevice, void *targetData){
        //Find which MultiTouch device this is
        int i=0;
        while(fwdevice != gDevices[i] && i < gTotalDevices) i++;

        if(i == gTotalDevices) return; //Device not found in tracking list

        FWHID_getContactFrame(gDevices[i],&gDeviceFrames[i]);
}

//Called everytime a FW device is removed.
//Note: If a device is plugged in all devices are removed and then rediscovered
void DeviceDisposalCallback(FWMultiTouchDevicePtr fwdevice, void *targetData){
        int i=0;
        while(fwdevice != gDevices[i] && i < gTotalDevices) i++;

        if(i == gTotalDevices) return; //device removed was not found in devices I am keeping track of

        FWHID_disableStreams(fwdevice,kFW_ContactPathStream);
        
        if(i+1 < kMAX_DEVICES) memmove(&gDevices[i],&gDevices[i+1],sizeof(FWMultiTouchDevicePtr)*(gTotalDevices-i+1));

        gTotalDevices--;
}

//This function draws the contacts onto the screen
void MyPaint(void){
        int i,k;
        glClear(GL_COLOR_BUFFER_BIT);

        //Enumerates throught the device list and then enumerates through the valid contacts
        for(i=0;i<gTotalDevices;i++){
                FWSurfaceRectangle dim = FWHID_getSurfaceDimensions(gDevices[i]);
                for(k=0;k < gDeviceFrames[i].contact_count;k++){
                        if(gDeviceFrames[i].contacts[k].identity_active) drawContact(&gDeviceFrames[i].contacts[k],&dim);
                }
        }

        glFlush();
        SwapBuffers(gHdc);
}

// Window procedure - the message handler
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
        HDC         hdc = NULL;
        PAINTSTRUCT ps;


        switch (msg) {
                case WM_CREATE:
                        // Get a handle to the device context
                        hdc = BeginPaint(hwnd, &ps);
                        gHdc = hdc;
                        // Setup pixel format for the device context
                        SetupPixelFormat(hdc);
                        // Create a rendering context associated to the device context
                        gHrc = wglCreateContext(hdc);
                        // Make the rendering context current
                        wglMakeCurrent(hdc, gHrc);
                        //return 0;
                        break;
                case WM_CLOSE:
                        // De-select the rendering context
                        wglMakeCurrent(hdc, NULL);
                        // Release the rendering context
                        wglDeleteContext(gHrc);
                        // Release the device context
                        EndPaint(hwnd, &ps);
                        break;
                case WM_TIMER:
                        MyPaint();
                        break;
                case WM_SETFOCUS:
                        SetTimer(hwnd,             // handle to main window
                                0,            // timer identifier
                                33,                 // 33-msecond interval
                                (TIMERPROC) NULL);     // no timer callback

                        break;
                case WM_KILLFOCUS:
                        KillTimer(hwnd,0);
                        break;
                case WM_CHAR:
                        switch (wParam) {
                                case 'q':
                                case 'Q':
                                        gQuit =true;
                                        break;
                        }
                        break;
        }

        //This is required for the FW Hand Tracking SDK
        if(FWHID_WndProc(hwnd, msg, wParam,lParam)) return TRUE;
        return DefWindowProc(hwnd, msg, wParam, lParam);

}

// WinMain function - the entry point
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int iCmdShow) {
        HWND     hwnd;
        MSG      msg;
        WNDCLASS wndclass;
        int i;


        // Specify a window class
        wndclass.style         = 0;
        wndclass.lpfnWndProc   = WndProc;
        wndclass.cbClsExtra    = 0;
        wndclass.cbWndExtra    = 0;
        wndclass.hInstance     = hInstance;
        wndclass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
        wndclass.hCursor       = LoadCursor(NULL, IDC_ARROW);
        wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
        wndclass.lpszMenuName  = NULL;
        wndclass.lpszClassName = "VisualContact";

        // Register the window class
        RegisterClass(&wndclass);

        DEVMODE screenSettings;
        // Specify values for relevant data fields
        screenSettings.dmPelsWidth  = kSCREEN_WIDTH;
        screenSettings.dmPelsHeight = kSCREEN_HEIGHT;
        screenSettings.dmBitsPerPel = 32;
        screenSettings.dmDisplayFrequency = kREFRESH_RATE;
        // Indicate which fields are manually initialized
        screenSettings.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY;
        // Apply changes
        if(ChangeDisplaySettings(&screenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL){
                screenSettings.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
                ChangeDisplaySettings(&screenSettings, CDS_FULLSCREEN);
        }
        ShowCursor(false);//Hide the Cursor
        // Create a window based on the window class
        hwnd = CreateWindow("VisualContact", "FW VisualContact", WS_POPUP,
                0, 0, kSCREEN_WIDTH, kSCREEN_HEIGHT, NULL, NULL, hInstance, NULL);

        // Display the window on the screen
        ShowWindow(hwnd, iCmdShow);
        UpdateWindow(hwnd);


        glInit();

        initializeColorLUT();


        //Initialize FingerWorks Handtracking SDK
        FWHID_setDeviceCreationCallback(DeviceCreationCallback);
        FWHID_setDeviceDisposalCallback(DeviceDisposalCallback);
        FWHID_registerMultiTouchDevices(hwnd);


        while (!gQuit) {
                GetMessage (&msg, NULL, 0, 0);
                TranslateMessage (&msg);
                DispatchMessage (&msg);
        }

        FWHID_releaseMultiTouchDevices();

        return (int)msg.wParam;
}

void glInit(){
        glClearColor(1, 1, 1, 0.0);      // White Background
        glEnable(GL_NORMALIZE);


        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 100.0);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

}

void SetupPixelFormat(HDC hdc)
{
        static PIXELFORMATDESCRIPTOR pfd = {
                sizeof(PIXELFORMATDESCRIPTOR), 1,
                        //PFD_DRAW_TO_WINDOW |
                        PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
                        PFD_TYPE_RGBA, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                        16, 0, 0, PFD_MAIN_PLANE, 0, 0, 0, 0
        };

        int index = ChoosePixelFormat(hdc, &pfd);
        SetPixelFormat(hdc, index, &pfd);
}

//Initializes the Color Look Up Table
void initializeColorLUT(){
        int i;
        for(i=0; i < kFWHID_MAX_CONTACTS_PER_HAND; i++){
                gFingerColors[i][0] = ((float)i+1.0)/((float)kFWHID_MAX_CONTACTS_PER_HAND+1.0);
                gFingerColors[i][1] = gFingerColors[i][0];
                gFingerColors[i][2] = 1;
        }

        //red
        gFingerColors[kFWHIDthumb][0] = 1;
        gFingerColors[kFWHIDthumb][2] = 0;
        //green
        gFingerColors[kFWHIDindex][1] = 1;
        gFingerColors[kFWHIDindex][2] = 0;
        //yellow
        gFingerColors[kFWHIDring][1] = 1;
        gFingerColors[kFWHIDring][0] = 1;
        gFingerColors[kFWHIDring][2] = 0;
        //pink
        gFingerColors[kFWHIDmiddle][0] = 1;
        //cyan
        gFingerColors[kFWHIDpinky][1] = 1;

}

//Draws a contact on the screen using the xpos,ypos, eccentricity, orientation, and proximity data
void drawContact(FWHID_ContactPtr pContact,FWSurfaceRectanglePtr surface_dim){
    static bool init = true;
    static GLUquadricObj *quad;
    if (init) {
        init = false;
        quad = gluNewQuadric();

    }

    glColor3fv(gFingerColors[pContact->finger_id]);
    glPushMatrix();
    glLoadIdentity();
    glTranslatef((float)(pContact->xpos - surface_dim->left_edge) / (float)surface_dim->width_cm*2.0-1.0,(float)(pContact->ypos - surface_dim->bottom_edge) / (float)surface_dim->height_cm*2.0-1.0,0);
    glRotatef(pContact->orientation-90,0,0,1); //Subtract 90 b/c the nominal value is 90
    glScalef(pContact->proximity,pContact->eccentricity*pContact->proximity,1);
    gluDisk(quad,0,kCIRCLE_SIZE,100,1);
    glPopMatrix();
}

Previous: Device and Stream Setup Next: Paths Up to FingerWorks Hand Tracking SDK


Generated on Fri Dec 10 10:08:12 2004 for FingerWorks Hand Tracking SDK by doxygen 1.3.8