Smart sampling for geometric inputs.
Gesture: +1 227 -1 131 +2 0 -2 0 +3 0 -3 0 +4 261 -4 167 +5 73 -5 263 +6 0 -6 0 +7 0 -7 0 Gesture incremental: +1 228 -1 127 +2 0 -2 0 +3 0 -3 0 +4 269 -4 167 +5 68 -5 271 +6 0 -6 0 +7 0 -7 0 On device: 0: all, 1:initialize (0) 56285.82 (99.99%) (1) 3886.59 (6.90%) -> (0) 42795.78 (99.98%) (1) 3916.80 (9.15%) Change-Id: I3eed99cbd75b22fd2d8b5404a4f7e0972f284a85main
parent
8251036616
commit
d9c10b1979
|
@ -76,10 +76,24 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi
|
||||||
mTimes.clear();
|
mTimes.clear();
|
||||||
mLengthCache.clear();
|
mLengthCache.clear();
|
||||||
mDistanceCache.clear();
|
mDistanceCache.clear();
|
||||||
|
|
||||||
mInputSize = 0;
|
mInputSize = 0;
|
||||||
|
|
||||||
if (xCoordinates && yCoordinates) {
|
if (xCoordinates && yCoordinates) {
|
||||||
const bool proximityOnly = !isGeometric && (xCoordinates[0] < 0 || yCoordinates[0] < 0);
|
const bool proximityOnly = !isGeometric && (xCoordinates[0] < 0 || yCoordinates[0] < 0);
|
||||||
|
int lastInputIndex = 0;
|
||||||
|
for (int i = 0; i < inputSize; ++i) {
|
||||||
|
const int pid = pointerIds ? pointerIds[i] : 0;
|
||||||
|
if (pointerId == pid) {
|
||||||
|
lastInputIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Working space to save near keys distances for current, prev and prevprev input point.
|
||||||
|
NearKeysDistanceMap nearKeysDistances[3];
|
||||||
|
// These pointers are swapped for each inputs points.
|
||||||
|
NearKeysDistanceMap *currentNearKeysDistances = &nearKeysDistances[0];
|
||||||
|
NearKeysDistanceMap *prevNearKeysDistances = &nearKeysDistances[1];
|
||||||
|
NearKeysDistanceMap *prevPrevNearKeysDistances = &nearKeysDistances[2];
|
||||||
|
|
||||||
for (int i = 0; i < inputSize; ++i) {
|
for (int i = 0; i < inputSize; ++i) {
|
||||||
// Assuming pointerId == 0 if pointerIds is null.
|
// Assuming pointerId == 0 if pointerIds is null.
|
||||||
const int pid = pointerIds ? pointerIds[i] : 0;
|
const int pid = pointerIds ? pointerIds[i] : 0;
|
||||||
|
@ -88,11 +102,22 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi
|
||||||
const int x = proximityOnly ? NOT_A_COORDINATE : xCoordinates[i];
|
const int x = proximityOnly ? NOT_A_COORDINATE : xCoordinates[i];
|
||||||
const int y = proximityOnly ? NOT_A_COORDINATE : yCoordinates[i];
|
const int y = proximityOnly ? NOT_A_COORDINATE : yCoordinates[i];
|
||||||
const int time = times ? times[i] : -1;
|
const int time = times ? times[i] : -1;
|
||||||
if (pushTouchPoint(c, x, y, time, isGeometric)) {
|
if (pushTouchPoint(c, x, y, time, isGeometric, i == lastInputIndex,
|
||||||
++mInputSize;
|
currentNearKeysDistances, prevNearKeysDistances,
|
||||||
|
prevPrevNearKeysDistances)) {
|
||||||
|
// Previous point information was popped.
|
||||||
|
NearKeysDistanceMap *tmp = prevNearKeysDistances;
|
||||||
|
prevNearKeysDistances = currentNearKeysDistances;
|
||||||
|
currentNearKeysDistances = tmp;
|
||||||
|
} else {
|
||||||
|
NearKeysDistanceMap *tmp = prevPrevNearKeysDistances;
|
||||||
|
prevPrevNearKeysDistances = prevNearKeysDistances;
|
||||||
|
prevNearKeysDistances = currentNearKeysDistances;
|
||||||
|
currentNearKeysDistances = tmp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mInputSize = mInputXs.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mInputSize > 0) {
|
if (mInputSize > 0) {
|
||||||
|
@ -153,20 +178,151 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ProximityInfoState::pushTouchPoint(const int nodeChar, int x, int y,
|
// Calculating point to key distance for all near keys and returning the distance between
|
||||||
const int time, const bool sample) {
|
// the given point and the nearest key position.
|
||||||
const uint32_t size = mInputXs.size();
|
float ProximityInfoState::updateNearKeysDistances(const int x, const int y,
|
||||||
// TODO: Should have a const variable for 10
|
NearKeysDistanceMap *const currentNearKeysDistances) {
|
||||||
const int sampleRate = mProximityInfo->getMostCommonKeyWidth() / 10;
|
static const float NEAR_KEY_THRESHOLD = 10.0f;
|
||||||
if (size > 0) {
|
|
||||||
const int dist = getDistanceInt(x, y, mInputXs[size - 1], mInputYs[size - 1]);
|
currentNearKeysDistances->clear();
|
||||||
if (sample && dist < sampleRate) {
|
const int keyCount = mProximityInfo->getKeyCount();
|
||||||
return false;
|
float nearestKeyDistance = mMaxPointToKeyLength;
|
||||||
|
for (int k = 0; k < keyCount; ++k) {
|
||||||
|
const float dist = mProximityInfo->getNormalizedSquaredDistanceFromCenterFloat(k, x, y);
|
||||||
|
if (dist < NEAR_KEY_THRESHOLD) {
|
||||||
|
currentNearKeysDistances->insert(std::pair<int, float>(k, dist));
|
||||||
|
}
|
||||||
|
if (nearestKeyDistance > dist) {
|
||||||
|
nearestKeyDistance = dist;
|
||||||
}
|
}
|
||||||
mLengthCache.push_back(mLengthCache[size - 1] + dist);
|
|
||||||
} else {
|
|
||||||
mLengthCache.push_back(0);
|
|
||||||
}
|
}
|
||||||
|
return nearestKeyDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if previous point is at local minimum position to near keys.
|
||||||
|
bool ProximityInfoState::isPrevLocalMin(const NearKeysDistanceMap *const currentNearKeysDistances,
|
||||||
|
const NearKeysDistanceMap *const prevNearKeysDistances,
|
||||||
|
const NearKeysDistanceMap *const prevPrevNearKeysDistances) const {
|
||||||
|
static const float MARGIN = 0.5f;
|
||||||
|
|
||||||
|
for (NearKeysDistanceMap::const_iterator it = prevNearKeysDistances->begin();
|
||||||
|
it != prevNearKeysDistances->end(); ++it) {
|
||||||
|
NearKeysDistanceMap::const_iterator itPP = prevPrevNearKeysDistances->find(it->first);
|
||||||
|
NearKeysDistanceMap::const_iterator itC = currentNearKeysDistances->find(it->first);
|
||||||
|
if ((itPP == prevPrevNearKeysDistances->end() || itPP->second > it->second + MARGIN)
|
||||||
|
&& (itC == currentNearKeysDistances->end() || itC->second > it->second + MARGIN)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculating a point score that indicates usefulness of the point.
|
||||||
|
float ProximityInfoState::getPointScore(
|
||||||
|
const int x, const int y, const int time, const bool lastPoint, const float nearest,
|
||||||
|
const NearKeysDistanceMap *const currentNearKeysDistances,
|
||||||
|
const NearKeysDistanceMap *const prevNearKeysDistances,
|
||||||
|
const NearKeysDistanceMap *const prevPrevNearKeysDistances) const {
|
||||||
|
static const float BASE_SAMPLE_RATE_SCALE = 0.1f;
|
||||||
|
static const float SAVE_DISTANCE_SCALE = 12.0f;
|
||||||
|
static const float SAVE_DISTANCE_SCORE = 2.0f;
|
||||||
|
static const float SKIP_DISTANCE_SCALE = 1.5f;
|
||||||
|
static const float SKIP_DISTANCE_SCORE = -1.0f;
|
||||||
|
static const float CHECK_LOCALMIN_DISTANCE_THRESHOLD_SCALE = 2.5f;
|
||||||
|
static const float CHECK_LOCALMIN_DISTANCE_SCORE = -1.0f;
|
||||||
|
static const float STRAIGHT_ANGLE_THRESHOLD = M_PI_F / 32.0f;
|
||||||
|
static const float STRAIGHT_SKIP_DISTANCE_THRESHOLD_SCALE = 4.0f;
|
||||||
|
static const float STRAIGHT_SKIP_NEAREST_DISTANCE_THRESHOLD = 0.5f;
|
||||||
|
static const float STRAIGHT_SKIP_SCORE = -1.0f;
|
||||||
|
|
||||||
|
const std::size_t size = mInputXs.size();
|
||||||
|
if (size <= 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const float baseSampleRate = mProximityInfo->getMostCommonKeyWidth() * BASE_SAMPLE_RATE_SCALE;
|
||||||
|
const float distNext = getDistanceFloat(x, y, mInputXs.back(), mInputYs.back());
|
||||||
|
const float distPrev = getDistanceFloat(mInputXs.back(), mInputYs.back(),
|
||||||
|
mInputXs[size - 2], mInputYs[size - 2]);
|
||||||
|
float score = 0.0f;
|
||||||
|
|
||||||
|
// Sum of distances
|
||||||
|
if (distPrev + distNext > baseSampleRate * SAVE_DISTANCE_SCALE) {
|
||||||
|
score += SAVE_DISTANCE_SCORE;
|
||||||
|
}
|
||||||
|
// Distance
|
||||||
|
if (distPrev < baseSampleRate * SKIP_DISTANCE_SCALE) {
|
||||||
|
score += SKIP_DISTANCE_SCORE;
|
||||||
|
}
|
||||||
|
// Location
|
||||||
|
if (!isPrevLocalMin(currentNearKeysDistances, currentNearKeysDistances,
|
||||||
|
prevPrevNearKeysDistances)) {
|
||||||
|
if (distPrev < baseSampleRate * CHECK_LOCALMIN_DISTANCE_THRESHOLD_SCALE) {
|
||||||
|
score += CHECK_LOCALMIN_DISTANCE_SCORE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Angle
|
||||||
|
const float angle1 = getAngle(x, y, mInputXs.back(), mInputYs.back());
|
||||||
|
const float angle2 = getAngle(mInputXs.back(), mInputYs.back(),
|
||||||
|
mInputXs[size - 2], mInputYs[size - 2]);
|
||||||
|
if (getAngleDiff(angle1, angle2) < STRAIGHT_ANGLE_THRESHOLD) {
|
||||||
|
if (nearest > STRAIGHT_SKIP_NEAREST_DISTANCE_THRESHOLD
|
||||||
|
&& distPrev < baseSampleRate * STRAIGHT_SKIP_DISTANCE_THRESHOLD_SCALE) {
|
||||||
|
score += STRAIGHT_SKIP_SCORE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sampling touch point and pushing information to vectors.
|
||||||
|
// Returning if previous point is popped or not.
|
||||||
|
bool ProximityInfoState::pushTouchPoint(const int nodeChar, int x, int y, const int time,
|
||||||
|
const bool sample, const bool isLastPoint,
|
||||||
|
NearKeysDistanceMap *const currentNearKeysDistances,
|
||||||
|
const NearKeysDistanceMap *const prevNearKeysDistances,
|
||||||
|
const NearKeysDistanceMap *const prevPrevNearKeysDistances) {
|
||||||
|
static const float LAST_POINT_SKIP_DISTANCE_SCALE = 0.25f;
|
||||||
|
|
||||||
|
uint32_t size = mInputXs.size();
|
||||||
|
bool popped = false;
|
||||||
|
if (nodeChar < 0 && sample) {
|
||||||
|
const float nearest = updateNearKeysDistances(x, y, currentNearKeysDistances);
|
||||||
|
const float score = getPointScore(x, y, time, isLastPoint, nearest,
|
||||||
|
currentNearKeysDistances, prevNearKeysDistances, prevPrevNearKeysDistances);
|
||||||
|
if (score < 0) {
|
||||||
|
// Pop previous point because it would be useless.
|
||||||
|
mInputXs.pop_back();
|
||||||
|
mInputYs.pop_back();
|
||||||
|
mTimes.pop_back();
|
||||||
|
mLengthCache.pop_back();
|
||||||
|
size = mInputXs.size();
|
||||||
|
popped = true;
|
||||||
|
} else {
|
||||||
|
popped = false;
|
||||||
|
}
|
||||||
|
// Check if the last point should be skipped.
|
||||||
|
if (isLastPoint) {
|
||||||
|
if (size > 0 && getDistanceFloat(x, y, mInputXs.back(), mInputYs.back())
|
||||||
|
< mProximityInfo->getMostCommonKeyWidth() * LAST_POINT_SKIP_DISTANCE_SCALE) {
|
||||||
|
return popped;
|
||||||
|
} else if (size > 1) {
|
||||||
|
int minChar = 0;
|
||||||
|
float minDist = mMaxPointToKeyLength;
|
||||||
|
for (NearKeysDistanceMap::const_iterator it = currentNearKeysDistances->begin();
|
||||||
|
it != currentNearKeysDistances->end(); ++it) {
|
||||||
|
if(minDist > it->second){
|
||||||
|
minChar = it->first;
|
||||||
|
minDist = it->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NearKeysDistanceMap::const_iterator itPP =
|
||||||
|
prevNearKeysDistances->find(minChar);
|
||||||
|
if (itPP != prevNearKeysDistances->end() && minDist > itPP->second) {
|
||||||
|
return popped;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (nodeChar >= 0 && (x < 0 || y < 0)) {
|
if (nodeChar >= 0 && (x < 0 || y < 0)) {
|
||||||
const int keyId = mProximityInfo->getKeyIndex(nodeChar);
|
const int keyId = mProximityInfo->getKeyIndex(nodeChar);
|
||||||
if (keyId >= 0) {
|
if (keyId >= 0) {
|
||||||
|
@ -174,10 +330,18 @@ bool ProximityInfoState::pushTouchPoint(const int nodeChar, int x, int y,
|
||||||
y = mProximityInfo->getKeyCenterYOfIdG(keyId);
|
y = mProximityInfo->getKeyCenterYOfIdG(keyId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pushing point information.
|
||||||
|
if (size > 0) {
|
||||||
|
mLengthCache.push_back(
|
||||||
|
mLengthCache.back() + getDistanceInt(x, y, mInputXs.back(), mInputYs.back()));
|
||||||
|
} else {
|
||||||
|
mLengthCache.push_back(0);
|
||||||
|
}
|
||||||
mInputXs.push_back(x);
|
mInputXs.push_back(x);
|
||||||
mInputYs.push_back(y);
|
mInputYs.push_back(y);
|
||||||
mTimes.push_back(time);
|
mTimes.push_back(time);
|
||||||
return true;
|
return popped;
|
||||||
}
|
}
|
||||||
|
|
||||||
float ProximityInfoState::calculateNormalizedSquaredDistance(
|
float ProximityInfoState::calculateNormalizedSquaredDistance(
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
#include "char_utils.h"
|
#include "char_utils.h"
|
||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
|
#include "hash_map_compat.h"
|
||||||
|
|
||||||
namespace latinime {
|
namespace latinime {
|
||||||
|
|
||||||
|
@ -216,6 +217,7 @@ class ProximityInfoState {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DISALLOW_COPY_AND_ASSIGN(ProximityInfoState);
|
DISALLOW_COPY_AND_ASSIGN(ProximityInfoState);
|
||||||
|
typedef hash_map_compat<int, float> NearKeysDistanceMap;
|
||||||
/////////////////////////////////////////
|
/////////////////////////////////////////
|
||||||
// Defined in proximity_info_state.cpp //
|
// Defined in proximity_info_state.cpp //
|
||||||
/////////////////////////////////////////
|
/////////////////////////////////////////
|
||||||
|
@ -224,7 +226,11 @@ class ProximityInfoState {
|
||||||
float calculateSquaredDistanceFromSweetSpotCenter(
|
float calculateSquaredDistanceFromSweetSpotCenter(
|
||||||
const int keyIndex, const int inputIndex) const;
|
const int keyIndex, const int inputIndex) const;
|
||||||
|
|
||||||
bool pushTouchPoint(const int nodeChar, int x, int y, const int time, const bool sample);
|
bool pushTouchPoint(const int nodeChar, int x, int y, const int time,
|
||||||
|
const bool sample, const bool isLastPoint,
|
||||||
|
NearKeysDistanceMap *const currentNearKeysDistances,
|
||||||
|
const NearKeysDistanceMap *const prevNearKeysDistances,
|
||||||
|
const NearKeysDistanceMap *const prevPrevNearKeysDistances);
|
||||||
/////////////////////////////////////////
|
/////////////////////////////////////////
|
||||||
// Defined here //
|
// Defined here //
|
||||||
/////////////////////////////////////////
|
/////////////////////////////////////////
|
||||||
|
@ -238,6 +244,17 @@ class ProximityInfoState {
|
||||||
return mInputCodes + (index * MAX_PROXIMITY_CHARS_SIZE_INTERNAL);
|
return mInputCodes + (index * MAX_PROXIMITY_CHARS_SIZE_INTERNAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float updateNearKeysDistances(const int x, const int y,
|
||||||
|
NearKeysDistanceMap *const currentNearKeysDistances);
|
||||||
|
bool isPrevLocalMin(const NearKeysDistanceMap *const currentNearKeysDistances,
|
||||||
|
const NearKeysDistanceMap *const prevNearKeysDistances,
|
||||||
|
const NearKeysDistanceMap *const prevPrevNearKeysDistances) const;
|
||||||
|
float getPointScore(
|
||||||
|
const int x, const int y, const int time, const bool last, const float nearest,
|
||||||
|
const NearKeysDistanceMap *const currentNearKeysDistances,
|
||||||
|
const NearKeysDistanceMap *const prevNearKeysDistances,
|
||||||
|
const NearKeysDistanceMap *const prevPrevNearKeysDistances) const;
|
||||||
|
|
||||||
// const
|
// const
|
||||||
const ProximityInfo *mProximityInfo;
|
const ProximityInfo *mProximityInfo;
|
||||||
float mMaxPointToKeyLength;
|
float mMaxPointToKeyLength;
|
||||||
|
|
Loading…
Reference in New Issue