proximity_info_state.cpp revision d4828d5053ac30476b884c177235be0cac982c92
13e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka/*
23e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * Copyright (C) 2012 The Android Open Source Project
33e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka *
43e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * Licensed under the Apache License, Version 2.0 (the "License");
53e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * you may not use this file except in compliance with the License.
63e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * You may obtain a copy of the License at
73e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka *
83e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka *      http://www.apache.org/licenses/LICENSE-2.0
93e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka *
103e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * Unless required by applicable law or agreed to in writing, software
113e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * distributed under the License is distributed on an "AS IS" BASIS,
123e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * See the License for the specific language governing permissions and
143e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * limitations under the License.
153e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka */
163e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka
1777e8e81ad95cfc1eb8f8407fc872674b8d08bbe9Ken Wakasa#include <cstring> // for memset()
18806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi#include <sstream> // for debug prints
193e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka
203e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka#define LOG_TAG "LatinIME: proximity_info_state.cpp"
213e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka
223e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka#include "defines.h"
236cee61deebd0ca2b85054ccc239523d1e5fdfab1Ken Wakasa#include "geometry_utils.h"
243e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka#include "proximity_info.h"
253e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka#include "proximity_info_state.h"
2647cc52415e3affb83eb4369190425b2a17b956c5Satoshi Kataoka#include "proximity_info_state_utils.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) {
40fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka    mIsContinuationPossible = checkAndReturnIsContinuationPossible(
41fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka            inputSize, xCoordinates, yCoordinates, times, isGeometric);
42096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi
434a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    mProximityInfo = proximityInfo;
444a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    mHasTouchPositionCorrectionData = proximityInfo->hasTouchPositionCorrectionData();
454a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    mMostCommonKeyWidthSquare = proximityInfo->getMostCommonKeyWidthSquare();
464a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    mKeyCount = proximityInfo->getKeyCount();
474a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    mCellHeight = proximityInfo->getCellHeight();
484a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    mCellWidth = proximityInfo->getCellWidth();
494a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    mGridHeight = proximityInfo->getGridWidth();
504a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    mGridWidth = proximityInfo->getGridHeight();
513e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka
52bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka    memset(mInputProximities, 0, sizeof(mInputProximities));
533e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka
5408f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka    if (!isGeometric && pointerId == 0) {
55bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        mProximityInfo->initializeProximities(inputCodes, xCoordinates, yCoordinates,
56bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                inputSize, mInputProximities);
573e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka    }
58687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka
59687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka    ///////////////////////
60687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka    // Setup touch points
61096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi    int pushTouchPointStartIndex = 0;
62096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi    int lastSavedInputSize = 0;
6308f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka    mMaxPointToKeyLength = maxPointToKeyLength;
64096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi    if (mIsContinuationPossible && mInputIndice.size() > 1) {
65096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi        // Just update difference.
66096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi        // Two points prior is never skipped. Thus, we pop 2 input point data here.
67096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi        pushTouchPointStartIndex = mInputIndice[mInputIndice.size() - 2];
68096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi        popInputData();
69096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi        popInputData();
70feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka        lastSavedInputSize = mSampledInputXs.size();
71096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi    } else {
72096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi        // Clear all data.
73feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka        mSampledInputXs.clear();
74feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka        mSampledInputYs.clear();
75096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi        mTimes.clear();
76096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi        mInputIndice.clear();
77096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi        mLengthCache.clear();
78a9763f93d76f97b9c6ed7dd1369a4d8cb016f06fSatoshi Kataoka        mDistanceCache_G.clear();
79096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi        mNearKeysVector.clear();
80ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        mSearchKeysVector.clear();
819af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka        mSpeedRates.clear();
826ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka        mBeelineSpeedPercentiles.clear();
83806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        mCharProbabilities.clear();
841e06a4d8e9e71188ed685282155ea52a48ddc050Keisuke Kuroyanagi        mDirections.clear();
85096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi    }
869182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka    if (DEBUG_GEO_FULL) {
879182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka        AKLOGI("Init ProximityInfoState: reused points =  %d, last input size = %d",
889182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka                pushTouchPointStartIndex, lastSavedInputSize);
899182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka    }
90feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka    mSampledInputSize = 0;
91d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi
92687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka    if (xCoordinates && yCoordinates) {
9347cc52415e3affb83eb4369190425b2a17b956c5Satoshi Kataoka        mSampledInputSize = ProximityInfoStateUtils::updateTouchPoints(
9447cc52415e3affb83eb4369190425b2a17b956c5Satoshi Kataoka                mProximityInfo->getMostCommonKeyWidth(), mProximityInfo, mMaxPointToKeyLength,
9547cc52415e3affb83eb4369190425b2a17b956c5Satoshi Kataoka                mInputProximities, xCoordinates, yCoordinates, times, pointerIds, inputSize,
9647cc52415e3affb83eb4369190425b2a17b956c5Satoshi Kataoka                isGeometric, pointerId, pushTouchPointStartIndex,
9747cc52415e3affb83eb4369190425b2a17b956c5Satoshi Kataoka                &mSampledInputXs, &mSampledInputYs, &mTimes, &mLengthCache, &mInputIndice);
983e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka    }
99687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka
100feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka    if (mSampledInputSize > 0 && isGeometric) {
101ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        mAverageSpeed = ProximityInfoStateUtils::refreshSpeedRates(
102ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                inputSize, xCoordinates, yCoordinates, times, lastSavedInputSize,
103ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                mSampledInputSize, &mSampledInputXs, &mSampledInputYs, &mTimes, &mLengthCache,
104ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                &mInputIndice, &mSpeedRates, &mDirections);
105ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        ProximityInfoStateUtils::refreshBeelineSpeedRates(
106ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                mProximityInfo->getMostCommonKeyWidth(), mAverageSpeed, inputSize,
107ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                xCoordinates, yCoordinates, times, mSampledInputSize, &mSampledInputXs,
108ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                &mSampledInputYs, &mInputIndice, &mBeelineSpeedPercentiles);
10928661069591fd1d6a8e25981aaade2e5d8b20b9aKeisuke Kuroyanagi    }
11028661069591fd1d6a8e25981aaade2e5d8b20b9aKeisuke Kuroyanagi
111ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    if (DEBUG_GEO_FULL) {
112feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka        for (int i = 0; i < mSampledInputSize; ++i) {
113feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka            AKLOGI("Sampled(%d): x = %d, y = %d, time = %d", i, mSampledInputXs[i],
114feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka                    mSampledInputYs[i], mTimes[i]);
115ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        }
116ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    }
117ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
118feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka    if (mSampledInputSize > 0) {
119687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka        const int keyCount = mProximityInfo->getKeyCount();
120feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka        mNearKeysVector.resize(mSampledInputSize);
121feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka        mSearchKeysVector.resize(mSampledInputSize);
122a9763f93d76f97b9c6ed7dd1369a4d8cb016f06fSatoshi Kataoka        mDistanceCache_G.resize(mSampledInputSize * keyCount);
123feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka        for (int i = lastSavedInputSize; i < mSampledInputSize; ++i) {
12495a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi            mNearKeysVector[i].reset();
125ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            mSearchKeysVector[i].reset();
12695a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi            static const float NEAR_KEY_NORMALIZED_SQUARED_THRESHOLD = 4.0f;
127687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka            for (int k = 0; k < keyCount; ++k) {
128687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka                const int index = i * keyCount + k;
129feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka                const int x = mSampledInputXs[i];
130feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka                const int y = mSampledInputYs[i];
13195a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi                const float normalizedSquaredDistance =
1320edab9d2fcc30667c79aa9221dbb27f042d8b455Satoshi Kataoka                        mProximityInfo->getNormalizedSquaredDistanceFromCenterFloatG(k, x, y);
133a9763f93d76f97b9c6ed7dd1369a4d8cb016f06fSatoshi Kataoka                mDistanceCache_G[index] = normalizedSquaredDistance;
13495a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi                if (normalizedSquaredDistance < NEAR_KEY_NORMALIZED_SQUARED_THRESHOLD) {
135ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    mNearKeysVector[i][k] = true;
13695a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi                }
13795a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi            }
13895a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi        }
139ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        if (isGeometric) {
140ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            // updates probabilities of skipping or mapping each key for all points.
141d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            ProximityInfoStateUtils::updateAlignPointProbabilities(
142d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                    mMaxPointToKeyLength, mProximityInfo->getMostCommonKeyWidth(),
143d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                    keyCount, lastSavedInputSize, mSampledInputSize, &mSampledInputXs,
144d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                    &mSampledInputYs, &mSpeedRates, &mLengthCache, &mDistanceCache_G,
145d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                    &mNearKeysVector, &mCharProbabilities);
146ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
147ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            static const float READ_FORWORD_LENGTH_SCALE = 0.95f;
148ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            const int readForwordLength = static_cast<int>(
149ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    hypotf(mProximityInfo->getKeyboardWidth(), mProximityInfo->getKeyboardHeight())
150ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                            * READ_FORWORD_LENGTH_SCALE);
151feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka            for (int i = 0; i < mSampledInputSize; ++i) {
152ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                if (i >= lastSavedInputSize) {
153ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    mSearchKeysVector[i].reset();
154ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                }
155feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka                for (int j = max(i, lastSavedInputSize); j < mSampledInputSize; ++j) {
156ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    if (mLengthCache[j] - mLengthCache[i] >= readForwordLength) {
157ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                        break;
158ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    }
159ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                    mSearchKeysVector[i] |= mNearKeysVector[j];
16095a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi                }
161687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka            }
162687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka        }
163687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka    }
16408f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka
165806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    if (DEBUG_SAMPLING_POINTS) {
166806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        std::stringstream originalX, originalY, sampledX, sampledY;
167806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        for (int i = 0; i < inputSize; ++i) {
168806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            originalX << xCoordinates[i];
169806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            originalY << yCoordinates[i];
170806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            if (i != inputSize - 1) {
171806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                originalX << ";";
172806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                originalY << ";";
173806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            }
174806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        }
1759af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka        AKLOGI("===== sampled points =====");
176feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka        for (int i = 0; i < mSampledInputSize; ++i) {
1779af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka            if (isGeometric) {
1786ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka                AKLOGI("%d: x = %d, y = %d, time = %d, relative speed = %.4f, beeline speed = %d",
1799af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka                        i, mSampledInputXs[i], mSampledInputYs[i], mTimes[i], mSpeedRates[i],
1806ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka                        getBeelineSpeedPercentile(i));
1819af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka            }
182feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka            sampledX << mSampledInputXs[i];
183feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka            sampledY << mSampledInputYs[i];
184feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka            if (i != mSampledInputSize - 1) {
185806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                sampledX << ";";
186806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                sampledY << ";";
187806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            }
188806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        }
189f25cc4405e329447425e52c3c5514a8802097fb8Satoshi Kataoka        AKLOGI("original points:\n%s, %s,\nsampled points:\n%s, %s,\n",
190f25cc4405e329447425e52c3c5514a8802097fb8Satoshi Kataoka                originalX.str().c_str(), originalY.str().c_str(), sampledX.str().c_str(),
191f25cc4405e329447425e52c3c5514a8802097fb8Satoshi Kataoka                sampledY.str().c_str());
192806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    }
193687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka    // end
194687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka    ///////////////////////
195687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka
19608f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka    memset(mNormalizedSquaredDistances, NOT_A_DISTANCE, sizeof(mNormalizedSquaredDistances));
19708f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka    memset(mPrimaryInputWord, 0, sizeof(mPrimaryInputWord));
198feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka    mTouchPositionCorrectionEnabled = mSampledInputSize > 0 && mHasTouchPositionCorrectionData
1990edab9d2fcc30667c79aa9221dbb27f042d8b455Satoshi Kataoka            && xCoordinates && yCoordinates;
20008f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka    if (!isGeometric && pointerId == 0) {
20108f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka        for (int i = 0; i < inputSize; ++i) {
2021e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa            mPrimaryInputWord[i] = getPrimaryCodePointAt(i);
2033e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka        }
20408f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka
205feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka        for (int i = 0; i < mSampledInputSize && mTouchPositionCorrectionEnabled; ++i) {
2061e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa            const int *proximityCodePoints = getProximityCodePointsAt(i);
2071e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa            const int primaryKey = proximityCodePoints[0];
20808f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka            const int x = xCoordinates[i];
20908f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka            const int y = yCoordinates[i];
2103e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka            if (DEBUG_PROXIMITY_CHARS) {
21108f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                int a = x + y + primaryKey;
21208f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                a += 0;
21308f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                AKLOGI("--- Primary = %c, x = %d, y = %d", primaryKey, x, y);
21408f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka            }
2156c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa            for (int j = 0; j < MAX_PROXIMITY_CHARS_SIZE && proximityCodePoints[j] > 0;
2161e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa                    ++j) {
2171e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa                const int currentCodePoint = proximityCodePoints[j];
21808f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                const float squaredDistance =
21908f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                        hasInputCoordinates() ? calculateNormalizedSquaredDistance(
2201e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa                                mProximityInfo->getKeyIndexOf(currentCodePoint), i) :
22108f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                                NOT_A_DISTANCE_FLOAT;
22208f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                if (squaredDistance >= 0.0f) {
2236c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa                    mNormalizedSquaredDistances[i * MAX_PROXIMITY_CHARS_SIZE + j] =
22408f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                            (int) (squaredDistance * NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR);
22508f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                } else {
2266c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa                    mNormalizedSquaredDistances[i * MAX_PROXIMITY_CHARS_SIZE + j] =
22708f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                            (j == 0) ? EQUIVALENT_CHAR_WITHOUT_DISTANCE_INFO :
22808f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                                    PROXIMITY_CHAR_WITHOUT_DISTANCE_INFO;
22908f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                }
23008f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                if (DEBUG_PROXIMITY_CHARS) {
2311e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa                    AKLOGI("--- Proximity (%d) = %c", j, currentCodePoint);
23208f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka                }
2333e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka            }
2343e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka        }
2353e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka    }
236952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka
237952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka    if (DEBUG_GEO_FULL) {
238feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka        AKLOGI("ProximityState init finished: %d points out of %d", mSampledInputSize, inputSize);
239feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka    }
240feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka}
241feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka
242096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagibool ProximityInfoState::checkAndReturnIsContinuationPossible(const int inputSize,
243fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka        const int *const xCoordinates, const int *const yCoordinates, const int *const times,
244fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka        const bool isGeometric) const {
245fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka    if (isGeometric) {
246fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka        for (int i = 0; i < mSampledInputSize; ++i) {
247fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka            const int index = mInputIndice[i];
248fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka            if (index > inputSize || xCoordinates[index] != mSampledInputXs[i] ||
249fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka                    yCoordinates[index] != mSampledInputYs[i] || times[index] != mTimes[i]) {
250fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka                return false;
251fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka            }
252fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka        }
253fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka    } else {
254fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka        if (inputSize < mSampledInputSize) {
255fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka            // Assuming the cache is invalid if the previous input size is larger than the new one.
256096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi            return false;
257096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi        }
2585db594abbad2d9e8d2cf1aa6e417aa50ffc5dfc1Ken Wakasa        for (int i = 0; i < mSampledInputSize && i < MAX_WORD_LENGTH; ++i) {
259fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka            if (xCoordinates[i] != mSampledInputXs[i]
260fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka                    || yCoordinates[i] != mSampledInputYs[i]) {
261fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka                return false;
262fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka            }
263fe4f1ce26ca41ef51b5245d70e93b502f76262a5Satoshi Kataoka        }
264096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi    }
265096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi    return true;
266096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi}
267096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi
2684a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataokafloat ProximityInfoState::calculateNormalizedSquaredDistance(
2694a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka        const int keyIndex, const int inputIndex) const {
2704a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    if (keyIndex == NOT_AN_INDEX) {
2714a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka        return NOT_A_DISTANCE_FLOAT;
2724a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    }
2734a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    if (!mProximityInfo->hasSweetSpotData(keyIndex)) {
2744a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka        return NOT_A_DISTANCE_FLOAT;
2754a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    }
276feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka    if (NOT_A_COORDINATE == mSampledInputXs[inputIndex]) {
2774a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka        return NOT_A_DISTANCE_FLOAT;
2784a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    }
2794a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    const float squaredDistance = calculateSquaredDistanceFromSweetSpotCenter(
2804a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka            keyIndex, inputIndex);
2814a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    const float squaredRadius = square(mProximityInfo->getSweetSpotRadiiAt(keyIndex));
2824a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    return squaredDistance / squaredRadius;
2834a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka}
2844a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka
285687a244703a02323ebd64433cbaead5def499861Satoshi Kataokaint ProximityInfoState::getDuration(const int index) const {
286feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka    if (index >= 0 && index < mSampledInputSize - 1) {
287a811938d40070b96557df0f2a36ba8daa561fdd4Tom Ouyang        return mTimes[index + 1] - mTimes[index];
288687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka    }
28937b153e205c9672b299b47e97921fee2462a78bbSatoshi Kataoka    return 0;
290687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka}
291687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka
2920519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataoka// TODO: Remove the "scale" parameter
2930519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataoka// This function basically converts from a length to an edit distance. Accordingly, it's obviously
2940519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataoka// wrong to compare with mMaxPointToKeyLength.
2950519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataokafloat ProximityInfoState::getPointToKeyLength(
2960519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataoka        const int inputIndex, const int codePoint, const float scale) const {
297ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    const int keyId = mProximityInfo->getKeyIndexOf(codePoint);
298ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    if (keyId != NOT_AN_INDEX) {
299ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        const int index = inputIndex * mProximityInfo->getKeyCount() + keyId;
300a9763f93d76f97b9c6ed7dd1369a4d8cb016f06fSatoshi Kataoka        return min(mDistanceCache_G[index] * scale, mMaxPointToKeyLength);
301ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    }
3021e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa    if (isSkippableCodePoint(codePoint)) {
303806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        return 0.0f;
304806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    }
305ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    // If the char is not a key on the keyboard then return the max length.
306ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    return MAX_POINT_TO_KEY_LENGTH;
307806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi}
308806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi
309a9763f93d76f97b9c6ed7dd1369a4d8cb016f06fSatoshi Kataokafloat ProximityInfoState::getPointToKeyLength_G(const int inputIndex, const int codePoint) const {
3100519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataoka    return getPointToKeyLength(inputIndex, codePoint, 1.0f);
3110519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataoka}
3120519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataoka
3130519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataoka// TODO: Remove the "scale" parameter
3140519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataokafloat ProximityInfoState::getPointToKeyByIdLength(
3150519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataoka        const int inputIndex, const int keyId, const float scale) const {
316d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    return ProximityInfoStateUtils::getPointToKeyByIdLength(mMaxPointToKeyLength,
317d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            &mDistanceCache_G, mProximityInfo->getKeyCount(), inputIndex, keyId, scale);
318687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka}
319687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka
3200519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataokafloat ProximityInfoState::getPointToKeyByIdLength(const int inputIndex, const int keyId) const {
3210519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataoka    return getPointToKeyByIdLength(inputIndex, keyId, 1.0f);
3220519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataoka}
3230519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataoka
3242c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa// In the following function, c is the current character of the dictionary word currently examined.
3252c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa// currentChars is an array containing the keys close to the character the user actually typed at
3262c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa// the same position. We want to see if c is in it: if so, then the word contains at that position
3272c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa// a character close to what the user typed.
3282c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa// What the user typed is actually the first character of the array.
3292c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa// proximityIndex is a pointer to the variable where getMatchedProximityId returns the index of c
3302c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa// in the proximity chars of the input index.
3312c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa// Notice : accented characters do not have a proximity list, so they are alone in their list. The
3322c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa// non-accented version of the character should be considered "close", but not the other keys close
3332c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa// to the non-accented version.
3342c2f3a90d8115777adbe9ffd597f344aede84276Ken WakasaProximityType ProximityInfoState::getMatchedProximityId(const int index, const int c,
3352c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa        const bool checkProximityChars, int *proximityIndex) const {
3362c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa    const int *currentCodePoints = getProximityCodePointsAt(index);
3372c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa    const int firstCodePoint = currentCodePoints[0];
3382c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa    const int baseLowerC = toBaseLowerCase(c);
3392c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa
3402c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa    // The first char in the array is what user typed. If it matches right away, that means the
3412c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa    // user typed that same char for this pos.
3422c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa    if (firstCodePoint == baseLowerC || firstCodePoint == c) {
3432c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa        return EQUIVALENT_CHAR;
3442c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa    }
3452c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa
3462c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa    if (!checkProximityChars) return UNRELATED_CHAR;
3472c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa
3482c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa    // If the non-accented, lowercased version of that first character matches c, then we have a
3492c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa    // non-accented version of the accented character the user typed. Treat it as a close char.
3502c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa    if (toBaseLowerCase(firstCodePoint) == baseLowerC) {
3512c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa        return NEAR_PROXIMITY_CHAR;
3522c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa    }
3532c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa
3542c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa    // Not an exact nor an accent-alike match: search the list of close keys
3552c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa    int j = 1;
3566c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa    while (j < MAX_PROXIMITY_CHARS_SIZE
3572c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa            && currentCodePoints[j] > ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE) {
3582c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa        const bool matched = (currentCodePoints[j] == baseLowerC || currentCodePoints[j] == c);
3592c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa        if (matched) {
3602c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa            if (proximityIndex) {
3612c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa                *proximityIndex = j;
3622c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa            }
3632c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa            return NEAR_PROXIMITY_CHAR;
3642c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa        }
3652c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa        ++j;
3662c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa    }
3676c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa    if (j < MAX_PROXIMITY_CHARS_SIZE
3682c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa            && currentCodePoints[j] == ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE) {
3692c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa        ++j;
3706c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa        while (j < MAX_PROXIMITY_CHARS_SIZE
3712c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa                && currentCodePoints[j] > ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE) {
3722c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa            const bool matched = (currentCodePoints[j] == baseLowerC || currentCodePoints[j] == c);
3732c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa            if (matched) {
3742c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa                if (proximityIndex) {
3752c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa                    *proximityIndex = j;
3762c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa                }
3772c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa                return ADDITIONAL_PROXIMITY_CHAR;
3782c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa            }
3792c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa            ++j;
3802c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa        }
3812c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa    }
3822c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa    // Was not included, signal this as an unrelated character.
3832c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa    return UNRELATED_CHAR;
3842c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa}
3852c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa
3863811a28ddc07201930e0bbd2e1d01045b59af308Keisuke Kuroyanagiint ProximityInfoState::getSpaceY() const {
387b02ee3d67a1884b6ff59cc16c29a476845c0694fKen Wakasa    const int keyId = mProximityInfo->getKeyIndexOf(KEYCODE_SPACE);
388f2789819bd005b5b0581e8439601b5501306327dKen Wakasa    return mProximityInfo->getKeyCenterYOfKeyIdG(keyId);
389687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka}
390687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka
3914a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataokafloat ProximityInfoState::calculateSquaredDistanceFromSweetSpotCenter(
3924a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka        const int keyIndex, const int inputIndex) const {
3934a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    const float sweetSpotCenterX = mProximityInfo->getSweetSpotCenterXAt(keyIndex);
3944a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    const float sweetSpotCenterY = mProximityInfo->getSweetSpotCenterYAt(keyIndex);
395feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka    const float inputX = static_cast<float>(mSampledInputXs[inputIndex]);
396feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka    const float inputY = static_cast<float>(mSampledInputYs[inputIndex]);
3974a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    return square(inputX - sweetSpotCenterX) + square(inputY - sweetSpotCenterY);
3984a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka}
39995a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi
40095a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi// Puts possible characters into filter and returns new filter size.
401082507e1da56c6cefe575ec3d6a334e9b717e3faKen Wakasaint ProximityInfoState::getAllPossibleChars(
402082507e1da56c6cefe575ec3d6a334e9b717e3faKen Wakasa        const size_t index, int *const filter, const int filterSize) const {
403feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka    if (index >= mSampledInputXs.size()) {
40495a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi        return filterSize;
40595a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi    }
40641f12ee27b269033fe818f7d52e81ba948a046c3Keisuke Kuroyanagi    int newFilterSize = filterSize;
407ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    const int keyCount = mProximityInfo->getKeyCount();
408ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    for (int j = 0; j < keyCount; ++j) {
409ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        if (mSearchKeysVector[index].test(j)) {
410082507e1da56c6cefe575ec3d6a334e9b717e3faKen Wakasa            const int keyCodePoint = mProximityInfo->getCodePointOf(j);
41195a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi            bool insert = true;
41295a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi            // TODO: Avoid linear search
41395a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi            for (int k = 0; k < filterSize; ++k) {
41495a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi                if (filter[k] == keyCodePoint) {
41595a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi                    insert = false;
41695a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi                    break;
41795a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi                }
41895a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi            }
41995a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi            if (insert) {
42041f12ee27b269033fe818f7d52e81ba948a046c3Keisuke Kuroyanagi                filter[newFilterSize++] = keyCodePoint;
42195a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi            }
42295a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi        }
42395a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi    }
42441f12ee27b269033fe818f7d52e81ba948a046c3Keisuke Kuroyanagi    return newFilterSize;
42595a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi}
4263811a28ddc07201930e0bbd2e1d01045b59af308Keisuke Kuroyanagi
427ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagibool ProximityInfoState::isKeyInSerchKeysAfterIndex(const int index, const int keyId) const {
428ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    ASSERT(keyId >= 0);
429feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka    ASSERT(index >= 0 && index < mSampledInputSize);
430ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    return mSearchKeysVector[index].test(keyId);
431ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi}
432ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
433096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagivoid ProximityInfoState::popInputData() {
43447cc52415e3affb83eb4369190425b2a17b956c5Satoshi Kataoka    ProximityInfoStateUtils::popInputData(&mSampledInputXs, &mSampledInputYs, &mTimes,
43547cc52415e3affb83eb4369190425b2a17b956c5Satoshi Kataoka            &mLengthCache, &mInputIndice);
436096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi}
437096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi
438ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagifloat ProximityInfoState::getDirection(const int index0, const int index1) const {
439ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    return ProximityInfoStateUtils::getDirection(
440ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            &mSampledInputXs, &mSampledInputYs, index0, index1);
441ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi}
442ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
443ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagifloat ProximityInfoState::getLineToKeyDistance(
444ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        const int from, const int to, const int keyId, const bool extend) const {
445feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka    if (from < 0 || from > mSampledInputSize - 1) {
446ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        return 0.0f;
447ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    }
448feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka    if (to < 0 || to > mSampledInputSize - 1) {
449ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        return 0.0f;
450ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    }
451feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka    const int x0 = mSampledInputXs[from];
452feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka    const int y0 = mSampledInputYs[from];
453feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka    const int x1 = mSampledInputXs[to];
454feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka    const int y1 = mSampledInputYs[to];
455ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
456ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    const int keyX = mProximityInfo->getKeyCenterXOfKeyIdG(keyId);
457ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    const int keyY = mProximityInfo->getKeyCenterYOfKeyIdG(keyId);
458ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
4590c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa    return ProximityInfoUtils::pointToLineSegSquaredDistanceFloat(
4600c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa            keyX, keyY, x0, y0, x1, y1, extend);
461806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi}
462806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi
463e0349619acdba79223390c9925d81f7e88c7f8adSatoshi Kataoka// Get a word that is detected by tracing the most probable string into codePointBuf and
4641e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa// returns probability of generating the word.
465e0349619acdba79223390c9925d81f7e88c7f8adSatoshi Kataokafloat ProximityInfoState::getMostProbableString(int *const codePointBuf) const {
466350309aeb81ad1924af4d2e6d0bceaa6f98e4821Keisuke Kuroyanagi    static const float DEMOTION_LOG_PROBABILITY = 0.3f;
467ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    int index = 0;
468ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    float sumLogProbability = 0.0f;
469806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    // TODO: Current implementation is greedy algorithm. DP would be efficient for many cases.
4705db594abbad2d9e8d2cf1aa6e417aa50ffc5dfc1Ken Wakasa    for (int i = 0; i < mSampledInputSize && index < MAX_WORD_LENGTH - 1; ++i) {
471ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        float minLogProbability = static_cast<float>(MAX_POINT_TO_KEY_LENGTH);
472ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        int character = NOT_AN_INDEX;
473806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        for (hash_map_compat<int, float>::const_iterator it = mCharProbabilities[i].begin();
474806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi                it != mCharProbabilities[i].end(); ++it) {
475ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            const float logProbability = (it->first != NOT_AN_INDEX)
476350309aeb81ad1924af4d2e6d0bceaa6f98e4821Keisuke Kuroyanagi                    ? it->second + DEMOTION_LOG_PROBABILITY : it->second;
477ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            if (logProbability < minLogProbability) {
478ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                minLogProbability = logProbability;
479ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi                character = it->first;
480806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            }
481806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        }
482ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        if (character != NOT_AN_INDEX) {
4831e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa            codePointBuf[index] = mProximityInfo->getCodePointOf(character);
484806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi            index++;
485806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        }
486ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        sumLogProbability += minLogProbability;
487806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    }
4881e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa    codePointBuf[index] = '\0';
489ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    return sumLogProbability;
490ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi}
491ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
492f32869c6b6296a8bf594abdf0b18281d9312e54fSatoshi Kataokabool ProximityInfoState::hasSpaceProximity(const int index) const {
493f32869c6b6296a8bf594abdf0b18281d9312e54fSatoshi Kataoka    ASSERT(0 <= index && index < mSampledInputSize);
494f32869c6b6296a8bf594abdf0b18281d9312e54fSatoshi Kataoka    return mProximityInfo->hasSpaceProximity(getInputX(index), getInputY(index));
495f32869c6b6296a8bf594abdf0b18281d9312e54fSatoshi Kataoka}
496f32869c6b6296a8bf594abdf0b18281d9312e54fSatoshi Kataoka
497ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi// Returns a probability of mapping index to keyIndex.
498ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagifloat ProximityInfoState::getProbability(const int index, const int keyIndex) const {
499feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka    ASSERT(0 <= index && index < mSampledInputSize);
500ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    hash_map_compat<int, float>::const_iterator it = mCharProbabilities[index].find(keyIndex);
501ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    if (it != mCharProbabilities[index].end()) {
502ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        return it->second;
503ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    }
504ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    return static_cast<float>(MAX_POINT_TO_KEY_LENGTH);
505806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi}
5063e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka} // namespace latinime
507