proximity_info_state.cpp revision 1e06a4d8e9e71188ed685282155ea52a48ddc050
13e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka/*
23e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * Copyright (C) 2012 The Android Open Source Project
33e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka *
43e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * Licensed under the Apache License, Version 2.0 (the "License");
53e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * you may not use this file except in compliance with the License.
63e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * You may obtain a copy of the License at
73e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka *
83e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka *      http://www.apache.org/licenses/LICENSE-2.0
93e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka *
103e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * Unless required by applicable law or agreed to in writing, software
113e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * distributed under the License is distributed on an "AS IS" BASIS,
123e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * See the License for the specific language governing permissions and
143e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * limitations under the License.
153e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka */
163e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka
1777e8e81ad95cfc1eb8f8407fc872674b8d08bbe9Ken Wakasa#include <cstring> // for memset()
18806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi#include <sstream> // for debug prints
193e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka#include <stdint.h>
203e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka
213e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka#define LOG_TAG "LatinIME: proximity_info_state.cpp"
223e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka
233e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka#include "defines.h"
24687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka#include "geometry_utils.h"
253e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka#include "proximity_info.h"
263e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka#include "proximity_info_state.h"
273e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka
283e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataokanamespace latinime {
29764dd712032d7b8012797b1116b523bef7b907f3Ken Wakasa
30764dd712032d7b8012797b1116b523bef7b907f3Ken Wakasaconst int ProximityInfoState::NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR_LOG_2 = 10;
31764dd712032d7b8012797b1116b523bef7b907f3Ken Wakasaconst int ProximityInfoState::NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR =
32764dd712032d7b8012797b1116b523bef7b907f3Ken Wakasa        1 << NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR_LOG_2;
33764dd712032d7b8012797b1116b523bef7b907f3Ken Wakasaconst float ProximityInfoState::NOT_A_DISTANCE_FLOAT = -1.0f;
34764dd712032d7b8012797b1116b523bef7b907f3Ken Wakasaconst int ProximityInfoState::NOT_A_CODE = -1;
35764dd712032d7b8012797b1116b523bef7b907f3Ken Wakasa
36233aad5e5c7567a97af30f38f50a65365f729dfeSatoshi Kataokavoid ProximityInfoState::initInputParams(const int pointerId, const float maxPointToKeyLength,
3708f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka        const ProximityInfo *proximityInfo, const int32_t *const inputCodes, const int inputSize,
38687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka        const int *const xCoordinates, const int *const yCoordinates, const int *const times,
39687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka        const int *const pointerIds, const bool isGeometric) {
40096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi
41096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi    if (isGeometric) {
42096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi        mIsContinuationPossible = checkAndReturnIsContinuationPossible(
43096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi                inputSize, xCoordinates, yCoordinates, times);
44096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi    } else {
45096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi        mIsContinuationPossible = false;
46096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi    }
47096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi
484a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    mProximityInfo = proximityInfo;
494a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    mHasTouchPositionCorrectionData = proximityInfo->hasTouchPositionCorrectionData();
504a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    mMostCommonKeyWidthSquare = proximityInfo->getMostCommonKeyWidthSquare();
514a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    mLocaleStr = proximityInfo->getLocaleStr();
524a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    mKeyCount = proximityInfo->getKeyCount();
534a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    mCellHeight = proximityInfo->getCellHeight();
544a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    mCellWidth = proximityInfo->getCellWidth();
554a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    mGridHeight = proximityInfo->getGridWidth();
564a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    mGridWidth = proximityInfo->getGridHeight();
573e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka
5808f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka    memset(mInputCodes, 0, sizeof(mInputCodes));
593e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka
6008f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka    if (!isGeometric && pointerId == 0) {
6108f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka        // Initialize
6208f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka        // - mInputCodes
6308f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka        // - mNormalizedSquaredDistances
6408f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka        // TODO: Merge
65687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka        for (int i = 0; i < inputSize; ++i) {
6608f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka            const int32_t primaryKey = inputCodes[i];
6708f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka            const int x = xCoordinates[i];
6808f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka            const int y = yCoordinates[i];
6908f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka            int *proximities = &mInputCodes[i * MAX_PROXIMITY_CHARS_SIZE_INTERNAL];
7008f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka            mProximityInfo->calculateNearbyKeyCodes(x, y, primaryKey, proximities);
7108f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka        }
7208f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka
7308f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka        if (DEBUG_PROXIMITY_CHARS) {
7408f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka            for (int i = 0; i < inputSize; ++i) {
7508f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                AKLOGI("---");
7608f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                for (int j = 0; j < MAX_PROXIMITY_CHARS_SIZE_INTERNAL; ++j) {
7708f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                    int icc = mInputCodes[i * MAX_PROXIMITY_CHARS_SIZE_INTERNAL + j];
7808f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                    int icfjc = inputCodes[i * MAX_PROXIMITY_CHARS_SIZE_INTERNAL + j];
7908f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                    icc += 0;
8008f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                    icfjc += 0;
8108f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                    AKLOGI("--- (%d)%c,%c", i, icc, icfjc); AKLOGI("--- A<%d>,B<%d>", icc, icfjc);
8208f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                }
833e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka            }
843e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka        }
853e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka    }
86687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka
87687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka    ///////////////////////
88687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka    // Setup touch points
89096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi    int pushTouchPointStartIndex = 0;
90096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi    int lastSavedInputSize = 0;
9108f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka    mMaxPointToKeyLength = maxPointToKeyLength;
92096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi    if (mIsContinuationPossible && mInputIndice.size() > 1) {
93096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi        // Just update difference.
94096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi        // Two points prior is never skipped. Thus, we pop 2 input point data here.
95096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi        pushTouchPointStartIndex = mInputIndice[mInputIndice.size() - 2];
96096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi        popInputData();
97096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi        popInputData();
98096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi        lastSavedInputSize = mInputXs.size();
99096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi    } else {
100096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi        // Clear all data.
101096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi        mInputXs.clear();
102096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi        mInputYs.clear();
103096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi        mTimes.clear();
104096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi        mInputIndice.clear();
105096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi        mLengthCache.clear();
106096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi        mDistanceCache.clear();
107096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi        mNearKeysVector.clear();
108ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        mSearchKeysVector.clear();
10928661069591fd1d6a8e25981aaade2e5d8b20b9aKeisuke Kuroyanagi        mRelativeSpeeds.clear();
110806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        mCharProbabilities.clear();
1111e06a4d8e9e71188ed685282155ea52a48ddc050Keisuke Kuroyanagi        mDirections.clear();
112096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi    }
1139182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka    if (DEBUG_GEO_FULL) {
1149182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka        AKLOGI("Init ProximityInfoState: reused points =  %d, last input size = %d",
1159182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka                pushTouchPointStartIndex, lastSavedInputSize);
1169182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka    }
117687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka    mInputSize = 0;
118d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi
119687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka    if (xCoordinates && yCoordinates) {
120687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka        const bool proximityOnly = !isGeometric && (xCoordinates[0] < 0 || yCoordinates[0] < 0);
121096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi        int lastInputIndex = pushTouchPointStartIndex;
122096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi        for (int i = lastInputIndex; i < inputSize; ++i) {
123d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi            const int pid = pointerIds ? pointerIds[i] : 0;
124d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi            if (pointerId == pid) {
125d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi                lastInputIndex = i;
126d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi            }
127d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi        }
1289182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka        if (DEBUG_GEO_FULL) {
1299182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka            AKLOGI("Init ProximityInfoState: last input index = %d", lastInputIndex);
1309182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka        }
131d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi        // Working space to save near keys distances for current, prev and prevprev input point.
132d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi        NearKeysDistanceMap nearKeysDistances[3];
133d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi        // These pointers are swapped for each inputs points.
134d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi        NearKeysDistanceMap *currentNearKeysDistances = &nearKeysDistances[0];
135d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi        NearKeysDistanceMap *prevNearKeysDistances = &nearKeysDistances[1];
136d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi        NearKeysDistanceMap *prevPrevNearKeysDistances = &nearKeysDistances[2];
137ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        // "sumAngle" is accumulated by each angle of input points. And when "sumAngle" exceeds
138ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        // the threshold we save that point, reset sumAngle. This aims to keep the figure of
139ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        // the curve.
140ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        float sumAngle = 0.0f;
141d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi
142096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi        for (int i = pushTouchPointStartIndex; i <= lastInputIndex; ++i) {
143687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka            // Assuming pointerId == 0 if pointerIds is null.
144687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka            const int pid = pointerIds ? pointerIds[i] : 0;
1459182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka            if (DEBUG_GEO_FULL) {
1469182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka                AKLOGI("Init ProximityInfoState: (%d)PID = %d", i, pid);
1479182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka            }
148687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka            if (pointerId == pid) {
149687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka                const int c = isGeometric ? NOT_A_COORDINATE : getPrimaryCharAt(i);
150687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka                const int x = proximityOnly ? NOT_A_COORDINATE : xCoordinates[i];
151687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka                const int y = proximityOnly ? NOT_A_COORDINATE : yCoordinates[i];
152687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka                const int time = times ? times[i] : -1;
153ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
154ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                if (i > 1) {
155ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    const float prevAngle = getAngle(xCoordinates[i - 2], yCoordinates[i - 2],
156ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                            xCoordinates[i - 1], yCoordinates[i - 1]);
157ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    const float currentAngle =
158ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                            getAngle(xCoordinates[i - 1], yCoordinates[i - 1], x, y);
159ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    sumAngle += getAngleDiff(prevAngle, currentAngle);
160ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                }
161ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
162952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka                if (pushTouchPoint(i, c, x, y, time, isGeometric /* do sampling */,
163ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                        i == lastInputIndex, sumAngle, currentNearKeysDistances,
164ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                        prevNearKeysDistances, prevPrevNearKeysDistances)) {
165d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi                    // Previous point information was popped.
166d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi                    NearKeysDistanceMap *tmp = prevNearKeysDistances;
167d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi                    prevNearKeysDistances = currentNearKeysDistances;
168d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi                    currentNearKeysDistances = tmp;
169d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi                } else {
170d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi                    NearKeysDistanceMap *tmp = prevPrevNearKeysDistances;
171d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi                    prevPrevNearKeysDistances = prevNearKeysDistances;
172d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi                    prevNearKeysDistances = currentNearKeysDistances;
173d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi                    currentNearKeysDistances = tmp;
174ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    sumAngle = 0.0f;
17537b153e205c9672b299b47e97921fee2462a78bbSatoshi Kataoka                }
176687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka            }
177687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka        }
178d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi        mInputSize = mInputXs.size();
1793e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka    }
180687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka
18128661069591fd1d6a8e25981aaade2e5d8b20b9aKeisuke Kuroyanagi    if (mInputSize > 0 && isGeometric) {
182ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        // Relative speed calculation.
183806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        const int sumDuration = mTimes.back() - mTimes.front();
184806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        const int sumLength = mLengthCache.back() - mLengthCache.front();
185806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        const float averageSpeed = static_cast<float>(sumLength) / static_cast<float>(sumDuration);
18628661069591fd1d6a8e25981aaade2e5d8b20b9aKeisuke Kuroyanagi        mRelativeSpeeds.resize(mInputSize);
18728661069591fd1d6a8e25981aaade2e5d8b20b9aKeisuke Kuroyanagi        for (int i = lastSavedInputSize; i < mInputSize; ++i) {
18828661069591fd1d6a8e25981aaade2e5d8b20b9aKeisuke Kuroyanagi            const int index = mInputIndice[i];
18928661069591fd1d6a8e25981aaade2e5d8b20b9aKeisuke Kuroyanagi            int length = 0;
19028661069591fd1d6a8e25981aaade2e5d8b20b9aKeisuke Kuroyanagi            int duration = 0;
191806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi
192806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            // Calculate velocity by using distances and durations of
193806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            // NUM_POINTS_FOR_SPEED_CALCULATION points for both forward and backward.
194ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            static const int NUM_POINTS_FOR_SPEED_CALCULATION = 2;
195806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            for (int j = index; j < min(inputSize - 1, index + NUM_POINTS_FOR_SPEED_CALCULATION);
196806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                    ++j) {
197806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                if (i < mInputSize - 1 && j >= mInputIndice[i + 1]) {
198806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                    break;
199806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                }
200806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                length += getDistanceInt(xCoordinates[j], yCoordinates[j],
201806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                        xCoordinates[j + 1], yCoordinates[j + 1]);
202806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                duration += times[j + 1] - times[j];
203806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            }
204806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            for (int j = index - 1; j >= max(0, index - NUM_POINTS_FOR_SPEED_CALCULATION); --j) {
205806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                if (i > 0 && j < mInputIndice[i - 1]) {
206806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                    break;
207806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                }
208806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                length += getDistanceInt(xCoordinates[j], yCoordinates[j],
209806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                        xCoordinates[j + 1], yCoordinates[j + 1]);
210806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                duration += times[j + 1] - times[j];
211806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            }
212806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            if (duration == 0 || sumDuration == 0) {
213806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                // Cannot calculate speed; thus, it gives an average value (1.0);
214806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                mRelativeSpeeds[i] = 1.0f;
21528661069591fd1d6a8e25981aaade2e5d8b20b9aKeisuke Kuroyanagi            } else {
216806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                const float speed = static_cast<float>(length) / static_cast<float>(duration);
217806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                mRelativeSpeeds[i] = speed / averageSpeed;
21828661069591fd1d6a8e25981aaade2e5d8b20b9aKeisuke Kuroyanagi            }
21928661069591fd1d6a8e25981aaade2e5d8b20b9aKeisuke Kuroyanagi        }
2201e06a4d8e9e71188ed685282155ea52a48ddc050Keisuke Kuroyanagi
2211e06a4d8e9e71188ed685282155ea52a48ddc050Keisuke Kuroyanagi        // Direction calculation.
2221e06a4d8e9e71188ed685282155ea52a48ddc050Keisuke Kuroyanagi        mDirections.resize(mInputSize - 1);
2231e06a4d8e9e71188ed685282155ea52a48ddc050Keisuke Kuroyanagi        for (int i = max(0, lastSavedInputSize - 1); i < mInputSize - 1; ++i) {
2241e06a4d8e9e71188ed685282155ea52a48ddc050Keisuke Kuroyanagi            mDirections[i] = getDirection(i, i + 1);
2251e06a4d8e9e71188ed685282155ea52a48ddc050Keisuke Kuroyanagi        }
2261e06a4d8e9e71188ed685282155ea52a48ddc050Keisuke Kuroyanagi
22728661069591fd1d6a8e25981aaade2e5d8b20b9aKeisuke Kuroyanagi    }
22828661069591fd1d6a8e25981aaade2e5d8b20b9aKeisuke Kuroyanagi
229ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    if (DEBUG_GEO_FULL) {
230ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        for (int i = 0; i < mInputSize; ++i) {
231ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            AKLOGI("Sampled(%d): x = %d, y = %d, time = %d", i, mInputXs[i], mInputYs[i],
232ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    mTimes[i]);
233ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        }
234ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    }
235ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
236687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka    if (mInputSize > 0) {
237687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka        const int keyCount = mProximityInfo->getKeyCount();
23895a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi        mNearKeysVector.resize(mInputSize);
239ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        mSearchKeysVector.resize(mInputSize);
240687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka        mDistanceCache.resize(mInputSize * keyCount);
241096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi        for (int i = lastSavedInputSize; i < mInputSize; ++i) {
24295a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi            mNearKeysVector[i].reset();
243ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            mSearchKeysVector[i].reset();
24495a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi            static const float NEAR_KEY_NORMALIZED_SQUARED_THRESHOLD = 4.0f;
245687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka            for (int k = 0; k < keyCount; ++k) {
246687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka                const int index = i * keyCount + k;
247687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka                const int x = mInputXs[i];
248687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka                const int y = mInputYs[i];
24995a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi                const float normalizedSquaredDistance =
2500edab9d2fcc30667c79aa9221dbb27f042d8b455Satoshi Kataoka                        mProximityInfo->getNormalizedSquaredDistanceFromCenterFloatG(k, x, y);
25195a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi                mDistanceCache[index] = normalizedSquaredDistance;
25295a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi                if (normalizedSquaredDistance < NEAR_KEY_NORMALIZED_SQUARED_THRESHOLD) {
253ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    mNearKeysVector[i][k] = true;
25495a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi                }
25595a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi            }
25695a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi        }
257ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        if (isGeometric) {
258ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            // updates probabilities of skipping or mapping each key for all points.
259ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            updateAlignPointProbabilities(lastSavedInputSize);
260ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
261ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            static const float READ_FORWORD_LENGTH_SCALE = 0.95f;
262ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            const int readForwordLength = static_cast<int>(
263ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    hypotf(mProximityInfo->getKeyboardWidth(), mProximityInfo->getKeyboardHeight())
264ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                            * READ_FORWORD_LENGTH_SCALE);
265ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            for (int i = 0; i < mInputSize; ++i) {
266ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                if (i >= lastSavedInputSize) {
267ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    mSearchKeysVector[i].reset();
268ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                }
269ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                for (int j = max(i, lastSavedInputSize); j < mInputSize; ++j) {
270ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    if (mLengthCache[j] - mLengthCache[i] >= readForwordLength) {
271ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                        break;
272ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    }
273ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    mSearchKeysVector[i] |= mNearKeysVector[j];
27495a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi                }
275687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka            }
276687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka        }
277687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka    }
27808f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka
279806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    if (DEBUG_SAMPLING_POINTS) {
280806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        std::stringstream originalX, originalY, sampledX, sampledY;
281806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        for (int i = 0; i < inputSize; ++i) {
282806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            originalX << xCoordinates[i];
283806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            originalY << yCoordinates[i];
284806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            if (i != inputSize - 1) {
285806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                originalX << ";";
286806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                originalY << ";";
287806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            }
288806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        }
289806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        for (int i = 0; i < mInputSize; ++i) {
290806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            sampledX << mInputXs[i];
291806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            sampledY << mInputYs[i];
292806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            if (i != mInputSize - 1) {
293806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                sampledX << ";";
294806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                sampledY << ";";
295806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            }
296806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        }
297806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        AKLOGI("\n%s, %s,\n%s, %s,\n", originalX.str().c_str(), originalY.str().c_str(),
298806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                sampledX.str().c_str(), sampledY.str().c_str());
299806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    }
300687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka    // end
301687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka    ///////////////////////
302687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka
30308f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka    memset(mNormalizedSquaredDistances, NOT_A_DISTANCE, sizeof(mNormalizedSquaredDistances));
30408f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka    memset(mPrimaryInputWord, 0, sizeof(mPrimaryInputWord));
305233aad5e5c7567a97af30f38f50a65365f729dfeSatoshi Kataoka    mTouchPositionCorrectionEnabled = mInputSize > 0 && mHasTouchPositionCorrectionData
3060edab9d2fcc30667c79aa9221dbb27f042d8b455Satoshi Kataoka            && xCoordinates && yCoordinates;
30708f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka    if (!isGeometric && pointerId == 0) {
30808f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka        for (int i = 0; i < inputSize; ++i) {
30908f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka            mPrimaryInputWord[i] = getPrimaryCharAt(i);
3103e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka        }
31108f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka
31208f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka        for (int i = 0; i < mInputSize && mTouchPositionCorrectionEnabled; ++i) {
31308f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka            const int *proximityChars = getProximityCharsAt(i);
31408f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka            const int primaryKey = proximityChars[0];
31508f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka            const int x = xCoordinates[i];
31608f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka            const int y = yCoordinates[i];
3173e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka            if (DEBUG_PROXIMITY_CHARS) {
31808f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                int a = x + y + primaryKey;
31908f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                a += 0;
32008f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                AKLOGI("--- Primary = %c, x = %d, y = %d", primaryKey, x, y);
32108f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka            }
32208f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka            for (int j = 0; j < MAX_PROXIMITY_CHARS_SIZE_INTERNAL && proximityChars[j] > 0; ++j) {
32308f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                const int currentChar = proximityChars[j];
32408f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                const float squaredDistance =
32508f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                        hasInputCoordinates() ? calculateNormalizedSquaredDistance(
326f2789819bd005b5b0581e8439601b5501306327dKen Wakasa                                mProximityInfo->getKeyIndexOf(currentChar), i) :
32708f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                                NOT_A_DISTANCE_FLOAT;
32808f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                if (squaredDistance >= 0.0f) {
32908f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                    mNormalizedSquaredDistances[i * MAX_PROXIMITY_CHARS_SIZE_INTERNAL + j] =
33008f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                            (int) (squaredDistance * NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR);
33108f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                } else {
33208f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                    mNormalizedSquaredDistances[i * MAX_PROXIMITY_CHARS_SIZE_INTERNAL + j] =
33308f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                            (j == 0) ? EQUIVALENT_CHAR_WITHOUT_DISTANCE_INFO :
33408f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                                    PROXIMITY_CHAR_WITHOUT_DISTANCE_INFO;
33508f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                }
33608f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                if (DEBUG_PROXIMITY_CHARS) {
33708f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                    AKLOGI("--- Proximity (%d) = %c", j, currentChar);
33808f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                }
3393e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka            }
3403e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka        }
3413e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka    }
342952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka
343952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka    if (DEBUG_GEO_FULL) {
344952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka        AKLOGI("ProximityState init finished: %d points out of %d", mInputSize, inputSize);
345952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka    }
3463e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka}
3474a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka
348096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagibool ProximityInfoState::checkAndReturnIsContinuationPossible(const int inputSize,
349096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi        const int *const xCoordinates, const int *const yCoordinates, const int *const times) {
350096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi    for (int i = 0; i < mInputSize; ++i) {
351096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi        const int index = mInputIndice[i];
352096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi        if (index > inputSize || xCoordinates[index] != mInputXs[i] ||
353096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi                yCoordinates[index] != mInputYs[i] || times[index] != mTimes[i]) {
354096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi            return false;
355096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi        }
356096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi    }
357096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi    return true;
358096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi}
359096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi
360d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi// Calculating point to key distance for all near keys and returning the distance between
361d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi// the given point and the nearest key position.
362d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagifloat ProximityInfoState::updateNearKeysDistances(const int x, const int y,
363d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi        NearKeysDistanceMap *const currentNearKeysDistances) {
364ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    static const float NEAR_KEY_THRESHOLD = 2.0f;
365d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi
366d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi    currentNearKeysDistances->clear();
367d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi    const int keyCount = mProximityInfo->getKeyCount();
368d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi    float nearestKeyDistance = mMaxPointToKeyLength;
369d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi    for (int k = 0; k < keyCount; ++k) {
3700edab9d2fcc30667c79aa9221dbb27f042d8b455Satoshi Kataoka        const float dist = mProximityInfo->getNormalizedSquaredDistanceFromCenterFloatG(k, x, y);
371d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi        if (dist < NEAR_KEY_THRESHOLD) {
372d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi            currentNearKeysDistances->insert(std::pair<int, float>(k, dist));
373687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka        }
374d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi        if (nearestKeyDistance > dist) {
375d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi            nearestKeyDistance = dist;
376d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi        }
377d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi    }
378d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi    return nearestKeyDistance;
379d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi}
380d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi
381d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi// Check if previous point is at local minimum position to near keys.
382d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagibool ProximityInfoState::isPrevLocalMin(const NearKeysDistanceMap *const currentNearKeysDistances,
383d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi        const NearKeysDistanceMap *const prevNearKeysDistances,
384d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi        const NearKeysDistanceMap *const prevPrevNearKeysDistances) const {
385ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    static const float MARGIN = 0.01f;
386d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi
387d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi    for (NearKeysDistanceMap::const_iterator it = prevNearKeysDistances->begin();
388d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi        it != prevNearKeysDistances->end(); ++it) {
389d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi        NearKeysDistanceMap::const_iterator itPP = prevPrevNearKeysDistances->find(it->first);
390d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi        NearKeysDistanceMap::const_iterator itC = currentNearKeysDistances->find(it->first);
391d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi        if ((itPP == prevPrevNearKeysDistances->end() || itPP->second > it->second + MARGIN)
392d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi                && (itC == currentNearKeysDistances->end() || itC->second > it->second + MARGIN)) {
393d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi            return true;
394d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi        }
395d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi    }
396d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi    return false;
397d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi}
398d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi
399d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi// Calculating a point score that indicates usefulness of the point.
400d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagifloat ProximityInfoState::getPointScore(
401d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi        const int x, const int y, const int time, const bool lastPoint, const float nearest,
402ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        const float sumAngle, const NearKeysDistanceMap *const currentNearKeysDistances,
403d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi        const NearKeysDistanceMap *const prevNearKeysDistances,
404d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi        const NearKeysDistanceMap *const prevPrevNearKeysDistances) const {
40503dc8fe141fa9f6fa5fe8362d9d35b3f3c954b87Ken Wakasa    static const int DISTANCE_BASE_SCALE = 100;
406ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    static const float NEAR_KEY_THRESHOLD = 0.6f;
407ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    static const int CORNER_CHECK_DISTANCE_THRESHOLD_SCALE = 25;
408806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    static const float NOT_LOCALMIN_DISTANCE_SCORE = -1.0f;
409ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    static const float LOCALMIN_DISTANCE_AND_NEAR_TO_KEY_SCORE = 1.0f;
410ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    static const float CORNER_ANGLE_THRESHOLD = M_PI_F * 2.0f / 3.0f;
411ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    static const float CORNER_SUM_ANGLE_THRESHOLD = M_PI_F / 4.0f;
412aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi    static const float CORNER_SCORE = 1.0f;
413d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi
414ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    const size_t size = mInputXs.size();
415ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    // If there is only one point, add this point. Besides, if the previous point's distance map
416ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    // is empty, we re-compute nearby keys distances from the current point.
417ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    // Note that the current point is the first point in the incremental input that needs to
418ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    // be re-computed.
419ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    if (size <= 1 || prevNearKeysDistances->empty()) {
42003dc8fe141fa9f6fa5fe8362d9d35b3f3c954b87Ken Wakasa        return 0.0f;
421687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka    }
422ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
42303dc8fe141fa9f6fa5fe8362d9d35b3f3c954b87Ken Wakasa    const int baseSampleRate = mProximityInfo->getMostCommonKeyWidth();
42403dc8fe141fa9f6fa5fe8362d9d35b3f3c954b87Ken Wakasa    const int distPrev = getDistanceInt(mInputXs.back(), mInputYs.back(),
42503dc8fe141fa9f6fa5fe8362d9d35b3f3c954b87Ken Wakasa            mInputXs[size - 2], mInputYs[size - 2]) * DISTANCE_BASE_SCALE;
426d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi    float score = 0.0f;
427d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi
428d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi    // Location
429ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    if (!isPrevLocalMin(currentNearKeysDistances, prevNearKeysDistances,
430ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        prevPrevNearKeysDistances)) {
431ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        score += NOT_LOCALMIN_DISTANCE_SCORE;
432ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    } else if (nearest < NEAR_KEY_THRESHOLD) {
433ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        // Promote points nearby keys
434ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        score += LOCALMIN_DISTANCE_AND_NEAR_TO_KEY_SCORE;
435d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi    }
436d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi    // Angle
437aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi    const float angle1 = getAngle(x, y, mInputXs.back(), mInputYs.back());
438aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi    const float angle2 = getAngle(mInputXs.back(), mInputYs.back(),
439aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi            mInputXs[size - 2], mInputYs[size - 2]);
440aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi    const float angleDiff = getAngleDiff(angle1, angle2);
441ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
442aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi    // Save corner
443aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi    if (distPrev > baseSampleRate * CORNER_CHECK_DISTANCE_THRESHOLD_SCALE
444ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            && (sumAngle > CORNER_SUM_ANGLE_THRESHOLD || angleDiff > CORNER_ANGLE_THRESHOLD)) {
445aba26e4f6355bf2cf59ffc5a31fc4b09041f5bc0Keisuke Kuroyanagi        score += CORNER_SCORE;
446d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi    }
447d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi    return score;
448d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi}
449d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi
450d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi// Sampling touch point and pushing information to vectors.
451d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi// Returning if previous point is popped or not.
452096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagibool ProximityInfoState::pushTouchPoint(const int inputIndex, const int nodeChar, int x, int y,
453ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        const int time, const bool sample, const bool isLastPoint, const float sumAngle,
454d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi        NearKeysDistanceMap *const currentNearKeysDistances,
455d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi        const NearKeysDistanceMap *const prevNearKeysDistances,
456d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi        const NearKeysDistanceMap *const prevPrevNearKeysDistances) {
457806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    static const int LAST_POINT_SKIP_DISTANCE_SCALE = 4;
458d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi
459f2789819bd005b5b0581e8439601b5501306327dKen Wakasa    size_t size = mInputXs.size();
460d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi    bool popped = false;
461d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi    if (nodeChar < 0 && sample) {
462d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi        const float nearest = updateNearKeysDistances(x, y, currentNearKeysDistances);
463ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        const float score = getPointScore(x, y, time, isLastPoint, nearest, sumAngle,
464d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi                currentNearKeysDistances, prevNearKeysDistances, prevPrevNearKeysDistances);
465d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi        if (score < 0) {
466d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi            // Pop previous point because it would be useless.
467096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi            popInputData();
468d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi            size = mInputXs.size();
469d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi            popped = true;
470d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi        } else {
471d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi            popped = false;
472d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi        }
473d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi        // Check if the last point should be skipped.
474806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        if (isLastPoint && size > 0) {
475ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            if (getDistanceInt(x, y, mInputXs.back(), mInputYs.back())
476ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    * LAST_POINT_SKIP_DISTANCE_SCALE < mProximityInfo->getMostCommonKeyWidth()) {
477806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                // This point is not used because it's too close to the previous point.
4789182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka                if (DEBUG_GEO_FULL) {
479806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                    AKLOGI("p0: size = %zd, x = %d, y = %d, lx = %d, ly = %d, dist = %d, "
480806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                           "width = %d", size, x, y, mInputXs.back(), mInputYs.back(),
481806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                           getDistanceInt(x, y, mInputXs.back(), mInputYs.back()),
4829182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka                           mProximityInfo->getMostCommonKeyWidth()
483806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                                   / LAST_POINT_SKIP_DISTANCE_SCALE);
4849182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka                }
485d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi                return popped;
486d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi            }
487d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi        }
488d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi    }
489d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi
490687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka    if (nodeChar >= 0 && (x < 0 || y < 0)) {
491f2789819bd005b5b0581e8439601b5501306327dKen Wakasa        const int keyId = mProximityInfo->getKeyIndexOf(nodeChar);
492687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka        if (keyId >= 0) {
493f2789819bd005b5b0581e8439601b5501306327dKen Wakasa            x = mProximityInfo->getKeyCenterXOfKeyIdG(keyId);
494f2789819bd005b5b0581e8439601b5501306327dKen Wakasa            y = mProximityInfo->getKeyCenterYOfKeyIdG(keyId);
495687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka        }
496687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka    }
497d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi
498d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi    // Pushing point information.
499d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi    if (size > 0) {
500d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi        mLengthCache.push_back(
501d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi                mLengthCache.back() + getDistanceInt(x, y, mInputXs.back(), mInputYs.back()));
502d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi    } else {
503d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi        mLengthCache.push_back(0);
504d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi    }
505687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka    mInputXs.push_back(x);
506687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka    mInputYs.push_back(y);
507687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka    mTimes.push_back(time);
508096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi    mInputIndice.push_back(inputIndex);
509952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka    if (DEBUG_GEO_FULL) {
510952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka        AKLOGI("pushTouchPoint: x = %03d, y = %03d, time = %d, index = %d, popped ? %01d",
511952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka                x, y, time, inputIndex, popped);
512952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka    }
513d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi    return popped;
514687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka}
515687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka
5164a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataokafloat ProximityInfoState::calculateNormalizedSquaredDistance(
5174a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka        const int keyIndex, const int inputIndex) const {
5184a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    if (keyIndex == NOT_AN_INDEX) {
5194a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka        return NOT_A_DISTANCE_FLOAT;
5204a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    }
5214a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    if (!mProximityInfo->hasSweetSpotData(keyIndex)) {
5224a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka        return NOT_A_DISTANCE_FLOAT;
5234a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    }
524687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka    if (NOT_A_COORDINATE == mInputXs[inputIndex]) {
5254a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka        return NOT_A_DISTANCE_FLOAT;
5264a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    }
5274a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    const float squaredDistance = calculateSquaredDistanceFromSweetSpotCenter(
5284a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka            keyIndex, inputIndex);
5294a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    const float squaredRadius = square(mProximityInfo->getSweetSpotRadiiAt(keyIndex));
5304a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    return squaredDistance / squaredRadius;
5314a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka}
5324a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka
533687a244703a02323ebd64433cbaead5def499861Satoshi Kataokaint ProximityInfoState::getDuration(const int index) const {
53428661069591fd1d6a8e25981aaade2e5d8b20b9aKeisuke Kuroyanagi    if (index >= 0 && index < mInputSize - 1) {
535a811938d40070b96557df0f2a36ba8daa561fdd4Tom Ouyang        return mTimes[index + 1] - mTimes[index];
536687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka    }
53737b153e205c9672b299b47e97921fee2462a78bbSatoshi Kataoka    return 0;
538687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka}
539687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka
540806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagifloat ProximityInfoState::getPointToKeyLength(const int inputIndex, const int codePoint) const {
541ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    const int keyId = mProximityInfo->getKeyIndexOf(codePoint);
542ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    if (keyId != NOT_AN_INDEX) {
543ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        const int index = inputIndex * mProximityInfo->getKeyCount() + keyId;
544ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        return min(mDistanceCache[index], mMaxPointToKeyLength);
545ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    }
546806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    if (isSkippableChar(codePoint)) {
547806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        return 0.0f;
548806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    }
549ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    // If the char is not a key on the keyboard then return the max length.
550ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    return MAX_POINT_TO_KEY_LENGTH;
551806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi}
552806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi
553806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagifloat ProximityInfoState::getPointToKeyByIdLength(const int inputIndex, const int keyId) const {
5548c220a0aa2c5139a3b12af20e68c420f6402294aTom Ouyang    if (keyId != NOT_AN_INDEX) {
555687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka        const int index = inputIndex * mProximityInfo->getKeyCount() + keyId;
556806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        return min(mDistanceCache[index], mMaxPointToKeyLength);
557cde005c05ec6b552ec26740b578be12c7d24013bSatoshi Kataoka    }
5588c220a0aa2c5139a3b12af20e68c420f6402294aTom Ouyang    // If the char is not a key on the keyboard then return the max length.
559806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    return static_cast<float>(MAX_POINT_TO_KEY_LENGTH);
560687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka}
561687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka
5623811a28ddc07201930e0bbd2e1d01045b59af308Keisuke Kuroyanagiint ProximityInfoState::getSpaceY() const {
563b02ee3d67a1884b6ff59cc16c29a476845c0694fKen Wakasa    const int keyId = mProximityInfo->getKeyIndexOf(KEYCODE_SPACE);
564f2789819bd005b5b0581e8439601b5501306327dKen Wakasa    return mProximityInfo->getKeyCenterYOfKeyIdG(keyId);
565687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka}
566687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka
5674a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataokafloat ProximityInfoState::calculateSquaredDistanceFromSweetSpotCenter(
5684a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka        const int keyIndex, const int inputIndex) const {
5694a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    const float sweetSpotCenterX = mProximityInfo->getSweetSpotCenterXAt(keyIndex);
5704a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    const float sweetSpotCenterY = mProximityInfo->getSweetSpotCenterYAt(keyIndex);
571687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka    const float inputX = static_cast<float>(mInputXs[inputIndex]);
572687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka    const float inputY = static_cast<float>(mInputYs[inputIndex]);
5734a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    return square(inputX - sweetSpotCenterX) + square(inputY - sweetSpotCenterY);
5744a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka}
57595a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi
57695a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi// Puts possible characters into filter and returns new filter size.
57795a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagiint32_t ProximityInfoState::getAllPossibleChars(
57895a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi        const size_t index, int32_t *const filter, const int32_t filterSize) const {
57995a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi    if (index >= mInputXs.size()) {
58095a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi        return filterSize;
58195a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi    }
58241f12ee27b269033fe818f7d52e81ba948a046c3Keisuke Kuroyanagi    int newFilterSize = filterSize;
583ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    const int keyCount = mProximityInfo->getKeyCount();
584ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    for (int j = 0; j < keyCount; ++j) {
585ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        if (mSearchKeysVector[index].test(j)) {
58695a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi            const int32_t keyCodePoint = mProximityInfo->getCodePointOf(j);
58795a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi            bool insert = true;
58895a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi            // TODO: Avoid linear search
58995a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi            for (int k = 0; k < filterSize; ++k) {
59095a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi                if (filter[k] == keyCodePoint) {
59195a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi                    insert = false;
59295a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi                    break;
59395a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi                }
59495a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi            }
59595a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi            if (insert) {
59641f12ee27b269033fe818f7d52e81ba948a046c3Keisuke Kuroyanagi                filter[newFilterSize++] = keyCodePoint;
59795a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi            }
59895a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi        }
59995a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi    }
60041f12ee27b269033fe818f7d52e81ba948a046c3Keisuke Kuroyanagi    return newFilterSize;
60195a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi}
6023811a28ddc07201930e0bbd2e1d01045b59af308Keisuke Kuroyanagi
603ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagibool ProximityInfoState::isKeyInSerchKeysAfterIndex(const int index, const int keyId) const {
604ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    ASSERT(keyId >= 0);
605ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    ASSERT(index >= 0 && index < mInputSize);
606ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    return mSearchKeysVector[index].test(keyId);
607ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi}
608ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
609096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagivoid ProximityInfoState::popInputData() {
610096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi    mInputXs.pop_back();
611096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi    mInputYs.pop_back();
612096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi    mTimes.pop_back();
613096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi    mLengthCache.pop_back();
614096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi    mInputIndice.pop_back();
615096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi}
616096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi
617ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagifloat ProximityInfoState::getDirection(const int index0, const int index1) const {
618ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    if (index0 < 0 || index0 > mInputSize - 1) {
619ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        return 0.0f;
620ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    }
621ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    if (index1 < 0 || index1 > mInputSize - 1) {
622ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        return 0.0f;
623ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    }
624ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    const int x1 = mInputXs[index0];
625ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    const int y1 = mInputYs[index0];
626ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    const int x2 = mInputXs[index1];
627ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    const int y2 = mInputYs[index1];
628ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    return getAngle(x1, y1, x2, y2);
629ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi}
630ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
631806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagifloat ProximityInfoState::getPointAngle(const int index) const {
632806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    if (index <= 0 || index >= mInputSize - 1) {
633806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        return 0.0f;
634806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    }
635ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    const float previousDirection = getDirection(index - 1, index);
636ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    const float nextDirection = getDirection(index, index + 1);
637806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    const float directionDiff = getAngleDiff(previousDirection, nextDirection);
638806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    return directionDiff;
639806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi}
640806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi
641806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagifloat ProximityInfoState::getPointsAngle(
642806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        const int index0, const int index1, const int index2) const {
643806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    if (index0 < 0 || index0 > mInputSize - 1) {
644806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        return 0.0f;
645806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    }
646806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    if (index1 < 0 || index1 > mInputSize - 1) {
647806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        return 0.0f;
648806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    }
649806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    if (index2 < 0 || index2 > mInputSize - 1) {
650806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        return 0.0f;
651806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    }
652ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    const float previousDirection = getDirection(index0, index1);
653ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    const float nextDirection = getDirection(index1, index2);
654ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    return getAngleDiff(previousDirection, nextDirection);
655ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi}
656ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
657ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagifloat ProximityInfoState::getLineToKeyDistance(
658ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        const int from, const int to, const int keyId, const bool extend) const {
659ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    if (from < 0 || from > mInputSize - 1) {
660ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        return 0.0f;
661ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    }
662ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    if (to < 0 || to > mInputSize - 1) {
663ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        return 0.0f;
664ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    }
665ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    const int x0 = mInputXs[from];
666ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    const int y0 = mInputYs[from];
667ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    const int x1 = mInputXs[to];
668ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    const int y1 = mInputYs[to];
669ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
670ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    const int keyX = mProximityInfo->getKeyCenterXOfKeyIdG(keyId);
671ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    const int keyY = mProximityInfo->getKeyCenterYOfKeyIdG(keyId);
672ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
673ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    return pointToLineSegSquaredDistanceFloat(keyX, keyY, x0, y0, x1, y1, extend);
674806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi}
675806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi
676806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi// Updates probabilities of aligning to some keys and skipping.
677806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi// Word suggestion should be based on this probabilities.
678ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagivoid ProximityInfoState::updateAlignPointProbabilities(const int start) {
679ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    static const float MIN_PROBABILITY = 0.000001f;
680ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    static const float MAX_SKIP_PROBABILITY = 0.95f;
681806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    static const float SKIP_FIRST_POINT_PROBABILITY = 0.01f;
682806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    static const float SKIP_LAST_POINT_PROBABILITY = 0.1f;
683ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    static const float MIN_SPEED_RATE_FOR_SKIP_PROBABILITY = 0.15f;
684ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    static const float SPEED_WEIGHT_FOR_SKIP_PROBABILITY = 0.9f;
685ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    static const float SLOW_STRAIGHT_WEIGHT_FOR_SKIP_PROBABILITY = 0.6f;
686ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    static const float NEAREST_DISTANCE_WEIGHT = 0.5f;
687ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    static const float NEAREST_DISTANCE_BIAS = 0.5f;
688ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    static const float NEAREST_DISTANCE_WEIGHT_FOR_LAST = 0.6f;
689ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    static const float NEAREST_DISTANCE_BIAS_FOR_LAST = 0.4f;
690ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
691ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    static const float ANGLE_WEIGHT = 0.90f;
692ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    static const float DEEP_CORNER_ANGLE_THRESHOLD = M_PI_F * 60.0f / 180.0f;
693ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    static const float SKIP_DEEP_CORNER_PROBABILITY = 0.1f;
694ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    static const float CORNER_ANGLE_THRESHOLD = M_PI_F * 30.0f / 180.0f;
695806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    static const float STRAIGHT_ANGLE_THRESHOLD = M_PI_F * 15.0f / 180.0f;
696ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    static const float SKIP_CORNER_PROBABILITY = 0.4f;
697ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    static const float SPEED_MARGIN = 0.1f;
698806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    static const float CENTER_VALUE_OF_NORMALIZED_DISTRIBUTION = 0.0f;
699806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi
700ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    const int keyCount = mProximityInfo->getKeyCount();
701806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    mCharProbabilities.resize(mInputSize);
702806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    // Calculates probabilities of using a point as a correlated point with the character
703806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    // for each point.
704ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    for (int i = start; i < mInputSize; ++i) {
705ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        mCharProbabilities[i].clear();
706ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        // First, calculates skip probability. Starts form MIN_SKIP_PROBABILITY.
707806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        // Note that all values that are multiplied to this probability should be in [0.0, 1.0];
708ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        float skipProbability = MAX_SKIP_PROBABILITY;
709ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
710ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        const float currentAngle = getPointAngle(i);
711ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        const float relativeSpeed = getRelativeSpeed(i);
712ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
713ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        float nearestKeyDistance = static_cast<float>(MAX_POINT_TO_KEY_LENGTH);
714ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        for (int j = 0; j < keyCount; ++j) {
715ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            if (mNearKeysVector[i].test(j)) {
716ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                const float distance = getPointToKeyByIdLength(i, j);
717ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                if (distance < nearestKeyDistance) {
718ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    nearestKeyDistance = distance;
719ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                }
720ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            }
721ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        }
722806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi
723806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        if (i == 0) {
724ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            skipProbability *= min(1.0f, nearestKeyDistance * NEAREST_DISTANCE_WEIGHT
725ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    + NEAREST_DISTANCE_BIAS);
726ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            // Promote the first point
727806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            skipProbability *= SKIP_FIRST_POINT_PROBABILITY;
728806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        } else if (i == mInputSize - 1) {
729ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            skipProbability *= min(1.0f, nearestKeyDistance * NEAREST_DISTANCE_WEIGHT_FOR_LAST
730ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    + NEAREST_DISTANCE_BIAS_FOR_LAST);
731ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            // Promote the last point
732806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            skipProbability *= SKIP_LAST_POINT_PROBABILITY;
733806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        } else {
734ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            // If the current speed is relatively slower than adjacent keys, we promote this point.
735ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            if (getRelativeSpeed(i - 1) - SPEED_MARGIN > relativeSpeed
736ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    && relativeSpeed < getRelativeSpeed(i + 1) - SPEED_MARGIN) {
737ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                if (currentAngle < CORNER_ANGLE_THRESHOLD) {
738ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    skipProbability *= min(1.0f, relativeSpeed
739ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                            * SLOW_STRAIGHT_WEIGHT_FOR_SKIP_PROBABILITY);
740ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                } else {
741ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    // If the angle is small enough, we promote this point more. (e.g. pit vs put)
742ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    skipProbability *= min(1.0f, relativeSpeed * SPEED_WEIGHT_FOR_SKIP_PROBABILITY
743ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                            + MIN_SPEED_RATE_FOR_SKIP_PROBABILITY);
744ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                }
745ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            }
746ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
747ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            skipProbability *= min(1.0f, relativeSpeed * nearestKeyDistance *
748ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    NEAREST_DISTANCE_WEIGHT + NEAREST_DISTANCE_BIAS);
749806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi
750806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            // Adjusts skip probability by a rate depending on angle.
751806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            // ANGLE_RATE of skipProbability is adjusted by current angle.
752ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            skipProbability *= (M_PI_F - currentAngle) / M_PI_F * ANGLE_WEIGHT
753ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    + (1.0f - ANGLE_WEIGHT);
754806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            if (currentAngle > DEEP_CORNER_ANGLE_THRESHOLD) {
755806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                skipProbability *= SKIP_DEEP_CORNER_PROBABILITY;
756806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            }
757ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            // We assume the angle of this point is the angle for point[i], point[i - 2]
758ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            // and point[i - 3]. The reason why we don't use the angle for point[i], point[i - 1]
759ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            // and point[i - 2] is this angle can be more affected by the noise.
760ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            const float prevAngle = getPointsAngle(i, i - 2, i - 3);
761ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            if (i >= 3 && prevAngle < STRAIGHT_ANGLE_THRESHOLD
762ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    && currentAngle > CORNER_ANGLE_THRESHOLD) {
763806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                skipProbability *= SKIP_CORNER_PROBABILITY;
764806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            }
765806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        }
766806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi
767ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        // probabilities must be in [0.0, MAX_SKIP_PROBABILITY];
768806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        ASSERT(skipProbability >= 0.0f);
769ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        ASSERT(skipProbability <= MAX_SKIP_PROBABILITY);
770806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        mCharProbabilities[i][NOT_AN_INDEX] = skipProbability;
771ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
772806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        // Second, calculates key probabilities by dividing the rest probability
773806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        // (1.0f - skipProbability).
774806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        const float inputCharProbability = 1.0f - skipProbability;
775ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
776ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        // TODO: The variance is critical for accuracy; thus, adjusting these parameter by machine
777ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        // learning or something would be efficient.
778ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        static const float SPEEDxANGLE_WEIGHT_FOR_STANDARD_DIVIATION = 0.3f;
779ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        static const float MAX_SPEEDxANGLE_RATE_FOR_STANDERD_DIVIATION = 0.25f;
780ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        static const float SPEEDxNEAREST_WEIGHT_FOR_STANDARD_DIVIATION = 0.5f;
781ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        static const float MAX_SPEEDxNEAREST_RATE_FOR_STANDERD_DIVIATION = 0.15f;
782ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        static const float MIN_STANDERD_DIVIATION = 0.37f;
783ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
784ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        const float speedxAngleRate = min(relativeSpeed * currentAngle / M_PI_F
785ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                * SPEEDxANGLE_WEIGHT_FOR_STANDARD_DIVIATION,
786ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                        MAX_SPEEDxANGLE_RATE_FOR_STANDERD_DIVIATION);
787ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        const float speedxNearestKeyDistanceRate = min(relativeSpeed * nearestKeyDistance
788ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                * SPEEDxNEAREST_WEIGHT_FOR_STANDARD_DIVIATION,
789ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                        MAX_SPEEDxNEAREST_RATE_FOR_STANDERD_DIVIATION);
790ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        const float sigma = speedxAngleRate + speedxNearestKeyDistanceRate + MIN_STANDERD_DIVIATION;
791ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
792806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        NormalDistribution distribution(CENTER_VALUE_OF_NORMALIZED_DISTRIBUTION, sigma);
793ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        static const float PREV_DISTANCE_WEIGHT = 0.5f;
794ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        static const float NEXT_DISTANCE_WEIGHT = 0.6f;
795ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        // Summing up probability densities of all near keys.
796ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        float sumOfProbabilityDensities = 0.0f;
797ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        for (int j = 0; j < keyCount; ++j) {
798806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            if (mNearKeysVector[i].test(j)) {
799ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                float distance = sqrtf(getPointToKeyByIdLength(i, j));
800ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                if (i == 0 && i != mInputSize - 1) {
801ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    // For the first point, weighted average of distances from first point and the
802ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    // next point to the key is used as a point to key distance.
803ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    const float nextDistance = sqrtf(getPointToKeyByIdLength(i + 1, j));
804ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    if (nextDistance < distance) {
805ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                        // The distance of the first point tends to bigger than continuing
806ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                        // points because the first touch by the user can be sloppy.
807ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                        // So we promote the first point if the distance of that point is larger
808ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                        // than the distance of the next point.
809ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                        distance = (distance + nextDistance * NEXT_DISTANCE_WEIGHT)
810ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                                / (1.0f + NEXT_DISTANCE_WEIGHT);
811ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    }
812ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                } else if (i != 0 && i == mInputSize - 1) {
813ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    // For the first point, weighted average of distances from last point and
814ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    // the previous point to the key is used as a point to key distance.
815ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    const float previousDistance = sqrtf(getPointToKeyByIdLength(i - 1, j));
816ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    if (previousDistance < distance) {
817ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                        // The distance of the last point tends to bigger than continuing points
818ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                        // because the last touch by the user can be sloppy. So we promote the
819ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                        // last point if the distance of that point is larger than the distance of
820ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                        // the previous point.
821ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                        distance = (distance + previousDistance * PREV_DISTANCE_WEIGHT)
822ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                                / (1.0f + PREV_DISTANCE_WEIGHT);
823ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    }
824ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                }
825ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                // TODO: Promote the first point when the extended line from the next input is near
826ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                // from a key. Also, promote the last point as well.
827ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                sumOfProbabilityDensities += distribution.getProbabilityDensity(distance);
828806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            }
829806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        }
830ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
831ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        // Split the probability of an input point to keys that are close to the input point.
832ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        for (int j = 0; j < keyCount; ++j) {
833806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            if (mNearKeysVector[i].test(j)) {
834ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                float distance = sqrtf(getPointToKeyByIdLength(i, j));
835ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                if (i == 0 && i != mInputSize - 1) {
836ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    // For the first point, weighted average of distances from the first point and
837ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    // the next point to the key is used as a point to key distance.
838ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    const float prevDistance = sqrtf(getPointToKeyByIdLength(i + 1, j));
839ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    if (prevDistance < distance) {
840ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                        distance = (distance + prevDistance * NEXT_DISTANCE_WEIGHT)
841ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                                / (1.0f + NEXT_DISTANCE_WEIGHT);
842ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    }
843ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                } else if (i != 0 && i == mInputSize - 1) {
844ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    // For the first point, weighted average of distances from last point and
845ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    // the previous point to the key is used as a point to key distance.
846ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    const float prevDistance = sqrtf(getPointToKeyByIdLength(i - 1, j));
847ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    if (prevDistance < distance) {
848ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                        distance = (distance + prevDistance * PREV_DISTANCE_WEIGHT)
849ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                                / (1.0f + PREV_DISTANCE_WEIGHT);
850ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    }
851806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                }
852ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                const float probabilityDensity = distribution.getProbabilityDensity(distance);
853ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                const float probability = inputCharProbability * probabilityDensity
854ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                        / sumOfProbabilityDensities;
855ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                mCharProbabilities[i][j] = probability;
856806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            }
857806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        }
858806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    }
859806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi
860ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
861ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    if (DEBUG_POINTS_PROBABILITY) {
862ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        for (int i = 0; i < mInputSize; ++i) {
863ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            std::stringstream sstream;
864ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            sstream << i << ", ";
865ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            sstream << "("<< mInputXs[i] << ", ";
866ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            sstream << ", "<< mInputYs[i] << "), ";
867ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            sstream << "Speed: "<< getRelativeSpeed(i) << ", ";
868ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            sstream << "Angle: "<< getPointAngle(i) << ", \n";
869ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
870ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            for (hash_map_compat<int, float>::iterator it = mCharProbabilities[i].begin();
871ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    it != mCharProbabilities[i].end(); ++it) {
872ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                if (it->first == NOT_AN_INDEX) {
873ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    sstream << it->first
874ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                            << "(skip):"
875ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                            << it->second
876ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                            << "\n";
877ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                } else {
878ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    sstream << it->first
879ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                            << "("
880ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                            << static_cast<char>(mProximityInfo->getCodePointOf(it->first))
881ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                            << "):"
882ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                            << it->second
883ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                            << "\n";
884ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                }
885ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            }
886ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            AKLOGI("%s", sstream.str().c_str());
887ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        }
888ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    }
889ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
890806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    // Decrease key probabilities of points which don't have the highest probability of that key
891806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    // among nearby points. Probabilities of the first point and the last point are not suppressed.
892ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    for (int i = max(start, 1); i < mInputSize; ++i) {
893806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        for (int j = i + 1; j < mInputSize; ++j) {
894ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            if (!suppressCharProbabilities(i, j)) {
895806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                break;
896806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            }
897806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        }
898ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        for (int j = i - 1; j >= max(start, 0); --j) {
899ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            if (!suppressCharProbabilities(i, j)) {
900806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                break;
901806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            }
902806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        }
903806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    }
904806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi
905ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    // Converting from raw probabilities to log probabilities to calculate spatial distance.
906ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    for (int i = start; i < mInputSize; ++i) {
907ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        for (int j = 0; j < keyCount; ++j) {
908ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            hash_map_compat<int, float>::iterator it = mCharProbabilities[i].find(j);
909ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            if (it == mCharProbabilities[i].end()){
910ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                mNearKeysVector[i].reset(j);
911ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            } else if(it->second < MIN_PROBABILITY) {
912ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                // Erases from near keys vector because it has very low probability.
913ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                mNearKeysVector[i].reset(j);
914ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                mCharProbabilities[i].erase(j);
915ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            } else {
916ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                it->second = -logf(it->second);
917806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            }
918806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        }
919ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        mCharProbabilities[i][NOT_AN_INDEX] = -logf(mCharProbabilities[i][NOT_AN_INDEX]);
920806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    }
921806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi}
922806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi
923ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi// Decreases char probabilities of index0 by checking probabilities of a near point (index1) and
924ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi// increases char probabilities of index1 by checking probabilities of index0.
925806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagibool ProximityInfoState::suppressCharProbabilities(const int index0, const int index1) {
926806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    ASSERT(0 <= index0 && index0 < mInputSize);
927806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    ASSERT(0 <= index1 && index1 < mInputSize);
928ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
929806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    static const float SUPPRESSION_LENGTH_WEIGHT = 1.5f;
930ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    static const float MIN_SUPPRESSION_RATE = 0.1f;
931ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    static const float SUPPRESSION_WEIGHT = 0.5f;
932ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    static const float SUPPRESSION_WEIGHT_FOR_PROBABILITY_GAIN = 0.1f;
933ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    static const float SKIP_PROBABALITY_WEIGHT_FOR_PROBABILITY_GAIN = 0.3f;
934ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
935806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    const float keyWidthFloat = static_cast<float>(mProximityInfo->getMostCommonKeyWidth());
936806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    const float diff = fabsf(static_cast<float>(mLengthCache[index0] - mLengthCache[index1]));
937806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    if (diff > keyWidthFloat * SUPPRESSION_LENGTH_WEIGHT) {
938806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        return false;
939806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    }
940ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    const float suppressionRate = MIN_SUPPRESSION_RATE
941ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            + diff / keyWidthFloat / SUPPRESSION_LENGTH_WEIGHT * SUPPRESSION_WEIGHT;
942806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    for (hash_map_compat<int, float>::iterator it = mCharProbabilities[index0].begin();
943806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            it != mCharProbabilities[index0].end(); ++it) {
944ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        hash_map_compat<int, float>::iterator it2 =  mCharProbabilities[index1].find(it->first);
945806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        if (it2 != mCharProbabilities[index1].end() && it->second < it2->second) {
946806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            const float newProbability = it->second * suppressionRate;
947ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            const float suppression = it->second - newProbability;
948806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            it->second = newProbability;
949ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            // mCharProbabilities[index0][NOT_AN_INDEX] is the probability of skipping this point.
950ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            mCharProbabilities[index0][NOT_AN_INDEX] += suppression;
951ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
952ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            // Add the probability of the same key nearby index1
953ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            const float probabilityGain = min(suppression * SUPPRESSION_WEIGHT_FOR_PROBABILITY_GAIN,
954ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    mCharProbabilities[index1][NOT_AN_INDEX]
955ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                            * SKIP_PROBABALITY_WEIGHT_FOR_PROBABILITY_GAIN);
956ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            it2->second += probabilityGain;
957ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            mCharProbabilities[index1][NOT_AN_INDEX] -= probabilityGain;
958806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        }
959806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    }
960806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    return true;
961806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi}
962806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi
963806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi// Get a word that is detected by tracing highest probability sequence into charBuf and returns
964806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi// probability of generating the word.
965806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagifloat ProximityInfoState::getHighestProbabilitySequence(uint16_t *const charBuf) const {
966ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    static const float LOG_PROBABILITY_MARGIN = 0.2f;
967ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    int index = 0;
968ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    float sumLogProbability = 0.0f;
969806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    // TODO: Current implementation is greedy algorithm. DP would be efficient for many cases.
970ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    for (int i = 0; i < mInputSize && index < MAX_WORD_LENGTH_INTERNAL - 1; ++i) {
971ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        float minLogProbability = static_cast<float>(MAX_POINT_TO_KEY_LENGTH);
972ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        int character = NOT_AN_INDEX;
973806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        for (hash_map_compat<int, float>::const_iterator it = mCharProbabilities[i].begin();
974806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                it != mCharProbabilities[i].end(); ++it) {
975ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            const float logProbability = (it->first != NOT_AN_INDEX)
976ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    ? it->second + LOG_PROBABILITY_MARGIN : it->second;
977ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            if (logProbability < minLogProbability) {
978ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                minLogProbability = logProbability;
979ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                character = it->first;
980806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            }
981806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        }
982ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        if (character != NOT_AN_INDEX) {
983ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            charBuf[index] = mProximityInfo->getCodePointOf(character);
984806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            index++;
985806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        }
986ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        sumLogProbability += minLogProbability;
987806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    }
988806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    charBuf[index] = '\0';
989ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    return sumLogProbability;
990ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi}
991ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
992ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi// Returns a probability of mapping index to keyIndex.
993ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagifloat ProximityInfoState::getProbability(const int index, const int keyIndex) const {
994ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    ASSERT(0 <= index && index < mInputSize);
995ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    hash_map_compat<int, float>::const_iterator it = mCharProbabilities[index].find(keyIndex);
996ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    if (it != mCharProbabilities[index].end()) {
997ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        return it->second;
998ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    }
999ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    return static_cast<float>(MAX_POINT_TO_KEY_LENGTH);
1000806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi}
1001806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi
10023e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka} // namespace latinime
1003