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