1ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka/* 2ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka * Copyright (C) 2013 The Android Open Source Project 3ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka * 4ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka * Licensed under the Apache License, Version 2.0 (the "License"); 5ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka * you may not use this file except in compliance with the License. 6ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka * You may obtain a copy of the License at 7ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka * 8ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka * http://www.apache.org/licenses/LICENSE-2.0 9ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka * 10ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka * Unless required by applicable law or agreed to in writing, software 11ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka * distributed under the License is distributed on an "AS IS" BASIS, 12ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka * See the License for the specific language governing permissions and 14ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka * limitations under the License. 15ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka */ 16ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka 1729432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa#include "suggest/core/layout/proximity_info_state_utils.h" 1829432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa 19ca0a0da8640d1469cb460120ff0aede2322c6802Ken Wakasa#include <algorithm> 20e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka#include <cmath> 2120b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka#include <cstring> // for memset() 22d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka#include <sstream> // for debug prints 238ca9be17db2f1845c7c7a3b584507cf60c9ca53dKen Wakasa#include <unordered_map> 24ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka#include <vector> 25ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka 266c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa#include "defines.h" 2729432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa#include "suggest/core/layout/geometry_utils.h" 2826c806620c26e048918624367ee624526613b0d2Keisuke Kuroyanagi#include "suggest/core/layout/normal_distribution_2d.h" 2929432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa#include "suggest/core/layout/proximity_info.h" 3029432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa#include "suggest/core/layout/proximity_info_params.h" 31ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka 32ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataokanamespace latinime { 33d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka 3420b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka/* static */ int ProximityInfoStateUtils::trimLastTwoTouchPoints(std::vector<int> *sampledInputXs, 3520b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka std::vector<int> *sampledInputYs, std::vector<int> *sampledInputTimes, 3620b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka std::vector<int> *sampledLengthCache, std::vector<int> *sampledInputIndice) { 3720b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka const int nextStartIndex = (*sampledInputIndice)[sampledInputIndice->size() - 2]; 3820b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka popInputData(sampledInputXs, sampledInputYs, sampledInputTimes, sampledLengthCache, 3920b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka sampledInputIndice); 4020b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka popInputData(sampledInputXs, sampledInputYs, sampledInputTimes, sampledLengthCache, 4120b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka sampledInputIndice); 4220b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka return nextStartIndex; 4320b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka} 4420b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka 4528c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa/* static */ int ProximityInfoStateUtils::updateTouchPoints( 46ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const ProximityInfo *const proximityInfo, const int maxPointToKeyLength, 476c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa const int *const inputProximities, const int *const inputXCoordinates, 486c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa const int *const inputYCoordinates, const int *const times, const int *const pointerIds, 490052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi const int inputSize, const bool isGeometric, const int pointerId, 500052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi const int pushTouchPointStartIndex, std::vector<int> *sampledInputXs, 516c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa std::vector<int> *sampledInputYs, std::vector<int> *sampledInputTimes, 526c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa std::vector<int> *sampledLengthCache, std::vector<int> *sampledInputIndice) { 53ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka if (DEBUG_SAMPLING_POINTS) { 54ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka if (times) { 55ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka for (int i = 0; i < inputSize; ++i) { 56ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka AKLOGI("(%d) x %d, y %d, time %d", 57e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka i, inputXCoordinates[i], inputYCoordinates[i], times[i]); 58ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 59ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 60ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 61ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka#ifdef DO_ASSERT_TEST 62ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka if (times) { 63ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka for (int i = 0; i < inputSize; ++i) { 64ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka if (i > 0) { 65e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka if (times[i] < times[i - 1]) { 66e9e4fa5af6a94dbd6e24e631cd4606d7e41c1f16Ken Wakasa AKLOGI("Invalid time sequence. %d, %d", times[i - 1], times[i]); 67e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka ASSERT(false); 68e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka } 69ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 70ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 71ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 72ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka#endif 73ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const bool proximityOnly = !isGeometric 74ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka && (inputXCoordinates[0] < 0 || inputYCoordinates[0] < 0); 75ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka int lastInputIndex = pushTouchPointStartIndex; 76ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka for (int i = lastInputIndex; i < inputSize; ++i) { 77ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const int pid = pointerIds ? pointerIds[i] : 0; 78ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka if (pointerId == pid) { 79ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka lastInputIndex = i; 80ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 81ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 82ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka if (DEBUG_GEO_FULL) { 83ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka AKLOGI("Init ProximityInfoState: last input index = %d", lastInputIndex); 84ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 85ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka // Working space to save near keys distances for current, prev and prevprev input point. 86ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka NearKeysDistanceMap nearKeysDistances[3]; 87ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka // These pointers are swapped for each inputs points. 88ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka NearKeysDistanceMap *currentNearKeysDistances = &nearKeysDistances[0]; 89ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka NearKeysDistanceMap *prevNearKeysDistances = &nearKeysDistances[1]; 90ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka NearKeysDistanceMap *prevPrevNearKeysDistances = &nearKeysDistances[2]; 91ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka // "sumAngle" is accumulated by each angle of input points. And when "sumAngle" exceeds 92ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka // the threshold we save that point, reset sumAngle. This aims to keep the figure of 93ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka // the curve. 94ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka float sumAngle = 0.0f; 95ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka 96ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka for (int i = pushTouchPointStartIndex; i <= lastInputIndex; ++i) { 97ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka // Assuming pointerId == 0 if pointerIds is null. 98ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const int pid = pointerIds ? pointerIds[i] : 0; 99ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka if (DEBUG_GEO_FULL) { 100ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka AKLOGI("Init ProximityInfoState: (%d)PID = %d", i, pid); 101ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 102ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka if (pointerId == pid) { 103ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const int c = isGeometric ? 104ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka NOT_A_COORDINATE : getPrimaryCodePointAt(inputProximities, i); 105ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const int x = proximityOnly ? NOT_A_COORDINATE : inputXCoordinates[i]; 106ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const int y = proximityOnly ? NOT_A_COORDINATE : inputYCoordinates[i]; 107ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const int time = times ? times[i] : -1; 108ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka 109ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka if (i > 1) { 11029432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa const float prevAngle = GeometryUtils::getAngle( 111ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka inputXCoordinates[i - 2], inputYCoordinates[i - 2], 112ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka inputXCoordinates[i - 1], inputYCoordinates[i - 1]); 11329432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa const float currentAngle = GeometryUtils::getAngle( 11428c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa inputXCoordinates[i - 1], inputYCoordinates[i - 1], x, y); 11529432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa sumAngle += GeometryUtils::getAngleDiff(prevAngle, currentAngle); 116ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 117ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka 11828c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa if (pushTouchPoint(proximityInfo, maxPointToKeyLength, i, c, x, y, time, 1190052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi isGeometric, isGeometric /* doSampling */, i == lastInputIndex, 120a1d84bcf8ffd031c135b6f3f8c94b6732071849bSatoshi Kataoka sumAngle, currentNearKeysDistances, prevNearKeysDistances, 121a1d84bcf8ffd031c135b6f3f8c94b6732071849bSatoshi Kataoka prevPrevNearKeysDistances, sampledInputXs, sampledInputYs, sampledInputTimes, 122a1d84bcf8ffd031c135b6f3f8c94b6732071849bSatoshi Kataoka sampledLengthCache, sampledInputIndice)) { 123ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka // Previous point information was popped. 124ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka NearKeysDistanceMap *tmp = prevNearKeysDistances; 125ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka prevNearKeysDistances = currentNearKeysDistances; 126ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka currentNearKeysDistances = tmp; 127ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } else { 128ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka NearKeysDistanceMap *tmp = prevPrevNearKeysDistances; 129ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka prevPrevNearKeysDistances = prevNearKeysDistances; 130ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka prevNearKeysDistances = currentNearKeysDistances; 131ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka currentNearKeysDistances = tmp; 132ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka sumAngle = 0.0f; 133ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 134ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 135ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 136ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka return sampledInputXs->size(); 137ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka} 138ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka 139ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka/* static */ const int *ProximityInfoStateUtils::getProximityCodePointsAt( 140ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const int *const inputProximities, const int index) { 1416c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa return inputProximities + (index * MAX_PROXIMITY_CHARS_SIZE); 142ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka} 143ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka 1444920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa/* static */ int ProximityInfoStateUtils::getPrimaryCodePointAt(const int *const inputProximities, 1454920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa const int index) { 146ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka return getProximityCodePointsAt(inputProximities, index)[0]; 147ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka} 148ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka 1494920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa/* static */ void ProximityInfoStateUtils::initPrimaryInputWord(const int inputSize, 1504920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa const int *const inputProximities, int *primaryInputWord) { 15120b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka memset(primaryInputWord, 0, sizeof(primaryInputWord[0]) * MAX_WORD_LENGTH); 152d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka for (int i = 0; i < inputSize; ++i) { 153d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka primaryInputWord[i] = getPrimaryCodePointAt(inputProximities, i); 154d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka } 155d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka} 156d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka 157d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka/* static */ float ProximityInfoStateUtils::calculateSquaredDistanceFromSweetSpotCenter( 158d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka const ProximityInfo *const proximityInfo, const std::vector<int> *const sampledInputXs, 1594920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa const std::vector<int> *const sampledInputYs, const int keyIndex, const int inputIndex) { 160d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka const float sweetSpotCenterX = proximityInfo->getSweetSpotCenterXAt(keyIndex); 161d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka const float sweetSpotCenterY = proximityInfo->getSweetSpotCenterYAt(keyIndex); 162d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka const float inputX = static_cast<float>((*sampledInputXs)[inputIndex]); 163d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka const float inputY = static_cast<float>((*sampledInputYs)[inputIndex]); 16429432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa return GeometryUtils::SQUARE_FLOAT(inputX - sweetSpotCenterX) 16529432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa + GeometryUtils::SQUARE_FLOAT(inputY - sweetSpotCenterY); 166d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka} 167d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka 168d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka/* static */ float ProximityInfoStateUtils::calculateNormalizedSquaredDistance( 169d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka const ProximityInfo *const proximityInfo, const std::vector<int> *const sampledInputXs, 1704920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa const std::vector<int> *const sampledInputYs, const int keyIndex, const int inputIndex) { 171d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka if (keyIndex == NOT_AN_INDEX) { 172d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka return ProximityInfoParams::NOT_A_DISTANCE_FLOAT; 173d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka } 174d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka if (!proximityInfo->hasSweetSpotData(keyIndex)) { 175d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka return ProximityInfoParams::NOT_A_DISTANCE_FLOAT; 176d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka } 177d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka if (NOT_A_COORDINATE == (*sampledInputXs)[inputIndex]) { 178d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka return ProximityInfoParams::NOT_A_DISTANCE_FLOAT; 179d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka } 180d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka const float squaredDistance = calculateSquaredDistanceFromSweetSpotCenter(proximityInfo, 181d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka sampledInputXs, sampledInputYs, keyIndex, inputIndex); 18229432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa const float squaredRadius = GeometryUtils::SQUARE_FLOAT( 18329432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa proximityInfo->getSweetSpotRadiiAt(keyIndex)); 184d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka return squaredDistance / squaredRadius; 185d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka} 186d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka 187d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka/* static */ void ProximityInfoStateUtils::initGeometricDistanceInfos( 18828c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa const ProximityInfo *const proximityInfo, const int sampledInputSize, 1890052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi const int lastSavedInputSize, const bool isGeometric, 190a1d84bcf8ffd031c135b6f3f8c94b6732071849bSatoshi Kataoka const std::vector<int> *const sampledInputXs, 191d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka const std::vector<int> *const sampledInputYs, 192837f46dcb35a8f42a6bd5bc5fc6395d7386acb81Satoshi Kataoka std::vector<float> *sampledNormalizedSquaredLengthCache) { 19328c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa const int keyCount = proximityInfo->getKeyCount(); 194837f46dcb35a8f42a6bd5bc5fc6395d7386acb81Satoshi Kataoka sampledNormalizedSquaredLengthCache->resize(sampledInputSize * keyCount); 195d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka for (int i = lastSavedInputSize; i < sampledInputSize; ++i) { 196d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka for (int k = 0; k < keyCount; ++k) { 197d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka const int index = i * keyCount + k; 198d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka const int x = (*sampledInputXs)[i]; 199d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka const int y = (*sampledInputYs)[i]; 200d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka const float normalizedSquaredDistance = 201a1d84bcf8ffd031c135b6f3f8c94b6732071849bSatoshi Kataoka proximityInfo->getNormalizedSquaredDistanceFromCenterFloatG( 2020052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi k, x, y, isGeometric); 203837f46dcb35a8f42a6bd5bc5fc6395d7386acb81Satoshi Kataoka (*sampledNormalizedSquaredLengthCache)[index] = normalizedSquaredDistance; 204d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka } 205d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka } 206d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka} 207d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka 208ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka/* static */ void ProximityInfoStateUtils::popInputData(std::vector<int> *sampledInputXs, 209ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka std::vector<int> *sampledInputYs, std::vector<int> *sampledInputTimes, 210ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka std::vector<int> *sampledLengthCache, std::vector<int> *sampledInputIndice) { 211ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka sampledInputXs->pop_back(); 212ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka sampledInputYs->pop_back(); 213ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka sampledInputTimes->pop_back(); 214ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka sampledLengthCache->pop_back(); 215ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka sampledInputIndice->pop_back(); 216ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka} 217ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka 218ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka/* static */ float ProximityInfoStateUtils::refreshSpeedRates(const int inputSize, 219ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const int *const xCoordinates, const int *const yCoordinates, const int *const times, 220ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const int lastSavedInputSize, const int sampledInputSize, 2214920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa const std::vector<int> *const sampledInputXs, const std::vector<int> *const sampledInputYs, 222ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const std::vector<int> *const sampledInputTimes, 223ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const std::vector<int> *const sampledLengthCache, 224ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const std::vector<int> *const sampledInputIndice, std::vector<float> *sampledSpeedRates, 225ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka std::vector<float> *sampledDirections) { 226ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka // Relative speed calculation. 227ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const int sumDuration = sampledInputTimes->back() - sampledInputTimes->front(); 228ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const int sumLength = sampledLengthCache->back() - sampledLengthCache->front(); 229ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const float averageSpeed = static_cast<float>(sumLength) / static_cast<float>(sumDuration); 230ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka sampledSpeedRates->resize(sampledInputSize); 231ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka for (int i = lastSavedInputSize; i < sampledInputSize; ++i) { 232ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const int index = (*sampledInputIndice)[i]; 233ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka int length = 0; 234ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka int duration = 0; 235ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka 236ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka // Calculate velocity by using distances and durations of 23728c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa // ProximityInfoParams::NUM_POINTS_FOR_SPEED_CALCULATION points for both forward and 23828c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa // backward. 239865e6cf49764f3a411ee32861d927b15653ee398Keisuke Kuroyanagi const int forwardNumPoints = std::min(inputSize - 1, 24028c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa index + ProximityInfoParams::NUM_POINTS_FOR_SPEED_CALCULATION); 24128c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa for (int j = index; j < forwardNumPoints; ++j) { 242ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka if (i < sampledInputSize - 1 && j >= (*sampledInputIndice)[i + 1]) { 243ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka break; 244ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 24529432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa length += GeometryUtils::getDistanceInt(xCoordinates[j], yCoordinates[j], 246ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka xCoordinates[j + 1], yCoordinates[j + 1]); 247ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka duration += times[j + 1] - times[j]; 248ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 249865e6cf49764f3a411ee32861d927b15653ee398Keisuke Kuroyanagi const int backwardNumPoints = std::max(0, 25028c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa index - ProximityInfoParams::NUM_POINTS_FOR_SPEED_CALCULATION); 25128c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa for (int j = index - 1; j >= backwardNumPoints; --j) { 252ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka if (i > 0 && j < (*sampledInputIndice)[i - 1]) { 253ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka break; 254ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 255d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka // TODO: use mSampledLengthCache instead? 25629432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa length += GeometryUtils::getDistanceInt(xCoordinates[j], yCoordinates[j], 257ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka xCoordinates[j + 1], yCoordinates[j + 1]); 258ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka duration += times[j + 1] - times[j]; 259ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 260ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka if (duration == 0 || sumDuration == 0) { 261ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka // Cannot calculate speed; thus, it gives an average value (1.0); 262ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka (*sampledSpeedRates)[i] = 1.0f; 263ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } else { 264ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const float speed = static_cast<float>(length) / static_cast<float>(duration); 265ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka (*sampledSpeedRates)[i] = speed / averageSpeed; 266ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 267ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 268ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka 269ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka // Direction calculation. 270ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka sampledDirections->resize(sampledInputSize - 1); 271865e6cf49764f3a411ee32861d927b15653ee398Keisuke Kuroyanagi for (int i = std::max(0, lastSavedInputSize - 1); i < sampledInputSize - 1; ++i) { 272ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka (*sampledDirections)[i] = getDirection(sampledInputXs, sampledInputYs, i, i + 1); 273ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 274ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka return averageSpeed; 275ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka} 276ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka 277ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka/* static */ void ProximityInfoStateUtils::refreshBeelineSpeedRates(const int mostCommonKeyWidth, 278ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const float averageSpeed, const int inputSize, const int *const xCoordinates, 279ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const int *const yCoordinates, const int *times, const int sampledInputSize, 280ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const std::vector<int> *const sampledInputXs, 281ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const std::vector<int> *const sampledInputYs, const std::vector<int> *const inputIndice, 282ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka std::vector<int> *beelineSpeedPercentiles) { 283ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka if (DEBUG_SAMPLING_POINTS) { 284ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka AKLOGI("--- refresh beeline speed rates"); 285ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 286ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka beelineSpeedPercentiles->resize(sampledInputSize); 287ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka for (int i = 0; i < sampledInputSize; ++i) { 288ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka (*beelineSpeedPercentiles)[i] = static_cast<int>(calculateBeelineSpeedRate( 289ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka mostCommonKeyWidth, averageSpeed, i, inputSize, xCoordinates, yCoordinates, times, 290ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka sampledInputSize, sampledInputXs, sampledInputYs, inputIndice) * MAX_PERCENTILE); 291ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 292ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka} 293ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka 294ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka/* static */float ProximityInfoStateUtils::getDirection( 295ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const std::vector<int> *const sampledInputXs, 296ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const std::vector<int> *const sampledInputYs, const int index0, const int index1) { 297ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka ASSERT(sampledInputXs && sampledInputYs); 298ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const int sampledInputSize =sampledInputXs->size(); 299ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka if (index0 < 0 || index0 > sampledInputSize - 1) { 300ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka return 0.0f; 301ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 302ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka if (index1 < 0 || index1 > sampledInputSize - 1) { 303ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka return 0.0f; 304ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 305ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const int x1 = (*sampledInputXs)[index0]; 306ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const int y1 = (*sampledInputYs)[index0]; 307ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const int x2 = (*sampledInputXs)[index1]; 308ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const int y2 = (*sampledInputYs)[index1]; 30929432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa return GeometryUtils::getAngle(x1, y1, x2, y2); 310ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka} 311ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka 312ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka// Calculating point to key distance for all near keys and returning the distance between 313ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka// the given point and the nearest key position. 314ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka/* static */ float ProximityInfoStateUtils::updateNearKeysDistances( 315ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const ProximityInfo *const proximityInfo, const float maxPointToKeyLength, const int x, 3160052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi const int y, const bool isGeometric, NearKeysDistanceMap *const currentNearKeysDistances) { 317ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka currentNearKeysDistances->clear(); 318ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const int keyCount = proximityInfo->getKeyCount(); 319ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka float nearestKeyDistance = maxPointToKeyLength; 320ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka for (int k = 0; k < keyCount; ++k) { 321a1d84bcf8ffd031c135b6f3f8c94b6732071849bSatoshi Kataoka const float dist = proximityInfo->getNormalizedSquaredDistanceFromCenterFloatG(k, x, y, 3220052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi isGeometric); 3234920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa if (dist < ProximityInfoParams::NEAR_KEY_THRESHOLD_FOR_DISTANCE) { 324ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka currentNearKeysDistances->insert(std::pair<int, float>(k, dist)); 325ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 326ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka if (nearestKeyDistance > dist) { 327ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka nearestKeyDistance = dist; 328ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 329ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 330ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka return nearestKeyDistance; 331ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka} 332ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka 333ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka// Check if previous point is at local minimum position to near keys. 334ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka/* static */ bool ProximityInfoStateUtils::isPrevLocalMin( 335ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const NearKeysDistanceMap *const currentNearKeysDistances, 336ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const NearKeysDistanceMap *const prevNearKeysDistances, 337ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const NearKeysDistanceMap *const prevPrevNearKeysDistances) { 338ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka for (NearKeysDistanceMap::const_iterator it = prevNearKeysDistances->begin(); 339ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka it != prevNearKeysDistances->end(); ++it) { 340ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka NearKeysDistanceMap::const_iterator itPP = prevPrevNearKeysDistances->find(it->first); 341ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka NearKeysDistanceMap::const_iterator itC = currentNearKeysDistances->find(it->first); 3424920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa const bool isPrevPrevNear = (itPP == prevPrevNearKeysDistances->end() 3434920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa || itPP->second > it->second + ProximityInfoParams::MARGIN_FOR_PREV_LOCAL_MIN); 3444920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa const bool isCurrentNear = (itC == currentNearKeysDistances->end() 3454920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa || itC->second > it->second + ProximityInfoParams::MARGIN_FOR_PREV_LOCAL_MIN); 3464920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa if (isPrevPrevNear && isCurrentNear) { 347ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka return true; 348ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 349ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 350ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka return false; 351ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka} 352ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka 353ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka// Calculating a point score that indicates usefulness of the point. 354ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka/* static */ float ProximityInfoStateUtils::getPointScore(const int mostCommonKeyWidth, 355ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const int x, const int y, const int time, const bool lastPoint, const float nearest, 356ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const float sumAngle, const NearKeysDistanceMap *const currentNearKeysDistances, 357ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const NearKeysDistanceMap *const prevNearKeysDistances, 358ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const NearKeysDistanceMap *const prevPrevNearKeysDistances, 359ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka std::vector<int> *sampledInputXs, std::vector<int> *sampledInputYs) { 360ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const size_t size = sampledInputXs->size(); 361ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka // If there is only one point, add this point. Besides, if the previous point's distance map 362ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka // is empty, we re-compute nearby keys distances from the current point. 363ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka // Note that the current point is the first point in the incremental input that needs to 364ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka // be re-computed. 365ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka if (size <= 1 || prevNearKeysDistances->empty()) { 366ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka return 0.0f; 367ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 368ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka 369ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const int baseSampleRate = mostCommonKeyWidth; 37029432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa const int distPrev = GeometryUtils::getDistanceInt(sampledInputXs->back(), 37129432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa sampledInputYs->back(), (*sampledInputXs)[size - 2], 37229432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa (*sampledInputYs)[size - 2]) * ProximityInfoParams::DISTANCE_BASE_SCALE; 373ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka float score = 0.0f; 374ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka 375ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka // Location 376ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka if (!isPrevLocalMin(currentNearKeysDistances, prevNearKeysDistances, 377ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka prevPrevNearKeysDistances)) { 3784920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa score += ProximityInfoParams::NOT_LOCALMIN_DISTANCE_SCORE; 3794920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa } else if (nearest < ProximityInfoParams::NEAR_KEY_THRESHOLD_FOR_POINT_SCORE) { 380ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka // Promote points nearby keys 3814920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa score += ProximityInfoParams::LOCALMIN_DISTANCE_AND_NEAR_TO_KEY_SCORE; 382ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 383ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka // Angle 38429432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa const float angle1 = GeometryUtils::getAngle(x, y, sampledInputXs->back(), 38529432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa sampledInputYs->back()); 38629432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa const float angle2 = GeometryUtils::getAngle(sampledInputXs->back(), sampledInputYs->back(), 387ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka (*sampledInputXs)[size - 2], (*sampledInputYs)[size - 2]); 38829432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa const float angleDiff = GeometryUtils::getAngleDiff(angle1, angle2); 389ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka 390ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka // Save corner 3914920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa if (distPrev > baseSampleRate * ProximityInfoParams::CORNER_CHECK_DISTANCE_THRESHOLD_SCALE 3924920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa && (sumAngle > ProximityInfoParams::CORNER_SUM_ANGLE_THRESHOLD 3934920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa || angleDiff > ProximityInfoParams::CORNER_ANGLE_THRESHOLD_FOR_POINT_SCORE)) { 3944920d370f2a9f14bcc14212738590c22bd3752d0Ken Wakasa score += ProximityInfoParams::CORNER_SCORE; 395ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 396ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka return score; 397ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka} 398ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka 399ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka// Sampling touch point and pushing information to vectors. 400ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka// Returning if previous point is popped or not. 40128c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa/* static */ bool ProximityInfoStateUtils::pushTouchPoint(const ProximityInfo *const proximityInfo, 40228c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa const int maxPointToKeyLength, const int inputIndex, const int nodeCodePoint, int x, int y, 4030052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi const int time, const bool isGeometric, const bool doSampling, 404a1d84bcf8ffd031c135b6f3f8c94b6732071849bSatoshi Kataoka const bool isLastPoint, const float sumAngle, 405ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka NearKeysDistanceMap *const currentNearKeysDistances, 406ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const NearKeysDistanceMap *const prevNearKeysDistances, 407ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const NearKeysDistanceMap *const prevPrevNearKeysDistances, 408ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka std::vector<int> *sampledInputXs, std::vector<int> *sampledInputYs, 409ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka std::vector<int> *sampledInputTimes, std::vector<int> *sampledLengthCache, 410ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka std::vector<int> *sampledInputIndice) { 41128c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa const int mostCommonKeyWidth = proximityInfo->getMostCommonKeyWidth(); 412ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka 413ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka size_t size = sampledInputXs->size(); 414ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka bool popped = false; 4156c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa if (nodeCodePoint < 0 && doSampling) { 416a1d84bcf8ffd031c135b6f3f8c94b6732071849bSatoshi Kataoka const float nearest = updateNearKeysDistances(proximityInfo, maxPointToKeyLength, x, y, 4170052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi isGeometric, currentNearKeysDistances); 418ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const float score = getPointScore(mostCommonKeyWidth, x, y, time, isLastPoint, nearest, 419ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka sumAngle, currentNearKeysDistances, prevNearKeysDistances, 420ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka prevPrevNearKeysDistances, sampledInputXs, sampledInputYs); 421ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka if (score < 0) { 422ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka // Pop previous point because it would be useless. 423ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka popInputData(sampledInputXs, sampledInputYs, sampledInputTimes, sampledLengthCache, 424ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka sampledInputIndice); 425ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka size = sampledInputXs->size(); 426ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka popped = true; 427ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } else { 428ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka popped = false; 429ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 430ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka // Check if the last point should be skipped. 431ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka if (isLastPoint && size > 0) { 43229432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa if (GeometryUtils::getDistanceInt(x, y, sampledInputXs->back(), sampledInputYs->back()) 43328c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa * ProximityInfoParams::LAST_POINT_SKIP_DISTANCE_SCALE < mostCommonKeyWidth) { 434ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka // This point is not used because it's too close to the previous point. 435ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka if (DEBUG_GEO_FULL) { 436ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka AKLOGI("p0: size = %zd, x = %d, y = %d, lx = %d, ly = %d, dist = %d, " 437e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka "width = %d", size, x, y, sampledInputXs->back(), 43829432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa sampledInputYs->back(), GeometryUtils::getDistanceInt( 439e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka x, y, sampledInputXs->back(), sampledInputYs->back()), 44028c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa mostCommonKeyWidth 44128c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa / ProximityInfoParams::LAST_POINT_SKIP_DISTANCE_SCALE); 442ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 443ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka return popped; 444ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 445ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 446ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 447ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka 448ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka if (nodeCodePoint >= 0 && (x < 0 || y < 0)) { 449ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const int keyId = proximityInfo->getKeyIndexOf(nodeCodePoint); 450ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka if (keyId >= 0) { 4510052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi x = proximityInfo->getKeyCenterXOfKeyIdG(keyId, NOT_AN_INDEX, isGeometric); 4520052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi y = proximityInfo->getKeyCenterYOfKeyIdG(keyId, NOT_AN_INDEX, isGeometric); 453ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 454ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 455ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka 456ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka // Pushing point information. 457ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka if (size > 0) { 458ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka sampledLengthCache->push_back( 45929432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa sampledLengthCache->back() + GeometryUtils::getDistanceInt( 460ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka x, y, sampledInputXs->back(), sampledInputYs->back())); 461ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } else { 462ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka sampledLengthCache->push_back(0); 463ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 464ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka sampledInputXs->push_back(x); 465ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka sampledInputYs->push_back(y); 466ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka sampledInputTimes->push_back(time); 467ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka sampledInputIndice->push_back(inputIndex); 468ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka if (DEBUG_GEO_FULL) { 469ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka AKLOGI("pushTouchPoint: x = %03d, y = %03d, time = %d, index = %d, popped ? %01d", 470ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka x, y, time, inputIndex, popped); 471ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 472ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka return popped; 473ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka} 474ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka 475ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka/* static */ float ProximityInfoStateUtils::calculateBeelineSpeedRate(const int mostCommonKeyWidth, 476ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const float averageSpeed, const int id, const int inputSize, const int *const xCoordinates, 477ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const int *const yCoordinates, const int *times, const int sampledInputSize, 478ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const std::vector<int> *const sampledInputXs, 479e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka const std::vector<int> *const sampledInputYs, 480e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka const std::vector<int> *const sampledInputIndices) { 481ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka if (sampledInputSize <= 0 || averageSpeed < 0.001f) { 482ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka if (DEBUG_SAMPLING_POINTS) { 483ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka AKLOGI("--- invalid state: cancel. size = %d, ave = %f", 484e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka sampledInputSize, averageSpeed); 485ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 486ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka return 1.0f; 487ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 488ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const int lookupRadius = mostCommonKeyWidth 489ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka * ProximityInfoParams::LOOKUP_RADIUS_PERCENTILE / MAX_PERCENTILE; 490ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const int x0 = (*sampledInputXs)[id]; 491ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const int y0 = (*sampledInputYs)[id]; 492e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka const int actualInputIndex = (*sampledInputIndices)[id]; 493ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka int tempTime = 0; 494ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka int tempBeelineDistance = 0; 495ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka int start = actualInputIndex; 496ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka // lookup forward 497ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka while (start > 0 && tempBeelineDistance < lookupRadius) { 498ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka tempTime += times[start] - times[start - 1]; 499ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka --start; 50029432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa tempBeelineDistance = GeometryUtils::getDistanceInt(x0, y0, xCoordinates[start], 50129432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa yCoordinates[start]); 502ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 503ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka // Exclusive unless this is an edge point 504ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka if (start > 0 && start < actualInputIndex) { 505ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka ++start; 506ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 507ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka tempTime= 0; 508ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka tempBeelineDistance = 0; 509ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka int end = actualInputIndex; 510ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka // lookup backward 511ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka while (end < (inputSize - 1) && tempBeelineDistance < lookupRadius) { 512ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka tempTime += times[end + 1] - times[end]; 513ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka ++end; 51429432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa tempBeelineDistance = GeometryUtils::getDistanceInt(x0, y0, xCoordinates[end], 51529432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa yCoordinates[end]); 516ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 517ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka // Exclusive unless this is an edge point 518ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka if (end > actualInputIndex && end < (inputSize - 1)) { 519ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka --end; 520ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 521ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka 522ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka if (start >= end) { 523ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka if (DEBUG_DOUBLE_LETTER) { 524ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka AKLOGI("--- double letter: start == end %d", start); 525ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 526ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka return 1.0f; 527ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 528ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka 529ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const int x2 = xCoordinates[start]; 530ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const int y2 = yCoordinates[start]; 531ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const int x3 = xCoordinates[end]; 532ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const int y3 = yCoordinates[end]; 53329432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa const int beelineDistance = GeometryUtils::getDistanceInt(x2, y2, x3, y3); 534ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka int adjustedStartTime = times[start]; 535ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka if (start == 0 && actualInputIndex == 0 && inputSize > 1) { 536ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka adjustedStartTime += ProximityInfoParams::FIRST_POINT_TIME_OFFSET_MILLIS; 537ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 538ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka int adjustedEndTime = times[end]; 539ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka if (end == (inputSize - 1) && inputSize > 1) { 540ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka adjustedEndTime -= ProximityInfoParams::FIRST_POINT_TIME_OFFSET_MILLIS; 541ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 542ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka const int time = adjustedEndTime - adjustedStartTime; 543ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka if (time <= 0) { 544ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka return 1.0f; 545ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 546ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka 547ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka if (time >= ProximityInfoParams::STRONG_DOUBLE_LETTER_TIME_MILLIS){ 548ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka return 0.0f; 549ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 550ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka if (DEBUG_DOUBLE_LETTER) { 551ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka AKLOGI("--- (%d, %d) double letter: start = %d, end = %d, dist = %d, time = %d," 552ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka " speed = %f, ave = %f, val = %f, start time = %d, end time = %d", 553e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka id, (*sampledInputIndices)[id], start, end, beelineDistance, time, 554e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka (static_cast<float>(beelineDistance) / static_cast<float>(time)), averageSpeed, 555ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka ((static_cast<float>(beelineDistance) / static_cast<float>(time)) 556e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka / averageSpeed), adjustedStartTime, adjustedEndTime); 557ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka } 558ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka // Offset 1% 559ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka // TODO: Detect double letter more smartly 560ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka return 0.01f + static_cast<float>(beelineDistance) / static_cast<float>(time) / averageSpeed; 561ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka} 562d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka 563d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka/* static */ float ProximityInfoStateUtils::getPointAngle( 564d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka const std::vector<int> *const sampledInputXs, 565d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka const std::vector<int> *const sampledInputYs, const int index) { 566d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka if (!sampledInputXs || !sampledInputYs) { 567d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka return 0.0f; 568d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka } 569d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka const int sampledInputSize = sampledInputXs->size(); 570d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka if (index <= 0 || index >= sampledInputSize - 1) { 571d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka return 0.0f; 572d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka } 573d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka const float previousDirection = getDirection(sampledInputXs, sampledInputYs, index - 1, index); 574d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka const float nextDirection = getDirection(sampledInputXs, sampledInputYs, index, index + 1); 57529432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa const float directionDiff = GeometryUtils::getAngleDiff(previousDirection, nextDirection); 576d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka return directionDiff; 577d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka} 578d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka 579d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka/* static */ float ProximityInfoStateUtils::getPointsAngle( 580d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka const std::vector<int> *const sampledInputXs, 581d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka const std::vector<int> *const sampledInputYs, 582d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka const int index0, const int index1, const int index2) { 583d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka if (!sampledInputXs || !sampledInputYs) { 584d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka return 0.0f; 585d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka } 586d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka const int sampledInputSize = sampledInputXs->size(); 587d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka if (index0 < 0 || index0 > sampledInputSize - 1) { 588d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka return 0.0f; 589d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka } 590d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka if (index1 < 0 || index1 > sampledInputSize - 1) { 591d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka return 0.0f; 592d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka } 593d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka if (index2 < 0 || index2 > sampledInputSize - 1) { 594d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka return 0.0f; 595d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka } 596d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka const float previousDirection = getDirection(sampledInputXs, sampledInputYs, index0, index1); 597d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka const float nextDirection = getDirection(sampledInputXs, sampledInputYs, index1, index2); 59829432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa return GeometryUtils::getAngleDiff(previousDirection, nextDirection); 599d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka} 600d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka 601d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka// This function basically converts from a length to an edit distance. Accordingly, it's obviously 602d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka// wrong to compare with mMaxPointToKeyLength. 603d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka/* static */ float ProximityInfoStateUtils::getPointToKeyByIdLength(const float maxPointToKeyLength, 604837f46dcb35a8f42a6bd5bc5fc6395d7386acb81Satoshi Kataoka const std::vector<float> *const sampledNormalizedSquaredLengthCache, const int keyCount, 6052192d08b9cca6a40d834d6a5001d19b5845ed8a0Tom Ouyang const int inputIndex, const int keyId) { 606d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka if (keyId != NOT_AN_INDEX) { 607d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka const int index = inputIndex * keyCount + keyId; 608865e6cf49764f3a411ee32861d927b15653ee398Keisuke Kuroyanagi return std::min((*sampledNormalizedSquaredLengthCache)[index], maxPointToKeyLength); 609d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka } 610d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka // If the char is not a key on the keyboard then return the max length. 611830ba67498c6da53b38212dd9ac5ba318a00de11Satoshi Kataoka return static_cast<float>(MAX_VALUE_FOR_WEIGHTING); 612d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka} 613d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka 614d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka// Updates probabilities of aligning to some keys and skipping. 615d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka// Word suggestion should be based on this probabilities. 616d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka/* static */ void ProximityInfoStateUtils::updateAlignPointProbabilities( 617d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka const float maxPointToKeyLength, const int mostCommonKeyWidth, const int keyCount, 618d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka const int start, const int sampledInputSize, const std::vector<int> *const sampledInputXs, 619d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka const std::vector<int> *const sampledInputYs, 620d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka const std::vector<float> *const sampledSpeedRates, 621d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka const std::vector<int> *const sampledLengthCache, 622837f46dcb35a8f42a6bd5bc5fc6395d7386acb81Satoshi Kataoka const std::vector<float> *const sampledNormalizedSquaredLengthCache, 62326c806620c26e048918624367ee624526613b0d2Keisuke Kuroyanagi const ProximityInfo *const proximityInfo, 6240b1fa0c1c7572893365c019780357a817158e5eaKen Wakasa std::vector<std::unordered_map<int, float>> *charProbabilities) { 625d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka charProbabilities->resize(sampledInputSize); 626d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka // Calculates probabilities of using a point as a correlated point with the character 627d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka // for each point. 628d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka for (int i = start; i < sampledInputSize; ++i) { 629d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka (*charProbabilities)[i].clear(); 63028c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa // First, calculates skip probability. Starts from MAX_SKIP_PROBABILITY. 631d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka // Note that all values that are multiplied to this probability should be in [0.0, 1.0]; 63228c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa float skipProbability = ProximityInfoParams::MAX_SKIP_PROBABILITY; 633d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka 634d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka const float currentAngle = getPointAngle(sampledInputXs, sampledInputYs, i); 635d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka const float speedRate = (*sampledSpeedRates)[i]; 636d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka 637830ba67498c6da53b38212dd9ac5ba318a00de11Satoshi Kataoka float nearestKeyDistance = static_cast<float>(MAX_VALUE_FOR_WEIGHTING); 638d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka for (int j = 0; j < keyCount; ++j) { 639bc9500fb14622f8b185e30a10a7c0b4c5a29930aKeisuke Kuroyanagi const float distance = getPointToKeyByIdLength( 640bc9500fb14622f8b185e30a10a7c0b4c5a29930aKeisuke Kuroyanagi maxPointToKeyLength, sampledNormalizedSquaredLengthCache, keyCount, i, j); 641bc9500fb14622f8b185e30a10a7c0b4c5a29930aKeisuke Kuroyanagi if (distance < nearestKeyDistance) { 642bc9500fb14622f8b185e30a10a7c0b4c5a29930aKeisuke Kuroyanagi nearestKeyDistance = distance; 643d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka } 644d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka } 645d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka 646d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka if (i == 0) { 647865e6cf49764f3a411ee32861d927b15653ee398Keisuke Kuroyanagi skipProbability *= std::min(1.0f, 64828c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa nearestKeyDistance * ProximityInfoParams::NEAREST_DISTANCE_WEIGHT 64928c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa + ProximityInfoParams::NEAREST_DISTANCE_BIAS); 650d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka // Promote the first point 65128c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa skipProbability *= ProximityInfoParams::SKIP_FIRST_POINT_PROBABILITY; 652d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka } else if (i == sampledInputSize - 1) { 653865e6cf49764f3a411ee32861d927b15653ee398Keisuke Kuroyanagi skipProbability *= std::min(1.0f, 65428c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa nearestKeyDistance * ProximityInfoParams::NEAREST_DISTANCE_WEIGHT_FOR_LAST 65528c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa + ProximityInfoParams::NEAREST_DISTANCE_BIAS_FOR_LAST); 656d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka // Promote the last point 65728c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa skipProbability *= ProximityInfoParams::SKIP_LAST_POINT_PROBABILITY; 658d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka } else { 659d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka // If the current speed is relatively slower than adjacent keys, we promote this point. 66028c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa if ((*sampledSpeedRates)[i - 1] - ProximityInfoParams::SPEED_MARGIN > speedRate 66128c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa && speedRate 66228c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa < (*sampledSpeedRates)[i + 1] - ProximityInfoParams::SPEED_MARGIN) { 66328c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa if (currentAngle < ProximityInfoParams::CORNER_ANGLE_THRESHOLD) { 664865e6cf49764f3a411ee32861d927b15653ee398Keisuke Kuroyanagi skipProbability *= std::min(1.0f, speedRate 66528c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa * ProximityInfoParams::SLOW_STRAIGHT_WEIGHT_FOR_SKIP_PROBABILITY); 666d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka } else { 667d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka // If the angle is small enough, we promote this point more. (e.g. pit vs put) 668865e6cf49764f3a411ee32861d927b15653ee398Keisuke Kuroyanagi skipProbability *= std::min(1.0f, 66928c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa speedRate * ProximityInfoParams::SPEED_WEIGHT_FOR_SKIP_PROBABILITY 67028c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa + ProximityInfoParams::MIN_SPEED_RATE_FOR_SKIP_PROBABILITY); 671d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka } 672d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka } 673d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka 674865e6cf49764f3a411ee32861d927b15653ee398Keisuke Kuroyanagi skipProbability *= std::min(1.0f, 67528c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa speedRate * nearestKeyDistance * ProximityInfoParams::NEAREST_DISTANCE_WEIGHT 67628c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa + ProximityInfoParams::NEAREST_DISTANCE_BIAS); 677d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka 678d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka // Adjusts skip probability by a rate depending on angle. 679d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka // ANGLE_RATE of skipProbability is adjusted by current angle. 68028c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa skipProbability *= (M_PI_F - currentAngle) / M_PI_F * ProximityInfoParams::ANGLE_WEIGHT 68128c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa + (1.0f - ProximityInfoParams::ANGLE_WEIGHT); 68228c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa if (currentAngle > ProximityInfoParams::DEEP_CORNER_ANGLE_THRESHOLD) { 68328c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa skipProbability *= ProximityInfoParams::SKIP_DEEP_CORNER_PROBABILITY; 684d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka } 685d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka // We assume the angle of this point is the angle for point[i], point[i - 2] 686d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka // and point[i - 3]. The reason why we don't use the angle for point[i], point[i - 1] 687d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka // and point[i - 2] is this angle can be more affected by the noise. 688d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka const float prevAngle = getPointsAngle(sampledInputXs, sampledInputYs, i, i - 2, i - 3); 68928c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa if (i >= 3 && prevAngle < ProximityInfoParams::STRAIGHT_ANGLE_THRESHOLD 69028c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa && currentAngle > ProximityInfoParams::CORNER_ANGLE_THRESHOLD) { 69128c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa skipProbability *= ProximityInfoParams::SKIP_CORNER_PROBABILITY; 692d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka } 693d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka } 694d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka 69528c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa // probabilities must be in [0.0, ProximityInfoParams::MAX_SKIP_PROBABILITY]; 696d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka ASSERT(skipProbability >= 0.0f); 69728c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa ASSERT(skipProbability <= ProximityInfoParams::MAX_SKIP_PROBABILITY); 698d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka (*charProbabilities)[i][NOT_AN_INDEX] = skipProbability; 699d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka 700d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka // Second, calculates key probabilities by dividing the rest probability 701d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka // (1.0f - skipProbability). 702d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka const float inputCharProbability = 1.0f - skipProbability; 703d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka 70426c806620c26e048918624367ee624526613b0d2Keisuke Kuroyanagi const float speedMultipliedByAngleRate = std::min(speedRate * currentAngle / M_PI_F 7053e954347e3a7b381d7e94feb002e158f3bc69a32Jean Chalard * ProximityInfoParams::SPEEDxANGLE_WEIGHT_FOR_STANDARD_DEVIATION, 7063e954347e3a7b381d7e94feb002e158f3bc69a32Jean Chalard ProximityInfoParams::MAX_SPEEDxANGLE_RATE_FOR_STANDARD_DEVIATION); 70726c806620c26e048918624367ee624526613b0d2Keisuke Kuroyanagi const float speedMultipliedByNearestKeyDistanceRate = std::min( 70826c806620c26e048918624367ee624526613b0d2Keisuke Kuroyanagi speedRate * nearestKeyDistance 70926c806620c26e048918624367ee624526613b0d2Keisuke Kuroyanagi * ProximityInfoParams::SPEEDxNEAREST_WEIGHT_FOR_STANDARD_DEVIATION, 71026c806620c26e048918624367ee624526613b0d2Keisuke Kuroyanagi ProximityInfoParams::MAX_SPEEDxNEAREST_RATE_FOR_STANDARD_DEVIATION); 71126c806620c26e048918624367ee624526613b0d2Keisuke Kuroyanagi const float sigma = (speedMultipliedByAngleRate + speedMultipliedByNearestKeyDistanceRate 71226c806620c26e048918624367ee624526613b0d2Keisuke Kuroyanagi + ProximityInfoParams::MIN_STANDARD_DEVIATION) * mostCommonKeyWidth; 71326c806620c26e048918624367ee624526613b0d2Keisuke Kuroyanagi float theta = 0.0f; 71426c806620c26e048918624367ee624526613b0d2Keisuke Kuroyanagi // TODO: Use different metrics to compute sigmas. 71526c806620c26e048918624367ee624526613b0d2Keisuke Kuroyanagi float sigmaX = sigma; 71626c806620c26e048918624367ee624526613b0d2Keisuke Kuroyanagi float sigmaY = sigma; 71726c806620c26e048918624367ee624526613b0d2Keisuke Kuroyanagi if (i == 0 && i != sampledInputSize - 1) { 71826c806620c26e048918624367ee624526613b0d2Keisuke Kuroyanagi // First point 71926c806620c26e048918624367ee624526613b0d2Keisuke Kuroyanagi theta = getDirection(sampledInputXs, sampledInputYs, i + 1, i); 72026c806620c26e048918624367ee624526613b0d2Keisuke Kuroyanagi sigmaX *= ProximityInfoParams::STANDARD_DEVIATION_X_WEIGHT_FOR_FIRST; 72126c806620c26e048918624367ee624526613b0d2Keisuke Kuroyanagi sigmaY *= ProximityInfoParams::STANDARD_DEVIATION_Y_WEIGHT_FOR_FIRST; 72226c806620c26e048918624367ee624526613b0d2Keisuke Kuroyanagi } else { 72326c806620c26e048918624367ee624526613b0d2Keisuke Kuroyanagi if (i == sampledInputSize - 1) { 72426c806620c26e048918624367ee624526613b0d2Keisuke Kuroyanagi // Last point 72526c806620c26e048918624367ee624526613b0d2Keisuke Kuroyanagi sigmaX *= ProximityInfoParams::STANDARD_DEVIATION_X_WEIGHT_FOR_LAST; 72626c806620c26e048918624367ee624526613b0d2Keisuke Kuroyanagi sigmaY *= ProximityInfoParams::STANDARD_DEVIATION_Y_WEIGHT_FOR_LAST; 72726c806620c26e048918624367ee624526613b0d2Keisuke Kuroyanagi } else { 72826c806620c26e048918624367ee624526613b0d2Keisuke Kuroyanagi sigmaX *= ProximityInfoParams::STANDARD_DEVIATION_X_WEIGHT; 72926c806620c26e048918624367ee624526613b0d2Keisuke Kuroyanagi sigmaY *= ProximityInfoParams::STANDARD_DEVIATION_Y_WEIGHT; 73026c806620c26e048918624367ee624526613b0d2Keisuke Kuroyanagi } 73126c806620c26e048918624367ee624526613b0d2Keisuke Kuroyanagi theta = getDirection(sampledInputXs, sampledInputYs, i, i - 1); 73226c806620c26e048918624367ee624526613b0d2Keisuke Kuroyanagi } 73326c806620c26e048918624367ee624526613b0d2Keisuke Kuroyanagi NormalDistribution2D distribution((*sampledInputXs)[i], sigmaX, (*sampledInputYs)[i], 73426c806620c26e048918624367ee624526613b0d2Keisuke Kuroyanagi sigmaY, theta); 735d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka // Summing up probability densities of all near keys. 736d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka float sumOfProbabilityDensities = 0.0f; 737d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka for (int j = 0; j < keyCount; ++j) { 738bc9500fb14622f8b185e30a10a7c0b4c5a29930aKeisuke Kuroyanagi sumOfProbabilityDensities += distribution.getProbabilityDensity( 739bc9500fb14622f8b185e30a10a7c0b4c5a29930aKeisuke Kuroyanagi proximityInfo->getKeyCenterXOfKeyIdG(j, 740bc9500fb14622f8b185e30a10a7c0b4c5a29930aKeisuke Kuroyanagi NOT_A_COORDINATE /* referencePointX */, true /* isGeometric */), 741bc9500fb14622f8b185e30a10a7c0b4c5a29930aKeisuke Kuroyanagi proximityInfo->getKeyCenterYOfKeyIdG(j, 742bc9500fb14622f8b185e30a10a7c0b4c5a29930aKeisuke Kuroyanagi NOT_A_COORDINATE /* referencePointY */, true /* isGeometric */)); 743d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka } 744d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka 745d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka // Split the probability of an input point to keys that are close to the input point. 746d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka for (int j = 0; j < keyCount; ++j) { 747bc9500fb14622f8b185e30a10a7c0b4c5a29930aKeisuke Kuroyanagi const float probabilityDensity = distribution.getProbabilityDensity( 748bc9500fb14622f8b185e30a10a7c0b4c5a29930aKeisuke Kuroyanagi proximityInfo->getKeyCenterXOfKeyIdG(j, 749bc9500fb14622f8b185e30a10a7c0b4c5a29930aKeisuke Kuroyanagi NOT_A_COORDINATE /* referencePointX */, true /* isGeometric */), 750bc9500fb14622f8b185e30a10a7c0b4c5a29930aKeisuke Kuroyanagi proximityInfo->getKeyCenterYOfKeyIdG(j, 751bc9500fb14622f8b185e30a10a7c0b4c5a29930aKeisuke Kuroyanagi NOT_A_COORDINATE /* referencePointY */, true /* isGeometric */)); 752bc9500fb14622f8b185e30a10a7c0b4c5a29930aKeisuke Kuroyanagi const float probability = inputCharProbability * probabilityDensity 753bc9500fb14622f8b185e30a10a7c0b4c5a29930aKeisuke Kuroyanagi / sumOfProbabilityDensities; 754bc9500fb14622f8b185e30a10a7c0b4c5a29930aKeisuke Kuroyanagi (*charProbabilities)[i][j] = probability; 755d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka } 756d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka } 757d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka 758d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka if (DEBUG_POINTS_PROBABILITY) { 759d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka for (int i = 0; i < sampledInputSize; ++i) { 760d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka std::stringstream sstream; 761d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka sstream << i << ", "; 762d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka sstream << "(" << (*sampledInputXs)[i] << ", " << (*sampledInputYs)[i] << "), "; 763d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka sstream << "Speed: "<< (*sampledSpeedRates)[i] << ", "; 764d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka sstream << "Angle: "<< getPointAngle(sampledInputXs, sampledInputYs, i) << ", \n"; 765d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka 7668ca9be17db2f1845c7c7a3b584507cf60c9ca53dKen Wakasa for (std::unordered_map<int, float>::iterator it = (*charProbabilities)[i].begin(); 767d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka it != (*charProbabilities)[i].end(); ++it) { 768d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka if (it->first == NOT_AN_INDEX) { 769d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka sstream << it->first 770d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka << "(skip):" 771d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka << it->second 772d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka << "\n"; 773d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka } else { 774d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka sstream << it->first 775d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka << "(" 776d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka //<< static_cast<char>(mProximityInfo->getCodePointOf(it->first)) 777d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka << "):" 778d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka << it->second 779d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka << "\n"; 780d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka } 781d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka } 782d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka AKLOGI("%s", sstream.str().c_str()); 783d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka } 784d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka } 785d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka 786d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka // Decrease key probabilities of points which don't have the highest probability of that key 787d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka // among nearby points. Probabilities of the first point and the last point are not suppressed. 788865e6cf49764f3a411ee32861d927b15653ee398Keisuke Kuroyanagi for (int i = std::max(start, 1); i < sampledInputSize; ++i) { 789d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka for (int j = i + 1; j < sampledInputSize; ++j) { 790d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka if (!suppressCharProbabilities( 791d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka mostCommonKeyWidth, sampledInputSize, sampledLengthCache, i, j, 792d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka charProbabilities)) { 793d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka break; 794d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka } 795d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka } 796865e6cf49764f3a411ee32861d927b15653ee398Keisuke Kuroyanagi for (int j = i - 1; j >= std::max(start, 0); --j) { 797d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka if (!suppressCharProbabilities( 798d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka mostCommonKeyWidth, sampledInputSize, sampledLengthCache, i, j, 799d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka charProbabilities)) { 800d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka break; 801d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka } 802d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka } 803d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka } 804d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka 805d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka // Converting from raw probabilities to log probabilities to calculate spatial distance. 806d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka for (int i = start; i < sampledInputSize; ++i) { 807d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka for (int j = 0; j < keyCount; ++j) { 8088ca9be17db2f1845c7c7a3b584507cf60c9ca53dKen Wakasa std::unordered_map<int, float>::iterator it = (*charProbabilities)[i].find(j); 809d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka if (it == (*charProbabilities)[i].end()){ 810bc9500fb14622f8b185e30a10a7c0b4c5a29930aKeisuke Kuroyanagi continue; 81128c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa } else if(it->second < ProximityInfoParams::MIN_PROBABILITY) { 812d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka // Erases from near keys vector because it has very low probability. 813d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka (*charProbabilities)[i].erase(j); 814d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka } else { 815d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka it->second = -logf(it->second); 816d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka } 817d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka } 818d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka (*charProbabilities)[i][NOT_AN_INDEX] = -logf((*charProbabilities)[i][NOT_AN_INDEX]); 819d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka } 820d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka} 821d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka 822e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka/* static */ void ProximityInfoStateUtils::updateSampledSearchKeySets( 823e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka const ProximityInfo *const proximityInfo, const int sampledInputSize, 824bc9500fb14622f8b185e30a10a7c0b4c5a29930aKeisuke Kuroyanagi const int lastSavedInputSize, const std::vector<int> *const sampledLengthCache, 8250b1fa0c1c7572893365c019780357a817158e5eaKen Wakasa const std::vector<std::unordered_map<int, float>> *const charProbabilities, 826e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka std::vector<NearKeycodesSet> *sampledSearchKeySets, 8270b1fa0c1c7572893365c019780357a817158e5eaKen Wakasa std::vector<std::vector<int>> *sampledSearchKeyVectors) { 828e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka sampledSearchKeySets->resize(sampledInputSize); 829e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka sampledSearchKeyVectors->resize(sampledInputSize); 830e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka const int readForwordLength = static_cast<int>( 831e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka hypotf(proximityInfo->getKeyboardWidth(), proximityInfo->getKeyboardHeight()) 832e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka * ProximityInfoParams::SEARCH_KEY_RADIUS_RATIO); 833e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka for (int i = 0; i < sampledInputSize; ++i) { 834e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka if (i >= lastSavedInputSize) { 835e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka (*sampledSearchKeySets)[i].reset(); 836e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka } 837865e6cf49764f3a411ee32861d927b15653ee398Keisuke Kuroyanagi for (int j = std::max(i, lastSavedInputSize); j < sampledInputSize; ++j) { 838e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka // TODO: Investigate if this is required. This may not fail. 839e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka if ((*sampledLengthCache)[j] - (*sampledLengthCache)[i] >= readForwordLength) { 840e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka break; 841e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka } 842bc9500fb14622f8b185e30a10a7c0b4c5a29930aKeisuke Kuroyanagi for(const auto& charProbability : charProbabilities->at(j)) { 843bc9500fb14622f8b185e30a10a7c0b4c5a29930aKeisuke Kuroyanagi if (charProbability.first == NOT_AN_INDEX) { 844bc9500fb14622f8b185e30a10a7c0b4c5a29930aKeisuke Kuroyanagi continue; 845bc9500fb14622f8b185e30a10a7c0b4c5a29930aKeisuke Kuroyanagi } 846bc9500fb14622f8b185e30a10a7c0b4c5a29930aKeisuke Kuroyanagi (*sampledSearchKeySets)[i].set(charProbability.first); 847bc9500fb14622f8b185e30a10a7c0b4c5a29930aKeisuke Kuroyanagi } 848e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka } 849e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka } 850e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka const int keyCount = proximityInfo->getKeyCount(); 851e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka for (int i = 0; i < sampledInputSize; ++i) { 852e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka std::vector<int> *searchKeyVector = &(*sampledSearchKeyVectors)[i]; 853e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka searchKeyVector->clear(); 854e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka for (int j = 0; j < keyCount; ++j) { 855e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka if ((*sampledSearchKeySets)[i].test(j)) { 856e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka const int keyCodePoint = proximityInfo->getCodePointOf(j); 857e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka if (std::find(searchKeyVector->begin(), searchKeyVector->end(), keyCodePoint) 858e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka == searchKeyVector->end()) { 859e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka searchKeyVector->push_back(keyCodePoint); 860e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka } 861e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka } 862e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka } 863e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka } 864e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka} 865e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka 866d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka// Decreases char probabilities of index0 by checking probabilities of a near point (index1) and 867d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka// increases char probabilities of index1 by checking probabilities of index0. 868d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka/* static */ bool ProximityInfoStateUtils::suppressCharProbabilities(const int mostCommonKeyWidth, 869d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka const int sampledInputSize, const std::vector<int> *const lengthCache, 870d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka const int index0, const int index1, 8710b1fa0c1c7572893365c019780357a817158e5eaKen Wakasa std::vector<std::unordered_map<int, float>> *charProbabilities) { 872d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka ASSERT(0 <= index0 && index0 < sampledInputSize); 873d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka ASSERT(0 <= index1 && index1 < sampledInputSize); 874d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka const float keyWidthFloat = static_cast<float>(mostCommonKeyWidth); 875d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka const float diff = fabsf(static_cast<float>((*lengthCache)[index0] - (*lengthCache)[index1])); 87628c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa if (diff > keyWidthFloat * ProximityInfoParams::SUPPRESSION_LENGTH_WEIGHT) { 877d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka return false; 878d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka } 87928c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa const float suppressionRate = ProximityInfoParams::MIN_SUPPRESSION_RATE 88028c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa + diff / keyWidthFloat / ProximityInfoParams::SUPPRESSION_LENGTH_WEIGHT 88128c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa * ProximityInfoParams::SUPPRESSION_WEIGHT; 8828ca9be17db2f1845c7c7a3b584507cf60c9ca53dKen Wakasa for (std::unordered_map<int, float>::iterator it = (*charProbabilities)[index0].begin(); 883d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka it != (*charProbabilities)[index0].end(); ++it) { 8848ca9be17db2f1845c7c7a3b584507cf60c9ca53dKen Wakasa std::unordered_map<int, float>::iterator it2 = (*charProbabilities)[index1].find(it->first); 885d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka if (it2 != (*charProbabilities)[index1].end() && it->second < it2->second) { 886d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka const float newProbability = it->second * suppressionRate; 887d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka const float suppression = it->second - newProbability; 888d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka it->second = newProbability; 889d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka // mCharProbabilities[index0][NOT_AN_INDEX] is the probability of skipping this point. 890d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka (*charProbabilities)[index0][NOT_AN_INDEX] += suppression; 891d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka 892d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka // Add the probability of the same key nearby index1 893865e6cf49764f3a411ee32861d927b15653ee398Keisuke Kuroyanagi const float probabilityGain = std::min(suppression 89428c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa * ProximityInfoParams::SUPPRESSION_WEIGHT_FOR_PROBABILITY_GAIN, 895d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka (*charProbabilities)[index1][NOT_AN_INDEX] 89628c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa * ProximityInfoParams::SKIP_PROBABALITY_WEIGHT_FOR_PROBABILITY_GAIN); 897d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka it2->second += probabilityGain; 898d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka (*charProbabilities)[index1][NOT_AN_INDEX] -= probabilityGain; 899d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka } 900d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka } 901d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka return true; 902d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka} 903d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka 904394b0bd345f33b1314613a433478fd0bb711e0f7Satoshi Kataoka/* static */ bool ProximityInfoStateUtils::checkAndReturnIsContinuousSuggestionPossible( 905394b0bd345f33b1314613a433478fd0bb711e0f7Satoshi Kataoka const int inputSize, const int *const xCoordinates, const int *const yCoordinates, 906394b0bd345f33b1314613a433478fd0bb711e0f7Satoshi Kataoka const int *const times, const int sampledInputSize, 907394b0bd345f33b1314613a433478fd0bb711e0f7Satoshi Kataoka const std::vector<int> *const sampledInputXs, const std::vector<int> *const sampledInputYs, 9089d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka const std::vector<int> *const sampledTimes, 9099d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka const std::vector<int> *const sampledInputIndices) { 9109d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka if (inputSize < sampledInputSize) { 9119d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka return false; 9129d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka } 9139d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka for (int i = 0; i < sampledInputSize; ++i) { 9149d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka const int index = (*sampledInputIndices)[i]; 9159d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka if (index >= inputSize) { 9169d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka return false; 9179d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka } 9189d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka if (xCoordinates[index] != (*sampledInputXs)[i] 9199d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka || yCoordinates[index] != (*sampledInputYs)[i]) { 9209d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka return false; 9219d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka } 9229d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka if (!times) { 9239d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka continue; 9249d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka } 9259d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka if (times[index] != (*sampledTimes)[i]) { 9269d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka return false; 9279d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka } 9289d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka } 9299d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka return true; 9309d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka} 9319d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka 93220b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka// Get a word that is detected by tracing the most probable string into codePointBuf and 93320b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka// returns probability of generating the word. 93420b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka/* static */ float ProximityInfoStateUtils::getMostProbableString( 93520b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka const ProximityInfo *const proximityInfo, const int sampledInputSize, 9360b1fa0c1c7572893365c019780357a817158e5eaKen Wakasa const std::vector<std::unordered_map<int, float>> *const charProbabilities, 93720b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka int *const codePointBuf) { 938a8ce88bf447c7de1ec7c35130d7cec8be63633cfKen Wakasa ASSERT(sampledInputSize >= 0); 93920b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka memset(codePointBuf, 0, sizeof(codePointBuf[0]) * MAX_WORD_LENGTH); 94020b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka int index = 0; 94120b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka float sumLogProbability = 0.0f; 94220b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka // TODO: Current implementation is greedy algorithm. DP would be efficient for many cases. 94320b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka for (int i = 0; i < sampledInputSize && index < MAX_WORD_LENGTH - 1; ++i) { 944830ba67498c6da53b38212dd9ac5ba318a00de11Satoshi Kataoka float minLogProbability = static_cast<float>(MAX_VALUE_FOR_WEIGHTING); 94520b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka int character = NOT_AN_INDEX; 9468ca9be17db2f1845c7c7a3b584507cf60c9ca53dKen Wakasa for (std::unordered_map<int, float>::const_iterator it = (*charProbabilities)[i].begin(); 94720b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka it != (*charProbabilities)[i].end(); ++it) { 94820b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka const float logProbability = (it->first != NOT_AN_INDEX) 94928c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa ? it->second + ProximityInfoParams::DEMOTION_LOG_PROBABILITY : it->second; 95020b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka if (logProbability < minLogProbability) { 95120b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka minLogProbability = logProbability; 95220b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka character = it->first; 95320b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka } 95420b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka } 95520b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka if (character != NOT_AN_INDEX) { 95633e38096ad68164a4033eb5a77df75a532f3a7ecKeisuke Kuroyanagi const int codePoint = proximityInfo->getCodePointOf(character); 95733e38096ad68164a4033eb5a77df75a532f3a7ecKeisuke Kuroyanagi if (codePoint == NOT_A_CODE_POINT) { 95833e38096ad68164a4033eb5a77df75a532f3a7ecKeisuke Kuroyanagi AKLOGE("Key index(%d) is not found. Cannot construct most probable string", 95933e38096ad68164a4033eb5a77df75a532f3a7ecKeisuke Kuroyanagi character); 96033e38096ad68164a4033eb5a77df75a532f3a7ecKeisuke Kuroyanagi ASSERT(false); 96133e38096ad68164a4033eb5a77df75a532f3a7ecKeisuke Kuroyanagi // Make the length zero, which means most probable string won't be used. 96233e38096ad68164a4033eb5a77df75a532f3a7ecKeisuke Kuroyanagi index = 0; 96333e38096ad68164a4033eb5a77df75a532f3a7ecKeisuke Kuroyanagi break; 96433e38096ad68164a4033eb5a77df75a532f3a7ecKeisuke Kuroyanagi } 96533e38096ad68164a4033eb5a77df75a532f3a7ecKeisuke Kuroyanagi codePointBuf[index] = codePoint; 96620b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka index++; 96720b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka } 96820b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka sumLogProbability += minLogProbability; 96920b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka } 97020b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka codePointBuf[index] = '\0'; 97120b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka return sumLogProbability; 97220b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka} 97320b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka 974d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka/* static */ void ProximityInfoStateUtils::dump(const bool isGeometric, const int inputSize, 975d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka const int *const inputXCoordinates, const int *const inputYCoordinates, 976d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka const int sampledInputSize, const std::vector<int> *const sampledInputXs, 977d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka const std::vector<int> *const sampledInputYs, 978e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka const std::vector<int> *const sampledTimes, 979d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka const std::vector<float> *const sampledSpeedRates, 980d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka const std::vector<int> *const sampledBeelineSpeedPercentiles) { 981d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka if (DEBUG_GEO_FULL) { 982d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka for (int i = 0; i < sampledInputSize; ++i) { 983e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka AKLOGI("Sampled(%d): x = %d, y = %d, time = %d", i, (*sampledInputXs)[i], 984e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka (*sampledInputYs)[i], sampledTimes ? (*sampledTimes)[i] : -1); 985d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka } 986d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka } 987d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka 988d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka std::stringstream originalX, originalY, sampledX, sampledY; 989d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka for (int i = 0; i < inputSize; ++i) { 990d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka originalX << inputXCoordinates[i]; 991d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka originalY << inputYCoordinates[i]; 992d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka if (i != inputSize - 1) { 993d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka originalX << ";"; 994d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka originalY << ";"; 995d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka } 996d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka } 997d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka AKLOGI("===== sampled points ====="); 998d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka for (int i = 0; i < sampledInputSize; ++i) { 999d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka if (isGeometric) { 1000d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka AKLOGI("%d: x = %d, y = %d, time = %d, relative speed = %.4f, beeline speed = %d", 1001e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka i, (*sampledInputXs)[i], (*sampledInputYs)[i], (*sampledTimes)[i], 1002e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka (*sampledSpeedRates)[i], (*sampledBeelineSpeedPercentiles)[i]); 1003d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka } 1004d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka sampledX << (*sampledInputXs)[i]; 1005d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka sampledY << (*sampledInputYs)[i]; 1006d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka if (i != sampledInputSize - 1) { 1007d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka sampledX << ";"; 1008d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka sampledY << ";"; 1009d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka } 1010d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka } 1011d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka AKLOGI("original points:\n%s, %s,\nsampled points:\n%s, %s,\n", 1012d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka originalX.str().c_str(), originalY.str().c_str(), sampledX.str().c_str(), 1013d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka sampledY.str().c_str()); 1014d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka} 1015ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka} // namespace latinime 1016