[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [38497] branches/merwin-spacenav/intern/ ghost/intern: consistent Starting/InProgress/ Finishing ndof events with dead-zone filtering

Mike Erwin significant.bit at gmail.com
Tue Jul 19 00:42:09 CEST 2011


Revision: 38497
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=38497
Author:   merwin
Date:     2011-07-18 22:42:09 +0000 (Mon, 18 Jul 2011)
Log Message:
-----------
consistent Starting/InProgress/Finishing ndof events with dead-zone filtering

Modified Paths:
--------------
    branches/merwin-spacenav/intern/ghost/intern/GHOST_NDOFManager.cpp
    branches/merwin-spacenav/intern/ghost/intern/GHOST_NDOFManager.h
    branches/merwin-spacenav/intern/ghost/intern/GHOST_NDOFManagerX11.cpp
    branches/merwin-spacenav/intern/ghost/intern/GHOST_SystemX11.cpp

Modified: branches/merwin-spacenav/intern/ghost/intern/GHOST_NDOFManager.cpp
===================================================================
--- branches/merwin-spacenav/intern/ghost/intern/GHOST_NDOFManager.cpp	2011-07-18 22:37:48 UTC (rev 38496)
+++ branches/merwin-spacenav/intern/ghost/intern/GHOST_NDOFManager.cpp	2011-07-18 22:42:09 UTC (rev 38497)
@@ -149,6 +149,7 @@
 	, m_prevMotionTime(0)
 	, m_motionState(GHOST_kNotStarted)
 	, m_motionEventPending(false)
+	, m_deadZone(0.f)
 	{
 	// to avoid the rare situation where one triple is updated and
 	// the other is not, initialize them both here:
@@ -201,7 +202,7 @@
 				}
 			break;
 		default:
-			printf("ndof: unknown vendor %04hx\n", vendor_id);
+			printf("ndof: unknown device %04hx:%04hx\n", vendor_id, product_id);
 		}
 
 	m_buttonMask = ~(-1 << m_buttonCount);
@@ -211,41 +212,18 @@
 	#endif
 	}
 
-void GHOST_NDOFManager::updateMotionState()
-	{
-	if (m_motionEventPending)
-		return;
-
-	switch (m_motionState)
-		{
-		case GHOST_kFinished:
-		case GHOST_kNotStarted:
-			m_motionState = GHOST_kStarting;
-			break;
-		case GHOST_kStarting:
-			m_motionState = GHOST_kInProgress;
-			break;		
-		default:
-			// InProgress remains InProgress
-			// should never be Finishing
-			break;
-		}
-
-	m_motionEventPending = true;
-	}
-
 void GHOST_NDOFManager::updateTranslation(short t[3], GHOST_TUns64 time)
 	{
 	memcpy(m_translation, t, sizeof(m_translation));
 	m_motionTime = time;
-	updateMotionState();
+	m_motionEventPending = true;
 	}
 
 void GHOST_NDOFManager::updateRotation(short r[3], GHOST_TUns64 time)
 	{
 	memcpy(m_rotation, r, sizeof(m_rotation));
 	m_motionTime = time;
-	updateMotionState();
+	m_motionEventPending = true;
 	}
 
 void GHOST_NDOFManager::sendButtonEvent(NDOF_ButtonT button, bool press, GHOST_TUns64 time, GHOST_IWindow* window)
@@ -338,6 +316,20 @@
 		}
 	}
 
