Working constant-time touch interaction decay. Needs a speed limit when close to camera focus node.

This commit is contained in:
GPayne
2018-04-11 11:40:40 -06:00
parent 97ef55b4be
commit dbb0915417
2 changed files with 170 additions and 4 deletions

View File

@@ -38,6 +38,8 @@
#include <openspace/properties/vector/vec4property.h>
//#define TOUCH_DEBUG_PROPERTIES
#define CONST_TIME_DECAY
namespace openspace {
@@ -184,6 +186,10 @@ private:
properties::Vec4Property _friction;
properties::FloatProperty _pickingRadiusMinimum;
properties::BoolProperty _ignoreGui;
#ifdef CONST_TIME_DECAY
properties::FloatProperty _constTimeDecay_secs;
#endif
properties::FloatProperty _speedLimitDistanceFraction;
#ifdef TOUCH_DEBUG_PROPERTIES
struct DebugProperties : PropertyOwner {
@@ -222,6 +228,47 @@ private:
LMstat _lmstat;
glm::dquat _toSlerp;
glm::dvec3 _centroid;
#ifdef CONST_TIME_DECAY
class FrameTimeAverage
{
public:
void updateWithNewFrame (double sample)
{
if (sample > 0.0005) {
_samples[index++] = sample;
if (index >= totalSamples)
index = 0;
if (_nSamples < totalSamples)
_nSamples++;
}
}
double getAvgFrameTime () {
if (_nSamples == 0)
return 1.0 / 60.0;
else
return std::accumulate(_samples, _samples + _nSamples, 0.0)
/ (double)(_nSamples);
}
private:
static const int totalSamples = 10;
int _nSamples = 0;
double _samples[totalSamples];
double _runningTotal = 0.0;
int index = 0;
};
FrameTimeAverage _frameTimeAvg;
struct ConstantTimeDecayCoefficients {
double zoom = 0.0;
double orbit = 0.0;
double roll = 0.0;
double pan = 0.0;
};
ConstantTimeDecayCoefficients _constTimeDecayCoeff;
#endif
};
} // openspace namespace

View File

