proximity_info_state.cpp revision 0edab9d2fcc30667c79aa9221dbb27f042d8b455
13e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka/* 23e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * Copyright (C) 2012 The Android Open Source Project 33e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * 43e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * Licensed under the Apache License, Version 2.0 (the "License"); 53e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * you may not use this file except in compliance with the License. 63e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * You may obtain a copy of the License at 73e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * 83e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * http://www.apache.org/licenses/LICENSE-2.0 93e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * 103e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * Unless required by applicable law or agreed to in writing, software 113e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * distributed under the License is distributed on an "AS IS" BASIS, 123e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * See the License for the specific language governing permissions and 143e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * limitations under the License. 153e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka */ 163e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka 1777e8e81ad95cfc1eb8f8407fc872674b8d08bbe9Ken Wakasa#include <cstring> // for memset() 183e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka#include <stdint.h> 193e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka 203e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka#define LOG_TAG "LatinIME: proximity_info_state.cpp" 213e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka 223e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka#include "defines.h" 23687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka#include "geometry_utils.h" 243e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka#include "proximity_info.h" 253e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka#include "proximity_info_state.h" 263e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka 273e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataokanamespace latinime { 28764dd712032d7b8012797b1116b523bef7b907f3Ken Wakasa 29764dd712032d7b8012797b1116b523bef7b907f3Ken Wakasaconst int ProximityInfoState::NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR_LOG_2 = 10; 30764dd712032d7b8012797b1116b523bef7b907f3Ken Wakasaconst int ProximityInfoState::NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR = 31764dd712032d7b8012797b1116b523bef7b907f3Ken Wakasa 1 << NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR_LOG_2; 32764dd712032d7b8012797b1116b523bef7b907f3Ken Wakasaconst float ProximityInfoState::NOT_A_DISTANCE_FLOAT = -1.0f; 33764dd712032d7b8012797b1116b523bef7b907f3Ken Wakasaconst int ProximityInfoState::NOT_A_CODE = -1; 34764dd712032d7b8012797b1116b523bef7b907f3Ken Wakasa 35233aad5e5c7567a97af30f38f50a65365f729dfeSatoshi Kataokavoid ProximityInfoState::initInputParams(const int pointerId, const float maxPointToKeyLength, 3608f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka const ProximityInfo *proximityInfo, const int32_t *const inputCodes, const int inputSize, 37687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const int *const xCoordinates, const int *const yCoordinates, const int *const times, 38687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const int *const pointerIds, const bool isGeometric) { 39096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi 40096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi if (isGeometric) { 41096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mIsContinuationPossible = checkAndReturnIsContinuationPossible( 42096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi inputSize, xCoordinates, yCoordinates, times); 43096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi } else { 44096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mIsContinuationPossible = false; 45096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi } 46096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi 474a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka mProximityInfo = proximityInfo; 484a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka mHasTouchPositionCorrectionData = proximityInfo->hasTouchPositionCorrectionData(); 494a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka mMostCommonKeyWidthSquare = proximityInfo->getMostCommonKeyWidthSquare(); 504a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka mLocaleStr = proximityInfo->getLocaleStr(); 514a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka mKeyCount = proximityInfo->getKeyCount(); 524a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka mCellHeight = proximityInfo->getCellHeight(); 534a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka mCellWidth = proximityInfo->getCellWidth(); 544a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka mGridHeight = proximityInfo->getGridWidth(); 554a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka mGridWidth = proximityInfo->getGridHeight(); 563e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka 5708f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka memset(mInputCodes, 0, sizeof(mInputCodes)); 583e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka 5908f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka if (!isGeometric && pointerId == 0) { 6008f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka // Initialize 6108f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka // - mInputCodes 6208f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka // - mNormalizedSquaredDistances 6308f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka // TODO: Merge 64687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka for (int i = 0; i < inputSize; ++i) { 6508f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka const int32_t primaryKey = inputCodes[i]; 6608f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka const int x = xCoordinates[i]; 6708f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka const int y = yCoordinates[i]; 6808f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka int *proximities = &mInputCodes[i * MAX_PROXIMITY_CHARS_SIZE_INTERNAL]; 6908f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka mProximityInfo->calculateNearbyKeyCodes(x, y, primaryKey, proximities); 7008f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka } 7108f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka 7208f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka if (DEBUG_PROXIMITY_CHARS) { 7308f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka for (int i = 0; i < inputSize; ++i) { 7408f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka AKLOGI("---"); 7508f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka for (int j = 0; j < MAX_PROXIMITY_CHARS_SIZE_INTERNAL; ++j) { 7608f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka int icc = mInputCodes[i * MAX_PROXIMITY_CHARS_SIZE_INTERNAL + j]; 7708f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka int icfjc = inputCodes[i * MAX_PROXIMITY_CHARS_SIZE_INTERNAL + j]; 7808f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka icc += 0; 7908f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka icfjc += 0; 8008f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka AKLOGI("--- (%d)%c,%c", i, icc, icfjc); AKLOGI("--- A<%d>,B<%d>", icc, icfjc); 8108f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka } 823e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka } 833e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka } 843e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka } 85687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka 86687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka /////////////////////// 87687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka // Setup touch points 88096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi int pushTouchPointStartIndex = 0; 89096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi int lastSavedInputSize = 0; 9008f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka mMaxPointToKeyLength = maxPointToKeyLength; 91096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi if (mIsContinuationPossible && mInputIndice.size() > 1) { 92096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi // Just update difference. 93096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi // Two points prior is never skipped. Thus, we pop 2 input point data here. 94096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi pushTouchPointStartIndex = mInputIndice[mInputIndice.size() - 2]; 95096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi popInputData(); 96096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi popInputData(); 97096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi lastSavedInputSize = mInputXs.size(); 98096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi } else { 99096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi // Clear all data. 100096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mInputXs.clear(); 101096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mInputYs.clear(); 102096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mTimes.clear(); 103096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mInputIndice.clear(); 104096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mLengthCache.clear(); 105096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mDistanceCache.clear(); 106096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mNearKeysVector.clear(); 107096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi } 1089182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka if (DEBUG_GEO_FULL) { 1099182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka AKLOGI("Init ProximityInfoState: reused points = %d, last input size = %d", 1109182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka pushTouchPointStartIndex, lastSavedInputSize); 1119182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka } 112687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka mInputSize = 0; 113d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi 114687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka if (xCoordinates && yCoordinates) { 115687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const bool proximityOnly = !isGeometric && (xCoordinates[0] < 0 || yCoordinates[0] < 0); 116096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi int lastInputIndex = pushTouchPointStartIndex; 117096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi for (int i = lastInputIndex; i < inputSize; ++i) { 118d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi const int pid = pointerIds ? pointerIds[i] : 0; 119d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi if (pointerId == pid) { 120d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi lastInputIndex = i; 121d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 122d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 1239182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka if (DEBUG_GEO_FULL) { 1249182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka AKLOGI("Init ProximityInfoState: last input index = %d", lastInputIndex); 1259182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka } 126d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi // Working space to save near keys distances for current, prev and prevprev input point. 127d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi NearKeysDistanceMap nearKeysDistances[3]; 128d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi // These pointers are swapped for each inputs points. 129d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi NearKeysDistanceMap *currentNearKeysDistances = &nearKeysDistances[0]; 130d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi NearKeysDistanceMap *prevNearKeysDistances = &nearKeysDistances[1]; 131d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi NearKeysDistanceMap *prevPrevNearKeysDistances = &nearKeysDistances[2]; 132d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi 133096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi for (int i = pushTouchPointStartIndex; i <= lastInputIndex; ++i) { 134687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka // Assuming pointerId == 0 if pointerIds is null. 135687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const int pid = pointerIds ? pointerIds[i] : 0; 1369182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka if (DEBUG_GEO_FULL) { 1379182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka AKLOGI("Init ProximityInfoState: (%d)PID = %d", i, pid); 1389182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka } 139687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka if (pointerId == pid) { 140687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const int c = isGeometric ? NOT_A_COORDINATE : getPrimaryCharAt(i); 141687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const int x = proximityOnly ? NOT_A_COORDINATE : xCoordinates[i]; 142687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const int y = proximityOnly ? NOT_A_COORDINATE : yCoordinates[i]; 143687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const int time = times ? times[i] : -1; 144952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka if (pushTouchPoint(i, c, x, y, time, isGeometric /* do sampling */, 145952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka i == lastInputIndex, currentNearKeysDistances, prevNearKeysDistances, 146d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi prevPrevNearKeysDistances)) { 147d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi // Previous point information was popped. 148d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi NearKeysDistanceMap *tmp = prevNearKeysDistances; 149d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi prevNearKeysDistances = currentNearKeysDistances; 150d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi currentNearKeysDistances = tmp; 151d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } else { 152d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi NearKeysDistanceMap *tmp = prevPrevNearKeysDistances; 153d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi prevPrevNearKeysDistances = prevNearKeysDistances; 154d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi prevNearKeysDistances = currentNearKeysDistances; 155d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi currentNearKeysDistances = tmp; 15637b153e205c9672b299b47e97921fee2462a78bbSatoshi Kataoka } 157687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka } 158687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka } 159d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi mInputSize = mInputXs.size(); 1603e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka } 161687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka 162687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka if (mInputSize > 0) { 163687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const int keyCount = mProximityInfo->getKeyCount(); 16495a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi mNearKeysVector.resize(mInputSize); 165687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka mDistanceCache.resize(mInputSize * keyCount); 166096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi for (int i = lastSavedInputSize; i < mInputSize; ++i) { 16795a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi mNearKeysVector[i].reset(); 16895a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi static const float NEAR_KEY_NORMALIZED_SQUARED_THRESHOLD = 4.0f; 169687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka for (int k = 0; k < keyCount; ++k) { 170687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const int index = i * keyCount + k; 171687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const int x = mInputXs[i]; 172687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const int y = mInputYs[i]; 17395a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi const float normalizedSquaredDistance = 1740edab9d2fcc30667c79aa9221dbb27f042d8b455Satoshi Kataoka mProximityInfo->getNormalizedSquaredDistanceFromCenterFloatG(k, x, y); 17595a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi mDistanceCache[index] = normalizedSquaredDistance; 17695a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi if (normalizedSquaredDistance < NEAR_KEY_NORMALIZED_SQUARED_THRESHOLD) { 17795a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi mNearKeysVector[i].set(k, 1); 17895a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi } 17995a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi } 18095a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi } 18195a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi 18295a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi static const float READ_FORWORD_LENGTH_SCALE = 0.95f; 18395a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi const int readForwordLength = static_cast<int>( 18495a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi hypotf(mProximityInfo->getKeyboardWidth(), mProximityInfo->getKeyboardHeight()) 18595a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi * READ_FORWORD_LENGTH_SCALE); 18695a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi for (int i = 0; i < mInputSize; ++i) { 187f4554d8b10f25ab300d057ff0ebd16b2b7a70be8Satoshi Kataoka if (DEBUG_GEO_FULL) { 188f4554d8b10f25ab300d057ff0ebd16b2b7a70be8Satoshi Kataoka AKLOGI("Sampled(%d): x = %d, y = %d, time = %d", i, mInputXs[i], mInputYs[i], 189f4554d8b10f25ab300d057ff0ebd16b2b7a70be8Satoshi Kataoka mTimes[i]); 190f4554d8b10f25ab300d057ff0ebd16b2b7a70be8Satoshi Kataoka } 191096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi for (int j = max(i + 1, lastSavedInputSize); j < mInputSize; ++j) { 19295a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi if (mLengthCache[j] - mLengthCache[i] >= readForwordLength) { 19395a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi break; 19495a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi } 19595a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi mNearKeysVector[i] |= mNearKeysVector[j]; 196687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka } 197687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka } 198687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka } 19908f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka 200687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka // end 201687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka /////////////////////// 202687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka 20308f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka memset(mNormalizedSquaredDistances, NOT_A_DISTANCE, sizeof(mNormalizedSquaredDistances)); 20408f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka memset(mPrimaryInputWord, 0, sizeof(mPrimaryInputWord)); 205233aad5e5c7567a97af30f38f50a65365f729dfeSatoshi Kataoka mTouchPositionCorrectionEnabled = mInputSize > 0 && mHasTouchPositionCorrectionData 2060edab9d2fcc30667c79aa9221dbb27f042d8b455Satoshi Kataoka && xCoordinates && yCoordinates; 20708f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka if (!isGeometric && pointerId == 0) { 20808f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka for (int i = 0; i < inputSize; ++i) { 20908f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka mPrimaryInputWord[i] = getPrimaryCharAt(i); 2103e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka } 21108f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka 21208f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka for (int i = 0; i < mInputSize && mTouchPositionCorrectionEnabled; ++i) { 21308f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka const int *proximityChars = getProximityCharsAt(i); 21408f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka const int primaryKey = proximityChars[0]; 21508f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka const int x = xCoordinates[i]; 21608f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka const int y = yCoordinates[i]; 2173e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka if (DEBUG_PROXIMITY_CHARS) { 21808f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka int a = x + y + primaryKey; 21908f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka a += 0; 22008f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka AKLOGI("--- Primary = %c, x = %d, y = %d", primaryKey, x, y); 22108f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka } 22208f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka for (int j = 0; j < MAX_PROXIMITY_CHARS_SIZE_INTERNAL && proximityChars[j] > 0; ++j) { 22308f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka const int currentChar = proximityChars[j]; 22408f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka const float squaredDistance = 22508f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka hasInputCoordinates() ? calculateNormalizedSquaredDistance( 226f2789819bd005b5b0581e8439601b5501306327dKen Wakasa mProximityInfo->getKeyIndexOf(currentChar), i) : 22708f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka NOT_A_DISTANCE_FLOAT; 22808f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka if (squaredDistance >= 0.0f) { 22908f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka mNormalizedSquaredDistances[i * MAX_PROXIMITY_CHARS_SIZE_INTERNAL + j] = 23008f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka (int) (squaredDistance * NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR); 23108f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka } else { 23208f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka mNormalizedSquaredDistances[i * MAX_PROXIMITY_CHARS_SIZE_INTERNAL + j] = 23308f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka (j == 0) ? EQUIVALENT_CHAR_WITHOUT_DISTANCE_INFO : 23408f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka PROXIMITY_CHAR_WITHOUT_DISTANCE_INFO; 23508f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka } 23608f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka if (DEBUG_PROXIMITY_CHARS) { 23708f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka AKLOGI("--- Proximity (%d) = %c", j, currentChar); 23808f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka } 2393e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka } 2403e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka } 2413e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka } 242952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka 243952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka if (DEBUG_GEO_FULL) { 244952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka AKLOGI("ProximityState init finished: %d points out of %d", mInputSize, inputSize); 245952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka } 2463e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka} 2474a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka 248096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagibool ProximityInfoState::checkAndReturnIsContinuationPossible(const int inputSize, 249096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi const int *const xCoordinates, const int *const yCoordinates, const int *const times) { 250096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi for (int i = 0; i < mInputSize; ++i) { 251096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi const int index = mInputIndice[i]; 252096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi if (index > inputSize || xCoordinates[index] != mInputXs[i] || 253096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi yCoordinates[index] != mInputYs[i] || times[index] != mTimes[i]) { 254096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi return false; 255096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi } 256096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi } 257096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi return true; 258096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi} 259096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi 260d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi// Calculating point to key distance for all near keys and returning the distance between 261d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi// the given point and the nearest key position. 262d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagifloat ProximityInfoState::updateNearKeysDistances(const int x, const int y, 263d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi NearKeysDistanceMap *const currentNearKeysDistances) { 26495a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi static const float NEAR_KEY_THRESHOLD = 4.0f; 265d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi 266d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi currentNearKeysDistances->clear(); 267d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi const int keyCount = mProximityInfo->getKeyCount(); 268d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi float nearestKeyDistance = mMaxPointToKeyLength; 269d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi for (int k = 0; k < keyCount; ++k) { 2700edab9d2fcc30667c79aa9221dbb27f042d8b455Satoshi Kataoka const float dist = mProximityInfo->getNormalizedSquaredDistanceFromCenterFloatG(k, x, y); 271d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi if (dist < NEAR_KEY_THRESHOLD) { 272d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi currentNearKeysDistances->insert(std::pair<int, float>(k, dist)); 273687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka } 274d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi if (nearestKeyDistance > dist) { 275d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi nearestKeyDistance = dist; 276d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 277d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 278d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi return nearestKeyDistance; 279d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi} 280d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi 281d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi// Check if previous point is at local minimum position to near keys. 282d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagibool ProximityInfoState::isPrevLocalMin(const NearKeysDistanceMap *const currentNearKeysDistances, 283d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi const NearKeysDistanceMap *const prevNearKeysDistances, 284d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi const NearKeysDistanceMap *const prevPrevNearKeysDistances) const { 285aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi static const float MARGIN = 0.01f; 286d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi 287d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi for (NearKeysDistanceMap::const_iterator it = prevNearKeysDistances->begin(); 288d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi it != prevNearKeysDistances->end(); ++it) { 289d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi NearKeysDistanceMap::const_iterator itPP = prevPrevNearKeysDistances->find(it->first); 290d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi NearKeysDistanceMap::const_iterator itC = currentNearKeysDistances->find(it->first); 291d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi if ((itPP == prevPrevNearKeysDistances->end() || itPP->second > it->second + MARGIN) 292d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi && (itC == currentNearKeysDistances->end() || itC->second > it->second + MARGIN)) { 293d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi return true; 294d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 295d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 296d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi return false; 297d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi} 298d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi 299d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi// Calculating a point score that indicates usefulness of the point. 300d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagifloat ProximityInfoState::getPointScore( 301d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi const int x, const int y, const int time, const bool lastPoint, const float nearest, 302d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi const NearKeysDistanceMap *const currentNearKeysDistances, 303d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi const NearKeysDistanceMap *const prevNearKeysDistances, 304d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi const NearKeysDistanceMap *const prevPrevNearKeysDistances) const { 30503dc8fe141fa9f6fa5fe8362d9d35b3f3c954b87Ken Wakasa static const int DISTANCE_BASE_SCALE = 100; 30603dc8fe141fa9f6fa5fe8362d9d35b3f3c954b87Ken Wakasa static const int SAVE_DISTANCE_SCALE = 200; 30703dc8fe141fa9f6fa5fe8362d9d35b3f3c954b87Ken Wakasa static const int SKIP_DISTANCE_SCALE = 25; 30803dc8fe141fa9f6fa5fe8362d9d35b3f3c954b87Ken Wakasa static const int CHECK_LOCALMIN_DISTANCE_THRESHOLD_SCALE = 40; 30903dc8fe141fa9f6fa5fe8362d9d35b3f3c954b87Ken Wakasa static const int STRAIGHT_SKIP_DISTANCE_THRESHOLD_SCALE = 50; 31003dc8fe141fa9f6fa5fe8362d9d35b3f3c954b87Ken Wakasa static const int CORNER_CHECK_DISTANCE_THRESHOLD_SCALE = 27; 311d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi static const float SAVE_DISTANCE_SCORE = 2.0f; 312d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi static const float SKIP_DISTANCE_SCORE = -1.0f; 313d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi static const float CHECK_LOCALMIN_DISTANCE_SCORE = -1.0f; 314aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi static const float STRAIGHT_ANGLE_THRESHOLD = M_PI_F / 36.0f; 315d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi static const float STRAIGHT_SKIP_NEAREST_DISTANCE_THRESHOLD = 0.5f; 316d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi static const float STRAIGHT_SKIP_SCORE = -1.0f; 317aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi static const float CORNER_ANGLE_THRESHOLD = M_PI_F / 2.0f; 318aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi static const float CORNER_SCORE = 1.0f; 319d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi 320d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi const std::size_t size = mInputXs.size(); 321d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi if (size <= 1) { 32203dc8fe141fa9f6fa5fe8362d9d35b3f3c954b87Ken Wakasa return 0.0f; 323687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka } 32403dc8fe141fa9f6fa5fe8362d9d35b3f3c954b87Ken Wakasa const int baseSampleRate = mProximityInfo->getMostCommonKeyWidth(); 32503dc8fe141fa9f6fa5fe8362d9d35b3f3c954b87Ken Wakasa const int distNext = getDistanceInt(x, y, mInputXs.back(), mInputYs.back()) 32603dc8fe141fa9f6fa5fe8362d9d35b3f3c954b87Ken Wakasa * DISTANCE_BASE_SCALE; 32703dc8fe141fa9f6fa5fe8362d9d35b3f3c954b87Ken Wakasa const int distPrev = getDistanceInt(mInputXs.back(), mInputYs.back(), 32803dc8fe141fa9f6fa5fe8362d9d35b3f3c954b87Ken Wakasa mInputXs[size - 2], mInputYs[size - 2]) * DISTANCE_BASE_SCALE; 329d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi float score = 0.0f; 330d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi 331d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi // Sum of distances 332d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi if (distPrev + distNext > baseSampleRate * SAVE_DISTANCE_SCALE) { 333d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi score += SAVE_DISTANCE_SCORE; 334d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 335d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi // Distance 336d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi if (distPrev < baseSampleRate * SKIP_DISTANCE_SCALE) { 337d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi score += SKIP_DISTANCE_SCORE; 338d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 339d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi // Location 3403811a28ddc07201930e0bbd2e1d01045b59af308Keisuke Kuroyanagi if (distPrev < baseSampleRate * CHECK_LOCALMIN_DISTANCE_THRESHOLD_SCALE) { 341aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi if (!isPrevLocalMin(currentNearKeysDistances, prevNearKeysDistances, 342d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi prevPrevNearKeysDistances)) { 343d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi score += CHECK_LOCALMIN_DISTANCE_SCORE; 344d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 345d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 346d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi // Angle 347aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi const float angle1 = getAngle(x, y, mInputXs.back(), mInputYs.back()); 348aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi const float angle2 = getAngle(mInputXs.back(), mInputYs.back(), 349aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi mInputXs[size - 2], mInputYs[size - 2]); 350aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi const float angleDiff = getAngleDiff(angle1, angle2); 351aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi // Skip straight 3523811a28ddc07201930e0bbd2e1d01045b59af308Keisuke Kuroyanagi if (nearest > STRAIGHT_SKIP_NEAREST_DISTANCE_THRESHOLD 353aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi && distPrev < baseSampleRate * STRAIGHT_SKIP_DISTANCE_THRESHOLD_SCALE 354aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi && angleDiff < STRAIGHT_ANGLE_THRESHOLD) { 355aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi score += STRAIGHT_SKIP_SCORE; 356aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi } 357aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi // Save corner 358aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi if (distPrev > baseSampleRate * CORNER_CHECK_DISTANCE_THRESHOLD_SCALE 359aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi && angleDiff > CORNER_ANGLE_THRESHOLD) { 360aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi score += CORNER_SCORE; 361d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 362d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi return score; 363d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi} 364d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi 365d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi// Sampling touch point and pushing information to vectors. 366d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi// Returning if previous point is popped or not. 367096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagibool ProximityInfoState::pushTouchPoint(const int inputIndex, const int nodeChar, int x, int y, 368096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi const int time, const bool sample, const bool isLastPoint, 369d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi NearKeysDistanceMap *const currentNearKeysDistances, 370d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi const NearKeysDistanceMap *const prevNearKeysDistances, 371d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi const NearKeysDistanceMap *const prevPrevNearKeysDistances) { 372d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi static const float LAST_POINT_SKIP_DISTANCE_SCALE = 0.25f; 373d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi 374f2789819bd005b5b0581e8439601b5501306327dKen Wakasa size_t size = mInputXs.size(); 375d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi bool popped = false; 376d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi if (nodeChar < 0 && sample) { 377d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi const float nearest = updateNearKeysDistances(x, y, currentNearKeysDistances); 378d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi const float score = getPointScore(x, y, time, isLastPoint, nearest, 379d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi currentNearKeysDistances, prevNearKeysDistances, prevPrevNearKeysDistances); 380d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi if (score < 0) { 381d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi // Pop previous point because it would be useless. 382096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi popInputData(); 383d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi size = mInputXs.size(); 384d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi popped = true; 385d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } else { 386d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi popped = false; 387d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 388d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi // Check if the last point should be skipped. 389d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi if (isLastPoint) { 390d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi if (size > 0 && getDistanceFloat(x, y, mInputXs.back(), mInputYs.back()) 391d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi < mProximityInfo->getMostCommonKeyWidth() * LAST_POINT_SKIP_DISTANCE_SCALE) { 3929182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka if (DEBUG_GEO_FULL) { 3939182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka AKLOGI("p0: size = %zd, x = %d, y = %d, lx = %d, ly = %d, dist = %f, " 3949182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka "width = %f", size, x, y, mInputXs.back(), mInputYs.back(), 3959182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka getDistanceFloat(x, y, mInputXs.back(), mInputYs.back()), 3969182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka mProximityInfo->getMostCommonKeyWidth() 3979182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka * LAST_POINT_SKIP_DISTANCE_SCALE); 3989182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka } 399d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi return popped; 400d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } else if (size > 1) { 401d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi int minChar = 0; 402d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi float minDist = mMaxPointToKeyLength; 403d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi for (NearKeysDistanceMap::const_iterator it = currentNearKeysDistances->begin(); 404d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi it != currentNearKeysDistances->end(); ++it) { 405f2789819bd005b5b0581e8439601b5501306327dKen Wakasa if (minDist > it->second) { 406d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi minChar = it->first; 407d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi minDist = it->second; 408d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 409d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 410d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi NearKeysDistanceMap::const_iterator itPP = 411d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi prevNearKeysDistances->find(minChar); 412d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi if (itPP != prevNearKeysDistances->end() && minDist > itPP->second) { 413246d227c5d19549cb00a8ee84e20d09ea00e14f4Ken Wakasa if (DEBUG_GEO_FULL) { 414246d227c5d19549cb00a8ee84e20d09ea00e14f4Ken Wakasa AKLOGI("p1: char = %c, minDist = %f, prevNear key minDist = %f", 415246d227c5d19549cb00a8ee84e20d09ea00e14f4Ken Wakasa minChar, itPP->second, minDist); 416246d227c5d19549cb00a8ee84e20d09ea00e14f4Ken Wakasa } 417d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi return popped; 418d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 419d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 420d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 421d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 422d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi 423687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka if (nodeChar >= 0 && (x < 0 || y < 0)) { 424f2789819bd005b5b0581e8439601b5501306327dKen Wakasa const int keyId = mProximityInfo->getKeyIndexOf(nodeChar); 425687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka if (keyId >= 0) { 426f2789819bd005b5b0581e8439601b5501306327dKen Wakasa x = mProximityInfo->getKeyCenterXOfKeyIdG(keyId); 427f2789819bd005b5b0581e8439601b5501306327dKen Wakasa y = mProximityInfo->getKeyCenterYOfKeyIdG(keyId); 428687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka } 429687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka } 430d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi 431d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi // Pushing point information. 432d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi if (size > 0) { 433d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi mLengthCache.push_back( 434d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi mLengthCache.back() + getDistanceInt(x, y, mInputXs.back(), mInputYs.back())); 435d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } else { 436d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi mLengthCache.push_back(0); 437d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 438687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka mInputXs.push_back(x); 439687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka mInputYs.push_back(y); 440687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka mTimes.push_back(time); 441096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mInputIndice.push_back(inputIndex); 442952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka if (DEBUG_GEO_FULL) { 443952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka AKLOGI("pushTouchPoint: x = %03d, y = %03d, time = %d, index = %d, popped ? %01d", 444952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka x, y, time, inputIndex, popped); 445952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka } 446d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi return popped; 447687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka} 448687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka 4494a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataokafloat ProximityInfoState::calculateNormalizedSquaredDistance( 4504a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka const int keyIndex, const int inputIndex) const { 4514a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka if (keyIndex == NOT_AN_INDEX) { 4524a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka return NOT_A_DISTANCE_FLOAT; 4534a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka } 4544a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka if (!mProximityInfo->hasSweetSpotData(keyIndex)) { 4554a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka return NOT_A_DISTANCE_FLOAT; 4564a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka } 457687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka if (NOT_A_COORDINATE == mInputXs[inputIndex]) { 4584a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka return NOT_A_DISTANCE_FLOAT; 4594a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka } 4604a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka const float squaredDistance = calculateSquaredDistanceFromSweetSpotCenter( 4614a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka keyIndex, inputIndex); 4624a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka const float squaredRadius = square(mProximityInfo->getSweetSpotRadiiAt(keyIndex)); 4634a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka return squaredDistance / squaredRadius; 4644a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka} 4654a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka 466687a244703a02323ebd64433cbaead5def499861Satoshi Kataokaint ProximityInfoState::getDuration(const int index) const { 467a811938d40070b96557df0f2a36ba8daa561fdd4Tom Ouyang if (mInputSize > 0 && index >= 0 && index < mInputSize - 1) { 468a811938d40070b96557df0f2a36ba8daa561fdd4Tom Ouyang return mTimes[index + 1] - mTimes[index]; 469687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka } 47037b153e205c9672b299b47e97921fee2462a78bbSatoshi Kataoka return 0; 471687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka} 472687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka 4733811a28ddc07201930e0bbd2e1d01045b59af308Keisuke Kuroyanagifloat ProximityInfoState::getPointToKeyLength(const int inputIndex, const int codePoint, 4743811a28ddc07201930e0bbd2e1d01045b59af308Keisuke Kuroyanagi const float scale) const { 475f2789819bd005b5b0581e8439601b5501306327dKen Wakasa const int keyId = mProximityInfo->getKeyIndexOf(codePoint); 4768c220a0aa2c5139a3b12af20e68c420f6402294aTom Ouyang if (keyId != NOT_AN_INDEX) { 477687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const int index = inputIndex * mProximityInfo->getKeyCount() + keyId; 478687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka return min(mDistanceCache[index] * scale, mMaxPointToKeyLength); 479687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka } 4801cd7ca991961937c1a84572a6cafa3eaf5181be4Keisuke Kuroyanagi if (isSkippableChar(codePoint)) { 481cde005c05ec6b552ec26740b578be12c7d24013bSatoshi Kataoka return 0; 482cde005c05ec6b552ec26740b578be12c7d24013bSatoshi Kataoka } 4838c220a0aa2c5139a3b12af20e68c420f6402294aTom Ouyang // If the char is not a key on the keyboard then return the max length. 4848c220a0aa2c5139a3b12af20e68c420f6402294aTom Ouyang return MAX_POINT_TO_KEY_LENGTH; 485687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka} 486687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka 4873811a28ddc07201930e0bbd2e1d01045b59af308Keisuke Kuroyanagiint ProximityInfoState::getSpaceY() const { 488f2789819bd005b5b0581e8439601b5501306327dKen Wakasa const int keyId = mProximityInfo->getKeyIndexOf(' '); 489f2789819bd005b5b0581e8439601b5501306327dKen Wakasa return mProximityInfo->getKeyCenterYOfKeyIdG(keyId); 490687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka} 491687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka 4924a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataokafloat ProximityInfoState::calculateSquaredDistanceFromSweetSpotCenter( 4934a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka const int keyIndex, const int inputIndex) const { 4944a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka const float sweetSpotCenterX = mProximityInfo->getSweetSpotCenterXAt(keyIndex); 4954a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka const float sweetSpotCenterY = mProximityInfo->getSweetSpotCenterYAt(keyIndex); 496687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const float inputX = static_cast<float>(mInputXs[inputIndex]); 497687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const float inputY = static_cast<float>(mInputYs[inputIndex]); 4984a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka return square(inputX - sweetSpotCenterX) + square(inputY - sweetSpotCenterY); 4994a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka} 50095a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi 50195a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi// Puts possible characters into filter and returns new filter size. 50295a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagiint32_t ProximityInfoState::getAllPossibleChars( 50395a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi const size_t index, int32_t *const filter, const int32_t filterSize) const { 50495a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi if (index >= mInputXs.size()) { 50595a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi return filterSize; 50695a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi } 50741f12ee27b269033fe818f7d52e81ba948a046c3Keisuke Kuroyanagi int newFilterSize = filterSize; 50895a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi for (int j = 0; j < mProximityInfo->getKeyCount(); ++j) { 50995a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi if (mNearKeysVector[index].test(j)) { 51095a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi const int32_t keyCodePoint = mProximityInfo->getCodePointOf(j); 51195a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi bool insert = true; 51295a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi // TODO: Avoid linear search 51395a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi for (int k = 0; k < filterSize; ++k) { 51495a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi if (filter[k] == keyCodePoint) { 51595a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi insert = false; 51695a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi break; 51795a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi } 51895a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi } 51995a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi if (insert) { 52041f12ee27b269033fe818f7d52e81ba948a046c3Keisuke Kuroyanagi filter[newFilterSize++] = keyCodePoint; 52195a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi } 52295a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi } 52395a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi } 52441f12ee27b269033fe818f7d52e81ba948a046c3Keisuke Kuroyanagi return newFilterSize; 52595a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi} 5263811a28ddc07201930e0bbd2e1d01045b59af308Keisuke Kuroyanagi 5273811a28ddc07201930e0bbd2e1d01045b59af308Keisuke Kuroyanagifloat ProximityInfoState::getAveragePointDuration() const { 5283811a28ddc07201930e0bbd2e1d01045b59af308Keisuke Kuroyanagi if (mInputSize == 0) { 529aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi return 0.0f; 5303811a28ddc07201930e0bbd2e1d01045b59af308Keisuke Kuroyanagi } 531aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi return static_cast<float>(mTimes[mInputSize - 1] - mTimes[0]) / static_cast<float>(mInputSize); 5323811a28ddc07201930e0bbd2e1d01045b59af308Keisuke Kuroyanagi} 5333811a28ddc07201930e0bbd2e1d01045b59af308Keisuke Kuroyanagi 534096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagivoid ProximityInfoState::popInputData() { 535096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mInputXs.pop_back(); 536096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mInputYs.pop_back(); 537096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mTimes.pop_back(); 538096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mLengthCache.pop_back(); 539096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mInputIndice.pop_back(); 540096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi} 541096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi 5423e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka} // namespace latinime 543