proximity_info_state.cpp revision 0519fdd18ac4414b8298d3338db1c8ccce032170
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 203e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka#define LOG_TAG "LatinIME: proximity_info_state.cpp" 213e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka 223e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka#include "defines.h" 233e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka#include "proximity_info.h" 243e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka#include "proximity_info_state.h" 253e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka 263e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataokanamespace latinime { 27764dd712032d7b8012797b1116b523bef7b907f3Ken Wakasa 28764dd712032d7b8012797b1116b523bef7b907f3Ken Wakasaconst int ProximityInfoState::NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR_LOG_2 = 10; 29764dd712032d7b8012797b1116b523bef7b907f3Ken Wakasaconst int ProximityInfoState::NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR = 30764dd712032d7b8012797b1116b523bef7b907f3Ken Wakasa 1 << NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR_LOG_2; 31764dd712032d7b8012797b1116b523bef7b907f3Ken Wakasaconst float ProximityInfoState::NOT_A_DISTANCE_FLOAT = -1.0f; 32764dd712032d7b8012797b1116b523bef7b907f3Ken Wakasaconst int ProximityInfoState::NOT_A_CODE = -1; 336ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataokaconst int ProximityInfoState::LOOKUP_RADIUS_PERCENTILE = 50; 346ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataokaconst int ProximityInfoState::FIRST_POINT_TIME_OFFSET_MILLIS = 150; 356ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataokaconst int ProximityInfoState::STRONG_DOUBLE_LETTER_TIME_MILLIS = 600; 366ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataokaconst int ProximityInfoState::MIN_DOUBLE_LETTER_BEELINE_SPEED_PERCENTILE = 5; 37764dd712032d7b8012797b1116b523bef7b907f3Ken Wakasa 38233aad5e5c7567a97af30f38f50a65365f729dfeSatoshi Kataokavoid ProximityInfoState::initInputParams(const int pointerId, const float maxPointToKeyLength, 391e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa const ProximityInfo *proximityInfo, const int *const inputCodes, const int inputSize, 40687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const int *const xCoordinates, const int *const yCoordinates, const int *const times, 41687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const int *const pointerIds, const bool isGeometric) { 42fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka mIsContinuationPossible = checkAndReturnIsContinuationPossible( 43fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka inputSize, xCoordinates, yCoordinates, times, isGeometric); 44096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi 454a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka mProximityInfo = proximityInfo; 464a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka mHasTouchPositionCorrectionData = proximityInfo->hasTouchPositionCorrectionData(); 474a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka mMostCommonKeyWidthSquare = proximityInfo->getMostCommonKeyWidthSquare(); 484a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka mLocaleStr = proximityInfo->getLocaleStr(); 494a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka mKeyCount = proximityInfo->getKeyCount(); 504a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka mCellHeight = proximityInfo->getCellHeight(); 514a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka mCellWidth = proximityInfo->getCellWidth(); 524a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka mGridHeight = proximityInfo->getGridWidth(); 534a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka mGridWidth = proximityInfo->getGridHeight(); 543e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka 5508f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka memset(mInputCodes, 0, sizeof(mInputCodes)); 563e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka 5708f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka if (!isGeometric && pointerId == 0) { 5808f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka // Initialize 5908f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka // - mInputCodes 6008f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka // - mNormalizedSquaredDistances 6108f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka // TODO: Merge 62687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka for (int i = 0; i < inputSize; ++i) { 631e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa const int primaryKey = inputCodes[i]; 6408f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka const int x = xCoordinates[i]; 6508f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka const int y = yCoordinates[i]; 6608f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka int *proximities = &mInputCodes[i * MAX_PROXIMITY_CHARS_SIZE_INTERNAL]; 6708f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka mProximityInfo->calculateNearbyKeyCodes(x, y, primaryKey, proximities); 6808f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka } 6908f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka 7008f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka if (DEBUG_PROXIMITY_CHARS) { 7108f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka for (int i = 0; i < inputSize; ++i) { 7208f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka AKLOGI("---"); 7308f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka for (int j = 0; j < MAX_PROXIMITY_CHARS_SIZE_INTERNAL; ++j) { 7408f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka int icc = mInputCodes[i * MAX_PROXIMITY_CHARS_SIZE_INTERNAL + j]; 7508f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka int icfjc = inputCodes[i * MAX_PROXIMITY_CHARS_SIZE_INTERNAL + j]; 7608f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka icc += 0; 7708f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka icfjc += 0; 7808f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka AKLOGI("--- (%d)%c,%c", i, icc, icfjc); AKLOGI("--- A<%d>,B<%d>", icc, icfjc); 7908f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka } 803e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka } 813e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka } 823e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka } 83687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka 84687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka /////////////////////// 85687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka // Setup touch points 86096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi int pushTouchPointStartIndex = 0; 87096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi int lastSavedInputSize = 0; 8808f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka mMaxPointToKeyLength = maxPointToKeyLength; 89096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi if (mIsContinuationPossible && mInputIndice.size() > 1) { 90096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi // Just update difference. 91096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi // Two points prior is never skipped. Thus, we pop 2 input point data here. 92096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi pushTouchPointStartIndex = mInputIndice[mInputIndice.size() - 2]; 93096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi popInputData(); 94096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi popInputData(); 95feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka lastSavedInputSize = mSampledInputXs.size(); 96096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi } else { 97096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi // Clear all data. 98feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka mSampledInputXs.clear(); 99feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka mSampledInputYs.clear(); 100096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mTimes.clear(); 101096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mInputIndice.clear(); 102096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mLengthCache.clear(); 103096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mDistanceCache.clear(); 104096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mNearKeysVector.clear(); 105ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi mSearchKeysVector.clear(); 1069af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka mSpeedRates.clear(); 1076ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka mBeelineSpeedPercentiles.clear(); 108806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi mCharProbabilities.clear(); 1091e06a4d8e9e71188ed685282155ea52a48ddc050Keisuke Kuroyanagi mDirections.clear(); 110096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi } 1119182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka if (DEBUG_GEO_FULL) { 1129182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka AKLOGI("Init ProximityInfoState: reused points = %d, last input size = %d", 1139182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka pushTouchPointStartIndex, lastSavedInputSize); 1149182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka } 115feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka mSampledInputSize = 0; 116d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi 117687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka if (xCoordinates && yCoordinates) { 1189af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka if (DEBUG_SAMPLING_POINTS) { 1199af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka if (isGeometric) { 1209af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka for (int i = 0; i < inputSize; ++i) { 1219af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka AKLOGI("(%d) x %d, y %d, time %d", 1229af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka i, xCoordinates[i], yCoordinates[i], times[i]); 1239af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka } 1249af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka } 1259af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka } 126687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const bool proximityOnly = !isGeometric && (xCoordinates[0] < 0 || yCoordinates[0] < 0); 127096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi int lastInputIndex = pushTouchPointStartIndex; 128096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi for (int i = lastInputIndex; i < inputSize; ++i) { 129d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi const int pid = pointerIds ? pointerIds[i] : 0; 130d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi if (pointerId == pid) { 131d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi lastInputIndex = i; 132d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 133d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 1349182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka if (DEBUG_GEO_FULL) { 1359182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka AKLOGI("Init ProximityInfoState: last input index = %d", lastInputIndex); 1369182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka } 137d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi // Working space to save near keys distances for current, prev and prevprev input point. 138d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi NearKeysDistanceMap nearKeysDistances[3]; 139d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi // These pointers are swapped for each inputs points. 140d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi NearKeysDistanceMap *currentNearKeysDistances = &nearKeysDistances[0]; 141d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi NearKeysDistanceMap *prevNearKeysDistances = &nearKeysDistances[1]; 142d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi NearKeysDistanceMap *prevPrevNearKeysDistances = &nearKeysDistances[2]; 143ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // "sumAngle" is accumulated by each angle of input points. And when "sumAngle" exceeds 144ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // the threshold we save that point, reset sumAngle. This aims to keep the figure of 145ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // the curve. 146ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi float sumAngle = 0.0f; 147d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi 148096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi for (int i = pushTouchPointStartIndex; i <= lastInputIndex; ++i) { 149687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka // Assuming pointerId == 0 if pointerIds is null. 150687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const int pid = pointerIds ? pointerIds[i] : 0; 1519182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka if (DEBUG_GEO_FULL) { 1529182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka AKLOGI("Init ProximityInfoState: (%d)PID = %d", i, pid); 1539182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka } 154687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka if (pointerId == pid) { 1551e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa const int c = isGeometric ? NOT_A_COORDINATE : getPrimaryCodePointAt(i); 156687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const int x = proximityOnly ? NOT_A_COORDINATE : xCoordinates[i]; 157687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const int y = proximityOnly ? NOT_A_COORDINATE : yCoordinates[i]; 158687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const int time = times ? times[i] : -1; 159ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 160ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (i > 1) { 161ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float prevAngle = getAngle(xCoordinates[i - 2], yCoordinates[i - 2], 162ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi xCoordinates[i - 1], yCoordinates[i - 1]); 163ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float currentAngle = 164ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi getAngle(xCoordinates[i - 1], yCoordinates[i - 1], x, y); 165ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi sumAngle += getAngleDiff(prevAngle, currentAngle); 166ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 167ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 168952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka if (pushTouchPoint(i, c, x, y, time, isGeometric /* do sampling */, 169ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi i == lastInputIndex, sumAngle, currentNearKeysDistances, 170ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi prevNearKeysDistances, prevPrevNearKeysDistances)) { 171d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi // Previous point information was popped. 172d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi NearKeysDistanceMap *tmp = prevNearKeysDistances; 173d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi prevNearKeysDistances = currentNearKeysDistances; 174d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi currentNearKeysDistances = tmp; 175d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } else { 176d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi NearKeysDistanceMap *tmp = prevPrevNearKeysDistances; 177d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi prevPrevNearKeysDistances = prevNearKeysDistances; 178d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi prevNearKeysDistances = currentNearKeysDistances; 179d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi currentNearKeysDistances = tmp; 180ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi sumAngle = 0.0f; 18137b153e205c9672b299b47e97921fee2462a78bbSatoshi Kataoka } 182687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka } 183687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka } 184feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka mSampledInputSize = mSampledInputXs.size(); 1853e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka } 186687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka 187feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka if (mSampledInputSize > 0 && isGeometric) { 1889af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka refreshSpeedRates(inputSize, xCoordinates, yCoordinates, times, lastSavedInputSize); 1899af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka refreshBeelineSpeedRates(inputSize, xCoordinates, yCoordinates, times); 19028661069591fd1d6a8e25981aaade2e5d8b20b9aKeisuke Kuroyanagi } 19128661069591fd1d6a8e25981aaade2e5d8b20b9aKeisuke Kuroyanagi 192ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (DEBUG_GEO_FULL) { 193feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka for (int i = 0; i < mSampledInputSize; ++i) { 194feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka AKLOGI("Sampled(%d): x = %d, y = %d, time = %d", i, mSampledInputXs[i], 195feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka mSampledInputYs[i], mTimes[i]); 196ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 197ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 198ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 199feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka if (mSampledInputSize > 0) { 200687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const int keyCount = mProximityInfo->getKeyCount(); 201feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka mNearKeysVector.resize(mSampledInputSize); 202feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka mSearchKeysVector.resize(mSampledInputSize); 203feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka mDistanceCache.resize(mSampledInputSize * keyCount); 204feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka for (int i = lastSavedInputSize; i < mSampledInputSize; ++i) { 20595a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi mNearKeysVector[i].reset(); 206ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi mSearchKeysVector[i].reset(); 20795a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi static const float NEAR_KEY_NORMALIZED_SQUARED_THRESHOLD = 4.0f; 208687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka for (int k = 0; k < keyCount; ++k) { 209687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const int index = i * keyCount + k; 210feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka const int x = mSampledInputXs[i]; 211feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka const int y = mSampledInputYs[i]; 21295a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi const float normalizedSquaredDistance = 2130edab9d2fcc30667c79aa9221dbb27f042d8b455Satoshi Kataoka mProximityInfo->getNormalizedSquaredDistanceFromCenterFloatG(k, x, y); 21495a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi mDistanceCache[index] = normalizedSquaredDistance; 21595a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi if (normalizedSquaredDistance < NEAR_KEY_NORMALIZED_SQUARED_THRESHOLD) { 216ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi mNearKeysVector[i][k] = true; 21795a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi } 21895a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi } 21995a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi } 220ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (isGeometric) { 221ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // updates probabilities of skipping or mapping each key for all points. 222ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi updateAlignPointProbabilities(lastSavedInputSize); 223ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 224ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float READ_FORWORD_LENGTH_SCALE = 0.95f; 225ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const int readForwordLength = static_cast<int>( 226ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi hypotf(mProximityInfo->getKeyboardWidth(), mProximityInfo->getKeyboardHeight()) 227ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi * READ_FORWORD_LENGTH_SCALE); 228feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka for (int i = 0; i < mSampledInputSize; ++i) { 229ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (i >= lastSavedInputSize) { 230ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi mSearchKeysVector[i].reset(); 231ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 232feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka for (int j = max(i, lastSavedInputSize); j < mSampledInputSize; ++j) { 233ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (mLengthCache[j] - mLengthCache[i] >= readForwordLength) { 234ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi break; 235ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 236ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi mSearchKeysVector[i] |= mNearKeysVector[j]; 23795a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi } 238687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka } 239687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka } 240687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka } 24108f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka 242806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi if (DEBUG_SAMPLING_POINTS) { 243806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi std::stringstream originalX, originalY, sampledX, sampledY; 244806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi for (int i = 0; i < inputSize; ++i) { 245806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi originalX << xCoordinates[i]; 246806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi originalY << yCoordinates[i]; 247806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi if (i != inputSize - 1) { 248806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi originalX << ";"; 249806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi originalY << ";"; 250806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 251806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 2529af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka AKLOGI("===== sampled points ====="); 253feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka for (int i = 0; i < mSampledInputSize; ++i) { 2549af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka if (isGeometric) { 2556ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka AKLOGI("%d: x = %d, y = %d, time = %d, relative speed = %.4f, beeline speed = %d", 2569af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka i, mSampledInputXs[i], mSampledInputYs[i], mTimes[i], mSpeedRates[i], 2576ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka getBeelineSpeedPercentile(i)); 2589af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka } 259feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka sampledX << mSampledInputXs[i]; 260feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka sampledY << mSampledInputYs[i]; 261feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka if (i != mSampledInputSize - 1) { 262806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi sampledX << ";"; 263806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi sampledY << ";"; 264806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 265806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 266f25cc4405e329447425e52c3c5514a8802097fb8Satoshi Kataoka AKLOGI("original points:\n%s, %s,\nsampled points:\n%s, %s,\n", 267f25cc4405e329447425e52c3c5514a8802097fb8Satoshi Kataoka originalX.str().c_str(), originalY.str().c_str(), sampledX.str().c_str(), 268f25cc4405e329447425e52c3c5514a8802097fb8Satoshi Kataoka sampledY.str().c_str()); 269806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 270687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka // end 271687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka /////////////////////// 272687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka 27308f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka memset(mNormalizedSquaredDistances, NOT_A_DISTANCE, sizeof(mNormalizedSquaredDistances)); 27408f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka memset(mPrimaryInputWord, 0, sizeof(mPrimaryInputWord)); 275feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka mTouchPositionCorrectionEnabled = mSampledInputSize > 0 && mHasTouchPositionCorrectionData 2760edab9d2fcc30667c79aa9221dbb27f042d8b455Satoshi Kataoka && xCoordinates && yCoordinates; 27708f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka if (!isGeometric && pointerId == 0) { 27808f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka for (int i = 0; i < inputSize; ++i) { 2791e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa mPrimaryInputWord[i] = getPrimaryCodePointAt(i); 2803e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka } 28108f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka 282feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka for (int i = 0; i < mSampledInputSize && mTouchPositionCorrectionEnabled; ++i) { 2831e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa const int *proximityCodePoints = getProximityCodePointsAt(i); 2841e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa const int primaryKey = proximityCodePoints[0]; 28508f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka const int x = xCoordinates[i]; 28608f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka const int y = yCoordinates[i]; 2873e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka if (DEBUG_PROXIMITY_CHARS) { 28808f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka int a = x + y + primaryKey; 28908f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka a += 0; 29008f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka AKLOGI("--- Primary = %c, x = %d, y = %d", primaryKey, x, y); 29108f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka } 2921e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa for (int j = 0; j < MAX_PROXIMITY_CHARS_SIZE_INTERNAL && proximityCodePoints[j] > 0; 2931e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa ++j) { 2941e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa const int currentCodePoint = proximityCodePoints[j]; 29508f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka const float squaredDistance = 29608f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka hasInputCoordinates() ? calculateNormalizedSquaredDistance( 2971e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa mProximityInfo->getKeyIndexOf(currentCodePoint), i) : 29808f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka NOT_A_DISTANCE_FLOAT; 29908f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka if (squaredDistance >= 0.0f) { 30008f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka mNormalizedSquaredDistances[i * MAX_PROXIMITY_CHARS_SIZE_INTERNAL + j] = 30108f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka (int) (squaredDistance * NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR); 30208f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka } else { 30308f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka mNormalizedSquaredDistances[i * MAX_PROXIMITY_CHARS_SIZE_INTERNAL + j] = 30408f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka (j == 0) ? EQUIVALENT_CHAR_WITHOUT_DISTANCE_INFO : 30508f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka PROXIMITY_CHAR_WITHOUT_DISTANCE_INFO; 30608f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka } 30708f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka if (DEBUG_PROXIMITY_CHARS) { 3081e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa AKLOGI("--- Proximity (%d) = %c", j, currentCodePoint); 30908f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka } 3103e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka } 3113e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka } 3123e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka } 313952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka 314952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka if (DEBUG_GEO_FULL) { 315feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka AKLOGI("ProximityState init finished: %d points out of %d", mSampledInputSize, inputSize); 316feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka } 317feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka} 318feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka 3199af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataokavoid ProximityInfoState::refreshSpeedRates(const int inputSize, const int *const xCoordinates, 320feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka const int *const yCoordinates, const int *const times, const int lastSavedInputSize) { 321feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka // Relative speed calculation. 322feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka const int sumDuration = mTimes.back() - mTimes.front(); 323feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka const int sumLength = mLengthCache.back() - mLengthCache.front(); 3249af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka mAverageSpeed = static_cast<float>(sumLength) / static_cast<float>(sumDuration); 3259af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka mSpeedRates.resize(mSampledInputSize); 326feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka for (int i = lastSavedInputSize; i < mSampledInputSize; ++i) { 327feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka const int index = mInputIndice[i]; 328feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka int length = 0; 329feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka int duration = 0; 330feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka 331feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka // Calculate velocity by using distances and durations of 332feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka // NUM_POINTS_FOR_SPEED_CALCULATION points for both forward and backward. 333feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka static const int NUM_POINTS_FOR_SPEED_CALCULATION = 2; 334feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka for (int j = index; j < min(inputSize - 1, index + NUM_POINTS_FOR_SPEED_CALCULATION); 335feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka ++j) { 336feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka if (i < mSampledInputSize - 1 && j >= mInputIndice[i + 1]) { 337feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka break; 338feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka } 339feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka length += getDistanceInt(xCoordinates[j], yCoordinates[j], 340feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka xCoordinates[j + 1], yCoordinates[j + 1]); 341feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka duration += times[j + 1] - times[j]; 342feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka } 343feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka for (int j = index - 1; j >= max(0, index - NUM_POINTS_FOR_SPEED_CALCULATION); --j) { 344feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka if (i > 0 && j < mInputIndice[i - 1]) { 345feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka break; 346feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka } 3479af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka // TODO: use mLengthCache instead? 348feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka length += getDistanceInt(xCoordinates[j], yCoordinates[j], 349feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka xCoordinates[j + 1], yCoordinates[j + 1]); 350feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka duration += times[j + 1] - times[j]; 351feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka } 352feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka if (duration == 0 || sumDuration == 0) { 353feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka // Cannot calculate speed; thus, it gives an average value (1.0); 3549af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka mSpeedRates[i] = 1.0f; 355feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka } else { 356feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka const float speed = static_cast<float>(length) / static_cast<float>(duration); 3579af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka mSpeedRates[i] = speed / mAverageSpeed; 358feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka } 359feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka } 360feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka 361feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka // Direction calculation. 362feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka mDirections.resize(mSampledInputSize - 1); 363feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka for (int i = max(0, lastSavedInputSize - 1); i < mSampledInputSize - 1; ++i) { 364feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka mDirections[i] = getDirection(i, i + 1); 365952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka } 3663e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka} 3674a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka 3686ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataokastatic const int MAX_PERCENTILE = 100; 3699af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataokavoid ProximityInfoState::refreshBeelineSpeedRates(const int inputSize, 3709af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka const int *const xCoordinates, const int *const yCoordinates, const int * times) { 3716ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka if (DEBUG_SAMPLING_POINTS){ 3726ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka AKLOGI("--- refresh beeline speed rates"); 3736ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka } 3746ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka mBeelineSpeedPercentiles.resize(mSampledInputSize); 3759af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka for (int i = 0; i < mSampledInputSize; ++i) { 3766ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka mBeelineSpeedPercentiles[i] = static_cast<int>(calculateBeelineSpeedRate( 3776ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka i, inputSize, xCoordinates, yCoordinates, times) * MAX_PERCENTILE); 3789af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka } 3799af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka} 3809af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka 3819af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataokafloat ProximityInfoState::calculateBeelineSpeedRate( 3829af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka const int id, const int inputSize, const int *const xCoordinates, 3839af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka const int *const yCoordinates, const int * times) const { 3846ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka if (mSampledInputSize <= 0 || mAverageSpeed < 0.001f) { 3856ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka if (DEBUG_SAMPLING_POINTS){ 3866ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka AKLOGI("--- invalid state: cancel. size = %d, ave = %f", 3876ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka mSampledInputSize, mAverageSpeed); 3886ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka } 3899af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka return 1.0f; 3909af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka } 3919af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka const int lookupRadius = 3929af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka mProximityInfo->getMostCommonKeyWidth() * LOOKUP_RADIUS_PERCENTILE / MAX_PERCENTILE; 3939af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka const int x0 = mSampledInputXs[id]; 3949af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka const int y0 = mSampledInputYs[id]; 3956ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka const int actualInputIndex = mInputIndice[id]; 3969af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka int tempTime = 0; 3979af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka int tempBeelineDistance = 0; 3986ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka int start = actualInputIndex; 3999af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka // lookup forward 4006ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka while (start > 0 && tempBeelineDistance < lookupRadius) { 4019af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka tempTime += times[start] - times[start - 1]; 4029af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka --start; 4039af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka tempBeelineDistance = getDistanceInt(x0, y0, xCoordinates[start], yCoordinates[start]); 4049af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka } 4056ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka // Exclusive unless this is an edge point 4066ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka if (start > 0 && start < actualInputIndex) { 4076ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka ++start; 4086ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka } 4099af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka tempTime= 0; 4109af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka tempBeelineDistance = 0; 4116ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka int end = actualInputIndex; 4129af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka // lookup backward 4136ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka while (end < (inputSize - 1) && tempBeelineDistance < lookupRadius) { 4149af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka tempTime += times[end + 1] - times[end]; 4159af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka ++end; 4166ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka tempBeelineDistance = getDistanceInt(x0, y0, xCoordinates[end], yCoordinates[end]); 4176ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka } 4186ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka // Exclusive unless this is an edge point 4196ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka if (end > actualInputIndex && end < (inputSize - 1)) { 4206ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka --end; 4219af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka } 4229af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka 4236ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka if (start >= end) { 4246ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka if (DEBUG_DOUBLE_LETTER) { 4256ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka AKLOGI("--- double letter: start == end %d", start); 4266ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka } 4279af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka return 1.0f; 4289af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka } 4299af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka 4309af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka const int x2 = xCoordinates[start]; 4319af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka const int y2 = yCoordinates[start]; 4329af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka const int x3 = xCoordinates[end]; 4339af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka const int y3 = yCoordinates[end]; 4349af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka const int beelineDistance = getDistanceInt(x2, y2, x3, y3); 4356ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka int adjustedStartTime = times[start]; 4366ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka if (start == 0 && actualInputIndex == 0 && inputSize > 1) { 4376ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka adjustedStartTime += FIRST_POINT_TIME_OFFSET_MILLIS; 4386ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka } 4396ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka int adjustedEndTime = times[end]; 4406ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka if (end == (inputSize - 1) && inputSize > 1) { 4416ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka adjustedEndTime -= FIRST_POINT_TIME_OFFSET_MILLIS; 4426ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka } 4436ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka const int time = adjustedEndTime - adjustedStartTime; 4449af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka if (time <= 0) { 4459af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka return 1.0f; 4469af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka } 4476ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka 4486ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka if (time >= STRONG_DOUBLE_LETTER_TIME_MILLIS){ 4496ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka return 0.0f; 4506ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka } 4516ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka if (DEBUG_DOUBLE_LETTER) { 4526ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka AKLOGI("--- (%d, %d) double letter: start = %d, end = %d, dist = %d, time = %d, speed = %f," 4536ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka " ave = %f, val = %f, start time = %d, end time = %d", 4546ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka id, mInputIndice[id], start, end, beelineDistance, time, 4556ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka (static_cast<float>(beelineDistance) / static_cast<float>(time)), mAverageSpeed, 4566ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka ((static_cast<float>(beelineDistance) / static_cast<float>(time)) / mAverageSpeed), 4576ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka adjustedStartTime, adjustedEndTime); 4586ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka } 4596ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka // Offset 1% 4606ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka // TODO: Detect double letter more smartly 4616ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka return 0.01f + static_cast<float>(beelineDistance) / static_cast<float>(time) / mAverageSpeed; 4629af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka} 4639af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka 464096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagibool ProximityInfoState::checkAndReturnIsContinuationPossible(const int inputSize, 465fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka const int *const xCoordinates, const int *const yCoordinates, const int *const times, 466fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka const bool isGeometric) const { 467fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka if (isGeometric) { 468fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka for (int i = 0; i < mSampledInputSize; ++i) { 469fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka const int index = mInputIndice[i]; 470fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka if (index > inputSize || xCoordinates[index] != mSampledInputXs[i] || 471fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka yCoordinates[index] != mSampledInputYs[i] || times[index] != mTimes[i]) { 472fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka return false; 473fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka } 474fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka } 475fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka } else { 476fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka if (inputSize < mSampledInputSize) { 477fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka // Assuming the cache is invalid if the previous input size is larger than the new one. 478096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi return false; 479096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi } 480fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka for (int i = 0; i < mSampledInputSize && i < MAX_WORD_LENGTH_INTERNAL; ++i) { 481fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka if (xCoordinates[i] != mSampledInputXs[i] 482fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka || yCoordinates[i] != mSampledInputYs[i]) { 483fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka return false; 484fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka } 485fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka } 486096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi } 487096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi return true; 488096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi} 489096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi 490d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi// Calculating point to key distance for all near keys and returning the distance between 491d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi// the given point and the nearest key position. 492d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagifloat ProximityInfoState::updateNearKeysDistances(const int x, const int y, 493d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi NearKeysDistanceMap *const currentNearKeysDistances) { 494ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float NEAR_KEY_THRESHOLD = 2.0f; 495d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi 496d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi currentNearKeysDistances->clear(); 497d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi const int keyCount = mProximityInfo->getKeyCount(); 498d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi float nearestKeyDistance = mMaxPointToKeyLength; 499d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi for (int k = 0; k < keyCount; ++k) { 5000edab9d2fcc30667c79aa9221dbb27f042d8b455Satoshi Kataoka const float dist = mProximityInfo->getNormalizedSquaredDistanceFromCenterFloatG(k, x, y); 501d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi if (dist < NEAR_KEY_THRESHOLD) { 502d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi currentNearKeysDistances->insert(std::pair<int, float>(k, dist)); 503687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka } 504d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi if (nearestKeyDistance > dist) { 505d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi nearestKeyDistance = dist; 506d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 507d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 508d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi return nearestKeyDistance; 509d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi} 510d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi 511d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi// Check if previous point is at local minimum position to near keys. 512d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagibool ProximityInfoState::isPrevLocalMin(const NearKeysDistanceMap *const currentNearKeysDistances, 513d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi const NearKeysDistanceMap *const prevNearKeysDistances, 514d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi const NearKeysDistanceMap *const prevPrevNearKeysDistances) const { 515ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float MARGIN = 0.01f; 516d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi 517d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi for (NearKeysDistanceMap::const_iterator it = prevNearKeysDistances->begin(); 518d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi it != prevNearKeysDistances->end(); ++it) { 519d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi NearKeysDistanceMap::const_iterator itPP = prevPrevNearKeysDistances->find(it->first); 520d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi NearKeysDistanceMap::const_iterator itC = currentNearKeysDistances->find(it->first); 521d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi if ((itPP == prevPrevNearKeysDistances->end() || itPP->second > it->second + MARGIN) 522d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi && (itC == currentNearKeysDistances->end() || itC->second > it->second + MARGIN)) { 523d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi return true; 524d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 525d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 526d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi return false; 527d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi} 528d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi 529d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi// Calculating a point score that indicates usefulness of the point. 530d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagifloat ProximityInfoState::getPointScore( 531d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi const int x, const int y, const int time, const bool lastPoint, const float nearest, 532ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float sumAngle, const NearKeysDistanceMap *const currentNearKeysDistances, 533d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi const NearKeysDistanceMap *const prevNearKeysDistances, 534d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi const NearKeysDistanceMap *const prevPrevNearKeysDistances) const { 53503dc8fe141fa9f6fa5fe8362d9d35b3f3c954b87Ken Wakasa static const int DISTANCE_BASE_SCALE = 100; 536ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float NEAR_KEY_THRESHOLD = 0.6f; 537ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const int CORNER_CHECK_DISTANCE_THRESHOLD_SCALE = 25; 538806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi static const float NOT_LOCALMIN_DISTANCE_SCORE = -1.0f; 539ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float LOCALMIN_DISTANCE_AND_NEAR_TO_KEY_SCORE = 1.0f; 540ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float CORNER_ANGLE_THRESHOLD = M_PI_F * 2.0f / 3.0f; 541ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float CORNER_SUM_ANGLE_THRESHOLD = M_PI_F / 4.0f; 542aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi static const float CORNER_SCORE = 1.0f; 543d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi 544feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka const size_t size = mSampledInputXs.size(); 545ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // If there is only one point, add this point. Besides, if the previous point's distance map 546ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // is empty, we re-compute nearby keys distances from the current point. 547ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // Note that the current point is the first point in the incremental input that needs to 548ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // be re-computed. 549ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (size <= 1 || prevNearKeysDistances->empty()) { 55003dc8fe141fa9f6fa5fe8362d9d35b3f3c954b87Ken Wakasa return 0.0f; 551687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka } 552ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 55303dc8fe141fa9f6fa5fe8362d9d35b3f3c954b87Ken Wakasa const int baseSampleRate = mProximityInfo->getMostCommonKeyWidth(); 554feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka const int distPrev = getDistanceInt(mSampledInputXs.back(), mSampledInputYs.back(), 555feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka mSampledInputXs[size - 2], mSampledInputYs[size - 2]) * DISTANCE_BASE_SCALE; 556d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi float score = 0.0f; 557d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi 558d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi // Location 559ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (!isPrevLocalMin(currentNearKeysDistances, prevNearKeysDistances, 560ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi prevPrevNearKeysDistances)) { 561ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi score += NOT_LOCALMIN_DISTANCE_SCORE; 562ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } else if (nearest < NEAR_KEY_THRESHOLD) { 563ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // Promote points nearby keys 564ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi score += LOCALMIN_DISTANCE_AND_NEAR_TO_KEY_SCORE; 565d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 566d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi // Angle 567feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka const float angle1 = getAngle(x, y, mSampledInputXs.back(), mSampledInputYs.back()); 568feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka const float angle2 = getAngle(mSampledInputXs.back(), mSampledInputYs.back(), 569feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka mSampledInputXs[size - 2], mSampledInputYs[size - 2]); 570aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi const float angleDiff = getAngleDiff(angle1, angle2); 571ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 572aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi // Save corner 573aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi if (distPrev > baseSampleRate * CORNER_CHECK_DISTANCE_THRESHOLD_SCALE 574ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi && (sumAngle > CORNER_SUM_ANGLE_THRESHOLD || angleDiff > CORNER_ANGLE_THRESHOLD)) { 575aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi score += CORNER_SCORE; 576d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 577d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi return score; 578d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi} 579d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi 580d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi// Sampling touch point and pushing information to vectors. 581d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi// Returning if previous point is popped or not. 5821e61493c50082264caaef862df02b1ccc84dc396Ken Wakasabool ProximityInfoState::pushTouchPoint(const int inputIndex, const int nodeCodePoint, int x, int y, 583ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const int time, const bool sample, const bool isLastPoint, const float sumAngle, 584d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi NearKeysDistanceMap *const currentNearKeysDistances, 585d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi const NearKeysDistanceMap *const prevNearKeysDistances, 586d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi const NearKeysDistanceMap *const prevPrevNearKeysDistances) { 587806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi static const int LAST_POINT_SKIP_DISTANCE_SCALE = 4; 588d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi 589feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka size_t size = mSampledInputXs.size(); 590d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi bool popped = false; 5911e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa if (nodeCodePoint < 0 && sample) { 592d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi const float nearest = updateNearKeysDistances(x, y, currentNearKeysDistances); 593ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float score = getPointScore(x, y, time, isLastPoint, nearest, sumAngle, 594d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi currentNearKeysDistances, prevNearKeysDistances, prevPrevNearKeysDistances); 595d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi if (score < 0) { 596d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi // Pop previous point because it would be useless. 597096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi popInputData(); 598feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka size = mSampledInputXs.size(); 599d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi popped = true; 600d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } else { 601d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi popped = false; 602d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 603d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi // Check if the last point should be skipped. 604806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi if (isLastPoint && size > 0) { 605feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka if (getDistanceInt(x, y, mSampledInputXs.back(), mSampledInputYs.back()) 606ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi * LAST_POINT_SKIP_DISTANCE_SCALE < mProximityInfo->getMostCommonKeyWidth()) { 607806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi // This point is not used because it's too close to the previous point. 6089182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka if (DEBUG_GEO_FULL) { 609806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi AKLOGI("p0: size = %zd, x = %d, y = %d, lx = %d, ly = %d, dist = %d, " 610feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka "width = %d", size, x, y, mSampledInputXs.back(), mSampledInputYs.back(), 611feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka getDistanceInt(x, y, mSampledInputXs.back(), mSampledInputYs.back()), 6129182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka mProximityInfo->getMostCommonKeyWidth() 613806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi / LAST_POINT_SKIP_DISTANCE_SCALE); 6149182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka } 615d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi return popped; 616d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 617d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 618d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 619d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi 6201e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa if (nodeCodePoint >= 0 && (x < 0 || y < 0)) { 6211e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa const int keyId = mProximityInfo->getKeyIndexOf(nodeCodePoint); 622687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka if (keyId >= 0) { 623f2789819bd005b5b0581e8439601b5501306327dKen Wakasa x = mProximityInfo->getKeyCenterXOfKeyIdG(keyId); 624f2789819bd005b5b0581e8439601b5501306327dKen Wakasa y = mProximityInfo->getKeyCenterYOfKeyIdG(keyId); 625687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka } 626687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka } 627d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi 628d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi // Pushing point information. 629d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi if (size > 0) { 630d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi mLengthCache.push_back( 631feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka mLengthCache.back() + getDistanceInt( 632feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka x, y, mSampledInputXs.back(), mSampledInputYs.back())); 633d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } else { 634d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi mLengthCache.push_back(0); 635d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi } 636feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka mSampledInputXs.push_back(x); 637feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka mSampledInputYs.push_back(y); 638687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka mTimes.push_back(time); 639096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mInputIndice.push_back(inputIndex); 640952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka if (DEBUG_GEO_FULL) { 641952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka AKLOGI("pushTouchPoint: x = %03d, y = %03d, time = %d, index = %d, popped ? %01d", 642952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka x, y, time, inputIndex, popped); 643952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka } 644d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi return popped; 645687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka} 646687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka 6474a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataokafloat ProximityInfoState::calculateNormalizedSquaredDistance( 6484a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka const int keyIndex, const int inputIndex) const { 6494a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka if (keyIndex == NOT_AN_INDEX) { 6504a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka return NOT_A_DISTANCE_FLOAT; 6514a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka } 6524a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka if (!mProximityInfo->hasSweetSpotData(keyIndex)) { 6534a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka return NOT_A_DISTANCE_FLOAT; 6544a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka } 655feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka if (NOT_A_COORDINATE == mSampledInputXs[inputIndex]) { 6564a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka return NOT_A_DISTANCE_FLOAT; 6574a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka } 6584a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka const float squaredDistance = calculateSquaredDistanceFromSweetSpotCenter( 6594a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka keyIndex, inputIndex); 6604a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka const float squaredRadius = square(mProximityInfo->getSweetSpotRadiiAt(keyIndex)); 6614a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka return squaredDistance / squaredRadius; 6624a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka} 6634a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka 664687a244703a02323ebd64433cbaead5def499861Satoshi Kataokaint ProximityInfoState::getDuration(const int index) const { 665feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka if (index >= 0 && index < mSampledInputSize - 1) { 666a811938d40070b96557df0f2a36ba8daa561fdd4Tom Ouyang return mTimes[index + 1] - mTimes[index]; 667687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka } 66837b153e205c9672b299b47e97921fee2462a78bbSatoshi Kataoka return 0; 669687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka} 670687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka 6710519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataoka// TODO: Remove the "scale" parameter 6720519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataoka// This function basically converts from a length to an edit distance. Accordingly, it's obviously 6730519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataoka// wrong to compare with mMaxPointToKeyLength. 6740519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataokafloat ProximityInfoState::getPointToKeyLength( 6750519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataoka const int inputIndex, const int codePoint, const float scale) const { 676ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const int keyId = mProximityInfo->getKeyIndexOf(codePoint); 677ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (keyId != NOT_AN_INDEX) { 678ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const int index = inputIndex * mProximityInfo->getKeyCount() + keyId; 6790519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataoka return min(mDistanceCache[index] * scale, mMaxPointToKeyLength); 680ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 6811e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa if (isSkippableCodePoint(codePoint)) { 682806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi return 0.0f; 683806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 684ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // If the char is not a key on the keyboard then return the max length. 685ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi return MAX_POINT_TO_KEY_LENGTH; 686806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi} 687806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi 6880519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataokafloat ProximityInfoState::getPointToKeyLength(const int inputIndex, const int codePoint) const { 6890519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataoka return getPointToKeyLength(inputIndex, codePoint, 1.0f); 6900519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataoka} 6910519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataoka 6920519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataoka// TODO: Remove the "scale" parameter 6930519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataoka// This function basically converts from a length to an edit distance. Accordingly, it's obviously 6940519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataoka// wrong to compare with mMaxPointToKeyLength. 6950519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataokafloat ProximityInfoState::getPointToKeyByIdLength( 6960519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataoka const int inputIndex, const int keyId, const float scale) const { 6978c220a0aa2c5139a3b12af20e68c420f6402294aTom Ouyang if (keyId != NOT_AN_INDEX) { 698687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka const int index = inputIndex * mProximityInfo->getKeyCount() + keyId; 6990519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataoka return min(mDistanceCache[index] * scale, mMaxPointToKeyLength); 700cde005c05ec6b552ec26740b578be12c7d24013bSatoshi Kataoka } 7018c220a0aa2c5139a3b12af20e68c420f6402294aTom Ouyang // If the char is not a key on the keyboard then return the max length. 702806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi return static_cast<float>(MAX_POINT_TO_KEY_LENGTH); 703687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka} 704687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka 7050519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataokafloat ProximityInfoState::getPointToKeyByIdLength(const int inputIndex, const int keyId) const { 7060519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataoka return getPointToKeyByIdLength(inputIndex, keyId, 1.0f); 7070519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataoka} 7080519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataoka 7092c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa// In the following function, c is the current character of the dictionary word currently examined. 7102c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa// currentChars is an array containing the keys close to the character the user actually typed at 7112c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa// the same position. We want to see if c is in it: if so, then the word contains at that position 7122c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa// a character close to what the user typed. 7132c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa// What the user typed is actually the first character of the array. 7142c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa// proximityIndex is a pointer to the variable where getMatchedProximityId returns the index of c 7152c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa// in the proximity chars of the input index. 7162c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa// Notice : accented characters do not have a proximity list, so they are alone in their list. The 7172c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa// non-accented version of the character should be considered "close", but not the other keys close 7182c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa// to the non-accented version. 7192c2f3a90d8115777adbe9ffd597f344aede84276Ken WakasaProximityType ProximityInfoState::getMatchedProximityId(const int index, const int c, 7202c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa const bool checkProximityChars, int *proximityIndex) const { 7212c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa const int *currentCodePoints = getProximityCodePointsAt(index); 7222c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa const int firstCodePoint = currentCodePoints[0]; 7232c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa const int baseLowerC = toBaseLowerCase(c); 7242c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa 7252c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa // The first char in the array is what user typed. If it matches right away, that means the 7262c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa // user typed that same char for this pos. 7272c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa if (firstCodePoint == baseLowerC || firstCodePoint == c) { 7282c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa return EQUIVALENT_CHAR; 7292c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa } 7302c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa 7312c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa if (!checkProximityChars) return UNRELATED_CHAR; 7322c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa 7332c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa // If the non-accented, lowercased version of that first character matches c, then we have a 7342c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa // non-accented version of the accented character the user typed. Treat it as a close char. 7352c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa if (toBaseLowerCase(firstCodePoint) == baseLowerC) { 7362c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa return NEAR_PROXIMITY_CHAR; 7372c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa } 7382c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa 7392c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa // Not an exact nor an accent-alike match: search the list of close keys 7402c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa int j = 1; 7412c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa while (j < MAX_PROXIMITY_CHARS_SIZE_INTERNAL 7422c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa && currentCodePoints[j] > ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE) { 7432c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa const bool matched = (currentCodePoints[j] == baseLowerC || currentCodePoints[j] == c); 7442c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa if (matched) { 7452c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa if (proximityIndex) { 7462c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa *proximityIndex = j; 7472c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa } 7482c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa return NEAR_PROXIMITY_CHAR; 7492c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa } 7502c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa ++j; 7512c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa } 7522c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa if (j < MAX_PROXIMITY_CHARS_SIZE_INTERNAL 7532c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa && currentCodePoints[j] == ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE) { 7542c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa ++j; 7552c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa while (j < MAX_PROXIMITY_CHARS_SIZE_INTERNAL 7562c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa && currentCodePoints[j] > ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE) { 7572c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa const bool matched = (currentCodePoints[j] == baseLowerC || currentCodePoints[j] == c); 7582c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa if (matched) { 7592c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa if (proximityIndex) { 7602c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa *proximityIndex = j; 7612c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa } 7622c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa return ADDITIONAL_PROXIMITY_CHAR; 7632c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa } 7642c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa ++j; 7652c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa } 7662c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa } 7672c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa // Was not included, signal this as an unrelated character. 7682c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa return UNRELATED_CHAR; 7692c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa} 7702c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa 7713811a28ddc07201930e0bbd2e1d01045b59af308Keisuke Kuroyanagiint ProximityInfoState::getSpaceY() const { 772b02ee3d67a1884b6ff59cc16c29a476845c0694fKen Wakasa const int keyId = mProximityInfo->getKeyIndexOf(KEYCODE_SPACE); 773f2789819bd005b5b0581e8439601b5501306327dKen Wakasa return mProximityInfo->getKeyCenterYOfKeyIdG(keyId); 774687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka} 775687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka 7764a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataokafloat ProximityInfoState::calculateSquaredDistanceFromSweetSpotCenter( 7774a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka const int keyIndex, const int inputIndex) const { 7784a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka const float sweetSpotCenterX = mProximityInfo->getSweetSpotCenterXAt(keyIndex); 7794a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka const float sweetSpotCenterY = mProximityInfo->getSweetSpotCenterYAt(keyIndex); 780feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka const float inputX = static_cast<float>(mSampledInputXs[inputIndex]); 781feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka const float inputY = static_cast<float>(mSampledInputYs[inputIndex]); 7824a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka return square(inputX - sweetSpotCenterX) + square(inputY - sweetSpotCenterY); 7834a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka} 78495a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi 78595a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi// Puts possible characters into filter and returns new filter size. 786082507e1da56c6cefe575ec3d6a334e9b717e3faKen Wakasaint ProximityInfoState::getAllPossibleChars( 787082507e1da56c6cefe575ec3d6a334e9b717e3faKen Wakasa const size_t index, int *const filter, const int filterSize) const { 788feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka if (index >= mSampledInputXs.size()) { 78995a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi return filterSize; 79095a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi } 79141f12ee27b269033fe818f7d52e81ba948a046c3Keisuke Kuroyanagi int newFilterSize = filterSize; 792ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const int keyCount = mProximityInfo->getKeyCount(); 793ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi for (int j = 0; j < keyCount; ++j) { 794ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (mSearchKeysVector[index].test(j)) { 795082507e1da56c6cefe575ec3d6a334e9b717e3faKen Wakasa const int keyCodePoint = mProximityInfo->getCodePointOf(j); 79695a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi bool insert = true; 79795a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi // TODO: Avoid linear search 79895a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi for (int k = 0; k < filterSize; ++k) { 79995a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi if (filter[k] == keyCodePoint) { 80095a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi insert = false; 80195a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi break; 80295a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi } 80395a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi } 80495a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi if (insert) { 80541f12ee27b269033fe818f7d52e81ba948a046c3Keisuke Kuroyanagi filter[newFilterSize++] = keyCodePoint; 80695a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi } 80795a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi } 80895a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi } 80941f12ee27b269033fe818f7d52e81ba948a046c3Keisuke Kuroyanagi return newFilterSize; 81095a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi} 8113811a28ddc07201930e0bbd2e1d01045b59af308Keisuke Kuroyanagi 812ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagibool ProximityInfoState::isKeyInSerchKeysAfterIndex(const int index, const int keyId) const { 813ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi ASSERT(keyId >= 0); 814feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka ASSERT(index >= 0 && index < mSampledInputSize); 815ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi return mSearchKeysVector[index].test(keyId); 816ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi} 817ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 818096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagivoid ProximityInfoState::popInputData() { 819feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka mSampledInputXs.pop_back(); 820feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka mSampledInputYs.pop_back(); 821096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mTimes.pop_back(); 822096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mLengthCache.pop_back(); 823096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi mInputIndice.pop_back(); 824096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi} 825096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi 826ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagifloat ProximityInfoState::getDirection(const int index0, const int index1) const { 827feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka if (index0 < 0 || index0 > mSampledInputSize - 1) { 828ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi return 0.0f; 829ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 830feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka if (index1 < 0 || index1 > mSampledInputSize - 1) { 831ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi return 0.0f; 832ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 833feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka const int x1 = mSampledInputXs[index0]; 834feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka const int y1 = mSampledInputYs[index0]; 835feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka const int x2 = mSampledInputXs[index1]; 836feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka const int y2 = mSampledInputYs[index1]; 837ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi return getAngle(x1, y1, x2, y2); 838ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi} 839ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 840806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagifloat ProximityInfoState::getPointAngle(const int index) const { 841feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka if (index <= 0 || index >= mSampledInputSize - 1) { 842806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi return 0.0f; 843806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 844ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float previousDirection = getDirection(index - 1, index); 845ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float nextDirection = getDirection(index, index + 1); 846806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi const float directionDiff = getAngleDiff(previousDirection, nextDirection); 847806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi return directionDiff; 848806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi} 849806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi 850806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagifloat ProximityInfoState::getPointsAngle( 851806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi const int index0, const int index1, const int index2) const { 852feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka if (index0 < 0 || index0 > mSampledInputSize - 1) { 853806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi return 0.0f; 854806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 855feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka if (index1 < 0 || index1 > mSampledInputSize - 1) { 856806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi return 0.0f; 857806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 858feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka if (index2 < 0 || index2 > mSampledInputSize - 1) { 859806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi return 0.0f; 860806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 861ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float previousDirection = getDirection(index0, index1); 862ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float nextDirection = getDirection(index1, index2); 863ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi return getAngleDiff(previousDirection, nextDirection); 864ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi} 865ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 866ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagifloat ProximityInfoState::getLineToKeyDistance( 867ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const int from, const int to, const int keyId, const bool extend) const { 868feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka if (from < 0 || from > mSampledInputSize - 1) { 869ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi return 0.0f; 870ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 871feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka if (to < 0 || to > mSampledInputSize - 1) { 872ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi return 0.0f; 873ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 874feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka const int x0 = mSampledInputXs[from]; 875feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka const int y0 = mSampledInputYs[from]; 876feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka const int x1 = mSampledInputXs[to]; 877feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka const int y1 = mSampledInputYs[to]; 878ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 879ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const int keyX = mProximityInfo->getKeyCenterXOfKeyIdG(keyId); 880ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const int keyY = mProximityInfo->getKeyCenterYOfKeyIdG(keyId); 881ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 882ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi return pointToLineSegSquaredDistanceFloat(keyX, keyY, x0, y0, x1, y1, extend); 883806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi} 884806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi 885806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi// Updates probabilities of aligning to some keys and skipping. 886806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi// Word suggestion should be based on this probabilities. 887ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagivoid ProximityInfoState::updateAlignPointProbabilities(const int start) { 888ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float MIN_PROBABILITY = 0.000001f; 889ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float MAX_SKIP_PROBABILITY = 0.95f; 890806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi static const float SKIP_FIRST_POINT_PROBABILITY = 0.01f; 891806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi static const float SKIP_LAST_POINT_PROBABILITY = 0.1f; 892ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float MIN_SPEED_RATE_FOR_SKIP_PROBABILITY = 0.15f; 893ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float SPEED_WEIGHT_FOR_SKIP_PROBABILITY = 0.9f; 894ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float SLOW_STRAIGHT_WEIGHT_FOR_SKIP_PROBABILITY = 0.6f; 895ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float NEAREST_DISTANCE_WEIGHT = 0.5f; 896ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float NEAREST_DISTANCE_BIAS = 0.5f; 897ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float NEAREST_DISTANCE_WEIGHT_FOR_LAST = 0.6f; 898ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float NEAREST_DISTANCE_BIAS_FOR_LAST = 0.4f; 899ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 900ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float ANGLE_WEIGHT = 0.90f; 901ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float DEEP_CORNER_ANGLE_THRESHOLD = M_PI_F * 60.0f / 180.0f; 902ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float SKIP_DEEP_CORNER_PROBABILITY = 0.1f; 903ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float CORNER_ANGLE_THRESHOLD = M_PI_F * 30.0f / 180.0f; 904806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi static const float STRAIGHT_ANGLE_THRESHOLD = M_PI_F * 15.0f / 180.0f; 905ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float SKIP_CORNER_PROBABILITY = 0.4f; 906ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float SPEED_MARGIN = 0.1f; 907806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi static const float CENTER_VALUE_OF_NORMALIZED_DISTRIBUTION = 0.0f; 908806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi 909ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const int keyCount = mProximityInfo->getKeyCount(); 910feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka mCharProbabilities.resize(mSampledInputSize); 911806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi // Calculates probabilities of using a point as a correlated point with the character 912806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi // for each point. 913feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka for (int i = start; i < mSampledInputSize; ++i) { 914ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi mCharProbabilities[i].clear(); 915ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // First, calculates skip probability. Starts form MIN_SKIP_PROBABILITY. 916806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi // Note that all values that are multiplied to this probability should be in [0.0, 1.0]; 917ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi float skipProbability = MAX_SKIP_PROBABILITY; 918ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 919ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float currentAngle = getPointAngle(i); 9209af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka const float speedRate = getSpeedRate(i); 921ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 922ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi float nearestKeyDistance = static_cast<float>(MAX_POINT_TO_KEY_LENGTH); 923ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi for (int j = 0; j < keyCount; ++j) { 924ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (mNearKeysVector[i].test(j)) { 925ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float distance = getPointToKeyByIdLength(i, j); 926ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (distance < nearestKeyDistance) { 927ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi nearestKeyDistance = distance; 928ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 929ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 930ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 931806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi 932806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi if (i == 0) { 933ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi skipProbability *= min(1.0f, nearestKeyDistance * NEAREST_DISTANCE_WEIGHT 934ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi + NEAREST_DISTANCE_BIAS); 935ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // Promote the first point 936806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi skipProbability *= SKIP_FIRST_POINT_PROBABILITY; 937feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka } else if (i == mSampledInputSize - 1) { 938ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi skipProbability *= min(1.0f, nearestKeyDistance * NEAREST_DISTANCE_WEIGHT_FOR_LAST 939ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi + NEAREST_DISTANCE_BIAS_FOR_LAST); 940ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // Promote the last point 941806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi skipProbability *= SKIP_LAST_POINT_PROBABILITY; 942806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } else { 943ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // If the current speed is relatively slower than adjacent keys, we promote this point. 9449af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka if (getSpeedRate(i - 1) - SPEED_MARGIN > speedRate 9459af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka && speedRate < getSpeedRate(i + 1) - SPEED_MARGIN) { 946ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (currentAngle < CORNER_ANGLE_THRESHOLD) { 9479af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka skipProbability *= min(1.0f, speedRate 948ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi * SLOW_STRAIGHT_WEIGHT_FOR_SKIP_PROBABILITY); 949ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } else { 950ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // If the angle is small enough, we promote this point more. (e.g. pit vs put) 9519af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka skipProbability *= min(1.0f, speedRate * SPEED_WEIGHT_FOR_SKIP_PROBABILITY 952ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi + MIN_SPEED_RATE_FOR_SKIP_PROBABILITY); 953ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 954ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 955ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 9569af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka skipProbability *= min(1.0f, speedRate * nearestKeyDistance * 957ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi NEAREST_DISTANCE_WEIGHT + NEAREST_DISTANCE_BIAS); 958806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi 959806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi // Adjusts skip probability by a rate depending on angle. 960806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi // ANGLE_RATE of skipProbability is adjusted by current angle. 961ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi skipProbability *= (M_PI_F - currentAngle) / M_PI_F * ANGLE_WEIGHT 962ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi + (1.0f - ANGLE_WEIGHT); 963806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi if (currentAngle > DEEP_CORNER_ANGLE_THRESHOLD) { 964806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi skipProbability *= SKIP_DEEP_CORNER_PROBABILITY; 965806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 966ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // We assume the angle of this point is the angle for point[i], point[i - 2] 967ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // and point[i - 3]. The reason why we don't use the angle for point[i], point[i - 1] 968ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // and point[i - 2] is this angle can be more affected by the noise. 969ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float prevAngle = getPointsAngle(i, i - 2, i - 3); 970ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (i >= 3 && prevAngle < STRAIGHT_ANGLE_THRESHOLD 971ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi && currentAngle > CORNER_ANGLE_THRESHOLD) { 972806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi skipProbability *= SKIP_CORNER_PROBABILITY; 973806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 974806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 975806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi 976ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // probabilities must be in [0.0, MAX_SKIP_PROBABILITY]; 977806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi ASSERT(skipProbability >= 0.0f); 978ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi ASSERT(skipProbability <= MAX_SKIP_PROBABILITY); 979806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi mCharProbabilities[i][NOT_AN_INDEX] = skipProbability; 980ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 981806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi // Second, calculates key probabilities by dividing the rest probability 982806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi // (1.0f - skipProbability). 983806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi const float inputCharProbability = 1.0f - skipProbability; 984ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 985ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // TODO: The variance is critical for accuracy; thus, adjusting these parameter by machine 986ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // learning or something would be efficient. 987ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float SPEEDxANGLE_WEIGHT_FOR_STANDARD_DIVIATION = 0.3f; 988ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float MAX_SPEEDxANGLE_RATE_FOR_STANDERD_DIVIATION = 0.25f; 989ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float SPEEDxNEAREST_WEIGHT_FOR_STANDARD_DIVIATION = 0.5f; 990ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float MAX_SPEEDxNEAREST_RATE_FOR_STANDERD_DIVIATION = 0.15f; 991ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float MIN_STANDERD_DIVIATION = 0.37f; 992ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 9939af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka const float speedxAngleRate = min(speedRate * currentAngle / M_PI_F 994ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi * SPEEDxANGLE_WEIGHT_FOR_STANDARD_DIVIATION, 995ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi MAX_SPEEDxANGLE_RATE_FOR_STANDERD_DIVIATION); 9969af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka const float speedxNearestKeyDistanceRate = min(speedRate * nearestKeyDistance 997ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi * SPEEDxNEAREST_WEIGHT_FOR_STANDARD_DIVIATION, 998ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi MAX_SPEEDxNEAREST_RATE_FOR_STANDERD_DIVIATION); 999ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float sigma = speedxAngleRate + speedxNearestKeyDistanceRate + MIN_STANDERD_DIVIATION; 1000ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 1001806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi NormalDistribution distribution(CENTER_VALUE_OF_NORMALIZED_DISTRIBUTION, sigma); 1002ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float PREV_DISTANCE_WEIGHT = 0.5f; 1003ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float NEXT_DISTANCE_WEIGHT = 0.6f; 1004ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // Summing up probability densities of all near keys. 1005ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi float sumOfProbabilityDensities = 0.0f; 1006ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi for (int j = 0; j < keyCount; ++j) { 1007806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi if (mNearKeysVector[i].test(j)) { 1008ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi float distance = sqrtf(getPointToKeyByIdLength(i, j)); 1009feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka if (i == 0 && i != mSampledInputSize - 1) { 1010ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // For the first point, weighted average of distances from first point and the 1011ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // next point to the key is used as a point to key distance. 1012ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float nextDistance = sqrtf(getPointToKeyByIdLength(i + 1, j)); 1013ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (nextDistance < distance) { 1014ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // The distance of the first point tends to bigger than continuing 1015ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // points because the first touch by the user can be sloppy. 1016ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // So we promote the first point if the distance of that point is larger 1017ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // than the distance of the next point. 1018ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi distance = (distance + nextDistance * NEXT_DISTANCE_WEIGHT) 1019ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi / (1.0f + NEXT_DISTANCE_WEIGHT); 1020ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 1021feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka } else if (i != 0 && i == mSampledInputSize - 1) { 1022ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // For the first point, weighted average of distances from last point and 1023ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // the previous point to the key is used as a point to key distance. 1024ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float previousDistance = sqrtf(getPointToKeyByIdLength(i - 1, j)); 1025ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (previousDistance < distance) { 1026ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // The distance of the last point tends to bigger than continuing points 1027ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // because the last touch by the user can be sloppy. So we promote the 1028ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // last point if the distance of that point is larger than the distance of 1029ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // the previous point. 1030ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi distance = (distance + previousDistance * PREV_DISTANCE_WEIGHT) 1031ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi / (1.0f + PREV_DISTANCE_WEIGHT); 1032ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 1033ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 1034ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // TODO: Promote the first point when the extended line from the next input is near 1035ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // from a key. Also, promote the last point as well. 1036ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi sumOfProbabilityDensities += distribution.getProbabilityDensity(distance); 1037806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 1038806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 1039ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 1040ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // Split the probability of an input point to keys that are close to the input point. 1041ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi for (int j = 0; j < keyCount; ++j) { 1042806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi if (mNearKeysVector[i].test(j)) { 1043ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi float distance = sqrtf(getPointToKeyByIdLength(i, j)); 1044feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka if (i == 0 && i != mSampledInputSize - 1) { 1045ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // For the first point, weighted average of distances from the first point and 1046ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // the next point to the key is used as a point to key distance. 1047ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float prevDistance = sqrtf(getPointToKeyByIdLength(i + 1, j)); 1048ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (prevDistance < distance) { 1049ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi distance = (distance + prevDistance * NEXT_DISTANCE_WEIGHT) 1050ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi / (1.0f + NEXT_DISTANCE_WEIGHT); 1051ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 1052feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka } else if (i != 0 && i == mSampledInputSize - 1) { 1053ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // For the first point, weighted average of distances from last point and 1054ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // the previous point to the key is used as a point to key distance. 1055ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float prevDistance = sqrtf(getPointToKeyByIdLength(i - 1, j)); 1056ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (prevDistance < distance) { 1057ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi distance = (distance + prevDistance * PREV_DISTANCE_WEIGHT) 1058ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi / (1.0f + PREV_DISTANCE_WEIGHT); 1059ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 1060806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 1061ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float probabilityDensity = distribution.getProbabilityDensity(distance); 1062ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float probability = inputCharProbability * probabilityDensity 1063ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi / sumOfProbabilityDensities; 1064ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi mCharProbabilities[i][j] = probability; 1065806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 1066806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 1067806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 1068806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi 1069ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 1070ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (DEBUG_POINTS_PROBABILITY) { 1071feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka for (int i = 0; i < mSampledInputSize; ++i) { 1072ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi std::stringstream sstream; 1073ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi sstream << i << ", "; 1074feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka sstream << "(" << mSampledInputXs[i] << ", " << mSampledInputYs[i] << "), "; 10759af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka sstream << "Speed: "<< getSpeedRate(i) << ", "; 1076ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi sstream << "Angle: "<< getPointAngle(i) << ", \n"; 1077ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 1078ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi for (hash_map_compat<int, float>::iterator it = mCharProbabilities[i].begin(); 1079ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi it != mCharProbabilities[i].end(); ++it) { 1080ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (it->first == NOT_AN_INDEX) { 1081ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi sstream << it->first 1082ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi << "(skip):" 1083ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi << it->second 1084ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi << "\n"; 1085ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } else { 1086ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi sstream << it->first 1087ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi << "(" 1088ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi << static_cast<char>(mProximityInfo->getCodePointOf(it->first)) 1089ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi << "):" 1090ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi << it->second 1091ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi << "\n"; 1092ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 1093ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 1094ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi AKLOGI("%s", sstream.str().c_str()); 1095ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 1096ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 1097ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 1098806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi // Decrease key probabilities of points which don't have the highest probability of that key 1099806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi // among nearby points. Probabilities of the first point and the last point are not suppressed. 1100feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka for (int i = max(start, 1); i < mSampledInputSize; ++i) { 1101feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka for (int j = i + 1; j < mSampledInputSize; ++j) { 1102ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (!suppressCharProbabilities(i, j)) { 1103806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi break; 1104806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 1105806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 1106ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi for (int j = i - 1; j >= max(start, 0); --j) { 1107ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (!suppressCharProbabilities(i, j)) { 1108806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi break; 1109806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 1110806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 1111806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 1112806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi 1113ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // Converting from raw probabilities to log probabilities to calculate spatial distance. 1114feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka for (int i = start; i < mSampledInputSize; ++i) { 1115ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi for (int j = 0; j < keyCount; ++j) { 1116ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi hash_map_compat<int, float>::iterator it = mCharProbabilities[i].find(j); 1117ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (it == mCharProbabilities[i].end()){ 1118ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi mNearKeysVector[i].reset(j); 1119ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } else if(it->second < MIN_PROBABILITY) { 1120ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // Erases from near keys vector because it has very low probability. 1121ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi mNearKeysVector[i].reset(j); 1122ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi mCharProbabilities[i].erase(j); 1123ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } else { 1124ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi it->second = -logf(it->second); 1125806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 1126806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 1127ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi mCharProbabilities[i][NOT_AN_INDEX] = -logf(mCharProbabilities[i][NOT_AN_INDEX]); 1128806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 1129806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi} 1130806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi 1131ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi// Decreases char probabilities of index0 by checking probabilities of a near point (index1) and 1132ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi// increases char probabilities of index1 by checking probabilities of index0. 1133806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagibool ProximityInfoState::suppressCharProbabilities(const int index0, const int index1) { 1134feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka ASSERT(0 <= index0 && index0 < mSampledInputSize); 1135feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka ASSERT(0 <= index1 && index1 < mSampledInputSize); 1136ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 1137806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi static const float SUPPRESSION_LENGTH_WEIGHT = 1.5f; 1138ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float MIN_SUPPRESSION_RATE = 0.1f; 1139ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float SUPPRESSION_WEIGHT = 0.5f; 1140ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float SUPPRESSION_WEIGHT_FOR_PROBABILITY_GAIN = 0.1f; 1141ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi static const float SKIP_PROBABALITY_WEIGHT_FOR_PROBABILITY_GAIN = 0.3f; 1142ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 1143806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi const float keyWidthFloat = static_cast<float>(mProximityInfo->getMostCommonKeyWidth()); 1144806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi const float diff = fabsf(static_cast<float>(mLengthCache[index0] - mLengthCache[index1])); 1145806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi if (diff > keyWidthFloat * SUPPRESSION_LENGTH_WEIGHT) { 1146806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi return false; 1147806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 1148ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float suppressionRate = MIN_SUPPRESSION_RATE 1149ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi + diff / keyWidthFloat / SUPPRESSION_LENGTH_WEIGHT * SUPPRESSION_WEIGHT; 1150806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi for (hash_map_compat<int, float>::iterator it = mCharProbabilities[index0].begin(); 1151806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi it != mCharProbabilities[index0].end(); ++it) { 1152ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi hash_map_compat<int, float>::iterator it2 = mCharProbabilities[index1].find(it->first); 1153806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi if (it2 != mCharProbabilities[index1].end() && it->second < it2->second) { 1154806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi const float newProbability = it->second * suppressionRate; 1155ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float suppression = it->second - newProbability; 1156806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi it->second = newProbability; 1157ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // mCharProbabilities[index0][NOT_AN_INDEX] is the probability of skipping this point. 1158ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi mCharProbabilities[index0][NOT_AN_INDEX] += suppression; 1159ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 1160ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi // Add the probability of the same key nearby index1 1161ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float probabilityGain = min(suppression * SUPPRESSION_WEIGHT_FOR_PROBABILITY_GAIN, 1162ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi mCharProbabilities[index1][NOT_AN_INDEX] 1163ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi * SKIP_PROBABALITY_WEIGHT_FOR_PROBABILITY_GAIN); 1164ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi it2->second += probabilityGain; 1165ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi mCharProbabilities[index1][NOT_AN_INDEX] -= probabilityGain; 1166806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 1167806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 1168806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi return true; 1169806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi} 1170806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi 1171a21187188fd17c2ce133fca8512106327212da5fSatoshi Kataoka// Get a word that is detected by tracing the most probable char sequence into codePointBuf and 11721e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa// returns probability of generating the word. 1173a21187188fd17c2ce133fca8512106327212da5fSatoshi Kataokafloat ProximityInfoState::getMostProbableCharSequence(int *const codePointBuf) const { 1174350309aeb81ad1924af4d2e6d0bceaa6f98e4821Keisuke Kuroyanagi static const float DEMOTION_LOG_PROBABILITY = 0.3f; 1175ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi int index = 0; 1176ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi float sumLogProbability = 0.0f; 1177806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi // TODO: Current implementation is greedy algorithm. DP would be efficient for many cases. 1178feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka for (int i = 0; i < mSampledInputSize && index < MAX_WORD_LENGTH_INTERNAL - 1; ++i) { 1179ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi float minLogProbability = static_cast<float>(MAX_POINT_TO_KEY_LENGTH); 1180ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi int character = NOT_AN_INDEX; 1181806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi for (hash_map_compat<int, float>::const_iterator it = mCharProbabilities[i].begin(); 1182806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi it != mCharProbabilities[i].end(); ++it) { 1183ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi const float logProbability = (it->first != NOT_AN_INDEX) 1184350309aeb81ad1924af4d2e6d0bceaa6f98e4821Keisuke Kuroyanagi ? it->second + DEMOTION_LOG_PROBABILITY : it->second; 1185ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (logProbability < minLogProbability) { 1186ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi minLogProbability = logProbability; 1187ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi character = it->first; 1188806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 1189806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 1190ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (character != NOT_AN_INDEX) { 11911e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa codePointBuf[index] = mProximityInfo->getCodePointOf(character); 1192806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi index++; 1193806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 1194ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi sumLogProbability += minLogProbability; 1195806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi } 11961e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa codePointBuf[index] = '\0'; 1197ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi return sumLogProbability; 1198ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi} 1199ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi 1200ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi// Returns a probability of mapping index to keyIndex. 1201ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagifloat ProximityInfoState::getProbability(const int index, const int keyIndex) const { 1202feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka ASSERT(0 <= index && index < mSampledInputSize); 1203ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi hash_map_compat<int, float>::const_iterator it = mCharProbabilities[index].find(keyIndex); 1204ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi if (it != mCharProbabilities[index].end()) { 1205ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi return it->second; 1206ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi } 1207ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi return static_cast<float>(MAX_POINT_TO_KEY_LENGTH); 1208806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi} 12093e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka} // namespace latinime 1210