proximity_info_state_utils.cpp revision ee62b78c9675bddaf2437e0cf521f6115e1d9feb
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
17ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka#include <vector>
18ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
19ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka#include "geometry_utils.h"
20ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka#include "proximity_info.h"
21ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka#include "proximity_info_params.h"
22ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka#include "proximity_info_state_utils.h"
23ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
24ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataokanamespace latinime {
25ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka/* static */ int ProximityInfoStateUtils::updateTouchPoints(const int mostCommonKeyWidth,
26ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const ProximityInfo *const proximityInfo, const int maxPointToKeyLength,
27ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const int *const inputProximities,
28ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const int *const inputXCoordinates, const int *const inputYCoordinates,
29ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const int *const times, const int *const pointerIds, const int inputSize,
30ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const bool isGeometric, const int pointerId, const int pushTouchPointStartIndex,
31ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        std::vector<int> *sampledInputXs, std::vector<int> *sampledInputYs,
32ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        std::vector<int> *sampledInputTimes, std::vector<int> *sampledLengthCache,
33ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        std::vector<int> *sampledInputIndice) {
34ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (DEBUG_SAMPLING_POINTS) {
35ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        if (times) {
36ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            for (int i = 0; i < inputSize; ++i) {
37ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                AKLOGI("(%d) x %d, y %d, time %d",
38ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                        i, xCoordinates[i], yCoordinates[i], times[i]);
39ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            }
40ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        }
41ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
42ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka#ifdef DO_ASSERT_TEST
43ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (times) {
44ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        for (int i = 0; i < inputSize; ++i) {
45ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            if (i > 0) {
46ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                ASSERT(times[i] >= times[i - 1]);
47ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            }
48ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        }
49ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
50ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka#endif
51ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const bool proximityOnly = !isGeometric
52ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            && (inputXCoordinates[0] < 0 || inputYCoordinates[0] < 0);
53ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    int lastInputIndex = pushTouchPointStartIndex;
54ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    for (int i = lastInputIndex; i < inputSize; ++i) {
55ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const int pid = pointerIds ? pointerIds[i] : 0;
56ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        if (pointerId == pid) {
57ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            lastInputIndex = i;
58ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        }
59ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
60ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (DEBUG_GEO_FULL) {
61ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        AKLOGI("Init ProximityInfoState: last input index = %d", lastInputIndex);
62ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
63ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // Working space to save near keys distances for current, prev and prevprev input point.
64ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    NearKeysDistanceMap nearKeysDistances[3];
65ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // These pointers are swapped for each inputs points.
66ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    NearKeysDistanceMap *currentNearKeysDistances = &nearKeysDistances[0];
67ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    NearKeysDistanceMap *prevNearKeysDistances = &nearKeysDistances[1];
68ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    NearKeysDistanceMap *prevPrevNearKeysDistances = &nearKeysDistances[2];
69ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // "sumAngle" is accumulated by each angle of input points. And when "sumAngle" exceeds
70ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // the threshold we save that point, reset sumAngle. This aims to keep the figure of
71ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // the curve.
72ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    float sumAngle = 0.0f;
73ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
74ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    for (int i = pushTouchPointStartIndex; i <= lastInputIndex; ++i) {
75ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        // Assuming pointerId == 0 if pointerIds is null.
76ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const int pid = pointerIds ? pointerIds[i] : 0;
77ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        if (DEBUG_GEO_FULL) {
78ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            AKLOGI("Init ProximityInfoState: (%d)PID = %d", i, pid);
79ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        }
80ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        if (pointerId == pid) {
81ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            const int c = isGeometric ?
82ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                    NOT_A_COORDINATE : getPrimaryCodePointAt(inputProximities, i);
83ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            const int x = proximityOnly ? NOT_A_COORDINATE : inputXCoordinates[i];
84ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            const int y = proximityOnly ? NOT_A_COORDINATE : inputYCoordinates[i];
85ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            const int time = times ? times[i] : -1;
86ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
87ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            if (i > 1) {
88ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                const float prevAngle = getAngle(
89ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                        inputXCoordinates[i - 2], inputYCoordinates[i - 2],
90ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                        inputXCoordinates[i - 1], inputYCoordinates[i - 1]);
91ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                const float currentAngle =
92ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                        getAngle(inputXCoordinates[i - 1], inputYCoordinates[i - 1], x, y);
93ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                sumAngle += getAngleDiff(prevAngle, currentAngle);
94ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            }
95ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
96ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            if (pushTouchPoint(mostCommonKeyWidth, proximityInfo, maxPointToKeyLength,
97ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                    i, c, x, y, time, isGeometric /* do sampling */,
98ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                    i == lastInputIndex, sumAngle, currentNearKeysDistances,
99ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                    prevNearKeysDistances, prevPrevNearKeysDistances,
100ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                    sampledInputXs, sampledInputYs, sampledInputTimes, sampledLengthCache,
101ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                    sampledInputIndice)) {
102ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                // Previous point information was popped.
103ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                NearKeysDistanceMap *tmp = prevNearKeysDistances;
104ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                prevNearKeysDistances = currentNearKeysDistances;
105ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                currentNearKeysDistances = tmp;
106ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            } else {
107ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                NearKeysDistanceMap *tmp = prevPrevNearKeysDistances;
108ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                prevPrevNearKeysDistances = prevNearKeysDistances;
109ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                prevNearKeysDistances = currentNearKeysDistances;
110ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                currentNearKeysDistances = tmp;
111ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                sumAngle = 0.0f;
112ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            }
113ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        }
114ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
115ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    return sampledInputXs->size();
116ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka}
117ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
118ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka/* static */ const int *ProximityInfoStateUtils::getProximityCodePointsAt(
119ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const int *const inputProximities, const int index) {
120ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    return inputProximities + (index * MAX_PROXIMITY_CHARS_SIZE_INTERNAL);
121ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka}
122ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
123ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka/* static */ int ProximityInfoStateUtils::getPrimaryCodePointAt(
124ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const int *const inputProximities, const int index) {
125ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    return getProximityCodePointsAt(inputProximities, index)[0];
126ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka}
127ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
128ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka/* static */ void ProximityInfoStateUtils::popInputData(std::vector<int> *sampledInputXs,
129ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        std::vector<int> *sampledInputYs, std::vector<int> *sampledInputTimes,
130ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        std::vector<int> *sampledLengthCache, std::vector<int> *sampledInputIndice) {
131ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    sampledInputXs->pop_back();
132ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    sampledInputYs->pop_back();
133ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    sampledInputTimes->pop_back();
134ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    sampledLengthCache->pop_back();
135ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    sampledInputIndice->pop_back();
136ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka}
137ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
138ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka/* static */ float ProximityInfoStateUtils::refreshSpeedRates(const int inputSize,
139ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const int *const xCoordinates, const int *const yCoordinates, const int *const times,
140ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const int lastSavedInputSize, const int sampledInputSize,
141ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const std::vector<int> *const sampledInputXs,
142ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const std::vector<int> *const sampledInputYs,
143ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const std::vector<int> *const sampledInputTimes,
144ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const std::vector<int> *const sampledLengthCache,
145ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const std::vector<int> *const sampledInputIndice, std::vector<float> *sampledSpeedRates,
146ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        std::vector<float> *sampledDirections) {
147ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // Relative speed calculation.
148ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const int sumDuration = sampledInputTimes->back() - sampledInputTimes->front();
149ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const int sumLength = sampledLengthCache->back() - sampledLengthCache->front();
150ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const float averageSpeed = static_cast<float>(sumLength) / static_cast<float>(sumDuration);
151ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    sampledSpeedRates->resize(sampledInputSize);
152ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    for (int i = lastSavedInputSize; i < sampledInputSize; ++i) {
153ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const int index = (*sampledInputIndice)[i];
154ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        int length = 0;
155ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        int duration = 0;
156ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
157ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        // Calculate velocity by using distances and durations of
158ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        // NUM_POINTS_FOR_SPEED_CALCULATION points for both forward and backward.
159ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        static const int NUM_POINTS_FOR_SPEED_CALCULATION = 2;
160ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        for (int j = index; j < min(inputSize - 1, index + NUM_POINTS_FOR_SPEED_CALCULATION);
161ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                ++j) {
162ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            if (i < sampledInputSize - 1 && j >= (*sampledInputIndice)[i + 1]) {
163ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                break;
164ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            }
165ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            length += getDistanceInt(xCoordinates[j], yCoordinates[j],
166ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                    xCoordinates[j + 1], yCoordinates[j + 1]);
167ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            duration += times[j + 1] - times[j];
168ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        }
169ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        for (int j = index - 1; j >= max(0, index - NUM_POINTS_FOR_SPEED_CALCULATION); --j) {
170ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            if (i > 0 && j < (*sampledInputIndice)[i - 1]) {
171ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                break;
172ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            }
173ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            // TODO: use mLengthCache instead?
174ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            length += getDistanceInt(xCoordinates[j], yCoordinates[j],
175ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                    xCoordinates[j + 1], yCoordinates[j + 1]);
176ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            duration += times[j + 1] - times[j];
177ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        }
178ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        if (duration == 0 || sumDuration == 0) {
179ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            // Cannot calculate speed; thus, it gives an average value (1.0);
180ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            (*sampledSpeedRates)[i] = 1.0f;
181ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        } else {
182ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            const float speed = static_cast<float>(length) / static_cast<float>(duration);
183ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            (*sampledSpeedRates)[i] = speed / averageSpeed;
184ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        }
185ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
186ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
187ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // Direction calculation.
188ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    sampledDirections->resize(sampledInputSize - 1);
189ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    for (int i = max(0, lastSavedInputSize - 1); i < sampledInputSize - 1; ++i) {
190ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        (*sampledDirections)[i] = getDirection(sampledInputXs, sampledInputYs, i, i + 1);
191ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
192ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    return averageSpeed;
193ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka}
194ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
195ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka/* static */ void ProximityInfoStateUtils::refreshBeelineSpeedRates(const int mostCommonKeyWidth,
196ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const float averageSpeed, const int inputSize, const int *const xCoordinates,
197ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const int *const yCoordinates, const int *times, const int sampledInputSize,
198ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const std::vector<int> *const sampledInputXs,
199ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const std::vector<int> *const sampledInputYs, const std::vector<int> *const inputIndice,
200ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        std::vector<int> *beelineSpeedPercentiles) {
201ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (DEBUG_SAMPLING_POINTS) {
202ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        AKLOGI("--- refresh beeline speed rates");
203ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
204ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    beelineSpeedPercentiles->resize(sampledInputSize);
205ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    for (int i = 0; i < sampledInputSize; ++i) {
206ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        (*beelineSpeedPercentiles)[i] = static_cast<int>(calculateBeelineSpeedRate(
207ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                mostCommonKeyWidth, averageSpeed, i, inputSize, xCoordinates, yCoordinates, times,
208ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                sampledInputSize, sampledInputXs, sampledInputYs, inputIndice) * MAX_PERCENTILE);
209ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
210ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka}
211ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
212ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka/* static */float ProximityInfoStateUtils::getDirection(
213ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const std::vector<int> *const sampledInputXs,
214ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const std::vector<int> *const sampledInputYs, const int index0, const int index1) {
215ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    ASSERT(sampledInputXs && sampledInputYs);
216ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const int sampledInputSize =sampledInputXs->size();
217ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (index0 < 0 || index0 > sampledInputSize - 1) {
218ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        return 0.0f;
219ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
220ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (index1 < 0 || index1 > sampledInputSize - 1) {
221ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        return 0.0f;
222ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
223ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const int x1 = (*sampledInputXs)[index0];
224ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const int y1 = (*sampledInputYs)[index0];
225ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const int x2 = (*sampledInputXs)[index1];
226ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const int y2 = (*sampledInputYs)[index1];
227ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    return getAngle(x1, y1, x2, y2);
228ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka}
229ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
230ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka// Calculating point to key distance for all near keys and returning the distance between
231ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka// the given point and the nearest key position.
232ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka/* static */ float ProximityInfoStateUtils::updateNearKeysDistances(
233ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const ProximityInfo *const proximityInfo, const float maxPointToKeyLength, const int x,
234ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const int y, NearKeysDistanceMap *const currentNearKeysDistances) {
235ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    static const float NEAR_KEY_THRESHOLD = 2.0f;
236ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
237ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    currentNearKeysDistances->clear();
238ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const int keyCount = proximityInfo->getKeyCount();
239ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    float nearestKeyDistance = maxPointToKeyLength;
240ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    for (int k = 0; k < keyCount; ++k) {
241ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const float dist = proximityInfo->getNormalizedSquaredDistanceFromCenterFloatG(k, x, y);
242ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        if (dist < NEAR_KEY_THRESHOLD) {
243ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            currentNearKeysDistances->insert(std::pair<int, float>(k, dist));
244ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        }
245ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        if (nearestKeyDistance > dist) {
246ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            nearestKeyDistance = dist;
247ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        }
248ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
249ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    return nearestKeyDistance;
250ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka}
251ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
252ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka// Check if previous point is at local minimum position to near keys.
253ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka/* static */ bool ProximityInfoStateUtils::isPrevLocalMin(
254ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const NearKeysDistanceMap *const currentNearKeysDistances,
255ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const NearKeysDistanceMap *const prevNearKeysDistances,
256ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const NearKeysDistanceMap *const prevPrevNearKeysDistances) {
257ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    static const float MARGIN = 0.01f;
258ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
259ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    for (NearKeysDistanceMap::const_iterator it = prevNearKeysDistances->begin();
260ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            it != prevNearKeysDistances->end(); ++it) {
261ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        NearKeysDistanceMap::const_iterator itPP = prevPrevNearKeysDistances->find(it->first);
262ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        NearKeysDistanceMap::const_iterator itC = currentNearKeysDistances->find(it->first);
263ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        if ((itPP == prevPrevNearKeysDistances->end() || itPP->second > it->second + MARGIN)
264ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                && (itC == currentNearKeysDistances->end() || itC->second > it->second + MARGIN)) {
265ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            return true;
266ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        }
267ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
268ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    return false;
269ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka}
270ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
271ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka// Calculating a point score that indicates usefulness of the point.
272ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka/* static */ float ProximityInfoStateUtils::getPointScore(const int mostCommonKeyWidth,
273ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const int x, const int y, const int time, const bool lastPoint, const float nearest,
274ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const float sumAngle, const NearKeysDistanceMap *const currentNearKeysDistances,
275ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const NearKeysDistanceMap *const prevNearKeysDistances,
276ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const NearKeysDistanceMap *const prevPrevNearKeysDistances,
277ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        std::vector<int> *sampledInputXs, std::vector<int> *sampledInputYs) {
278ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    static const int DISTANCE_BASE_SCALE = 100;
279ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    static const float NEAR_KEY_THRESHOLD = 0.6f;
280ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    static const int CORNER_CHECK_DISTANCE_THRESHOLD_SCALE = 25;
281ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    static const float NOT_LOCALMIN_DISTANCE_SCORE = -1.0f;
282ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    static const float LOCALMIN_DISTANCE_AND_NEAR_TO_KEY_SCORE = 1.0f;
283ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    static const float CORNER_ANGLE_THRESHOLD = M_PI_F * 2.0f / 3.0f;
284ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    static const float CORNER_SUM_ANGLE_THRESHOLD = M_PI_F / 4.0f;
285ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    static const float CORNER_SCORE = 1.0f;
286ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
287ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const size_t size = sampledInputXs->size();
288ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // If there is only one point, add this point. Besides, if the previous point's distance map
289ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // is empty, we re-compute nearby keys distances from the current point.
290ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // Note that the current point is the first point in the incremental input that needs to
291ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // be re-computed.
292ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (size <= 1 || prevNearKeysDistances->empty()) {
293ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        return 0.0f;
294ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
295ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
296ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const int baseSampleRate = mostCommonKeyWidth;
297ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const int distPrev = getDistanceInt(sampledInputXs->back(), sampledInputYs->back(),
298ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            (*sampledInputXs)[size - 2], (*sampledInputYs)[size - 2]) * DISTANCE_BASE_SCALE;
299ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    float score = 0.0f;
300ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
301ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // Location
302ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (!isPrevLocalMin(currentNearKeysDistances, prevNearKeysDistances,
303ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        prevPrevNearKeysDistances)) {
304ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        score += NOT_LOCALMIN_DISTANCE_SCORE;
305ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    } else if (nearest < NEAR_KEY_THRESHOLD) {
306ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        // Promote points nearby keys
307ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        score += LOCALMIN_DISTANCE_AND_NEAR_TO_KEY_SCORE;
308ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
309ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // Angle
310ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const float angle1 = getAngle(x, y, sampledInputXs->back(), sampledInputYs->back());
311ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const float angle2 = getAngle(sampledInputXs->back(), sampledInputYs->back(),
312ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            (*sampledInputXs)[size - 2], (*sampledInputYs)[size - 2]);
313ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const float angleDiff = getAngleDiff(angle1, angle2);
314ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
315ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // Save corner
316ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (distPrev > baseSampleRate * CORNER_CHECK_DISTANCE_THRESHOLD_SCALE
317ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            && (sumAngle > CORNER_SUM_ANGLE_THRESHOLD || angleDiff > CORNER_ANGLE_THRESHOLD)) {
318ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        score += CORNER_SCORE;
319ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
320ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    return score;
321ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka}
322ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
323ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka// Sampling touch point and pushing information to vectors.
324ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka// Returning if previous point is popped or not.
325ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka/* static */ bool ProximityInfoStateUtils::pushTouchPoint(const int mostCommonKeyWidth,
326ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const ProximityInfo *const proximityInfo, const int maxPointToKeyLength,
327ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const int inputIndex, const int nodeCodePoint, int x, int y,
328ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const int time, const bool sample, const bool isLastPoint, const float sumAngle,
329ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        NearKeysDistanceMap *const currentNearKeysDistances,
330ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const NearKeysDistanceMap *const prevNearKeysDistances,
331ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const NearKeysDistanceMap *const prevPrevNearKeysDistances,
332ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        std::vector<int> *sampledInputXs, std::vector<int> *sampledInputYs,
333ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        std::vector<int> *sampledInputTimes, std::vector<int> *sampledLengthCache,
334ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        std::vector<int> *sampledInputIndice) {
335ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    static const int LAST_POINT_SKIP_DISTANCE_SCALE = 4;
336ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
337ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    size_t size = sampledInputXs->size();
338ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    bool popped = false;
339ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (nodeCodePoint < 0 && sample) {
340ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const float nearest = updateNearKeysDistances(
341ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                proximityInfo, maxPointToKeyLength, x, y, currentNearKeysDistances);
342ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const float score = getPointScore(mostCommonKeyWidth, x, y, time, isLastPoint, nearest,
343ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                sumAngle, currentNearKeysDistances, prevNearKeysDistances,
344ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                prevPrevNearKeysDistances, sampledInputXs, sampledInputYs);
345ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        if (score < 0) {
346ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            // Pop previous point because it would be useless.
347ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            popInputData(sampledInputXs, sampledInputYs, sampledInputTimes, sampledLengthCache,
348ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                    sampledInputIndice);
349ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            size = sampledInputXs->size();
350ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            popped = true;
351ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        } else {
352ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            popped = false;
353ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        }
354ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        // Check if the last point should be skipped.
355ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        if (isLastPoint && size > 0) {
356ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            if (getDistanceInt(x, y, sampledInputXs->back(),
357ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                    sampledInputYs->back()) * LAST_POINT_SKIP_DISTANCE_SCALE
358ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                            < mostCommonKeyWidth) {
359ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                // This point is not used because it's too close to the previous point.
360ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                if (DEBUG_GEO_FULL) {
361ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                    AKLOGI("p0: size = %zd, x = %d, y = %d, lx = %d, ly = %d, dist = %d, "
362ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                           "width = %d", size, x, y, mSampledInputXs.back(),
363ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                           mSampledInputYs.back(), ProximityInfoUtils::getDistanceInt(
364ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                                   x, y, mSampledInputXs.back(), mSampledInputYs.back()),
365ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                           mProximityInfo->getMostCommonKeyWidth()
366ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                                   / LAST_POINT_SKIP_DISTANCE_SCALE);
367ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                }
368ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                return popped;
369ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            }
370ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        }
371ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
372ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
373ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (nodeCodePoint >= 0 && (x < 0 || y < 0)) {
374ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const int keyId = proximityInfo->getKeyIndexOf(nodeCodePoint);
375ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        if (keyId >= 0) {
376ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            x = proximityInfo->getKeyCenterXOfKeyIdG(keyId);
377ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            y = proximityInfo->getKeyCenterYOfKeyIdG(keyId);
378ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        }
379ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
380ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
381ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // Pushing point information.
382ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (size > 0) {
383ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        sampledLengthCache->push_back(
384ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                sampledLengthCache->back() + getDistanceInt(
385ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                        x, y, sampledInputXs->back(), sampledInputYs->back()));
386ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    } else {
387ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        sampledLengthCache->push_back(0);
388ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
389ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    sampledInputXs->push_back(x);
390ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    sampledInputYs->push_back(y);
391ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    sampledInputTimes->push_back(time);
392ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    sampledInputIndice->push_back(inputIndex);
393ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (DEBUG_GEO_FULL) {
394ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        AKLOGI("pushTouchPoint: x = %03d, y = %03d, time = %d, index = %d, popped ? %01d",
395ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                x, y, time, inputIndex, popped);
396ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
397ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    return popped;
398ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka}
399ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
400ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka/* static */ float ProximityInfoStateUtils::calculateBeelineSpeedRate(const int mostCommonKeyWidth,
401ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const float averageSpeed, const int id, const int inputSize, const int *const xCoordinates,
402ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const int *const yCoordinates, const int *times, const int sampledInputSize,
403ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const std::vector<int> *const sampledInputXs,
404ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        const std::vector<int> *const sampledInputYs, const std::vector<int> *const inputIndice) {
405ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (sampledInputSize <= 0 || averageSpeed < 0.001f) {
406ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        if (DEBUG_SAMPLING_POINTS) {
407ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            AKLOGI("--- invalid state: cancel. size = %d, ave = %f",
408ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                    mSampledInputSize, mAverageSpeed);
409ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        }
410ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        return 1.0f;
411ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
412ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const int lookupRadius = mostCommonKeyWidth
413ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            * ProximityInfoParams::LOOKUP_RADIUS_PERCENTILE / MAX_PERCENTILE;
414ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const int x0 = (*sampledInputXs)[id];
415ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const int y0 = (*sampledInputYs)[id];
416ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const int actualInputIndex = (*inputIndice)[id];
417ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    int tempTime = 0;
418ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    int tempBeelineDistance = 0;
419ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    int start = actualInputIndex;
420ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // lookup forward
421ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    while (start > 0 && tempBeelineDistance < lookupRadius) {
422ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        tempTime += times[start] - times[start - 1];
423ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        --start;
424ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        tempBeelineDistance = getDistanceInt(x0, y0, xCoordinates[start], yCoordinates[start]);
425ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
426ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // Exclusive unless this is an edge point
427ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (start > 0 && start < actualInputIndex) {
428ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        ++start;
429ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
430ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    tempTime= 0;
431ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    tempBeelineDistance = 0;
432ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    int end = actualInputIndex;
433ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // lookup backward
434ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    while (end < (inputSize - 1) && tempBeelineDistance < lookupRadius) {
435ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        tempTime += times[end + 1] - times[end];
436ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        ++end;
437ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        tempBeelineDistance = getDistanceInt(x0, y0, xCoordinates[end], yCoordinates[end]);
438ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
439ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // Exclusive unless this is an edge point
440ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (end > actualInputIndex && end < (inputSize - 1)) {
441ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        --end;
442ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
443ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
444ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (start >= end) {
445ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        if (DEBUG_DOUBLE_LETTER) {
446ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            AKLOGI("--- double letter: start == end %d", start);
447ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        }
448ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        return 1.0f;
449ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
450ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
451ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const int x2 = xCoordinates[start];
452ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const int y2 = yCoordinates[start];
453ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const int x3 = xCoordinates[end];
454ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const int y3 = yCoordinates[end];
455ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const int beelineDistance = getDistanceInt(x2, y2, x3, y3);
456ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    int adjustedStartTime = times[start];
457ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (start == 0 && actualInputIndex == 0 && inputSize > 1) {
458ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        adjustedStartTime += ProximityInfoParams::FIRST_POINT_TIME_OFFSET_MILLIS;
459ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
460ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    int adjustedEndTime = times[end];
461ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (end == (inputSize - 1) && inputSize > 1) {
462ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        adjustedEndTime -= ProximityInfoParams::FIRST_POINT_TIME_OFFSET_MILLIS;
463ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
464ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    const int time = adjustedEndTime - adjustedStartTime;
465ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (time <= 0) {
466ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        return 1.0f;
467ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
468ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka
469ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (time >= ProximityInfoParams::STRONG_DOUBLE_LETTER_TIME_MILLIS){
470ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        return 0.0f;
471ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
472ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    if (DEBUG_DOUBLE_LETTER) {
473ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka        AKLOGI("--- (%d, %d) double letter: start = %d, end = %d, dist = %d, time = %d,"
474ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                " speed = %f, ave = %f, val = %f, start time = %d, end time = %d",
475ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                id, mInputIndice[id], start, end, beelineDistance, time,
476ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                (static_cast<float>(beelineDistance) / static_cast<float>(time)), mAverageSpeed,
477ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                ((static_cast<float>(beelineDistance) / static_cast<float>(time))
478ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka                        / mAverageSpeed), adjustedStartTime, adjustedEndTime);
479ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    }
480ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // Offset 1%
481ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    // TODO: Detect double letter more smartly
482ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    return 0.01f + static_cast<float>(beelineDistance) / static_cast<float>(time) / averageSpeed;
483ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka}
484ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka} // namespace latinime
485