1ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka/*
2ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka * Copyright (C) 2013 The Android Open Source Project
3ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka *
4ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka * Licensed under the Apache License, Version 2.0 (the "License");
5ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka * you may not use this file except in compliance with the License.
6ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka * You may obtain a copy of the License at
7ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka *
8ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka *      http://www.apache.org/licenses/LICENSE-2.0
9ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka *
10ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka * Unless required by applicable law or agreed to in writing, software
11ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka * distributed under the License is distributed on an "AS IS" BASIS,
12ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka * See the License for the specific language governing permissions and
14ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka * limitations under the License.
15ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka */
16ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
1729432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa#include "suggest/core/layout/proximity_info_state_utils.h"
1829432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa
19e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka#include <cmath>
2020b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka#include <cstring> // for memset()
21d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka#include <sstream> // for debug prints
22ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka#include <vector>
23ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
246c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa#include "defines.h"
2529432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa#include "suggest/core/layout/geometry_utils.h"
2629432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa#include "suggest/core/layout/proximity_info.h"
2729432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa#include "suggest/core/layout/proximity_info_params.h"
28ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
29ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataokanamespace latinime {
30d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka
3120b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka/* static */ int ProximityInfoStateUtils::trimLastTwoTouchPoints(std::vector<int> *sampledInputXs,
3220b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka        std::vector<int> *sampledInputYs, std::vector<int> *sampledInputTimes,
3320b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka        std::vector<int> *sampledLengthCache, std::vector<int> *sampledInputIndice) {
3420b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka    const int nextStartIndex = (*sampledInputIndice)[sampledInputIndice->size() - 2];
3520b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka    popInputData(sampledInputXs, sampledInputYs, sampledInputTimes, sampledLengthCache,
3620b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka            sampledInputIndice);
3720b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka    popInputData(sampledInputXs, sampledInputYs, sampledInputTimes, sampledLengthCache,
3820b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka            sampledInputIndice);
3920b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka    return nextStartIndex;
4020b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka}
4120b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka
4228c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa/* static */ int ProximityInfoStateUtils::updateTouchPoints(
43ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const ProximityInfo *const proximityInfo, const int maxPointToKeyLength,
446c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa        const int *const inputProximities, const int *const inputXCoordinates,
456c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa        const int *const inputYCoordinates, const int *const times, const int *const pointerIds,
460052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi        const int inputSize, const bool isGeometric, const int pointerId,
470052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi        const int pushTouchPointStartIndex, std::vector<int> *sampledInputXs,
486c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa        std::vector<int> *sampledInputYs, std::vector<int> *sampledInputTimes,
496c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa        std::vector<int> *sampledLengthCache, std::vector<int> *sampledInputIndice) {
50ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (DEBUG_SAMPLING_POINTS) {
51ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        if (times) {
52ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            for (int i = 0; i < inputSize; ++i) {
53ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                AKLOGI("(%d) x %d, y %d, time %d",
54e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka                        i, inputXCoordinates[i], inputYCoordinates[i], times[i]);
55ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            }
56ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        }
57ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
58ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka#ifdef DO_ASSERT_TEST
59ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (times) {
60ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        for (int i = 0; i < inputSize; ++i) {
61ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            if (i > 0) {
62e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka                if (times[i] < times[i - 1]) {
63e9e4fa5af6a94dbd6e24e631cd4606d7e41c1f16Ken Wakasa                    AKLOGI("Invalid time sequence. %d, %d", times[i - 1], times[i]);
64e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka                    ASSERT(false);
65e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka                }
66ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            }
67ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        }
68ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
69ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka#endif
70ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const bool proximityOnly = !isGeometric
71ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            && (inputXCoordinates[0] < 0 || inputYCoordinates[0] < 0);
72ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    int lastInputIndex = pushTouchPointStartIndex;
73ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    for (int i = lastInputIndex; i < inputSize; ++i) {
74ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const int pid = pointerIds ? pointerIds[i] : 0;
75ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        if (pointerId == pid) {
76ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            lastInputIndex = i;
77ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        }
78ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
79ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (DEBUG_GEO_FULL) {
80ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        AKLOGI("Init ProximityInfoState: last input index = %d", lastInputIndex);
81ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
82ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // Working space to save near keys distances for current, prev and prevprev input point.
83ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    NearKeysDistanceMap nearKeysDistances[3];
84ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // These pointers are swapped for each inputs points.
85ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    NearKeysDistanceMap *currentNearKeysDistances = &nearKeysDistances[0];
86ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    NearKeysDistanceMap *prevNearKeysDistances = &nearKeysDistances[1];
87ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    NearKeysDistanceMap *prevPrevNearKeysDistances = &nearKeysDistances[2];
88ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // "sumAngle" is accumulated by each angle of input points. And when "sumAngle" exceeds
89ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // the threshold we save that point, reset sumAngle. This aims to keep the figure of
90ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // the curve.
91ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    float sumAngle = 0.0f;
92ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
93ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    for (int i = pushTouchPointStartIndex; i <= lastInputIndex; ++i) {
94ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        // Assuming pointerId == 0 if pointerIds is null.
95ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const int pid = pointerIds ? pointerIds[i] : 0;
96ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        if (DEBUG_GEO_FULL) {
97ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            AKLOGI("Init ProximityInfoState: (%d)PID = %d", i, pid);
98ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        }
99ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        if (pointerId == pid) {
100ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            const int c = isGeometric ?
101ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                    NOT_A_COORDINATE : getPrimaryCodePointAt(inputProximities, i);
102ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            const int x = proximityOnly ? NOT_A_COORDINATE : inputXCoordinates[i];
103ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            const int y = proximityOnly ? NOT_A_COORDINATE : inputYCoordinates[i];
104ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            const int time = times ? times[i] : -1;
105ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
106ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            if (i > 1) {
10729432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa                const float prevAngle = GeometryUtils::getAngle(
108ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                        inputXCoordinates[i - 2], inputYCoordinates[i - 2],
109ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                        inputXCoordinates[i - 1], inputYCoordinates[i - 1]);
11029432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa                const float currentAngle = GeometryUtils::getAngle(
11128c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                        inputXCoordinates[i - 1], inputYCoordinates[i - 1], x, y);
11229432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa                sumAngle += GeometryUtils::getAngleDiff(prevAngle, currentAngle);
113ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            }
114ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
11528c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa            if (pushTouchPoint(proximityInfo, maxPointToKeyLength, i, c, x, y, time,
1160052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi                    isGeometric, isGeometric /* doSampling */, i == lastInputIndex,
117a1d84bcf8ffd031c135b6f3f8c94b6732071849bSatoshi Kataoka                    sumAngle, currentNearKeysDistances, prevNearKeysDistances,
118a1d84bcf8ffd031c135b6f3f8c94b6732071849bSatoshi Kataoka                    prevPrevNearKeysDistances, sampledInputXs, sampledInputYs, sampledInputTimes,
119a1d84bcf8ffd031c135b6f3f8c94b6732071849bSatoshi Kataoka                    sampledLengthCache, sampledInputIndice)) {
120ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                // Previous point information was popped.
121ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                NearKeysDistanceMap *tmp = prevNearKeysDistances;
122ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                prevNearKeysDistances = currentNearKeysDistances;
123ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                currentNearKeysDistances = tmp;
124ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            } else {
125ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                NearKeysDistanceMap *tmp = prevPrevNearKeysDistances;
126ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                prevPrevNearKeysDistances = prevNearKeysDistances;
127ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                prevNearKeysDistances = currentNearKeysDistances;
128ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                currentNearKeysDistances = tmp;
129ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                sumAngle = 0.0f;
130ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            }
131ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        }
132ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
133ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    return sampledInputXs->size();
134ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka}
135ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
136ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka/* static */ const int *ProximityInfoStateUtils::getProximityCodePointsAt(
137ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const int *const inputProximities, const int index) {
1386c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa    return inputProximities + (index * MAX_PROXIMITY_CHARS_SIZE);
139ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka}
140ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
1414920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa/* static */ int ProximityInfoStateUtils::getPrimaryCodePointAt(const int *const inputProximities,
1424920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa        const int index) {
143ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    return getProximityCodePointsAt(inputProximities, index)[0];
144ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka}
145ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
1464920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa/* static */ void ProximityInfoStateUtils::initPrimaryInputWord(const int inputSize,
1474920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa        const int *const inputProximities, int *primaryInputWord) {
14820b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka    memset(primaryInputWord, 0, sizeof(primaryInputWord[0]) * MAX_WORD_LENGTH);
149d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka    for (int i = 0; i < inputSize; ++i) {
150d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka        primaryInputWord[i] = getPrimaryCodePointAt(inputProximities, i);
151d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka    }
152d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka}
153d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka
154d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka/* static */ float ProximityInfoStateUtils::calculateSquaredDistanceFromSweetSpotCenter(
155d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka        const ProximityInfo *const proximityInfo, const std::vector<int> *const sampledInputXs,
1564920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa        const std::vector<int> *const sampledInputYs, const int keyIndex, const int inputIndex) {
157d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka    const float sweetSpotCenterX = proximityInfo->getSweetSpotCenterXAt(keyIndex);
158d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka    const float sweetSpotCenterY = proximityInfo->getSweetSpotCenterYAt(keyIndex);
159d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka    const float inputX = static_cast<float>((*sampledInputXs)[inputIndex]);
160d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka    const float inputY = static_cast<float>((*sampledInputYs)[inputIndex]);
16129432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa    return GeometryUtils::SQUARE_FLOAT(inputX - sweetSpotCenterX)
16229432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa            + GeometryUtils::SQUARE_FLOAT(inputY - sweetSpotCenterY);
163d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka}
164d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka
165d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka/* static */ float ProximityInfoStateUtils::calculateNormalizedSquaredDistance(
166d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka        const ProximityInfo *const proximityInfo, const std::vector<int> *const sampledInputXs,
1674920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa        const std::vector<int> *const sampledInputYs, const int keyIndex, const int inputIndex) {
168d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka    if (keyIndex == NOT_AN_INDEX) {
169d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka        return ProximityInfoParams::NOT_A_DISTANCE_FLOAT;
170d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka    }
171d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka    if (!proximityInfo->hasSweetSpotData(keyIndex)) {
172d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka        return ProximityInfoParams::NOT_A_DISTANCE_FLOAT;
173d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka    }
174d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka    if (NOT_A_COORDINATE == (*sampledInputXs)[inputIndex]) {
175d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka        return ProximityInfoParams::NOT_A_DISTANCE_FLOAT;
176d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka    }
177d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka    const float squaredDistance = calculateSquaredDistanceFromSweetSpotCenter(proximityInfo,
178d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka            sampledInputXs, sampledInputYs, keyIndex, inputIndex);
17929432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa    const float squaredRadius = GeometryUtils::SQUARE_FLOAT(
18029432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa            proximityInfo->getSweetSpotRadiiAt(keyIndex));
181d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka    return squaredDistance / squaredRadius;
182d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka}
183d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka
184d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka/* static */ void ProximityInfoStateUtils::initGeometricDistanceInfos(
18528c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa        const ProximityInfo *const proximityInfo, const int sampledInputSize,
1860052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi        const int lastSavedInputSize, const bool isGeometric,
187a1d84bcf8ffd031c135b6f3f8c94b6732071849bSatoshi Kataoka        const std::vector<int> *const sampledInputXs,
188d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka        const std::vector<int> *const sampledInputYs,
189837f46dcb35a8f42a6bd5bc5fc6395d7386acb81Satoshi Kataoka        std::vector<NearKeycodesSet> *sampledNearKeySets,
190837f46dcb35a8f42a6bd5bc5fc6395d7386acb81Satoshi Kataoka        std::vector<float> *sampledNormalizedSquaredLengthCache) {
191837f46dcb35a8f42a6bd5bc5fc6395d7386acb81Satoshi Kataoka    sampledNearKeySets->resize(sampledInputSize);
19228c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa    const int keyCount = proximityInfo->getKeyCount();
193837f46dcb35a8f42a6bd5bc5fc6395d7386acb81Satoshi Kataoka    sampledNormalizedSquaredLengthCache->resize(sampledInputSize * keyCount);
194d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka    for (int i = lastSavedInputSize; i < sampledInputSize; ++i) {
195837f46dcb35a8f42a6bd5bc5fc6395d7386acb81Satoshi Kataoka        (*sampledNearKeySets)[i].reset();
196d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka        for (int k = 0; k < keyCount; ++k) {
197d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka            const int index = i * keyCount + k;
198d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka            const int x = (*sampledInputXs)[i];
199d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka            const int y = (*sampledInputYs)[i];
200d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka            const float normalizedSquaredDistance =
201a1d84bcf8ffd031c135b6f3f8c94b6732071849bSatoshi Kataoka                    proximityInfo->getNormalizedSquaredDistanceFromCenterFloatG(
2020052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi                            k, x, y, isGeometric);
203837f46dcb35a8f42a6bd5bc5fc6395d7386acb81Satoshi Kataoka            (*sampledNormalizedSquaredLengthCache)[index] = normalizedSquaredDistance;
2044920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa            if (normalizedSquaredDistance
2054920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa                    < ProximityInfoParams::NEAR_KEY_NORMALIZED_SQUARED_THRESHOLD) {
206837f46dcb35a8f42a6bd5bc5fc6395d7386acb81Satoshi Kataoka                (*sampledNearKeySets)[i][k] = true;
207d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka            }
208d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka        }
209d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka    }
210d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka}
211d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka
212ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka/* static */ void ProximityInfoStateUtils::popInputData(std::vector<int> *sampledInputXs,
213ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        std::vector<int> *sampledInputYs, std::vector<int> *sampledInputTimes,
214ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        std::vector<int> *sampledLengthCache, std::vector<int> *sampledInputIndice) {
215ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    sampledInputXs->pop_back();
216ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    sampledInputYs->pop_back();
217ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    sampledInputTimes->pop_back();
218ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    sampledLengthCache->pop_back();
219ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    sampledInputIndice->pop_back();
220ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka}
221ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
222ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka/* static */ float ProximityInfoStateUtils::refreshSpeedRates(const int inputSize,
223ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const int *const xCoordinates, const int *const yCoordinates, const int *const times,
224ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const int lastSavedInputSize, const int sampledInputSize,
2254920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa        const std::vector<int> *const sampledInputXs, const std::vector<int> *const sampledInputYs,
226ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const std::vector<int> *const sampledInputTimes,
227ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const std::vector<int> *const sampledLengthCache,
228ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const std::vector<int> *const sampledInputIndice, std::vector<float> *sampledSpeedRates,
229ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        std::vector<float> *sampledDirections) {
230ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // Relative speed calculation.
231ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const int sumDuration = sampledInputTimes->back() - sampledInputTimes->front();
232ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const int sumLength = sampledLengthCache->back() - sampledLengthCache->front();
233ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const float averageSpeed = static_cast<float>(sumLength) / static_cast<float>(sumDuration);
234ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    sampledSpeedRates->resize(sampledInputSize);
235ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    for (int i = lastSavedInputSize; i < sampledInputSize; ++i) {
236ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const int index = (*sampledInputIndice)[i];
237ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        int length = 0;
238ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        int duration = 0;
239ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
240ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        // Calculate velocity by using distances and durations of
24128c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa        // ProximityInfoParams::NUM_POINTS_FOR_SPEED_CALCULATION points for both forward and
24228c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa        // backward.
24328c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa        const int forwardNumPoints = min(inputSize - 1,
24428c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                index + ProximityInfoParams::NUM_POINTS_FOR_SPEED_CALCULATION);
24528c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa        for (int j = index; j < forwardNumPoints; ++j) {
246ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            if (i < sampledInputSize - 1 && j >= (*sampledInputIndice)[i + 1]) {
247ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                break;
248ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            }
24929432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa            length += GeometryUtils::getDistanceInt(xCoordinates[j], yCoordinates[j],
250ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                    xCoordinates[j + 1], yCoordinates[j + 1]);
251ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            duration += times[j + 1] - times[j];
252ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        }
25328c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa        const int backwardNumPoints = max(0,
25428c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                index - ProximityInfoParams::NUM_POINTS_FOR_SPEED_CALCULATION);
25528c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa        for (int j = index - 1; j >= backwardNumPoints; --j) {
256ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            if (i > 0 && j < (*sampledInputIndice)[i - 1]) {
257ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                break;
258ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            }
259d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka            // TODO: use mSampledLengthCache instead?
26029432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa            length += GeometryUtils::getDistanceInt(xCoordinates[j], yCoordinates[j],
261ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                    xCoordinates[j + 1], yCoordinates[j + 1]);
262ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            duration += times[j + 1] - times[j];
263ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        }
264ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        if (duration == 0 || sumDuration == 0) {
265ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            // Cannot calculate speed; thus, it gives an average value (1.0);
266ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            (*sampledSpeedRates)[i] = 1.0f;
267ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        } else {
268ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            const float speed = static_cast<float>(length) / static_cast<float>(duration);
269ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            (*sampledSpeedRates)[i] = speed / averageSpeed;
270ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        }
271ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
272ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
273ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // Direction calculation.
274ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    sampledDirections->resize(sampledInputSize - 1);
275ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    for (int i = max(0, lastSavedInputSize - 1); i < sampledInputSize - 1; ++i) {
276ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        (*sampledDirections)[i] = getDirection(sampledInputXs, sampledInputYs, i, i + 1);
277ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
278ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    return averageSpeed;
279ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka}
280ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
281ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka/* static */ void ProximityInfoStateUtils::refreshBeelineSpeedRates(const int mostCommonKeyWidth,
282ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const float averageSpeed, const int inputSize, const int *const xCoordinates,
283ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const int *const yCoordinates, const int *times, const int sampledInputSize,
284ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const std::vector<int> *const sampledInputXs,
285ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const std::vector<int> *const sampledInputYs, const std::vector<int> *const inputIndice,
286ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        std::vector<int> *beelineSpeedPercentiles) {
287ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (DEBUG_SAMPLING_POINTS) {
288ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        AKLOGI("--- refresh beeline speed rates");
289ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
290ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    beelineSpeedPercentiles->resize(sampledInputSize);
291ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    for (int i = 0; i < sampledInputSize; ++i) {
292ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        (*beelineSpeedPercentiles)[i] = static_cast<int>(calculateBeelineSpeedRate(
293ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                mostCommonKeyWidth, averageSpeed, i, inputSize, xCoordinates, yCoordinates, times,
294ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                sampledInputSize, sampledInputXs, sampledInputYs, inputIndice) * MAX_PERCENTILE);
295ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
296ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka}
297ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
298ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka/* static */float ProximityInfoStateUtils::getDirection(
299ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const std::vector<int> *const sampledInputXs,
300ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const std::vector<int> *const sampledInputYs, const int index0, const int index1) {
301ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    ASSERT(sampledInputXs && sampledInputYs);
302ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const int sampledInputSize =sampledInputXs->size();
303ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (index0 < 0 || index0 > sampledInputSize - 1) {
304ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        return 0.0f;
305ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
306ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (index1 < 0 || index1 > sampledInputSize - 1) {
307ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        return 0.0f;
308ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
309ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const int x1 = (*sampledInputXs)[index0];
310ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const int y1 = (*sampledInputYs)[index0];
311ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const int x2 = (*sampledInputXs)[index1];
312ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const int y2 = (*sampledInputYs)[index1];
31329432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa    return GeometryUtils::getAngle(x1, y1, x2, y2);
314ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka}
315ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
316ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka// Calculating point to key distance for all near keys and returning the distance between
317ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka// the given point and the nearest key position.
318ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka/* static */ float ProximityInfoStateUtils::updateNearKeysDistances(
319ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const ProximityInfo *const proximityInfo, const float maxPointToKeyLength, const int x,
3200052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi        const int y, const bool isGeometric, NearKeysDistanceMap *const currentNearKeysDistances) {
321ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    currentNearKeysDistances->clear();
322ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const int keyCount = proximityInfo->getKeyCount();
323ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    float nearestKeyDistance = maxPointToKeyLength;
324ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    for (int k = 0; k < keyCount; ++k) {
325a1d84bcf8ffd031c135b6f3f8c94b6732071849bSatoshi Kataoka        const float dist = proximityInfo->getNormalizedSquaredDistanceFromCenterFloatG(k, x, y,
3260052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi                isGeometric);
3274920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa        if (dist < ProximityInfoParams::NEAR_KEY_THRESHOLD_FOR_DISTANCE) {
328ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            currentNearKeysDistances->insert(std::pair<int, float>(k, dist));
329ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        }
330ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        if (nearestKeyDistance > dist) {
331ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            nearestKeyDistance = dist;
332ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        }
333ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
334ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    return nearestKeyDistance;
335ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka}
336ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
337ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka// Check if previous point is at local minimum position to near keys.
338ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka/* static */ bool ProximityInfoStateUtils::isPrevLocalMin(
339ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const NearKeysDistanceMap *const currentNearKeysDistances,
340ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const NearKeysDistanceMap *const prevNearKeysDistances,
341ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const NearKeysDistanceMap *const prevPrevNearKeysDistances) {
342ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    for (NearKeysDistanceMap::const_iterator it = prevNearKeysDistances->begin();
343ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            it != prevNearKeysDistances->end(); ++it) {
344ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        NearKeysDistanceMap::const_iterator itPP = prevPrevNearKeysDistances->find(it->first);
345ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        NearKeysDistanceMap::const_iterator itC = currentNearKeysDistances->find(it->first);
3464920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa        const bool isPrevPrevNear = (itPP == prevPrevNearKeysDistances->end()
3474920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa                || itPP->second > it->second + ProximityInfoParams::MARGIN_FOR_PREV_LOCAL_MIN);
3484920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa        const bool isCurrentNear = (itC == currentNearKeysDistances->end()
3494920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa                || itC->second > it->second + ProximityInfoParams::MARGIN_FOR_PREV_LOCAL_MIN);
3504920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa        if (isPrevPrevNear && isCurrentNear) {
351ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            return true;
352ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        }
353ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
354ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    return false;
355ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka}
356ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
357ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka// Calculating a point score that indicates usefulness of the point.
358ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka/* static */ float ProximityInfoStateUtils::getPointScore(const int mostCommonKeyWidth,
359ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const int x, const int y, const int time, const bool lastPoint, const float nearest,
360ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const float sumAngle, const NearKeysDistanceMap *const currentNearKeysDistances,
361ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const NearKeysDistanceMap *const prevNearKeysDistances,
362ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const NearKeysDistanceMap *const prevPrevNearKeysDistances,
363ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        std::vector<int> *sampledInputXs, std::vector<int> *sampledInputYs) {
364ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const size_t size = sampledInputXs->size();
365ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // If there is only one point, add this point. Besides, if the previous point's distance map
366ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // is empty, we re-compute nearby keys distances from the current point.
367ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // Note that the current point is the first point in the incremental input that needs to
368ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // be re-computed.
369ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (size <= 1 || prevNearKeysDistances->empty()) {
370ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        return 0.0f;
371ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
372ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
373ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const int baseSampleRate = mostCommonKeyWidth;
37429432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa    const int distPrev = GeometryUtils::getDistanceInt(sampledInputXs->back(),
37529432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa            sampledInputYs->back(), (*sampledInputXs)[size - 2],
37629432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa            (*sampledInputYs)[size - 2]) * ProximityInfoParams::DISTANCE_BASE_SCALE;
377ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    float score = 0.0f;
378ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
379ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // Location
380ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (!isPrevLocalMin(currentNearKeysDistances, prevNearKeysDistances,
381ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        prevPrevNearKeysDistances)) {
3824920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa        score += ProximityInfoParams::NOT_LOCALMIN_DISTANCE_SCORE;
3834920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa    } else if (nearest < ProximityInfoParams::NEAR_KEY_THRESHOLD_FOR_POINT_SCORE) {
384ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        // Promote points nearby keys
3854920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa        score += ProximityInfoParams::LOCALMIN_DISTANCE_AND_NEAR_TO_KEY_SCORE;
386ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
387ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // Angle
38829432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa    const float angle1 = GeometryUtils::getAngle(x, y, sampledInputXs->back(),
38929432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa            sampledInputYs->back());
39029432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa    const float angle2 = GeometryUtils::getAngle(sampledInputXs->back(), sampledInputYs->back(),
391ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            (*sampledInputXs)[size - 2], (*sampledInputYs)[size - 2]);
39229432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa    const float angleDiff = GeometryUtils::getAngleDiff(angle1, angle2);
393ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
394ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // Save corner
3954920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa    if (distPrev > baseSampleRate * ProximityInfoParams::CORNER_CHECK_DISTANCE_THRESHOLD_SCALE
3964920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa            && (sumAngle > ProximityInfoParams::CORNER_SUM_ANGLE_THRESHOLD
3974920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa                    || angleDiff > ProximityInfoParams::CORNER_ANGLE_THRESHOLD_FOR_POINT_SCORE)) {
3984920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa        score += ProximityInfoParams::CORNER_SCORE;
399ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
400ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    return score;
401ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka}
402ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
403ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka// Sampling touch point and pushing information to vectors.
404ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka// Returning if previous point is popped or not.
40528c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa/* static */ bool ProximityInfoStateUtils::pushTouchPoint(const ProximityInfo *const proximityInfo,
40628c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa        const int maxPointToKeyLength, const int inputIndex, const int nodeCodePoint, int x, int y,
4070052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi        const int time, const bool isGeometric, const bool doSampling,
408a1d84bcf8ffd031c135b6f3f8c94b6732071849bSatoshi Kataoka        const bool isLastPoint, const float sumAngle,
409ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        NearKeysDistanceMap *const currentNearKeysDistances,
410ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const NearKeysDistanceMap *const prevNearKeysDistances,
411ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const NearKeysDistanceMap *const prevPrevNearKeysDistances,
412ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        std::vector<int> *sampledInputXs, std::vector<int> *sampledInputYs,
413ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        std::vector<int> *sampledInputTimes, std::vector<int> *sampledLengthCache,
414ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        std::vector<int> *sampledInputIndice) {
41528c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa    const int mostCommonKeyWidth = proximityInfo->getMostCommonKeyWidth();
416ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
417ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    size_t size = sampledInputXs->size();
418ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    bool popped = false;
4196c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa    if (nodeCodePoint < 0 && doSampling) {
420a1d84bcf8ffd031c135b6f3f8c94b6732071849bSatoshi Kataoka        const float nearest = updateNearKeysDistances(proximityInfo, maxPointToKeyLength, x, y,
4210052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi                isGeometric, currentNearKeysDistances);
422ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const float score = getPointScore(mostCommonKeyWidth, x, y, time, isLastPoint, nearest,
423ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                sumAngle, currentNearKeysDistances, prevNearKeysDistances,
424ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                prevPrevNearKeysDistances, sampledInputXs, sampledInputYs);
425ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        if (score < 0) {
426ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            // Pop previous point because it would be useless.
427ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            popInputData(sampledInputXs, sampledInputYs, sampledInputTimes, sampledLengthCache,
428ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                    sampledInputIndice);
429ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            size = sampledInputXs->size();
430ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            popped = true;
431ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        } else {
432ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            popped = false;
433ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        }
434ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        // Check if the last point should be skipped.
435ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        if (isLastPoint && size > 0) {
43629432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa            if (GeometryUtils::getDistanceInt(x, y, sampledInputXs->back(), sampledInputYs->back())
43728c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                    * ProximityInfoParams::LAST_POINT_SKIP_DISTANCE_SCALE < mostCommonKeyWidth) {
438ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                // This point is not used because it's too close to the previous point.
439ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                if (DEBUG_GEO_FULL) {
440ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                    AKLOGI("p0: size = %zd, x = %d, y = %d, lx = %d, ly = %d, dist = %d, "
441e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka                           "width = %d", size, x, y, sampledInputXs->back(),
44229432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa                           sampledInputYs->back(), GeometryUtils::getDistanceInt(
443e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka                                   x, y, sampledInputXs->back(), sampledInputYs->back()),
44428c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                           mostCommonKeyWidth
44528c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                                   / ProximityInfoParams::LAST_POINT_SKIP_DISTANCE_SCALE);
446ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                }
447ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                return popped;
448ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            }
449ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        }
450ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
451ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
452ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (nodeCodePoint >= 0 && (x < 0 || y < 0)) {
453ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const int keyId = proximityInfo->getKeyIndexOf(nodeCodePoint);
454ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        if (keyId >= 0) {
4550052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi            x = proximityInfo->getKeyCenterXOfKeyIdG(keyId, NOT_AN_INDEX, isGeometric);
4560052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi            y = proximityInfo->getKeyCenterYOfKeyIdG(keyId, NOT_AN_INDEX, isGeometric);
457ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        }
458ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
459ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
460ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // Pushing point information.
461ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (size > 0) {
462ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        sampledLengthCache->push_back(
46329432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa                sampledLengthCache->back() + GeometryUtils::getDistanceInt(
464ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                        x, y, sampledInputXs->back(), sampledInputYs->back()));
465ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    } else {
466ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        sampledLengthCache->push_back(0);
467ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
468ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    sampledInputXs->push_back(x);
469ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    sampledInputYs->push_back(y);
470ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    sampledInputTimes->push_back(time);
471ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    sampledInputIndice->push_back(inputIndex);
472ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (DEBUG_GEO_FULL) {
473ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        AKLOGI("pushTouchPoint: x = %03d, y = %03d, time = %d, index = %d, popped ? %01d",
474ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                x, y, time, inputIndex, popped);
475ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
476ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    return popped;
477ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka}
478ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
479ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka/* static */ float ProximityInfoStateUtils::calculateBeelineSpeedRate(const int mostCommonKeyWidth,
480ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const float averageSpeed, const int id, const int inputSize, const int *const xCoordinates,
481ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const int *const yCoordinates, const int *times, const int sampledInputSize,
482ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const std::vector<int> *const sampledInputXs,
483e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka        const std::vector<int> *const sampledInputYs,
484e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka        const std::vector<int> *const sampledInputIndices) {
485ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (sampledInputSize <= 0 || averageSpeed < 0.001f) {
486ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        if (DEBUG_SAMPLING_POINTS) {
487ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            AKLOGI("--- invalid state: cancel. size = %d, ave = %f",
488e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka                    sampledInputSize, averageSpeed);
489ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        }
490ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        return 1.0f;
491ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
492ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const int lookupRadius = mostCommonKeyWidth
493ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            * ProximityInfoParams::LOOKUP_RADIUS_PERCENTILE / MAX_PERCENTILE;
494ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const int x0 = (*sampledInputXs)[id];
495ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const int y0 = (*sampledInputYs)[id];
496e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka    const int actualInputIndex = (*sampledInputIndices)[id];
497ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    int tempTime = 0;
498ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    int tempBeelineDistance = 0;
499ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    int start = actualInputIndex;
500ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // lookup forward
501ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    while (start > 0 && tempBeelineDistance < lookupRadius) {
502ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        tempTime += times[start] - times[start - 1];
503ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        --start;
50429432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa        tempBeelineDistance = GeometryUtils::getDistanceInt(x0, y0, xCoordinates[start],
50529432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa                yCoordinates[start]);
506ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
507ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // Exclusive unless this is an edge point
508ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (start > 0 && start < actualInputIndex) {
509ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        ++start;
510ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
511ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    tempTime= 0;
512ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    tempBeelineDistance = 0;
513ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    int end = actualInputIndex;
514ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // lookup backward
515ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    while (end < (inputSize - 1) && tempBeelineDistance < lookupRadius) {
516ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        tempTime += times[end + 1] - times[end];
517ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        ++end;
51829432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa        tempBeelineDistance = GeometryUtils::getDistanceInt(x0, y0, xCoordinates[end],
51929432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa                yCoordinates[end]);
520ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
521ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // Exclusive unless this is an edge point
522ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (end > actualInputIndex && end < (inputSize - 1)) {
523ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        --end;
524ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
525ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
526ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (start >= end) {
527ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        if (DEBUG_DOUBLE_LETTER) {
528ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            AKLOGI("--- double letter: start == end %d", start);
529ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        }
530ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        return 1.0f;
531ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
532ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
533ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const int x2 = xCoordinates[start];
534ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const int y2 = yCoordinates[start];
535ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const int x3 = xCoordinates[end];
536ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const int y3 = yCoordinates[end];
53729432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa    const int beelineDistance = GeometryUtils::getDistanceInt(x2, y2, x3, y3);
538ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    int adjustedStartTime = times[start];
539ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (start == 0 && actualInputIndex == 0 && inputSize > 1) {
540ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        adjustedStartTime += ProximityInfoParams::FIRST_POINT_TIME_OFFSET_MILLIS;
541ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
542ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    int adjustedEndTime = times[end];
543ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (end == (inputSize - 1) && inputSize > 1) {
544ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        adjustedEndTime -= ProximityInfoParams::FIRST_POINT_TIME_OFFSET_MILLIS;
545ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
546ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const int time = adjustedEndTime - adjustedStartTime;
547ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (time <= 0) {
548ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        return 1.0f;
549ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
550ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
551ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (time >= ProximityInfoParams::STRONG_DOUBLE_LETTER_TIME_MILLIS){
552ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        return 0.0f;
553ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
554ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (DEBUG_DOUBLE_LETTER) {
555ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        AKLOGI("--- (%d, %d) double letter: start = %d, end = %d, dist = %d, time = %d,"
556ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                " speed = %f, ave = %f, val = %f, start time = %d, end time = %d",
557e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka                id, (*sampledInputIndices)[id], start, end, beelineDistance, time,
558e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka                (static_cast<float>(beelineDistance) / static_cast<float>(time)), averageSpeed,
559ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                ((static_cast<float>(beelineDistance) / static_cast<float>(time))
560e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka                        / averageSpeed), adjustedStartTime, adjustedEndTime);
561ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
562ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // Offset 1%
563ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // TODO: Detect double letter more smartly
564ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    return 0.01f + static_cast<float>(beelineDistance) / static_cast<float>(time) / averageSpeed;
565ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka}
566d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka
567d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka/* static */ float ProximityInfoStateUtils::getPointAngle(
568d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        const std::vector<int> *const sampledInputXs,
569d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        const std::vector<int> *const sampledInputYs, const int index) {
570d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    if (!sampledInputXs || !sampledInputYs) {
571d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        return 0.0f;
572d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    }
573d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    const int sampledInputSize = sampledInputXs->size();
574d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    if (index <= 0 || index >= sampledInputSize - 1) {
575d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        return 0.0f;
576d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    }
577d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    const float previousDirection = getDirection(sampledInputXs, sampledInputYs, index - 1, index);
578d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    const float nextDirection = getDirection(sampledInputXs, sampledInputYs, index, index + 1);
57929432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa    const float directionDiff = GeometryUtils::getAngleDiff(previousDirection, nextDirection);
580d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    return directionDiff;
581d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka}
582d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka
583d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka/* static */ float ProximityInfoStateUtils::getPointsAngle(
584d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        const std::vector<int> *const sampledInputXs,
585d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        const std::vector<int> *const sampledInputYs,
586d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        const int index0, const int index1, const int index2) {
587d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    if (!sampledInputXs || !sampledInputYs) {
588d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        return 0.0f;
589d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    }
590d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    const int sampledInputSize = sampledInputXs->size();
591d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    if (index0 < 0 || index0 > sampledInputSize - 1) {
592d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        return 0.0f;
593d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    }
594d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    if (index1 < 0 || index1 > sampledInputSize - 1) {
595d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        return 0.0f;
596d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    }
597d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    if (index2 < 0 || index2 > sampledInputSize - 1) {
598d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        return 0.0f;
599d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    }
600d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    const float previousDirection = getDirection(sampledInputXs, sampledInputYs, index0, index1);
601d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    const float nextDirection = getDirection(sampledInputXs, sampledInputYs, index1, index2);
60229432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa    return GeometryUtils::getAngleDiff(previousDirection, nextDirection);
603d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka}
604d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka
605d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka// This function basically converts from a length to an edit distance. Accordingly, it's obviously
606d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka// wrong to compare with mMaxPointToKeyLength.
607d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka/* static */ float ProximityInfoStateUtils::getPointToKeyByIdLength(const float maxPointToKeyLength,
608837f46dcb35a8f42a6bd5bc5fc6395d7386acb81Satoshi Kataoka        const std::vector<float> *const sampledNormalizedSquaredLengthCache, const int keyCount,
6092192d08b9cca6a40d834d6a5001d19b5845ed8a0Tom Ouyang        const int inputIndex, const int keyId) {
610d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    if (keyId != NOT_AN_INDEX) {
611d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        const int index = inputIndex * keyCount + keyId;
612837f46dcb35a8f42a6bd5bc5fc6395d7386acb81Satoshi Kataoka        return min((*sampledNormalizedSquaredLengthCache)[index], maxPointToKeyLength);
613d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    }
614d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    // If the char is not a key on the keyboard then return the max length.
615830ba67498c6da53b38212dd9ac5ba318a00de11Satoshi Kataoka    return static_cast<float>(MAX_VALUE_FOR_WEIGHTING);
616d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka}
617d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka
618d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka// Updates probabilities of aligning to some keys and skipping.
619d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka// Word suggestion should be based on this probabilities.
620d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka/* static */ void ProximityInfoStateUtils::updateAlignPointProbabilities(
621d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        const float maxPointToKeyLength, const int mostCommonKeyWidth, const int keyCount,
622d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        const int start, const int sampledInputSize, const std::vector<int> *const sampledInputXs,
623d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        const std::vector<int> *const sampledInputYs,
624d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        const std::vector<float> *const sampledSpeedRates,
625d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        const std::vector<int> *const sampledLengthCache,
626837f46dcb35a8f42a6bd5bc5fc6395d7386acb81Satoshi Kataoka        const std::vector<float> *const sampledNormalizedSquaredLengthCache,
627837f46dcb35a8f42a6bd5bc5fc6395d7386acb81Satoshi Kataoka        std::vector<NearKeycodesSet> *sampledNearKeySets,
628d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        std::vector<hash_map_compat<int, float> > *charProbabilities) {
629d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    charProbabilities->resize(sampledInputSize);
630d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    // Calculates probabilities of using a point as a correlated point with the character
631d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    // for each point.
632d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    for (int i = start; i < sampledInputSize; ++i) {
633d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        (*charProbabilities)[i].clear();
63428c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa        // First, calculates skip probability. Starts from MAX_SKIP_PROBABILITY.
635d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        // Note that all values that are multiplied to this probability should be in [0.0, 1.0];
63628c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa        float skipProbability = ProximityInfoParams::MAX_SKIP_PROBABILITY;
637d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka
638d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        const float currentAngle = getPointAngle(sampledInputXs, sampledInputYs, i);
639d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        const float speedRate = (*sampledSpeedRates)[i];
640d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka
641830ba67498c6da53b38212dd9ac5ba318a00de11Satoshi Kataoka        float nearestKeyDistance = static_cast<float>(MAX_VALUE_FOR_WEIGHTING);
642d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        for (int j = 0; j < keyCount; ++j) {
643837f46dcb35a8f42a6bd5bc5fc6395d7386acb81Satoshi Kataoka            if ((*sampledNearKeySets)[i].test(j)) {
644d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                const float distance = getPointToKeyByIdLength(
645837f46dcb35a8f42a6bd5bc5fc6395d7386acb81Satoshi Kataoka                        maxPointToKeyLength, sampledNormalizedSquaredLengthCache, keyCount, i, j);
646d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                if (distance < nearestKeyDistance) {
647d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                    nearestKeyDistance = distance;
648d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                }
649d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            }
650d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        }
651d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka
652d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        if (i == 0) {
65328c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa            skipProbability *= min(1.0f,
65428c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                    nearestKeyDistance * ProximityInfoParams::NEAREST_DISTANCE_WEIGHT
65528c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                            + ProximityInfoParams::NEAREST_DISTANCE_BIAS);
656d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            // Promote the first point
65728c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa            skipProbability *= ProximityInfoParams::SKIP_FIRST_POINT_PROBABILITY;
658d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        } else if (i == sampledInputSize - 1) {
65928c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa            skipProbability *= min(1.0f,
66028c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                    nearestKeyDistance * ProximityInfoParams::NEAREST_DISTANCE_WEIGHT_FOR_LAST
66128c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                            + ProximityInfoParams::NEAREST_DISTANCE_BIAS_FOR_LAST);
662d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            // Promote the last point
66328c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa            skipProbability *= ProximityInfoParams::SKIP_LAST_POINT_PROBABILITY;
664d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        } else {
665d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            // If the current speed is relatively slower than adjacent keys, we promote this point.
66628c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa            if ((*sampledSpeedRates)[i - 1] - ProximityInfoParams::SPEED_MARGIN > speedRate
66728c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                    && speedRate
66828c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                            < (*sampledSpeedRates)[i + 1] - ProximityInfoParams::SPEED_MARGIN) {
66928c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                if (currentAngle < ProximityInfoParams::CORNER_ANGLE_THRESHOLD) {
670d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                    skipProbability *= min(1.0f, speedRate
67128c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                            * ProximityInfoParams::SLOW_STRAIGHT_WEIGHT_FOR_SKIP_PROBABILITY);
672d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                } else {
673d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                    // If the angle is small enough, we promote this point more. (e.g. pit vs put)
67428c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                    skipProbability *= min(1.0f,
67528c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                            speedRate * ProximityInfoParams::SPEED_WEIGHT_FOR_SKIP_PROBABILITY
67628c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                                    + ProximityInfoParams::MIN_SPEED_RATE_FOR_SKIP_PROBABILITY);
677d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                }
678d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            }
679d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka
68028c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa            skipProbability *= min(1.0f,
68128c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                    speedRate * nearestKeyDistance * ProximityInfoParams::NEAREST_DISTANCE_WEIGHT
68228c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                            + ProximityInfoParams::NEAREST_DISTANCE_BIAS);
683d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka
684d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            // Adjusts skip probability by a rate depending on angle.
685d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            // ANGLE_RATE of skipProbability is adjusted by current angle.
68628c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa            skipProbability *= (M_PI_F - currentAngle) / M_PI_F * ProximityInfoParams::ANGLE_WEIGHT
68728c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                    + (1.0f - ProximityInfoParams::ANGLE_WEIGHT);
68828c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa            if (currentAngle > ProximityInfoParams::DEEP_CORNER_ANGLE_THRESHOLD) {
68928c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                skipProbability *= ProximityInfoParams::SKIP_DEEP_CORNER_PROBABILITY;
690d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            }
691d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            // We assume the angle of this point is the angle for point[i], point[i - 2]
692d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            // and point[i - 3]. The reason why we don't use the angle for point[i], point[i - 1]
693d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            // and point[i - 2] is this angle can be more affected by the noise.
694d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            const float prevAngle = getPointsAngle(sampledInputXs, sampledInputYs, i, i - 2, i - 3);
69528c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa            if (i >= 3 && prevAngle < ProximityInfoParams::STRAIGHT_ANGLE_THRESHOLD
69628c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                    && currentAngle > ProximityInfoParams::CORNER_ANGLE_THRESHOLD) {
69728c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                skipProbability *= ProximityInfoParams::SKIP_CORNER_PROBABILITY;
698d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            }
699d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        }
700d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka
70128c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa        // probabilities must be in [0.0, ProximityInfoParams::MAX_SKIP_PROBABILITY];
702d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        ASSERT(skipProbability >= 0.0f);
70328c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa        ASSERT(skipProbability <= ProximityInfoParams::MAX_SKIP_PROBABILITY);
704d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        (*charProbabilities)[i][NOT_AN_INDEX] = skipProbability;
705d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka
706d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        // Second, calculates key probabilities by dividing the rest probability
707d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        // (1.0f - skipProbability).
708d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        const float inputCharProbability = 1.0f - skipProbability;
709d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka
710d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        const float speedxAngleRate = min(speedRate * currentAngle / M_PI_F
7113e954347e3a7b381d7e94feb002e158f3bc69a32Jean Chalard                * ProximityInfoParams::SPEEDxANGLE_WEIGHT_FOR_STANDARD_DEVIATION,
7123e954347e3a7b381d7e94feb002e158f3bc69a32Jean Chalard                        ProximityInfoParams::MAX_SPEEDxANGLE_RATE_FOR_STANDARD_DEVIATION);
713d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        const float speedxNearestKeyDistanceRate = min(speedRate * nearestKeyDistance
7143e954347e3a7b381d7e94feb002e158f3bc69a32Jean Chalard                * ProximityInfoParams::SPEEDxNEAREST_WEIGHT_FOR_STANDARD_DEVIATION,
7153e954347e3a7b381d7e94feb002e158f3bc69a32Jean Chalard                        ProximityInfoParams::MAX_SPEEDxNEAREST_RATE_FOR_STANDARD_DEVIATION);
71628c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa        const float sigma = speedxAngleRate + speedxNearestKeyDistanceRate
7173e954347e3a7b381d7e94feb002e158f3bc69a32Jean Chalard                + ProximityInfoParams::MIN_STANDARD_DEVIATION;
718d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka
719d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        ProximityInfoUtils::NormalDistribution
72028c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                distribution(ProximityInfoParams::CENTER_VALUE_OF_NORMALIZED_DISTRIBUTION, sigma);
721d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        // Summing up probability densities of all near keys.
722d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        float sumOfProbabilityDensities = 0.0f;
723d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        for (int j = 0; j < keyCount; ++j) {
724837f46dcb35a8f42a6bd5bc5fc6395d7386acb81Satoshi Kataoka            if ((*sampledNearKeySets)[i].test(j)) {
725d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                float distance = sqrtf(getPointToKeyByIdLength(
726837f46dcb35a8f42a6bd5bc5fc6395d7386acb81Satoshi Kataoka                        maxPointToKeyLength, sampledNormalizedSquaredLengthCache, keyCount, i, j));
727d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                if (i == 0 && i != sampledInputSize - 1) {
728d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                    // For the first point, weighted average of distances from first point and the
729d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                    // next point to the key is used as a point to key distance.
730d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                    const float nextDistance = sqrtf(getPointToKeyByIdLength(
731837f46dcb35a8f42a6bd5bc5fc6395d7386acb81Satoshi Kataoka                            maxPointToKeyLength, sampledNormalizedSquaredLengthCache, keyCount,
732837f46dcb35a8f42a6bd5bc5fc6395d7386acb81Satoshi Kataoka                            i + 1, j));
733d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                    if (nextDistance < distance) {
734d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                        // The distance of the first point tends to bigger than continuing
735d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                        // points because the first touch by the user can be sloppy.
736d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                        // So we promote the first point if the distance of that point is larger
737d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                        // than the distance of the next point.
73828c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                        distance = (distance
73928c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                                + nextDistance * ProximityInfoParams::NEXT_DISTANCE_WEIGHT)
74028c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                                        / (1.0f + ProximityInfoParams::NEXT_DISTANCE_WEIGHT);
741d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                    }
742d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                } else if (i != 0 && i == sampledInputSize - 1) {
743d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                    // For the first point, weighted average of distances from last point and
744d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                    // the previous point to the key is used as a point to key distance.
745d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                    const float previousDistance = sqrtf(getPointToKeyByIdLength(
746837f46dcb35a8f42a6bd5bc5fc6395d7386acb81Satoshi Kataoka                            maxPointToKeyLength, sampledNormalizedSquaredLengthCache, keyCount,
747837f46dcb35a8f42a6bd5bc5fc6395d7386acb81Satoshi Kataoka                            i - 1, j));
748d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                    if (previousDistance < distance) {
749d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                        // The distance of the last point tends to bigger than continuing points
750d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                        // because the last touch by the user can be sloppy. So we promote the
751d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                        // last point if the distance of that point is larger than the distance of
752d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                        // the previous point.
75328c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                        distance = (distance
75428c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                                + previousDistance * ProximityInfoParams::PREV_DISTANCE_WEIGHT)
75528c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                                        / (1.0f + ProximityInfoParams::PREV_DISTANCE_WEIGHT);
756d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                    }
757d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                }
758d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                // TODO: Promote the first point when the extended line from the next input is near
759d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                // from a key. Also, promote the last point as well.
760d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                sumOfProbabilityDensities += distribution.getProbabilityDensity(distance);
761d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            }
762d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        }
763d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka
764d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        // Split the probability of an input point to keys that are close to the input point.
765d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        for (int j = 0; j < keyCount; ++j) {
766837f46dcb35a8f42a6bd5bc5fc6395d7386acb81Satoshi Kataoka            if ((*sampledNearKeySets)[i].test(j)) {
767d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                float distance = sqrtf(getPointToKeyByIdLength(
768837f46dcb35a8f42a6bd5bc5fc6395d7386acb81Satoshi Kataoka                        maxPointToKeyLength, sampledNormalizedSquaredLengthCache, keyCount, i, j));
769d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                if (i == 0 && i != sampledInputSize - 1) {
770d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                    // For the first point, weighted average of distances from the first point and
771d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                    // the next point to the key is used as a point to key distance.
772d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                    const float prevDistance = sqrtf(getPointToKeyByIdLength(
773837f46dcb35a8f42a6bd5bc5fc6395d7386acb81Satoshi Kataoka                            maxPointToKeyLength, sampledNormalizedSquaredLengthCache, keyCount,
774837f46dcb35a8f42a6bd5bc5fc6395d7386acb81Satoshi Kataoka                            i + 1, j));
775d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                    if (prevDistance < distance) {
77628c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                        distance = (distance
77728c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                                + prevDistance * ProximityInfoParams::NEXT_DISTANCE_WEIGHT)
77828c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                                        / (1.0f + ProximityInfoParams::NEXT_DISTANCE_WEIGHT);
779d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                    }
780d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                } else if (i != 0 && i == sampledInputSize - 1) {
781d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                    // For the first point, weighted average of distances from last point and
782d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                    // the previous point to the key is used as a point to key distance.
783d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                    const float prevDistance = sqrtf(getPointToKeyByIdLength(
784837f46dcb35a8f42a6bd5bc5fc6395d7386acb81Satoshi Kataoka                            maxPointToKeyLength, sampledNormalizedSquaredLengthCache, keyCount,
785837f46dcb35a8f42a6bd5bc5fc6395d7386acb81Satoshi Kataoka                            i - 1, j));
786d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                    if (prevDistance < distance) {
78728c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                        distance = (distance
78828c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                                + prevDistance * ProximityInfoParams::PREV_DISTANCE_WEIGHT)
78928c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                                        / (1.0f + ProximityInfoParams::PREV_DISTANCE_WEIGHT);
790d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                    }
791d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                }
792d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                const float probabilityDensity = distribution.getProbabilityDensity(distance);
793d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                const float probability = inputCharProbability * probabilityDensity
794d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                        / sumOfProbabilityDensities;
795d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                (*charProbabilities)[i][j] = probability;
796d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            }
797d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        }
798d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    }
799d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka
800d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    if (DEBUG_POINTS_PROBABILITY) {
801d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        for (int i = 0; i < sampledInputSize; ++i) {
802d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            std::stringstream sstream;
803d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            sstream << i << ", ";
804d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            sstream << "(" << (*sampledInputXs)[i] << ", " << (*sampledInputYs)[i] << "), ";
805d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            sstream << "Speed: "<< (*sampledSpeedRates)[i] << ", ";
806d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            sstream << "Angle: "<< getPointAngle(sampledInputXs, sampledInputYs, i) << ", \n";
807d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka
808d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            for (hash_map_compat<int, float>::iterator it = (*charProbabilities)[i].begin();
809d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                    it != (*charProbabilities)[i].end(); ++it) {
810d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                if (it->first == NOT_AN_INDEX) {
811d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                    sstream << it->first
812d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                            << "(skip):"
813d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                            << it->second
814d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                            << "\n";
815d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                } else {
816d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                    sstream << it->first
817d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                            << "("
818d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                            //<< static_cast<char>(mProximityInfo->getCodePointOf(it->first))
819d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                            << "):"
820d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                            << it->second
821d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                            << "\n";
822d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                }
823d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            }
824d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            AKLOGI("%s", sstream.str().c_str());
825d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        }
826d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    }
827d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka
828d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    // Decrease key probabilities of points which don't have the highest probability of that key
829d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    // among nearby points. Probabilities of the first point and the last point are not suppressed.
830d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    for (int i = max(start, 1); i < sampledInputSize; ++i) {
831d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        for (int j = i + 1; j < sampledInputSize; ++j) {
832d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            if (!suppressCharProbabilities(
833d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                    mostCommonKeyWidth, sampledInputSize, sampledLengthCache, i, j,
834d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                    charProbabilities)) {
835d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                break;
836d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            }
837d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        }
838d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        for (int j = i - 1; j >= max(start, 0); --j) {
839d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            if (!suppressCharProbabilities(
840d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                    mostCommonKeyWidth, sampledInputSize, sampledLengthCache, i, j,
841d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                    charProbabilities)) {
842d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                break;
843d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            }
844d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        }
845d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    }
846d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka
847d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    // Converting from raw probabilities to log probabilities to calculate spatial distance.
848d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    for (int i = start; i < sampledInputSize; ++i) {
849d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        for (int j = 0; j < keyCount; ++j) {
850d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            hash_map_compat<int, float>::iterator it = (*charProbabilities)[i].find(j);
851d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            if (it == (*charProbabilities)[i].end()){
852837f46dcb35a8f42a6bd5bc5fc6395d7386acb81Satoshi Kataoka                (*sampledNearKeySets)[i].reset(j);
85328c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa            } else if(it->second < ProximityInfoParams::MIN_PROBABILITY) {
854d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                // Erases from near keys vector because it has very low probability.
855837f46dcb35a8f42a6bd5bc5fc6395d7386acb81Satoshi Kataoka                (*sampledNearKeySets)[i].reset(j);
856d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                (*charProbabilities)[i].erase(j);
857d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            } else {
858d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                it->second = -logf(it->second);
859d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            }
860d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        }
861d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        (*charProbabilities)[i][NOT_AN_INDEX] = -logf((*charProbabilities)[i][NOT_AN_INDEX]);
862d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    }
863d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka}
864d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka
865e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka/* static */ void ProximityInfoStateUtils::updateSampledSearchKeySets(
866e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka        const ProximityInfo *const proximityInfo, const int sampledInputSize,
867e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka        const int lastSavedInputSize,
868e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka        const std::vector<int> *const sampledLengthCache,
869837f46dcb35a8f42a6bd5bc5fc6395d7386acb81Satoshi Kataoka        const std::vector<NearKeycodesSet> *const sampledNearKeySets,
870e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka        std::vector<NearKeycodesSet> *sampledSearchKeySets,
871e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka        std::vector<std::vector<int> > *sampledSearchKeyVectors) {
872e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka    sampledSearchKeySets->resize(sampledInputSize);
873e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka    sampledSearchKeyVectors->resize(sampledInputSize);
874e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka    const int readForwordLength = static_cast<int>(
875e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka            hypotf(proximityInfo->getKeyboardWidth(), proximityInfo->getKeyboardHeight())
876e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka                    * ProximityInfoParams::SEARCH_KEY_RADIUS_RATIO);
877e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka    for (int i = 0; i < sampledInputSize; ++i) {
878e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka        if (i >= lastSavedInputSize) {
879e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka            (*sampledSearchKeySets)[i].reset();
880e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka        }
881e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka        for (int j = max(i, lastSavedInputSize); j < sampledInputSize; ++j) {
882e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka            // TODO: Investigate if this is required. This may not fail.
883e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka            if ((*sampledLengthCache)[j] - (*sampledLengthCache)[i] >= readForwordLength) {
884e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka                break;
885e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka            }
886837f46dcb35a8f42a6bd5bc5fc6395d7386acb81Satoshi Kataoka            (*sampledSearchKeySets)[i] |= (*sampledNearKeySets)[j];
887e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka        }
888e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka    }
889e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka    const int keyCount = proximityInfo->getKeyCount();
890e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka    for (int i = 0; i < sampledInputSize; ++i) {
891e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka        std::vector<int> *searchKeyVector = &(*sampledSearchKeyVectors)[i];
892e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka        searchKeyVector->clear();
893e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka        for (int j = 0; j < keyCount; ++j) {
894e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka            if ((*sampledSearchKeySets)[i].test(j)) {
895e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka                const int keyCodePoint = proximityInfo->getCodePointOf(j);
896e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka                if (std::find(searchKeyVector->begin(), searchKeyVector->end(), keyCodePoint)
897e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka                        == searchKeyVector->end()) {
898e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka                    searchKeyVector->push_back(keyCodePoint);
899e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka                }
900e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka            }
901e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka        }
902e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka    }
903e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka}
904e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka
905d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka// Decreases char probabilities of index0 by checking probabilities of a near point (index1) and
906d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka// increases char probabilities of index1 by checking probabilities of index0.
907d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka/* static */ bool ProximityInfoStateUtils::suppressCharProbabilities(const int mostCommonKeyWidth,
908d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        const int sampledInputSize, const std::vector<int> *const lengthCache,
909d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        const int index0, const int index1,
910d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        std::vector<hash_map_compat<int, float> > *charProbabilities) {
911d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    ASSERT(0 <= index0 && index0 < sampledInputSize);
912d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    ASSERT(0 <= index1 && index1 < sampledInputSize);
913d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    const float keyWidthFloat = static_cast<float>(mostCommonKeyWidth);
914d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    const float diff = fabsf(static_cast<float>((*lengthCache)[index0] - (*lengthCache)[index1]));
91528c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa    if (diff > keyWidthFloat * ProximityInfoParams::SUPPRESSION_LENGTH_WEIGHT) {
916d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        return false;
917d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    }
91828c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa    const float suppressionRate = ProximityInfoParams::MIN_SUPPRESSION_RATE
91928c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa            + diff / keyWidthFloat / ProximityInfoParams::SUPPRESSION_LENGTH_WEIGHT
92028c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                    * ProximityInfoParams::SUPPRESSION_WEIGHT;
921d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    for (hash_map_compat<int, float>::iterator it = (*charProbabilities)[index0].begin();
922d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            it != (*charProbabilities)[index0].end(); ++it) {
923d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        hash_map_compat<int, float>::iterator it2 =  (*charProbabilities)[index1].find(it->first);
924d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        if (it2 != (*charProbabilities)[index1].end() && it->second < it2->second) {
925d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            const float newProbability = it->second * suppressionRate;
926d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            const float suppression = it->second - newProbability;
927d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            it->second = newProbability;
928d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            // mCharProbabilities[index0][NOT_AN_INDEX] is the probability of skipping this point.
929d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            (*charProbabilities)[index0][NOT_AN_INDEX] += suppression;
930d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka
931d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            // Add the probability of the same key nearby index1
93228c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa            const float probabilityGain = min(suppression
93328c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                    * ProximityInfoParams::SUPPRESSION_WEIGHT_FOR_PROBABILITY_GAIN,
934d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                    (*charProbabilities)[index1][NOT_AN_INDEX]
93528c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                            * ProximityInfoParams::SKIP_PROBABALITY_WEIGHT_FOR_PROBABILITY_GAIN);
936d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            it2->second += probabilityGain;
937d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            (*charProbabilities)[index1][NOT_AN_INDEX] -= probabilityGain;
938d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka        }
939d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    }
940d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    return true;
941d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka}
942d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka
943394b0bd345f33b1314613a433478fd0bb711e0f7Satoshi Kataoka/* static */ bool ProximityInfoStateUtils::checkAndReturnIsContinuousSuggestionPossible(
944394b0bd345f33b1314613a433478fd0bb711e0f7Satoshi Kataoka        const int inputSize, const int *const xCoordinates, const int *const yCoordinates,
945394b0bd345f33b1314613a433478fd0bb711e0f7Satoshi Kataoka        const int *const times, const int sampledInputSize,
946394b0bd345f33b1314613a433478fd0bb711e0f7Satoshi Kataoka        const std::vector<int> *const sampledInputXs, const std::vector<int> *const sampledInputYs,
9479d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka        const std::vector<int> *const sampledTimes,
9489d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka        const std::vector<int> *const sampledInputIndices) {
9499d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka    if (inputSize < sampledInputSize) {
9509d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka        return false;
9519d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka    }
9529d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka    for (int i = 0; i < sampledInputSize; ++i) {
9539d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka        const int index = (*sampledInputIndices)[i];
9549d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka        if (index >= inputSize) {
9559d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka            return false;
9569d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka        }
9579d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka        if (xCoordinates[index] != (*sampledInputXs)[i]
9589d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka                || yCoordinates[index] != (*sampledInputYs)[i]) {
9599d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka            return false;
9609d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka        }
9619d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka        if (!times) {
9629d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka            continue;
9639d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka        }
9649d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka        if (times[index] != (*sampledTimes)[i]) {
9659d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka            return false;
9669d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka        }
9679d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka    }
9689d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka    return true;
9699d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka}
9709d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka
97120b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka// Get a word that is detected by tracing the most probable string into codePointBuf and
97220b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka// returns probability of generating the word.
97320b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka/* static */ float ProximityInfoStateUtils::getMostProbableString(
97420b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka        const ProximityInfo *const proximityInfo, const int sampledInputSize,
97520b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka        const std::vector<hash_map_compat<int, float> > *const charProbabilities,
97620b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka        int *const codePointBuf) {
977a8ce88bf447c7de1ec7c35130d7cec8be63633cfKen Wakasa    ASSERT(sampledInputSize >= 0);
97820b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka    memset(codePointBuf, 0, sizeof(codePointBuf[0]) * MAX_WORD_LENGTH);
97920b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka    int index = 0;
98020b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka    float sumLogProbability = 0.0f;
98120b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka    // TODO: Current implementation is greedy algorithm. DP would be efficient for many cases.
98220b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka    for (int i = 0; i < sampledInputSize && index < MAX_WORD_LENGTH - 1; ++i) {
983830ba67498c6da53b38212dd9ac5ba318a00de11Satoshi Kataoka        float minLogProbability = static_cast<float>(MAX_VALUE_FOR_WEIGHTING);
98420b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka        int character = NOT_AN_INDEX;
98520b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka        for (hash_map_compat<int, float>::const_iterator it = (*charProbabilities)[i].begin();
98620b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka                it != (*charProbabilities)[i].end(); ++it) {
98720b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka            const float logProbability = (it->first != NOT_AN_INDEX)
98828c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                    ? it->second + ProximityInfoParams::DEMOTION_LOG_PROBABILITY : it->second;
98920b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka            if (logProbability < minLogProbability) {
99020b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka                minLogProbability = logProbability;
99120b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka                character = it->first;
99220b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka            }
99320b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka        }
99420b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka        if (character != NOT_AN_INDEX) {
99520b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka            codePointBuf[index] = proximityInfo->getCodePointOf(character);
99620b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka            index++;
99720b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka        }
99820b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka        sumLogProbability += minLogProbability;
99920b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka    }
100020b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka    codePointBuf[index] = '\0';
100120b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka    return sumLogProbability;
100220b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka}
100320b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka
1004d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka/* static */ void ProximityInfoStateUtils::dump(const bool isGeometric, const int inputSize,
1005d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka        const int *const inputXCoordinates, const int *const inputYCoordinates,
1006d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka        const int sampledInputSize, const std::vector<int> *const sampledInputXs,
1007d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka        const std::vector<int> *const sampledInputYs,
1008e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka        const std::vector<int> *const sampledTimes,
1009d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka        const std::vector<float> *const sampledSpeedRates,
1010d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka        const std::vector<int> *const sampledBeelineSpeedPercentiles) {
1011d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka    if (DEBUG_GEO_FULL) {
1012d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka        for (int i = 0; i < sampledInputSize; ++i) {
1013e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka            AKLOGI("Sampled(%d): x = %d, y = %d, time = %d", i, (*sampledInputXs)[i],
1014e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka                    (*sampledInputYs)[i], sampledTimes ? (*sampledTimes)[i] : -1);
1015d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka        }
1016d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka    }
1017d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka
1018d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka    std::stringstream originalX, originalY, sampledX, sampledY;
1019d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka    for (int i = 0; i < inputSize; ++i) {
1020d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka        originalX << inputXCoordinates[i];
1021d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka        originalY << inputYCoordinates[i];
1022d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka        if (i != inputSize - 1) {
1023d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka            originalX << ";";
1024d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka            originalY << ";";
1025d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka        }
1026d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka    }
1027d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka    AKLOGI("===== sampled points =====");
1028d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka    for (int i = 0; i < sampledInputSize; ++i) {
1029d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka        if (isGeometric) {
1030d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka            AKLOGI("%d: x = %d, y = %d, time = %d, relative speed = %.4f, beeline speed = %d",
1031e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka                    i, (*sampledInputXs)[i], (*sampledInputYs)[i], (*sampledTimes)[i],
1032e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka                    (*sampledSpeedRates)[i], (*sampledBeelineSpeedPercentiles)[i]);
1033d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka        }
1034d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka        sampledX << (*sampledInputXs)[i];
1035d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka        sampledY << (*sampledInputYs)[i];
1036d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka        if (i != sampledInputSize - 1) {
1037d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka            sampledX << ";";
1038d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka            sampledY << ";";
1039d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka        }
1040d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka    }
1041d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka    AKLOGI("original points:\n%s, %s,\nsampled points:\n%s, %s,\n",
1042d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka            originalX.str().c_str(), originalY.str().c_str(), sampledX.str().c_str(),
1043d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka            sampledY.str().c_str());
1044d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka}
1045ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka} // namespace latinime
1046