+void GHOST_NDOFManager::setDeadZone(float dz)
+	{
+	if (dz < 0.f)
+		// negative values don't make sense, so clamp at zero
+		dz = 0.f;
+	else if (dz > 0.5f)
+		// warn the rogue user/programmer, but allow it
+		printf("ndof: dead zone of %.2f is rather high...\n", dz);
+
+	m_deadZone = dz;
+
+	printf("ndof: dead zone set to %.2f\n", dz);
+	}
+
 static bool atHomePosition(GHOST_TEventNDOFMotionData* ndof)
 	{
 	#define HOME(foo) (ndof->foo == 0)
@@ -346,16 +338,25 @@
 
 static bool nearHomePosition(GHOST_TEventNDOFMotionData* ndof, float threshold)
 	{
-	#define HOME1(foo) (fabsf(ndof->foo) < threshold)
-	return HOME1(tx) && HOME1(ty) && HOME1(tz) && HOME1(rx) && HOME1(ry) && HOME1(rz);
+	if (threshold == 0.f)
+		return atHomePosition(ndof);
+	else
+		{
+		#define HOME1(foo) (fabsf(ndof->foo) < threshold)
+		return HOME1(tx) && HOME1(ty) && HOME1(tz) && HOME1(rx) && HOME1(ry) && HOME1(rz);
+		}
 	}
 
 bool GHOST_NDOFManager::sendMotionEvent()
 	{
-	if (m_motionState == GHOST_kFinished || m_motionState == GHOST_kNotStarted)
+	if (!m_motionEventPending)
 		return false;
 
+	m_motionEventPending = false; // any pending motion is handled right now
+
 	GHOST_IWindow* window = m_system.getWindowManager()->getActiveWindow();
+	if (window == NULL)
+		return false; // delivery will fail, so don't bother sending
 
 	GHOST_EventNDOFMotion* event = new GHOST_EventNDOFMotion(m_motionTime, window);
 	GHOST_TEventNDOFMotionData* data = (GHOST_TEventNDOFMotionData*) event->getData();
@@ -363,7 +364,7 @@
 	const float scale = 1.f / 350.f; // 3Dconnexion devices send +/- 350 usually
 
 	// probable future enhancement
-	// scale *= m_sensitivity;
+	// scale *= U.ndof_sensitivity;
 
 	data->tx = scale * m_translation[0];
 	data->ty = scale * m_translation[1];
@@ -373,35 +374,57 @@
 	data->ry = scale * m_rotation[1];
 	data->rz = scale * m_rotation[2];
 
-	if (m_motionState == GHOST_kStarting)
-		// prev motion time will be ancient, so just make up something reasonable
-		data->dt = 0.0125f;
-	else
-		data->dt = 0.001f * (m_motionTime - m_prevMotionTime); // in seconds
+	data->dt = 0.001f * (m_motionTime - m_prevMotionTime); // in seconds
 
-	m_prevMotionTime = m_motionTime;
+	bool handMotion = !nearHomePosition(data, m_deadZone);
 
-	// 'at rest' test goes at the end so that the first 'rest' event gets sent
-	if (atHomePosition(data))
-//	if (nearHomePosition(data, 0.05f)) // Linux & Windows have trouble w/ calibration
+	// determine what kind of motion event to send (Starting, InProgress, Finishing)
+	// and where that leaves this NDOF manager (NotStarted, InProgress, Finished)
+	switch (m_motionState)
 		{
-		data->progress = GHOST_kFinishing;
-		// for internal state, skip Finishing & jump to Finished
-		m_motionState = GHOST_kFinished;
+		case GHOST_kNotStarted:
+		case GHOST_kFinished:
+			if (handMotion)
+				{
+				data->progress = GHOST_kStarting;
+				m_motionState = GHOST_kInProgress;
+				// prev motion time will be ancient, so just make up something reasonable
+				data->dt = 0.0125f;
+				}
+			else
+				{
+				// send no event and keep current state
+				delete event;
+				return false;
+				}
+			break;
+		case GHOST_kInProgress:
+			if (handMotion)
+				{
+				data->progress = GHOST_kInProgress;
+				// keep InProgress state
+				}
+			else
+				{
+				data->progress = GHOST_kFinishing;
+				m_motionState = GHOST_kFinished;
+				}
+			break;
 		}
-	else
-		data->progress = m_motionState; // Starting or InProgress
 
 	#ifdef DEBUG_NDOF_MOTION
-	printf("ndof %s: T=(%.2f,%.2f,%.2f) R=(%.2f,%.2f,%.2f) dt=%.3f\n",
-		progress_string[data->progress],
+	printf("ndof motion sent -- %s\n", progress_string[data->progress]);
+
+	// show details about this motion event
+	printf("    T=(%.2f,%.2f,%.2f) R=(%.2f,%.2f,%.2f) dt=%.3f\n",
 		data->tx, data->ty, data->tz,
 		data->rx, data->ry, data->rz,
 		data->dt);
 	#endif
 
 	m_system.pushEvent(event);
-	m_motionEventPending = false;
 
+	m_prevMotionTime = m_motionTime;
+
 	return true;
 	}

Modified: branches/merwin-spacenav/intern/ghost/intern/GHOST_NDOFManager.h
===================================================================
--- branches/merwin-spacenav/intern/ghost/intern/GHOST_NDOFManager.h	2011-07-18 22:37:48 UTC (rev 38496)
+++ branches/merwin-spacenav/intern/ghost/intern/GHOST_NDOFManager.h	2011-07-18 22:42:09 UTC (rev 38497)
@@ -30,7 +30,12 @@
 // #define DEBUG_NDOF_MOTION
 #define DEBUG_NDOF_BUTTONS
 
-typedef enum { NDOF_UnknownDevice, NDOF_SpaceNavigator, NDOF_SpaceExplorer, NDOF_SpacePilotPro } NDOF_DeviceT;
+typedef enum {
+	NDOF_UnknownDevice, // <-- motion will work fine, buttons are ignored
+	NDOF_SpaceNavigator,
+	NDOF_SpaceExplorer,
+	NDOF_SpacePilotPro
+	} NDOF_DeviceT;
 
 // NDOF device button event types
 typedef enum {
@@ -50,6 +55,7 @@
 	NDOF_BUTTON_ISO1,
 	NDOF_BUTTON_ISO2,
 	// 90 degree rotations
+	// these don't all correspond to physical buttons
 	NDOF_BUTTON_ROLL_CW,
 	NDOF_BUTTON_ROLL_CCW,
 	NDOF_BUTTON_SPIN_CW,
@@ -63,6 +69,7 @@
 	NDOF_BUTTON_PLUS,
 	NDOF_BUTTON_MINUS,
 	// general-purpose buttons
+	// TODO: expose these to keymap editor so users can assign functions
 	NDOF_BUTTON_1,
 	NDOF_BUTTON_2,
 	NDOF_BUTTON_3,
@@ -90,6 +97,12 @@
 	// use standard USB/HID identifiers
 	void setDevice(unsigned short vendor_id, unsigned short product_id);
 
+	// filter out small/accidental/uncalibrated motions by
+	// setting up a "dead zone" around home position
+	// set to 0 to disable
+	// 0.1 is a safe and reasonable value
+	void setDeadZone(float);
+
 	// the latest raw axis data from the device
 	// NOTE: axis data should be in blender view coordinates
 	//       +X is to the right
@@ -118,7 +131,6 @@
 private:
 	void sendButtonEvent(NDOF_ButtonT, bool press, GHOST_TUns64 time, GHOST_IWindow*);
 	void sendKeyEvent(GHOST_TKey, bool press, GHOST_TUns64 time, GHOST_IWindow*);
-	void updateMotionState();
 
 	NDOF_DeviceT m_deviceType;
 	int m_buttonCount;
@@ -130,8 +142,10 @@
 
 	GHOST_TUns64 m_motionTime; // in milliseconds
 	GHOST_TUns64 m_prevMotionTime; // time of most recent Motion event sent
+
 	GHOST_TProgress m_motionState;
 	bool m_motionEventPending;
+	float m_deadZone; // discard motion with each component < this
 };
 
 #endif

Modified: branches/merwin-spacenav/intern/ghost/intern/GHOST_NDOFManagerX11.cpp
===================================================================
--- branches/merwin-spacenav/intern/ghost/intern/GHOST_NDOFManagerX11.cpp	2011-07-18 22:37:48 UTC (rev 38496)
+++ branches/merwin-spacenav/intern/ghost/intern/GHOST_NDOFManagerX11.cpp	2011-07-18 22:42:09 UTC (rev 38497)
@@ -34,6 +34,8 @@
 		{
 		m_available = true;
 
+		setDeadZone(0.1f); // how to calibrate on Linux? throw away slight motion!
+
 		// determine exactly which device is plugged in
 
 		#define MAX_LINE_LENGTH 100

Modified: branches/merwin-spacenav/intern/ghost/intern/GHOST_SystemX11.cpp
===================================================================
--- branches/merwin-spacenav/intern/ghost/intern/GHOST_SystemX11.cpp	2011-07-18 22:37:48 UTC (rev 38496)
+++ branches/merwin-spacenav/intern/ghost/intern/GHOST_SystemX11.cpp	2011-07-18 22:42:09 UTC (rev 38497)
@@ -597,7 +597,8 @@
 		{
 			XFocusChangeEvent &xfe = xe->xfocus;
 
-			printf("X: focus %s for window %d\n", xfe.type == FocusIn ? "in" : "out", (int) xfe.window);
+			// TODO: make sure this is the correct place for activate/deactivate
+			// printf("X: focus %s for window %d\n", xfe.type == FocusIn ? "in" : "out", (int) xfe.window);
 		
 			// May have to look at the type of event and filter some
 			// out.
@@ -687,7 +688,7 @@
 				);
 			}
 
-			printf("X: %s window %d\n", xce.type == EnterNotify ? "entering" : "leaving", (int) xce.window);
+			// printf("X: %s window %d\n", xce.type == EnterNotify ? "entering" : "leaving", (int) xce.window);
 
 			if (xce.type == EnterNotify)
 				m_windowManager->setActiveWindow(window);




More information about the Bf-blender-cvs mailing list