proximity_info_state.cpp revision 1e61493c50082264caaef862df02b1ccc84dc396
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() 18806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi#include <sstream> // for debug prints 193e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka#include <stdint.h> 203e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka 213e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka#define LOG_TAG "LatinIME: proximity_info_state.cpp" 223e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka 233e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka#include "defines.h" 24687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka#include "geometry_utils.h" 253e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka#include "proximity_info.h" 263e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka#include "proximity_info_state.h" 273e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka 283e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataokanamespace latinime { 29764dd712032d7b8012797b1116b523bef7b907f3Ken Wakasa 30764dd712032d7b8012797b1116b523bef7b907f3Ken Wakasaconst int ProximityInfoState::NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR_LOG_2 = 10; 31764dd712032d7b8012797b1116b523bef7b907f3Ken Wakasaconst int ProximityInfoState::NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR = 32764dd712032d7b8012797b1116b523bef7b907f3Ken Wakasa 1 << NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR_LOG_2; 33764dd712032d7b8012797b1116b523bef7b907f3Ken Wakasaconst float ProximityInfoState::NOT_A_DISTANCE_FLOAT = -1.0f; 34764dd712032d7b8012797b1116b523bef7b907f3Ken Wakasaconst int ProximityInfoState::NOT_A_CODE = -1; 35764dd712032d7b8012797b1116b523bef7b907f3Ken Wakasa 36233aad5e5c7567a97af30f38f50a65365f729dfeSatoshi Kataokavoid ProximityInfoState::initInputParams(const int pointerId, const float maxPointToKeyLength, 371e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa const ProximityInfo *proximityInfo, const int *const inputCodes, const int inputSize, 38687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const int *const xCoordinates, const int *const yCoordinates, const int *const times, 39687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const int *const pointerIds, const bool isGeometric) { 40096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi 41096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi if (isGeometric) { 42096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mIsContinuationPossible = checkAndReturnIsContinuationPossible( 43096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi inputSize, xCoordinates, yCoordinates, times); 44096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi } else { 45096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mIsContinuationPossible = false; 46096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi } 47096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi 484a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka mProximityInfo = proximityInfo; 494a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka mHasTouchPositionCorrectionData = proximityInfo->hasTouchPositionCorrectionData(); 504a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka mMostCommonKeyWidthSquare = proximityInfo->getMostCommonKeyWidthSquare(); 514a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka mLocaleStr = proximityInfo->getLocaleStr(); 524a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka mKeyCount = proximityInfo->getKeyCount(); 534a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka mCellHeight = proximityInfo->getCellHeight(); 544a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka mCellWidth = proximityInfo->getCellWidth(); 554a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka mGridHeight = proximityInfo->getGridWidth(); 564a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka mGridWidth = proximityInfo->getGridHeight(); 573e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka 5808f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka memset(mInputCodes, 0, sizeof(mInputCodes)); 593e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka 6008f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka if (!isGeometric && pointerId == 0) { 6108f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka // Initialize 6208f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka // - mInputCodes 6308f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka // - mNormalizedSquaredDistances 6408f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka // TODO: Merge 65687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka for (int i = 0; i < inputSize; ++i) { 661e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa const int primaryKey = inputCodes[i]; 6708f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka const int x = xCoordinates[i]; 6808f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka const int y = yCoordinates[i]; 6908f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka int *proximities = &mInputCodes[i * MAX_PROXIMITY_CHARS_SIZE_INTERNAL]; 7008f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka mProximityInfo->calculateNearbyKeyCodes(x, y, primaryKey, proximities); 7108f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka } 7208f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka 7308f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka if (DEBUG_PROXIMITY_CHARS) { 7408f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka for (int i = 0; i < inputSize; ++i) { 7508f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka AKLOGI("---"); 7608f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka for (int j = 0; j < MAX_PROXIMITY_CHARS_SIZE_INTERNAL; ++j) { 7708f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka int icc = mInputCodes[i * MAX_PROXIMITY_CHARS_SIZE_INTERNAL + j]; 7808f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka int icfjc = inputCodes[i * MAX_PROXIMITY_CHARS_SIZE_INTERNAL + j]; 7908f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka icc += 0; 8008f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka icfjc += 0; 8108f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka AKLOGI("--- (%d)%c,%c", i, icc, icfjc); AKLOGI("--- A<%d>,B<%d>", icc, icfjc); 8208f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka } 833e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka } 843e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka } 853e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka } 86687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka 87687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka /////////////////////// 88687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka // Setup touch points 89096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi int pushTouchPointStartIndex = 0; 90096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi int lastSavedInputSize = 0; 9108f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka mMaxPointToKeyLength = maxPointToKeyLength; 92096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi if (mIsContinuationPossible && mInputIndice.size() > 1) { 93096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi // Just update difference. 94096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi // Two points prior is never skipped. Thus, we pop 2 input point data here. 95096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi pushTouchPointStartIndex = mInputIndice[mInputIndice.size() - 2]; 96096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi popInputData(); 97096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi popInputData(); 98096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi lastSavedInputSize = mInputXs.size(); 99096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi } else { 100096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi // Clear all data. 101096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mInputXs.clear(); 102096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mInputYs.clear(); 103096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mTimes.clear(); 104096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mInputIndice.clear(); 105096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mLengthCache.clear(); 106096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mDistanceCache.clear(); 107096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mNearKeysVector.clear(); 108ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi mSearchKeysVector.clear(); 10928661069591fd1d6a8e25981aaade2e5d8b20b9aKeisuke Kuroyanagi mRelativeSpeeds.clear(); 110806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi mCharProbabilities.clear(); 1111e06a4d8e9e71188ed685282155ea52a48ddc050Keisuke Kuroyanagi mDirections.clear(); 112096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi } 1139182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka if (DEBUG_GEO_FULL) { 1149182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka AKLOGI("Init ProximityInfoState: reused points = %d, last input size = %d", 1159182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka pushTouchPointStartIndex, lastSavedInputSize); 1169182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka } 117687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka mInputSize = 0; 118d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi 119687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka if (xCoordinates && yCoordinates) { 120687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const bool proximityOnly = !isGeometric && (xCoordinates[0] < 0 || yCoordinates[0] < 0); 121096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi int lastInputIndex = pushTouchPointStartIndex; 122096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi for (int i = lastInputIndex; i < inputSize; ++i) { 123d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi const int pid = pointerIds ? pointerIds[i] : 0; 124d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi if (pointerId == pid) { 125d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi lastInputIndex = i; 126d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 127d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 1289182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka if (DEBUG_GEO_FULL) { 1299182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka AKLOGI("Init ProximityInfoState: last input index = %d", lastInputIndex); 1309182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka } 131d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi // Working space to save near keys distances for current, prev and prevprev input point. 132d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi NearKeysDistanceMap nearKeysDistances[3]; 133d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi // These pointers are swapped for each inputs points. 134d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi NearKeysDistanceMap *currentNearKeysDistances = &nearKeysDistances[0]; 135d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi NearKeysDistanceMap *prevNearKeysDistances = &nearKeysDistances[1]; 136d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi NearKeysDistanceMap *prevPrevNearKeysDistances = &nearKeysDistances[2]; 137ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // "sumAngle" is accumulated by each angle of input points. And when "sumAngle" exceeds 138ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // the threshold we save that point, reset sumAngle. This aims to keep the figure of 139ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // the curve. 140ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi float sumAngle = 0.0f; 141d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi 142096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi for (int i = pushTouchPointStartIndex; i <= lastInputIndex; ++i) { 143687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka // Assuming pointerId == 0 if pointerIds is null. 144687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const int pid = pointerIds ? pointerIds[i] : 0; 1459182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka if (DEBUG_GEO_FULL) { 1469182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka AKLOGI("Init ProximityInfoState: (%d)PID = %d", i, pid); 1479182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka } 148687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka if (pointerId == pid) { 1491e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa const int c = isGeometric ? NOT_A_COORDINATE : getPrimaryCodePointAt(i); 150687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const int x = proximityOnly ? NOT_A_COORDINATE : xCoordinates[i]; 151687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const int y = proximityOnly ? NOT_A_COORDINATE : yCoordinates[i]; 152687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const int time = times ? times[i] : -1; 153ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 154ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (i > 1) { 155ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float prevAngle = getAngle(xCoordinates[i - 2], yCoordinates[i - 2], 156ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi xCoordinates[i - 1], yCoordinates[i - 1]); 157ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float currentAngle = 158ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi getAngle(xCoordinates[i - 1], yCoordinates[i - 1], x, y); 159ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi sumAngle += getAngleDiff(prevAngle, currentAngle); 160ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 161ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 162952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka if (pushTouchPoint(i, c, x, y, time, isGeometric /* do sampling */, 163ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi i == lastInputIndex, sumAngle, currentNearKeysDistances, 164ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi prevNearKeysDistances, prevPrevNearKeysDistances)) { 165d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi // Previous point information was popped. 166d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi NearKeysDistanceMap *tmp = prevNearKeysDistances; 167d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi prevNearKeysDistances = currentNearKeysDistances; 168d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi currentNearKeysDistances = tmp; 169d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } else { 170d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi NearKeysDistanceMap *tmp = prevPrevNearKeysDistances; 171d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi prevPrevNearKeysDistances = prevNearKeysDistances; 172d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi prevNearKeysDistances = currentNearKeysDistances; 173d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi currentNearKeysDistances = tmp; 174ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi sumAngle = 0.0f; 17537b153e205c9672b299b47e97921fee2462a78bbSatoshi Kataoka } 176687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka } 177687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka } 178d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi mInputSize = mInputXs.size(); 1793e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka } 180687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka 18128661069591fd1d6a8e25981aaade2e5d8b20b9aKeisuke Kuroyanagi if (mInputSize > 0 && isGeometric) { 182ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // Relative speed calculation. 183806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi const int sumDuration = mTimes.back() - mTimes.front(); 184806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi const int sumLength = mLengthCache.back() - mLengthCache.front(); 185806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi const float averageSpeed = static_cast<float>(sumLength) / static_cast<float>(sumDuration); 18628661069591fd1d6a8e25981aaade2e5d8b20b9aKeisuke Kuroyanagi mRelativeSpeeds.resize(mInputSize); 18728661069591fd1d6a8e25981aaade2e5d8b20b9aKeisuke Kuroyanagi for (int i = lastSavedInputSize; i < mInputSize; ++i) { 18828661069591fd1d6a8e25981aaade2e5d8b20b9aKeisuke Kuroyanagi const int index = mInputIndice[i]; 18928661069591fd1d6a8e25981aaade2e5d8b20b9aKeisuke Kuroyanagi int length = 0; 19028661069591fd1d6a8e25981aaade2e5d8b20b9aKeisuke Kuroyanagi int duration = 0; 191806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi 192806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi // Calculate velocity by using distances and durations of 193806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi // NUM_POINTS_FOR_SPEED_CALCULATION points for both forward and backward. 194ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const int NUM_POINTS_FOR_SPEED_CALCULATION = 2; 195806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi for (int j = index; j < min(inputSize - 1, index + NUM_POINTS_FOR_SPEED_CALCULATION); 196806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi ++j) { 197806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi if (i < mInputSize - 1 && j >= mInputIndice[i + 1]) { 198806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi break; 199806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 200806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi length += getDistanceInt(xCoordinates[j], yCoordinates[j], 201806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi xCoordinates[j + 1], yCoordinates[j + 1]); 202806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi duration += times[j + 1] - times[j]; 203806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 204806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi for (int j = index - 1; j >= max(0, index - NUM_POINTS_FOR_SPEED_CALCULATION); --j) { 205806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi if (i > 0 && j < mInputIndice[i - 1]) { 206806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi break; 207806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 208806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi length += getDistanceInt(xCoordinates[j], yCoordinates[j], 209806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi xCoordinates[j + 1], yCoordinates[j + 1]); 210806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi duration += times[j + 1] - times[j]; 211806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 212806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi if (duration == 0 || sumDuration == 0) { 213806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi // Cannot calculate speed; thus, it gives an average value (1.0); 214806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi mRelativeSpeeds[i] = 1.0f; 21528661069591fd1d6a8e25981aaade2e5d8b20b9aKeisuke Kuroyanagi } else { 216806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi const float speed = static_cast<float>(length) / static_cast<float>(duration); 217806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi mRelativeSpeeds[i] = speed / averageSpeed; 21828661069591fd1d6a8e25981aaade2e5d8b20b9aKeisuke Kuroyanagi } 21928661069591fd1d6a8e25981aaade2e5d8b20b9aKeisuke Kuroyanagi } 2201e06a4d8e9e71188ed685282155ea52a48ddc050Keisuke Kuroyanagi 2211e06a4d8e9e71188ed685282155ea52a48ddc050Keisuke Kuroyanagi // Direction calculation. 2221e06a4d8e9e71188ed685282155ea52a48ddc050Keisuke Kuroyanagi mDirections.resize(mInputSize - 1); 2231e06a4d8e9e71188ed685282155ea52a48ddc050Keisuke Kuroyanagi for (int i = max(0, lastSavedInputSize - 1); i < mInputSize - 1; ++i) { 2241e06a4d8e9e71188ed685282155ea52a48ddc050Keisuke Kuroyanagi mDirections[i] = getDirection(i, i + 1); 2251e06a4d8e9e71188ed685282155ea52a48ddc050Keisuke Kuroyanagi } 2261e06a4d8e9e71188ed685282155ea52a48ddc050Keisuke Kuroyanagi 22728661069591fd1d6a8e25981aaade2e5d8b20b9aKeisuke Kuroyanagi } 22828661069591fd1d6a8e25981aaade2e5d8b20b9aKeisuke Kuroyanagi 229ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (DEBUG_GEO_FULL) { 230ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi for (int i = 0; i < mInputSize; ++i) { 231ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi AKLOGI("Sampled(%d): x = %d, y = %d, time = %d", i, mInputXs[i], mInputYs[i], 232ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi mTimes[i]); 233ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 234ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 235ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 236687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka if (mInputSize > 0) { 237687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const int keyCount = mProximityInfo->getKeyCount(); 23895a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi mNearKeysVector.resize(mInputSize); 239ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi mSearchKeysVector.resize(mInputSize); 240687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka mDistanceCache.resize(mInputSize * keyCount); 241096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi for (int i = lastSavedInputSize; i < mInputSize; ++i) { 24295a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi mNearKeysVector[i].reset(); 243ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi mSearchKeysVector[i].reset(); 24495a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi static const float NEAR_KEY_NORMALIZED_SQUARED_THRESHOLD = 4.0f; 245687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka for (int k = 0; k < keyCount; ++k) { 246687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const int index = i * keyCount + k; 247687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const int x = mInputXs[i]; 248687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const int y = mInputYs[i]; 24995a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi const float normalizedSquaredDistance = 2500edab9d2fcc30667c79aa9221dbb27f042d8b455Satoshi Kataoka mProximityInfo->getNormalizedSquaredDistanceFromCenterFloatG(k, x, y); 25195a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi mDistanceCache[index] = normalizedSquaredDistance; 25295a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi if (normalizedSquaredDistance < NEAR_KEY_NORMALIZED_SQUARED_THRESHOLD) { 253ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi mNearKeysVector[i][k] = true; 25495a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi } 25595a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi } 25695a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi } 257ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (isGeometric) { 258ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // updates probabilities of skipping or mapping each key for all points. 259ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi updateAlignPointProbabilities(lastSavedInputSize); 260ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 261ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float READ_FORWORD_LENGTH_SCALE = 0.95f; 262ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const int readForwordLength = static_cast<int>( 263ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi hypotf(mProximityInfo->getKeyboardWidth(), mProximityInfo->getKeyboardHeight()) 264ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi * READ_FORWORD_LENGTH_SCALE); 265ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi for (int i = 0; i < mInputSize; ++i) { 266ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (i >= lastSavedInputSize) { 267ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi mSearchKeysVector[i].reset(); 268ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 269ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi for (int j = max(i, lastSavedInputSize); j < mInputSize; ++j) { 270ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (mLengthCache[j] - mLengthCache[i] >= readForwordLength) { 271ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi break; 272ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 273ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi mSearchKeysVector[i] |= mNearKeysVector[j]; 27495a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi } 275687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka } 276687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka } 277687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka } 27808f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka 279806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi if (DEBUG_SAMPLING_POINTS) { 280806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi std::stringstream originalX, originalY, sampledX, sampledY; 281806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi for (int i = 0; i < inputSize; ++i) { 282806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi originalX << xCoordinates[i]; 283806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi originalY << yCoordinates[i]; 284806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi if (i != inputSize - 1) { 285806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi originalX << ";"; 286806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi originalY << ";"; 287806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 288806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 289806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi for (int i = 0; i < mInputSize; ++i) { 290806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi sampledX << mInputXs[i]; 291806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi sampledY << mInputYs[i]; 292806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi if (i != mInputSize - 1) { 293806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi sampledX << ";"; 294806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi sampledY << ";"; 295806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 296806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 297806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi AKLOGI("\n%s, %s,\n%s, %s,\n", originalX.str().c_str(), originalY.str().c_str(), 298806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi sampledX.str().c_str(), sampledY.str().c_str()); 299806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 300687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka // end 301687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka /////////////////////// 302687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka 30308f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka memset(mNormalizedSquaredDistances, NOT_A_DISTANCE, sizeof(mNormalizedSquaredDistances)); 30408f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka memset(mPrimaryInputWord, 0, sizeof(mPrimaryInputWord)); 305233aad5e5c7567a97af30f38f50a65365f729dfeSatoshi Kataoka mTouchPositionCorrectionEnabled = mInputSize > 0 && mHasTouchPositionCorrectionData 3060edab9d2fcc30667c79aa9221dbb27f042d8b455Satoshi Kataoka && xCoordinates && yCoordinates; 30708f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka if (!isGeometric && pointerId == 0) { 30808f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka for (int i = 0; i < inputSize; ++i) { 3091e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa mPrimaryInputWord[i] = getPrimaryCodePointAt(i); 3103e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka } 31108f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka 31208f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka for (int i = 0; i < mInputSize && mTouchPositionCorrectionEnabled; ++i) { 3131e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa const int *proximityCodePoints = getProximityCodePointsAt(i); 3141e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa const int primaryKey = proximityCodePoints[0]; 31508f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka const int x = xCoordinates[i]; 31608f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka const int y = yCoordinates[i]; 3173e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka if (DEBUG_PROXIMITY_CHARS) { 31808f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka int a = x + y + primaryKey; 31908f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka a += 0; 32008f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka AKLOGI("--- Primary = %c, x = %d, y = %d", primaryKey, x, y); 32108f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka } 3221e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa for (int j = 0; j < MAX_PROXIMITY_CHARS_SIZE_INTERNAL && proximityCodePoints[j] > 0; 3231e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa ++j) { 3241e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa const int currentCodePoint = proximityCodePoints[j]; 32508f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka const float squaredDistance = 32608f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka hasInputCoordinates() ? calculateNormalizedSquaredDistance( 3271e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa mProximityInfo->getKeyIndexOf(currentCodePoint), i) : 32808f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka NOT_A_DISTANCE_FLOAT; 32908f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka if (squaredDistance >= 0.0f) { 33008f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka mNormalizedSquaredDistances[i * MAX_PROXIMITY_CHARS_SIZE_INTERNAL + j] = 33108f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka (int) (squaredDistance * NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR); 33208f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka } else { 33308f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka mNormalizedSquaredDistances[i * MAX_PROXIMITY_CHARS_SIZE_INTERNAL + j] = 33408f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka (j == 0) ? EQUIVALENT_CHAR_WITHOUT_DISTANCE_INFO : 33508f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka PROXIMITY_CHAR_WITHOUT_DISTANCE_INFO; 33608f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka } 33708f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka if (DEBUG_PROXIMITY_CHARS) { 3381e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa AKLOGI("--- Proximity (%d) = %c", j, currentCodePoint); 33908f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka } 3403e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka } 3413e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka } 3423e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka } 343952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka 344952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka if (DEBUG_GEO_FULL) { 345952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka AKLOGI("ProximityState init finished: %d points out of %d", mInputSize, inputSize); 346952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka } 3473e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka} 3484a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka 349096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagibool ProximityInfoState::checkAndReturnIsContinuationPossible(const int inputSize, 350096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi const int *const xCoordinates, const int *const yCoordinates, const int *const times) { 351096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi for (int i = 0; i < mInputSize; ++i) { 352096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi const int index = mInputIndice[i]; 353096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi if (index > inputSize || xCoordinates[index] != mInputXs[i] || 354096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi yCoordinates[index] != mInputYs[i] || times[index] != mTimes[i]) { 355096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi return false; 356096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi } 357096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi } 358096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi return true; 359096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi} 360096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi 361d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi// Calculating point to key distance for all near keys and returning the distance between 362d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi// the given point and the nearest key position. 363d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagifloat ProximityInfoState::updateNearKeysDistances(const int x, const int y, 364d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi NearKeysDistanceMap *const currentNearKeysDistances) { 365ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float NEAR_KEY_THRESHOLD = 2.0f; 366d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi 367d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi currentNearKeysDistances->clear(); 368d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi const int keyCount = mProximityInfo->getKeyCount(); 369d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi float nearestKeyDistance = mMaxPointToKeyLength; 370d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi for (int k = 0; k < keyCount; ++k) { 3710edab9d2fcc30667c79aa9221dbb27f042d8b455Satoshi Kataoka const float dist = mProximityInfo->getNormalizedSquaredDistanceFromCenterFloatG(k, x, y); 372d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi if (dist < NEAR_KEY_THRESHOLD) { 373d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi currentNearKeysDistances->insert(std::pair<int, float>(k, dist)); 374687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka } 375d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi if (nearestKeyDistance > dist) { 376d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi nearestKeyDistance = dist; 377d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 378d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 379d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi return nearestKeyDistance; 380d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi} 381d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi 382d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi// Check if previous point is at local minimum position to near keys. 383d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagibool ProximityInfoState::isPrevLocalMin(const NearKeysDistanceMap *const currentNearKeysDistances, 384d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi const NearKeysDistanceMap *const prevNearKeysDistances, 385d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi const NearKeysDistanceMap *const prevPrevNearKeysDistances) const { 386ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float MARGIN = 0.01f; 387d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi 388d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi for (NearKeysDistanceMap::const_iterator it = prevNearKeysDistances->begin(); 389d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi it != prevNearKeysDistances->end(); ++it) { 390d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi NearKeysDistanceMap::const_iterator itPP = prevPrevNearKeysDistances->find(it->first); 391d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi NearKeysDistanceMap::const_iterator itC = currentNearKeysDistances->find(it->first); 392d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi if ((itPP == prevPrevNearKeysDistances->end() || itPP->second > it->second + MARGIN) 393d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi && (itC == currentNearKeysDistances->end() || itC->second > it->second + MARGIN)) { 394d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi return true; 395d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 396d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 397d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi return false; 398d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi} 399d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi 400d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi// Calculating a point score that indicates usefulness of the point. 401d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagifloat ProximityInfoState::getPointScore( 402d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi const int x, const int y, const int time, const bool lastPoint, const float nearest, 403ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float sumAngle, const NearKeysDistanceMap *const currentNearKeysDistances, 404d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi const NearKeysDistanceMap *const prevNearKeysDistances, 405d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi const NearKeysDistanceMap *const prevPrevNearKeysDistances) const { 40603dc8fe141fa9f6fa5fe8362d9d35b3f3c954b87Ken Wakasa static const int DISTANCE_BASE_SCALE = 100; 407ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float NEAR_KEY_THRESHOLD = 0.6f; 408ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const int CORNER_CHECK_DISTANCE_THRESHOLD_SCALE = 25; 409806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi static const float NOT_LOCALMIN_DISTANCE_SCORE = -1.0f; 410ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float LOCALMIN_DISTANCE_AND_NEAR_TO_KEY_SCORE = 1.0f; 411ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float CORNER_ANGLE_THRESHOLD = M_PI_F * 2.0f / 3.0f; 412ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float CORNER_SUM_ANGLE_THRESHOLD = M_PI_F / 4.0f; 413aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi static const float CORNER_SCORE = 1.0f; 414d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi 415ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const size_t size = mInputXs.size(); 416ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // If there is only one point, add this point. Besides, if the previous point's distance map 417ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // is empty, we re-compute nearby keys distances from the current point. 418ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // Note that the current point is the first point in the incremental input that needs to 419ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // be re-computed. 420ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (size <= 1 || prevNearKeysDistances->empty()) { 42103dc8fe141fa9f6fa5fe8362d9d35b3f3c954b87Ken Wakasa return 0.0f; 422687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka } 423ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 42403dc8fe141fa9f6fa5fe8362d9d35b3f3c954b87Ken Wakasa const int baseSampleRate = mProximityInfo->getMostCommonKeyWidth(); 42503dc8fe141fa9f6fa5fe8362d9d35b3f3c954b87Ken Wakasa const int distPrev = getDistanceInt(mInputXs.back(), mInputYs.back(), 42603dc8fe141fa9f6fa5fe8362d9d35b3f3c954b87Ken Wakasa mInputXs[size - 2], mInputYs[size - 2]) * DISTANCE_BASE_SCALE; 427d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi float score = 0.0f; 428d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi 429d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi // Location 430ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (!isPrevLocalMin(currentNearKeysDistances, prevNearKeysDistances, 431ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi prevPrevNearKeysDistances)) { 432ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi score += NOT_LOCALMIN_DISTANCE_SCORE; 433ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } else if (nearest < NEAR_KEY_THRESHOLD) { 434ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // Promote points nearby keys 435ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi score += LOCALMIN_DISTANCE_AND_NEAR_TO_KEY_SCORE; 436d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 437d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi // Angle 438aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi const float angle1 = getAngle(x, y, mInputXs.back(), mInputYs.back()); 439aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi const float angle2 = getAngle(mInputXs.back(), mInputYs.back(), 440aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi mInputXs[size - 2], mInputYs[size - 2]); 441aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi const float angleDiff = getAngleDiff(angle1, angle2); 442ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 443aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi // Save corner 444aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi if (distPrev > baseSampleRate * CORNER_CHECK_DISTANCE_THRESHOLD_SCALE 445ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi && (sumAngle > CORNER_SUM_ANGLE_THRESHOLD || angleDiff > CORNER_ANGLE_THRESHOLD)) { 446aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi score += CORNER_SCORE; 447d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 448d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi return score; 449d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi} 450d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi 451d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi// Sampling touch point and pushing information to vectors. 452d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi// Returning if previous point is popped or not. 4531e61493c50082264caaef862df02b1ccc84dc396Ken Wakasabool ProximityInfoState::pushTouchPoint(const int inputIndex, const int nodeCodePoint, int x, int y, 454ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const int time, const bool sample, const bool isLastPoint, const float sumAngle, 455d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi NearKeysDistanceMap *const currentNearKeysDistances, 456d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi const NearKeysDistanceMap *const prevNearKeysDistances, 457d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi const NearKeysDistanceMap *const prevPrevNearKeysDistances) { 458806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi static const int LAST_POINT_SKIP_DISTANCE_SCALE = 4; 459d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi 460f2789819bd005b5b0581e8439601b5501306327dKen Wakasa size_t size = mInputXs.size(); 461d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi bool popped = false; 4621e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa if (nodeCodePoint < 0 && sample) { 463d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi const float nearest = updateNearKeysDistances(x, y, currentNearKeysDistances); 464ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float score = getPointScore(x, y, time, isLastPoint, nearest, sumAngle, 465d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi currentNearKeysDistances, prevNearKeysDistances, prevPrevNearKeysDistances); 466d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi if (score < 0) { 467d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi // Pop previous point because it would be useless. 468096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi popInputData(); 469d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi size = mInputXs.size(); 470d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi popped = true; 471d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } else { 472d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi popped = false; 473d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 474d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi // Check if the last point should be skipped. 475806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi if (isLastPoint && size > 0) { 476ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (getDistanceInt(x, y, mInputXs.back(), mInputYs.back()) 477ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi * LAST_POINT_SKIP_DISTANCE_SCALE < mProximityInfo->getMostCommonKeyWidth()) { 478806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi // This point is not used because it's too close to the previous point. 4799182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka if (DEBUG_GEO_FULL) { 480806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi AKLOGI("p0: size = %zd, x = %d, y = %d, lx = %d, ly = %d, dist = %d, " 481806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi "width = %d", size, x, y, mInputXs.back(), mInputYs.back(), 482806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi getDistanceInt(x, y, mInputXs.back(), mInputYs.back()), 4839182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka mProximityInfo->getMostCommonKeyWidth() 484806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi / LAST_POINT_SKIP_DISTANCE_SCALE); 4859182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka } 486d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi return popped; 487d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 488d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 489d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 490d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi 4911e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa if (nodeCodePoint >= 0 && (x < 0 || y < 0)) { 4921e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa const int keyId = mProximityInfo->getKeyIndexOf(nodeCodePoint); 493687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka if (keyId >= 0) { 494f2789819bd005b5b0581e8439601b5501306327dKen Wakasa x = mProximityInfo->getKeyCenterXOfKeyIdG(keyId); 495f2789819bd005b5b0581e8439601b5501306327dKen Wakasa y = mProximityInfo->getKeyCenterYOfKeyIdG(keyId); 496687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka } 497687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka } 498d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi 499d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi // Pushing point information. 500d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi if (size > 0) { 501d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi mLengthCache.push_back( 502d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi mLengthCache.back() + getDistanceInt(x, y, mInputXs.back(), mInputYs.back())); 503d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } else { 504d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi mLengthCache.push_back(0); 505d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 506687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka mInputXs.push_back(x); 507687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka mInputYs.push_back(y); 508687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka mTimes.push_back(time); 509096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mInputIndice.push_back(inputIndex); 510952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka if (DEBUG_GEO_FULL) { 511952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka AKLOGI("pushTouchPoint: x = %03d, y = %03d, time = %d, index = %d, popped ? %01d", 512952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka x, y, time, inputIndex, popped); 513952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka } 514d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi return popped; 515687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka} 516687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka 5174a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataokafloat ProximityInfoState::calculateNormalizedSquaredDistance( 5184a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka const int keyIndex, const int inputIndex) const { 5194a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka if (keyIndex == NOT_AN_INDEX) { 5204a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka return NOT_A_DISTANCE_FLOAT; 5214a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka } 5224a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka if (!mProximityInfo->hasSweetSpotData(keyIndex)) { 5234a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka return NOT_A_DISTANCE_FLOAT; 5244a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka } 525687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka if (NOT_A_COORDINATE == mInputXs[inputIndex]) { 5264a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka return NOT_A_DISTANCE_FLOAT; 5274a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka } 5284a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka const float squaredDistance = calculateSquaredDistanceFromSweetSpotCenter( 5294a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka keyIndex, inputIndex); 5304a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka const float squaredRadius = square(mProximityInfo->getSweetSpotRadiiAt(keyIndex)); 5314a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka return squaredDistance / squaredRadius; 5324a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka} 5334a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka 534687a244703a02323ebd64433cbaead5def499861Satoshi Kataokaint ProximityInfoState::getDuration(const int index) const { 53528661069591fd1d6a8e25981aaade2e5d8b20b9aKeisuke Kuroyanagi if (index >= 0 && index < mInputSize - 1) { 536a811938d40070b96557df0f2a36ba8daa561fdd4Tom Ouyang return mTimes[index + 1] - mTimes[index]; 537687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka } 53837b153e205c9672b299b47e97921fee2462a78bbSatoshi Kataoka return 0; 539687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka} 540687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka 541806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagifloat ProximityInfoState::getPointToKeyLength(const int inputIndex, const int codePoint) const { 542ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const int keyId = mProximityInfo->getKeyIndexOf(codePoint); 543ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (keyId != NOT_AN_INDEX) { 544ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const int index = inputIndex * mProximityInfo->getKeyCount() + keyId; 545ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi return min(mDistanceCache[index], mMaxPointToKeyLength); 546ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 5471e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa if (isSkippableCodePoint(codePoint)) { 548806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi return 0.0f; 549806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 550ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // If the char is not a key on the keyboard then return the max length. 551ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi return MAX_POINT_TO_KEY_LENGTH; 552806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi} 553806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi 554806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagifloat ProximityInfoState::getPointToKeyByIdLength(const int inputIndex, const int keyId) const { 5558c220a0aa2c5139a3b12af20e68c420f6402294aTom Ouyang if (keyId != NOT_AN_INDEX) { 556687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const int index = inputIndex * mProximityInfo->getKeyCount() + keyId; 557806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi return min(mDistanceCache[index], mMaxPointToKeyLength); 558cde005c05ec6b552ec26740b578be12c7d24013bSatoshi Kataoka } 5598c220a0aa2c5139a3b12af20e68c420f6402294aTom Ouyang // If the char is not a key on the keyboard then return the max length. 560806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi return static_cast<float>(MAX_POINT_TO_KEY_LENGTH); 561687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka} 562687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka 5633811a28ddc07201930e0bbd2e1d01045b59af308Keisuke Kuroyanagiint ProximityInfoState::getSpaceY() const { 564b02ee3d67a1884b6ff59cc16c29a476845c0694fKen Wakasa const int keyId = mProximityInfo->getKeyIndexOf(KEYCODE_SPACE); 565f2789819bd005b5b0581e8439601b5501306327dKen Wakasa return mProximityInfo->getKeyCenterYOfKeyIdG(keyId); 566687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka} 567687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka 5684a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataokafloat ProximityInfoState::calculateSquaredDistanceFromSweetSpotCenter( 5694a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka const int keyIndex, const int inputIndex) const { 5704a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka const float sweetSpotCenterX = mProximityInfo->getSweetSpotCenterXAt(keyIndex); 5714a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka const float sweetSpotCenterY = mProximityInfo->getSweetSpotCenterYAt(keyIndex); 572687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const float inputX = static_cast<float>(mInputXs[inputIndex]); 573687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const float inputY = static_cast<float>(mInputYs[inputIndex]); 5744a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka return square(inputX - sweetSpotCenterX) + square(inputY - sweetSpotCenterY); 5754a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka} 57695a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi 57795a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi// Puts possible characters into filter and returns new filter size. 57895a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagiint32_t ProximityInfoState::getAllPossibleChars( 57995a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi const size_t index, int32_t *const filter, const int32_t filterSize) const { 58095a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi if (index >= mInputXs.size()) { 58195a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi return filterSize; 58295a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi } 58341f12ee27b269033fe818f7d52e81ba948a046c3Keisuke Kuroyanagi int newFilterSize = filterSize; 584ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const int keyCount = mProximityInfo->getKeyCount(); 585ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi for (int j = 0; j < keyCount; ++j) { 586ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (mSearchKeysVector[index].test(j)) { 58795a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi const int32_t keyCodePoint = mProximityInfo->getCodePointOf(j); 58895a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi bool insert = true; 58995a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi // TODO: Avoid linear search 59095a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi for (int k = 0; k < filterSize; ++k) { 59195a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi if (filter[k] == keyCodePoint) { 59295a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi insert = false; 59395a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi break; 59495a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi } 59595a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi } 59695a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi if (insert) { 59741f12ee27b269033fe818f7d52e81ba948a046c3Keisuke Kuroyanagi filter[newFilterSize++] = keyCodePoint; 59895a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi } 59995a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi } 60095a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi } 60141f12ee27b269033fe818f7d52e81ba948a046c3Keisuke Kuroyanagi return newFilterSize; 60295a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi} 6033811a28ddc07201930e0bbd2e1d01045b59af308Keisuke Kuroyanagi 604ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagibool ProximityInfoState::isKeyInSerchKeysAfterIndex(const int index, const int keyId) const { 605ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi ASSERT(keyId >= 0); 606ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi ASSERT(index >= 0 && index < mInputSize); 607ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi return mSearchKeysVector[index].test(keyId); 608ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi} 609ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 610096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagivoid ProximityInfoState::popInputData() { 611096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mInputXs.pop_back(); 612096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mInputYs.pop_back(); 613096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mTimes.pop_back(); 614096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mLengthCache.pop_back(); 615096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mInputIndice.pop_back(); 616096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi} 617096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi 618ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagifloat ProximityInfoState::getDirection(const int index0, const int index1) const { 619ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (index0 < 0 || index0 > mInputSize - 1) { 620ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi return 0.0f; 621ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 622ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (index1 < 0 || index1 > mInputSize - 1) { 623ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi return 0.0f; 624ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 625ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const int x1 = mInputXs[index0]; 626ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const int y1 = mInputYs[index0]; 627ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const int x2 = mInputXs[index1]; 628ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const int y2 = mInputYs[index1]; 629ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi return getAngle(x1, y1, x2, y2); 630ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi} 631ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 632806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagifloat ProximityInfoState::getPointAngle(const int index) const { 633806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi if (index <= 0 || index >= mInputSize - 1) { 634806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi return 0.0f; 635806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 636ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float previousDirection = getDirection(index - 1, index); 637ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float nextDirection = getDirection(index, index + 1); 638806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi const float directionDiff = getAngleDiff(previousDirection, nextDirection); 639806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi return directionDiff; 640806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi} 641806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi 642806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagifloat ProximityInfoState::getPointsAngle( 643806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi const int index0, const int index1, const int index2) const { 644806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi if (index0 < 0 || index0 > mInputSize - 1) { 645806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi return 0.0f; 646806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 647806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi if (index1 < 0 || index1 > mInputSize - 1) { 648806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi return 0.0f; 649806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 650806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi if (index2 < 0 || index2 > mInputSize - 1) { 651806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi return 0.0f; 652806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 653ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float previousDirection = getDirection(index0, index1); 654ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float nextDirection = getDirection(index1, index2); 655ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi return getAngleDiff(previousDirection, nextDirection); 656ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi} 657ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 658ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagifloat ProximityInfoState::getLineToKeyDistance( 659ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const int from, const int to, const int keyId, const bool extend) const { 660ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (from < 0 || from > mInputSize - 1) { 661ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi return 0.0f; 662ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 663ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (to < 0 || to > mInputSize - 1) { 664ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi return 0.0f; 665ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 666ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const int x0 = mInputXs[from]; 667ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const int y0 = mInputYs[from]; 668ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const int x1 = mInputXs[to]; 669ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const int y1 = mInputYs[to]; 670ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 671ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const int keyX = mProximityInfo->getKeyCenterXOfKeyIdG(keyId); 672ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const int keyY = mProximityInfo->getKeyCenterYOfKeyIdG(keyId); 673ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 674ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi return pointToLineSegSquaredDistanceFloat(keyX, keyY, x0, y0, x1, y1, extend); 675806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi} 676806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi 677806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi// Updates probabilities of aligning to some keys and skipping. 678806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi// Word suggestion should be based on this probabilities. 679ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagivoid ProximityInfoState::updateAlignPointProbabilities(const int start) { 680ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float MIN_PROBABILITY = 0.000001f; 681ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float MAX_SKIP_PROBABILITY = 0.95f; 682806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi static const float SKIP_FIRST_POINT_PROBABILITY = 0.01f; 683806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi static const float SKIP_LAST_POINT_PROBABILITY = 0.1f; 684ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float MIN_SPEED_RATE_FOR_SKIP_PROBABILITY = 0.15f; 685ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float SPEED_WEIGHT_FOR_SKIP_PROBABILITY = 0.9f; 686ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float SLOW_STRAIGHT_WEIGHT_FOR_SKIP_PROBABILITY = 0.6f; 687ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float NEAREST_DISTANCE_WEIGHT = 0.5f; 688ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float NEAREST_DISTANCE_BIAS = 0.5f; 689ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float NEAREST_DISTANCE_WEIGHT_FOR_LAST = 0.6f; 690ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float NEAREST_DISTANCE_BIAS_FOR_LAST = 0.4f; 691ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 692ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float ANGLE_WEIGHT = 0.90f; 693ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float DEEP_CORNER_ANGLE_THRESHOLD = M_PI_F * 60.0f / 180.0f; 694ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float SKIP_DEEP_CORNER_PROBABILITY = 0.1f; 695ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float CORNER_ANGLE_THRESHOLD = M_PI_F * 30.0f / 180.0f; 696806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi static const float STRAIGHT_ANGLE_THRESHOLD = M_PI_F * 15.0f / 180.0f; 697ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float SKIP_CORNER_PROBABILITY = 0.4f; 698ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float SPEED_MARGIN = 0.1f; 699806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi static const float CENTER_VALUE_OF_NORMALIZED_DISTRIBUTION = 0.0f; 700806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi 701ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const int keyCount = mProximityInfo->getKeyCount(); 702806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi mCharProbabilities.resize(mInputSize); 703806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi // Calculates probabilities of using a point as a correlated point with the character 704806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi // for each point. 705ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi for (int i = start; i < mInputSize; ++i) { 706ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi mCharProbabilities[i].clear(); 707ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // First, calculates skip probability. Starts form MIN_SKIP_PROBABILITY. 708806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi // Note that all values that are multiplied to this probability should be in [0.0, 1.0]; 709ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi float skipProbability = MAX_SKIP_PROBABILITY; 710ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 711ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float currentAngle = getPointAngle(i); 712ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float relativeSpeed = getRelativeSpeed(i); 713ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 714ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi float nearestKeyDistance = static_cast<float>(MAX_POINT_TO_KEY_LENGTH); 715ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi for (int j = 0; j < keyCount; ++j) { 716ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (mNearKeysVector[i].test(j)) { 717ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float distance = getPointToKeyByIdLength(i, j); 718ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (distance < nearestKeyDistance) { 719ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi nearestKeyDistance = distance; 720ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 721ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 722ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 723806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi 724806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi if (i == 0) { 725ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi skipProbability *= min(1.0f, nearestKeyDistance * NEAREST_DISTANCE_WEIGHT 726ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi + NEAREST_DISTANCE_BIAS); 727ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // Promote the first point 728806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi skipProbability *= SKIP_FIRST_POINT_PROBABILITY; 729806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } else if (i == mInputSize - 1) { 730ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi skipProbability *= min(1.0f, nearestKeyDistance * NEAREST_DISTANCE_WEIGHT_FOR_LAST 731ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi + NEAREST_DISTANCE_BIAS_FOR_LAST); 732ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // Promote the last point 733806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi skipProbability *= SKIP_LAST_POINT_PROBABILITY; 734806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } else { 735ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // If the current speed is relatively slower than adjacent keys, we promote this point. 736ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (getRelativeSpeed(i - 1) - SPEED_MARGIN > relativeSpeed 737ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi && relativeSpeed < getRelativeSpeed(i + 1) - SPEED_MARGIN) { 738ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (currentAngle < CORNER_ANGLE_THRESHOLD) { 739ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi skipProbability *= min(1.0f, relativeSpeed 740ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi * SLOW_STRAIGHT_WEIGHT_FOR_SKIP_PROBABILITY); 741ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } else { 742ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // If the angle is small enough, we promote this point more. (e.g. pit vs put) 743ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi skipProbability *= min(1.0f, relativeSpeed * SPEED_WEIGHT_FOR_SKIP_PROBABILITY 744ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi + MIN_SPEED_RATE_FOR_SKIP_PROBABILITY); 745ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 746ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 747ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 748ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi skipProbability *= min(1.0f, relativeSpeed * nearestKeyDistance * 749ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi NEAREST_DISTANCE_WEIGHT + NEAREST_DISTANCE_BIAS); 750806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi 751806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi // Adjusts skip probability by a rate depending on angle. 752806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi // ANGLE_RATE of skipProbability is adjusted by current angle. 753ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi skipProbability *= (M_PI_F - currentAngle) / M_PI_F * ANGLE_WEIGHT 754ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi + (1.0f - ANGLE_WEIGHT); 755806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi if (currentAngle > DEEP_CORNER_ANGLE_THRESHOLD) { 756806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi skipProbability *= SKIP_DEEP_CORNER_PROBABILITY; 757806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 758ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // We assume the angle of this point is the angle for point[i], point[i - 2] 759ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // and point[i - 3]. The reason why we don't use the angle for point[i], point[i - 1] 760ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // and point[i - 2] is this angle can be more affected by the noise. 761ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float prevAngle = getPointsAngle(i, i - 2, i - 3); 762ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (i >= 3 && prevAngle < STRAIGHT_ANGLE_THRESHOLD 763ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi && currentAngle > CORNER_ANGLE_THRESHOLD) { 764806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi skipProbability *= SKIP_CORNER_PROBABILITY; 765806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 766806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 767806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi 768ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // probabilities must be in [0.0, MAX_SKIP_PROBABILITY]; 769806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi ASSERT(skipProbability >= 0.0f); 770ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi ASSERT(skipProbability <= MAX_SKIP_PROBABILITY); 771806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi mCharProbabilities[i][NOT_AN_INDEX] = skipProbability; 772ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 773806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi // Second, calculates key probabilities by dividing the rest probability 774806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi // (1.0f - skipProbability). 775806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi const float inputCharProbability = 1.0f - skipProbability; 776ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 777ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // TODO: The variance is critical for accuracy; thus, adjusting these parameter by machine 778ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // learning or something would be efficient. 779ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float SPEEDxANGLE_WEIGHT_FOR_STANDARD_DIVIATION = 0.3f; 780ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float MAX_SPEEDxANGLE_RATE_FOR_STANDERD_DIVIATION = 0.25f; 781ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float SPEEDxNEAREST_WEIGHT_FOR_STANDARD_DIVIATION = 0.5f; 782ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float MAX_SPEEDxNEAREST_RATE_FOR_STANDERD_DIVIATION = 0.15f; 783ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float MIN_STANDERD_DIVIATION = 0.37f; 784ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 785ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float speedxAngleRate = min(relativeSpeed * currentAngle / M_PI_F 786ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi * SPEEDxANGLE_WEIGHT_FOR_STANDARD_DIVIATION, 787ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi MAX_SPEEDxANGLE_RATE_FOR_STANDERD_DIVIATION); 788ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float speedxNearestKeyDistanceRate = min(relativeSpeed * nearestKeyDistance 789ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi * SPEEDxNEAREST_WEIGHT_FOR_STANDARD_DIVIATION, 790ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi MAX_SPEEDxNEAREST_RATE_FOR_STANDERD_DIVIATION); 791ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float sigma = speedxAngleRate + speedxNearestKeyDistanceRate + MIN_STANDERD_DIVIATION; 792ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 793806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi NormalDistribution distribution(CENTER_VALUE_OF_NORMALIZED_DISTRIBUTION, sigma); 794ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float PREV_DISTANCE_WEIGHT = 0.5f; 795ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float NEXT_DISTANCE_WEIGHT = 0.6f; 796ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // Summing up probability densities of all near keys. 797ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi float sumOfProbabilityDensities = 0.0f; 798ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi for (int j = 0; j < keyCount; ++j) { 799806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi if (mNearKeysVector[i].test(j)) { 800ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi float distance = sqrtf(getPointToKeyByIdLength(i, j)); 801ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (i == 0 && i != mInputSize - 1) { 802ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // For the first point, weighted average of distances from first point and the 803ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // next point to the key is used as a point to key distance. 804ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float nextDistance = sqrtf(getPointToKeyByIdLength(i + 1, j)); 805ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (nextDistance < distance) { 806ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // The distance of the first point tends to bigger than continuing 807ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // points because the first touch by the user can be sloppy. 808ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // So we promote the first point if the distance of that point is larger 809ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // than the distance of the next point. 810ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi distance = (distance + nextDistance * NEXT_DISTANCE_WEIGHT) 811ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi / (1.0f + NEXT_DISTANCE_WEIGHT); 812ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 813ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } else if (i != 0 && i == mInputSize - 1) { 814ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // For the first point, weighted average of distances from last point and 815ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // the previous point to the key is used as a point to key distance. 816ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float previousDistance = sqrtf(getPointToKeyByIdLength(i - 1, j)); 817ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (previousDistance < distance) { 818ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // The distance of the last point tends to bigger than continuing points 819ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // because the last touch by the user can be sloppy. So we promote the 820ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // last point if the distance of that point is larger than the distance of 821ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // the previous point. 822ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi distance = (distance + previousDistance * PREV_DISTANCE_WEIGHT) 823ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi / (1.0f + PREV_DISTANCE_WEIGHT); 824ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 825ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 826ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // TODO: Promote the first point when the extended line from the next input is near 827ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // from a key. Also, promote the last point as well. 828ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi sumOfProbabilityDensities += distribution.getProbabilityDensity(distance); 829806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 830806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 831ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 832ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // Split the probability of an input point to keys that are close to the input point. 833ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi for (int j = 0; j < keyCount; ++j) { 834806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi if (mNearKeysVector[i].test(j)) { 835ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi float distance = sqrtf(getPointToKeyByIdLength(i, j)); 836ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (i == 0 && i != mInputSize - 1) { 837ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // For the first point, weighted average of distances from the first point and 838ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // the next point to the key is used as a point to key distance. 839ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float prevDistance = sqrtf(getPointToKeyByIdLength(i + 1, j)); 840ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (prevDistance < distance) { 841ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi distance = (distance + prevDistance * NEXT_DISTANCE_WEIGHT) 842ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi / (1.0f + NEXT_DISTANCE_WEIGHT); 843ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 844ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } else if (i != 0 && i == mInputSize - 1) { 845ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // For the first point, weighted average of distances from last point and 846ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // the previous point to the key is used as a point to key distance. 847ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float prevDistance = sqrtf(getPointToKeyByIdLength(i - 1, j)); 848ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (prevDistance < distance) { 849ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi distance = (distance + prevDistance * PREV_DISTANCE_WEIGHT) 850ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi / (1.0f + PREV_DISTANCE_WEIGHT); 851ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 852806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 853ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float probabilityDensity = distribution.getProbabilityDensity(distance); 854ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float probability = inputCharProbability * probabilityDensity 855ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi / sumOfProbabilityDensities; 856ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi mCharProbabilities[i][j] = probability; 857806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 858806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 859806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 860806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi 861ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 862ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (DEBUG_POINTS_PROBABILITY) { 863ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi for (int i = 0; i < mInputSize; ++i) { 864ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi std::stringstream sstream; 865ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi sstream << i << ", "; 866ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi sstream << "("<< mInputXs[i] << ", "; 867ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi sstream << ", "<< mInputYs[i] << "), "; 868ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi sstream << "Speed: "<< getRelativeSpeed(i) << ", "; 869ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi sstream << "Angle: "<< getPointAngle(i) << ", \n"; 870ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 871ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi for (hash_map_compat<int, float>::iterator it = mCharProbabilities[i].begin(); 872ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi it != mCharProbabilities[i].end(); ++it) { 873ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (it->first == NOT_AN_INDEX) { 874ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi sstream << it->first 875ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi << "(skip):" 876ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi << it->second 877ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi << "\n"; 878ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } else { 879ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi sstream << it->first 880ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi << "(" 881ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi << static_cast<char>(mProximityInfo->getCodePointOf(it->first)) 882ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi << "):" 883ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi << it->second 884ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi << "\n"; 885ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 886ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 887ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi AKLOGI("%s", sstream.str().c_str()); 888ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 889ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 890ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 891806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi // Decrease key probabilities of points which don't have the highest probability of that key 892806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi // among nearby points. Probabilities of the first point and the last point are not suppressed. 893ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi for (int i = max(start, 1); i < mInputSize; ++i) { 894806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi for (int j = i + 1; j < mInputSize; ++j) { 895ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (!suppressCharProbabilities(i, j)) { 896806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi break; 897806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 898806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 899ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi for (int j = i - 1; j >= max(start, 0); --j) { 900ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (!suppressCharProbabilities(i, j)) { 901806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi break; 902806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 903806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 904806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 905806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi 906ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // Converting from raw probabilities to log probabilities to calculate spatial distance. 907ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi for (int i = start; i < mInputSize; ++i) { 908ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi for (int j = 0; j < keyCount; ++j) { 909ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi hash_map_compat<int, float>::iterator it = mCharProbabilities[i].find(j); 910ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (it == mCharProbabilities[i].end()){ 911ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi mNearKeysVector[i].reset(j); 912ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } else if(it->second < MIN_PROBABILITY) { 913ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // Erases from near keys vector because it has very low probability. 914ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi mNearKeysVector[i].reset(j); 915ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi mCharProbabilities[i].erase(j); 916ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } else { 917ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi it->second = -logf(it->second); 918806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 919806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 920ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi mCharProbabilities[i][NOT_AN_INDEX] = -logf(mCharProbabilities[i][NOT_AN_INDEX]); 921806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 922806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi} 923806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi 924ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi// Decreases char probabilities of index0 by checking probabilities of a near point (index1) and 925ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi// increases char probabilities of index1 by checking probabilities of index0. 926806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagibool ProximityInfoState::suppressCharProbabilities(const int index0, const int index1) { 927806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi ASSERT(0 <= index0 && index0 < mInputSize); 928806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi ASSERT(0 <= index1 && index1 < mInputSize); 929ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 930806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi static const float SUPPRESSION_LENGTH_WEIGHT = 1.5f; 931ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float MIN_SUPPRESSION_RATE = 0.1f; 932ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float SUPPRESSION_WEIGHT = 0.5f; 933ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float SUPPRESSION_WEIGHT_FOR_PROBABILITY_GAIN = 0.1f; 934ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float SKIP_PROBABALITY_WEIGHT_FOR_PROBABILITY_GAIN = 0.3f; 935ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 936806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi const float keyWidthFloat = static_cast<float>(mProximityInfo->getMostCommonKeyWidth()); 937806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi const float diff = fabsf(static_cast<float>(mLengthCache[index0] - mLengthCache[index1])); 938806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi if (diff > keyWidthFloat * SUPPRESSION_LENGTH_WEIGHT) { 939806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi return false; 940806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 941ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float suppressionRate = MIN_SUPPRESSION_RATE 942ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi + diff / keyWidthFloat / SUPPRESSION_LENGTH_WEIGHT * SUPPRESSION_WEIGHT; 943806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi for (hash_map_compat<int, float>::iterator it = mCharProbabilities[index0].begin(); 944806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi it != mCharProbabilities[index0].end(); ++it) { 945ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi hash_map_compat<int, float>::iterator it2 = mCharProbabilities[index1].find(it->first); 946806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi if (it2 != mCharProbabilities[index1].end() && it->second < it2->second) { 947806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi const float newProbability = it->second * suppressionRate; 948ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float suppression = it->second - newProbability; 949806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi it->second = newProbability; 950ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // mCharProbabilities[index0][NOT_AN_INDEX] is the probability of skipping this point. 951ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi mCharProbabilities[index0][NOT_AN_INDEX] += suppression; 952ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 953ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // Add the probability of the same key nearby index1 954ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float probabilityGain = min(suppression * SUPPRESSION_WEIGHT_FOR_PROBABILITY_GAIN, 955ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi mCharProbabilities[index1][NOT_AN_INDEX] 956ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi * SKIP_PROBABALITY_WEIGHT_FOR_PROBABILITY_GAIN); 957ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi it2->second += probabilityGain; 958ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi mCharProbabilities[index1][NOT_AN_INDEX] -= probabilityGain; 959806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 960806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 961806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi return true; 962806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi} 963806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi 9641e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa// Get a word that is detected by tracing highest probability sequence into codePointBuf and 9651e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa// returns probability of generating the word. 9661e61493c50082264caaef862df02b1ccc84dc396Ken Wakasafloat ProximityInfoState::getHighestProbabilitySequence(int *const codePointBuf) const { 967350309aeb81ad1924af4d2e6d0bceaa6f98e4821Keisuke Kuroyanagi static const float DEMOTION_LOG_PROBABILITY = 0.3f; 968ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi int index = 0; 969ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi float sumLogProbability = 0.0f; 970806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi // TODO: Current implementation is greedy algorithm. DP would be efficient for many cases. 971ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi for (int i = 0; i < mInputSize && index < MAX_WORD_LENGTH_INTERNAL - 1; ++i) { 972ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi float minLogProbability = static_cast<float>(MAX_POINT_TO_KEY_LENGTH); 973ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi int character = NOT_AN_INDEX; 974806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi for (hash_map_compat<int, float>::const_iterator it = mCharProbabilities[i].begin(); 975806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi it != mCharProbabilities[i].end(); ++it) { 976ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float logProbability = (it->first != NOT_AN_INDEX) 977350309aeb81ad1924af4d2e6d0bceaa6f98e4821Keisuke Kuroyanagi ? it->second + DEMOTION_LOG_PROBABILITY : it->second; 978ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (logProbability < minLogProbability) { 979ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi minLogProbability = logProbability; 980ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi character = it->first; 981806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 982806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 983ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (character != NOT_AN_INDEX) { 9841e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa codePointBuf[index] = mProximityInfo->getCodePointOf(character); 985806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi index++; 986806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 987ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi sumLogProbability += minLogProbability; 988806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 9891e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa codePointBuf[index] = '\0'; 990ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi return sumLogProbability; 991ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi} 992ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 993ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi// Returns a probability of mapping index to keyIndex. 994ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagifloat ProximityInfoState::getProbability(const int index, const int keyIndex) const { 995ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi ASSERT(0 <= index && index < mInputSize); 996ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi hash_map_compat<int, float>::const_iterator it = mCharProbabilities[index].find(keyIndex); 997ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (it != mCharProbabilities[index].end()) { 998ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi return it->second; 999ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 1000ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi return static_cast<float>(MAX_POINT_TO_KEY_LENGTH); 1001806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi} 1002806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi 10033e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka} // namespace latinime 1004