@@ -157,6 +157,20 @@ namespace {
"" // @TODO Missing documentation
};
#ifdef CONST_TIME_DECAY
static const openspace::properties::Property::PropertyInfo ConstantTimeDecaySecsInfo = {
"ConstantTimeDecaySecs",
"Time duration that a pitch/roll/zoom/pan should take to decay to zero (seconds)",
""
};
#endif
static const openspace::properties::Property::PropertyInfo SpeedLimitDistanceFractionInfo = {
"SpeedLimitDistanceFraction",
"Speed limiting factor as a fraction of distance to focus node",
""
};
static const openspace::properties::Property::PropertyInfo InputSensitivityInfo = {
"InputSensitivity",
"Threshold for interpreting input as still",
@@ -224,7 +238,7 @@ TouchInteraction::TouchInteraction()
, _rollAngleThreshold(RollThresholdInfo, 0.025f, 0.f, 0.05f)
, _orbitSpeedThreshold(OrbitSpinningThreshold, 0.005f, 0.f, 0.01f)
, _spinSensitivity(SpinningSensitivityInfo, 1.f, 0.f, 2.f)
, _zoomSensitivity(ZoomSensitivityInfo, 1.025f, 1.0f, 1.1f)
, _zoomSensitivity(ZoomSensitivityInfo, 1.035f, 1.0f, 1.1f)
, _zoomSensitivityDistanceThreshold(ZoomSensitivityDistanceThresholdInfo, 0.05, 0.01, 0.25)
, _zoomBoundarySphereMultiplier(ZoomBoundarySphereMultiplierInfo, 1.001, 1.0, 1.01)
, _inputStillThreshold(InputSensitivityInfo, 0.0005f, 0.f, 0.001f)
@@ -257,6 +271,10 @@ TouchInteraction::TouchInteraction()
)
, _vel{ glm::dvec2(0.0), 0.0, 0.0, glm::dvec2(0.0) }
, _sensitivity{ glm::dvec2(0.08, 0.045), 4.0, 2.75, glm::dvec2(0.08, 0.045) }
, _speedLimitDistanceFraction(SpeedLimitDistanceFractionInfo, 7.f, 0.1f, 20.0f)
#ifdef CONST_TIME_DECAY
, _constTimeDecay_secs(ConstantTimeDecaySecsInfo, 2.0f, 0.1f, 2.5f)
#endif
// calculated with two vectors with known diff in length, then
// projDiffLength/diffLength.
, _projectionScaleFactor(1.000004)
@@ -288,6 +306,7 @@ TouchInteraction::TouchInteraction()
addProperty(_zoomSensitivity);
addProperty(_zoomSensitivityDistanceThreshold);
addProperty(_zoomBoundarySphereMultiplier);
addProperty(_speedLimitDistanceFraction);
addProperty(_inputStillThreshold);
addProperty(_centroidStillThreshold);
addProperty(_panEnabled);
@@ -926,6 +945,9 @@ void TouchInteraction::computeVelocities(const std::vector<TuioCursor>& list,
{
TuioCursor cursor = list.at(0);
const int action = interpretInteraction(list, lastProcessed);
#ifdef CONST_TIME_DECAY
double stepsToDecay = _constTimeDecay_secs / _frameTimeAvg.getAvgFrameTime();
#endif
#ifdef TOUCH_DEBUG_PROPERTIES
const std::map<int, std::string> interactionNames = {
@@ -950,6 +972,16 @@ void TouchInteraction::computeVelocities(const std::vector<TuioCursor>& list,
_vel.orbit += glm::dvec2(cursor.getXSpeed() *
_sensitivity.orbit.x, cursor.getYSpeed() *
_sensitivity.orbit.y);
#ifdef CONST_TIME_DECAY
/*double orbitVelocityAvg = (cursor.getXSpeed() * _sensitivity.orbit.x
+ cursor.getYSpeed() * _sensitivity.orbit.y) / 2.0;*/
double orbitVelocityAvg = glm::distance(_vel.orbit.x, _vel.orbit.y);
if( stepsToDecay > 0.0 )
_constTimeDecayCoeff.orbit = std::pow((1e-6 / std::abs(orbitVelocityAvg)), (1.0 / stepsToDecay));
else
_constTimeDecayCoeff.orbit = 1.0;
//LINFO("Orbit coeff " << _constTimeDecayCoeff.orbit << " with velocity " << orbitVelocityAvg);
#endif
break;
}
case PINCH: {
@@ -988,11 +1020,26 @@ void TouchInteraction::computeVelocities(const std::vector<TuioCursor>& list,
pinchConsecCt++;
pinchConsecZoomFactor += zoomFactor;
#endif
#ifdef CONST_TIME_DECAY
if( stepsToDecay > 0.0 && std::abs(_vel.zoom) > 1e-6)
_constTimeDecayCoeff.zoom = std::pow((1e-6 / std::abs(_vel.zoom)), (1.0 / stepsToDecay));
else
_constTimeDecayCoeff.zoom = 1.0;
#endif
if ((length(currDistanceToFocusNode) / distanceFromFocusSurface) > _zoomSensitivityDistanceThreshold) {
zoomFactor *= pow(distanceFromFocusSurface, (float)_zoomSensitivity);
zoomFactor *= pow(std::abs(distanceFromFocusSurface), (float)_zoomSensitivity);
}
//LINFO("Zoom vel factor " << zoomFactor << " with velocity " << _vel.zoom);
_vel.zoom += zoomFactor * _sensitivity.zoom *
std::max(_touchScreenSize.value() * 0.1, 1.0);
//LINFO("VVelocity= " << _vel.zoom);
//Speed Limit on zoom velocity
double speedLimit = _speedLimitDistanceFraction * distanceFromFocusSurface;
if (std::abs(_vel.zoom) > 1e-7)
_vel.zoom = std::min(std::abs(speedLimit), std::abs(_vel.zoom)) * (_vel.zoom / std::abs(_vel.zoom));
else
_vel.zoom = 0.0;
break;
}
case ROLL: {
@@ -1031,12 +1078,27 @@ void TouchInteraction::computeVelocities(const std::vector<TuioCursor>& list,
) / list.size();
_vel.roll += -rollFactor * _sensitivity.roll;
#ifdef CONST_TIME_DECAY
if( stepsToDecay > 0.0 )
_constTimeDecayCoeff.roll = std::pow((1e-6 / std::abs(_vel.roll)), (1.0 / stepsToDecay));
else
_constTimeDecayCoeff.roll = 1.0;
#endif
break;
}
case PAN: {
// add local rotation velocity
_vel.pan += glm::dvec2(cursor.getXSpeed() *
_sensitivity.pan.x, cursor.getYSpeed() * _sensitivity.pan.y);
#ifdef CONST_TIME_DECAY
/*double panVelocityAvg = (cursor.getXSpeed() * _sensitivity.pan.x
+ cursor.getYSpeed() * _sensitivity.pan.y) / 2.0;*/
double panVelocityAvg = glm::distance(_vel.pan.x, _vel.pan.y);
if( stepsToDecay > 0.0 )
_constTimeDecayCoeff.pan = std::pow((1e-6 / std::abs(panVelocityAvg)), (1.0 / stepsToDecay));
else
_constTimeDecayCoeff.pan = 1.0;
#endif
break;
}
case PICK: {
@@ -1236,6 +1298,50 @@ void TouchInteraction::unitTest() {
// _timeSlack = 0.0501 % 0.01 = 0.01
void TouchInteraction::decelerate(double dt) {
#ifdef CONST_TIME_DECAY
_frameTimeAvg.updateWithNewFrame(dt);
double expectedFrameTime = _frameTimeAvg.getAvgFrameTime();
// Number of times velocities should decelerate, depending on chosen frequency and
// time slack over from last frame
int times = static_cast<int>((dt + _timeSlack) / expectedFrameTime);
// Save the new time slack for the next frame
_timeSlack = fmod((dt + _timeSlack), expectedFrameTime) * expectedFrameTime;
if (times > 0) {
if (_constTimeDecayCoeff.orbit > 0.0001)
_vel.orbit *= std::pow(_constTimeDecayCoeff.orbit, times);
else
_vel.orbit = { 0.0, 0.0 };
if (_constTimeDecayCoeff.roll > 0.0001)
_vel.roll *= std::pow(_constTimeDecayCoeff.roll, times);
else
_vel.roll = 0.0;
if (_constTimeDecayCoeff.pan > 0.0001)
_vel.pan *= std::pow(_constTimeDecayCoeff.pan, times);
else
_vel.pan = { 0.0, 0.0 };
if( _constTimeDecayCoeff.zoom > 0.0001) {
// Decelerate zoom velocity quicker if we're close enough to use direct-manipulation
if (!_directTouchMode && _currentRadius > _nodeRadiusThreshold &&
_vel.zoom > _focusNode->boundingSphere())
{
_vel.zoom *= std::pow(2 * _constTimeDecayCoeff.zoom, times);
}
else {
_vel.zoom *= std::pow(_constTimeDecayCoeff.zoom, times);
}
}
else {
_vel.zoom = 0.0;
}
}
//if(std::abs(_vel.zoom) > 10000) LINFO("Decelerate:velocity= " << _vel.zoom << " from " << times << " times using coeff " << _constTimeDecayCoeff.zoom);
#else
double frequency = 1.0 / _deceleratesPerSecond;
// Number of times velocities should decelerate, depending on chosen frequency and
// time slack over from last frame
@@ -1250,9 +1356,22 @@ void TouchInteraction::decelerate(double dt) {
_vel.zoom *= std::pow(1 - 2 * _friction.value().y, times);
}
_vel.orbit *= std::pow(1 - _friction.value().x, times);
_vel.zoom *= std::pow(1 - _friction.value().y, times);
_vel.roll *= std::pow(1 - _friction.value().z, times);
_vel.pan *= std::pow(1 - _friction.value().w, times);
#endif //#ifdef CONST_TIME_DECAY
#ifndef CONST_TIME_DECAY
float frictionDecayValue = _friction.value().y;
#endif //#ifndef CONST_TIME_DECAY
glm::dvec3 camPos = _camera->positionVec3();
glm::dvec3 centerPos = _focusNode->worldPosition();
glm::dvec3 centerToCamera = camPos - centerPos;
#ifndef CONST_TIME_DECAY
_vel.zoom *= std::pow((1 - frictionDecayValue), times);
#endif //#ifndef CONST_TIME_DECAY
}
// Called if all fingers are off the screen
@@ -1308,7 +1427,7 @@ void TouchInteraction::resetToDefault() {
_rollAngleThreshold.set(0.025f);
_orbitSpeedThreshold.set(0.005f);
_spinSensitivity.set(1.0f);
_zoomSensitivity.set(1.025f);
_zoomSensitivity.set(1.01f);
_inputStillThreshold.set(0.0005f);
_centroidStillThreshold.set(0.0018f);
_interpretPan.set(0.015f);