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