18fbd55229243cb66c03d5ea1f79dfb39f596590dsatok/*
28fbd55229243cb66c03d5ea1f79dfb39f596590dsatok * Copyright (C) 2011 The Android Open Source Project
38fbd55229243cb66c03d5ea1f79dfb39f596590dsatok *
48fbd55229243cb66c03d5ea1f79dfb39f596590dsatok * Licensed under the Apache License, Version 2.0 (the "License");
58fbd55229243cb66c03d5ea1f79dfb39f596590dsatok * you may not use this file except in compliance with the License.
68fbd55229243cb66c03d5ea1f79dfb39f596590dsatok * You may obtain a copy of the License at
78fbd55229243cb66c03d5ea1f79dfb39f596590dsatok *
88fbd55229243cb66c03d5ea1f79dfb39f596590dsatok *      http://www.apache.org/licenses/LICENSE-2.0
98fbd55229243cb66c03d5ea1f79dfb39f596590dsatok *
108fbd55229243cb66c03d5ea1f79dfb39f596590dsatok * Unless required by applicable law or agreed to in writing, software
118fbd55229243cb66c03d5ea1f79dfb39f596590dsatok * distributed under the License is distributed on an "AS IS" BASIS,
128fbd55229243cb66c03d5ea1f79dfb39f596590dsatok * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138fbd55229243cb66c03d5ea1f79dfb39f596590dsatok * See the License for the specific language governing permissions and
148fbd55229243cb66c03d5ea1f79dfb39f596590dsatok * limitations under the License.
158fbd55229243cb66c03d5ea1f79dfb39f596590dsatok */
168fbd55229243cb66c03d5ea1f79dfb39f596590dsatok
17f88f9dbbdec309c01feda06edc142470ba13cb2fKeisuke Kuroyanagi#define LOG_TAG "LatinIME: proximity_info.cpp"
18f88f9dbbdec309c01feda06edc142470ba13cb2fKeisuke Kuroyanagi
1929432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa#include "suggest/core/layout/proximity_info.h"
2029432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa
21865e6cf49764f3a411ee32861d927b15653ee398Keisuke Kuroyanagi#include <algorithm>
22f1008c550168e50f930ea1e043000b395ce0f129Ken Wakasa#include <cstring>
23625778fd36f4b304d9bc70c87be7fdc0f717cb50Tom Ouyang#include <cmath>
248fbd55229243cb66c03d5ea1f79dfb39f596590dsatok
253b088a2f365a9ce06f58243c83cb961ea2920b7eKen Wakasa#include "defines.h"
26bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa#include "jni.h"
2794da44e43eac54047fb690c753d3af2a7d3a03c8Ken Wakasa#include "suggest/core/layout/additional_proximity_chars.h"
2829432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa#include "suggest/core/layout/geometry_utils.h"
2929432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa#include "suggest/core/layout/proximity_info_params.h"
30addea83bad5751308fef508d79c6989b8872f050Ken Wakasa#include "utils/char_utils.h"
318fbd55229243cb66c03d5ea1f79dfb39f596590dsatok
328fbd55229243cb66c03d5ea1f79dfb39f596590dsatoknamespace latinime {
33ce9e52a12a6af8fca0eba42aaae24602fbd5c998Ken Wakasa
346e66349ed1d37c24a1a23bf117df6750ad53d322Ken Wakasastatic AK_FORCE_INLINE void safeGetOrFillZeroIntArrayRegion(JNIEnv *env, jintArray jArray,
356e66349ed1d37c24a1a23bf117df6750ad53d322Ken Wakasa        jsize len, jint *buffer) {
36bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa    if (jArray && buffer) {
37bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa        env->GetIntArrayRegion(jArray, 0, len, buffer);
38bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa    } else if (buffer) {
3944d9c1ebfc2a847233190f6201ae97b22df30ae7Ken Wakasa        memset(buffer, 0, len * sizeof(buffer[0]));
40de2f8424ea7e201ab8ee0d3c64fac0b52514d24eYusuke Nojima    }
41de2f8424ea7e201ab8ee0d3c64fac0b52514d24eYusuke Nojima}
42de2f8424ea7e201ab8ee0d3c64fac0b52514d24eYusuke Nojima
436e66349ed1d37c24a1a23bf117df6750ad53d322Ken Wakasastatic AK_FORCE_INLINE void safeGetOrFillZeroFloatArrayRegion(JNIEnv *env, jfloatArray jArray,
446e66349ed1d37c24a1a23bf117df6750ad53d322Ken Wakasa        jsize len, jfloat *buffer) {
45bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa    if (jArray && buffer) {
46bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa        env->GetFloatArrayRegion(jArray, 0, len, buffer);
47bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa    } else if (buffer) {
4844d9c1ebfc2a847233190f6201ae97b22df30ae7Ken Wakasa        memset(buffer, 0, len * sizeof(buffer[0]));
49bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa    }
50bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa}
51bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa
524ef27c035892888df82d9c9f32ac12ed48c8308fJean ChalardProximityInfo::ProximityInfo(JNIEnv *env, const int keyboardWidth, const int keyboardHeight,
534ef27c035892888df82d9c9f32ac12ed48c8308fJean Chalard        const int gridWidth, const int gridHeight, const int mostCommonKeyWidth,
544ef27c035892888df82d9c9f32ac12ed48c8308fJean Chalard        const int mostCommonKeyHeight, const jintArray proximityChars, const int keyCount,
554ef27c035892888df82d9c9f32ac12ed48c8308fJean Chalard        const jintArray keyXCoordinates, const jintArray keyYCoordinates,
564ef27c035892888df82d9c9f32ac12ed48c8308fJean Chalard        const jintArray keyWidths, const jintArray keyHeights, const jintArray keyCharCodes,
574ef27c035892888df82d9c9f32ac12ed48c8308fJean Chalard        const jfloatArray sweetSpotCenterXs, const jfloatArray sweetSpotCenterYs,
584ef27c035892888df82d9c9f32ac12ed48c8308fJean Chalard        const jfloatArray sweetSpotRadii)
596c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa        : GRID_WIDTH(gridWidth), GRID_HEIGHT(gridHeight), MOST_COMMON_KEY_WIDTH(mostCommonKeyWidth),
60a70ee6e3b3fe65acab205b935ebd52e7bb0eccb8satok          MOST_COMMON_KEY_WIDTH_SQUARE(mostCommonKeyWidth * mostCommonKeyWidth),
6187fdde6ec48844ddbb482c50fbda226c63ca5e85Keisuke Kuroynagi          NORMALIZED_SQUARED_MOST_COMMON_KEY_HYPOTENUSE(1.0f +
6229432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa                  GeometryUtils::SQUARE_FLOAT(static_cast<float>(mostCommonKeyHeight) /
6387fdde6ec48844ddbb482c50fbda226c63ca5e85Keisuke Kuroynagi                          static_cast<float>(mostCommonKeyWidth))),
64817e517e463cb32726ff5a62196ac8744848e29bsatok          CELL_WIDTH((keyboardWidth + gridWidth - 1) / gridWidth),
650e1f656c1be7f2916cf57c94d99b001795856270Yusuke Nojima          CELL_HEIGHT((keyboardHeight + gridHeight - 1) / gridHeight),
66865e6cf49764f3a411ee32861d927b15653ee398Keisuke Kuroyanagi          KEY_COUNT(std::min(keyCount, MAX_KEY_COUNT_IN_A_KEYBOARD)),
6795a49a527ac9c2c97cfcc758bd6f0d58fb4ad9c0Keisuke Kuroyanagi          KEYBOARD_WIDTH(keyboardWidth), KEYBOARD_HEIGHT(keyboardHeight),
68625778fd36f4b304d9bc70c87be7fdc0f717cb50Tom Ouyang          KEYBOARD_HYPOTENUSE(hypotf(KEYBOARD_WIDTH, KEYBOARD_HEIGHT)),
69a4c1f1c1fde5e9492523842dd95a4c9f17f40c3aYusuke Nojima          HAS_TOUCH_POSITION_CORRECTION_DATA(keyCount > 0 && keyXCoordinates && keyYCoordinates
70a4c1f1c1fde5e9492523842dd95a4c9f17f40c3aYusuke Nojima                  && keyWidths && keyHeights && keyCharCodes && sweetSpotCenterXs
71162c211b44c1546b2e9be36e0cec50de497217a9Ken Wakasa                  && sweetSpotCenterYs && sweetSpotRadii),
721d516fb1b08002cea6db060c9f8196d96ba5e428Ken Wakasa          mProximityCharsArray(new int[GRID_WIDTH * GRID_HEIGHT * MAX_PROXIMITY_CHARS_SIZE
736c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa                  /* proximityCharsLength */]),
742fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa          mLowerCodePointToKeyMap() {
756c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa    /* Let's check the input array length here to make sure */
766c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa    const jsize proximityCharsLength = env->GetArrayLength(proximityChars);
776c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa    if (proximityCharsLength != GRID_WIDTH * GRID_HEIGHT * MAX_PROXIMITY_CHARS_SIZE) {
786c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa        AKLOGE("Invalid proximityCharsLength: %d", proximityCharsLength);
796c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa        ASSERT(false);
806c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa        return;
816c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa    }
82817e517e463cb32726ff5a62196ac8744848e29bsatok    if (DEBUG_PROXIMITY_INFO) {
836c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa        AKLOGI("Create proximity info array %d", proximityCharsLength);
84817e517e463cb32726ff5a62196ac8744848e29bsatok    }
856c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa    safeGetOrFillZeroIntArrayRegion(env, proximityChars, proximityCharsLength,
866c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa            mProximityCharsArray);
87bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa    safeGetOrFillZeroIntArrayRegion(env, keyXCoordinates, KEY_COUNT, mKeyXCoordinates);
88bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa    safeGetOrFillZeroIntArrayRegion(env, keyYCoordinates, KEY_COUNT, mKeyYCoordinates);
89bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa    safeGetOrFillZeroIntArrayRegion(env, keyWidths, KEY_COUNT, mKeyWidths);
90bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa    safeGetOrFillZeroIntArrayRegion(env, keyHeights, KEY_COUNT, mKeyHeights);
91f2789819bd005b5b0581e8439601b5501306327dKen Wakasa    safeGetOrFillZeroIntArrayRegion(env, keyCharCodes, KEY_COUNT, mKeyCodePoints);
92bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa    safeGetOrFillZeroFloatArrayRegion(env, sweetSpotCenterXs, KEY_COUNT, mSweetSpotCenterXs);
93bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa    safeGetOrFillZeroFloatArrayRegion(env, sweetSpotCenterYs, KEY_COUNT, mSweetSpotCenterYs);
94bb005f787f4e00bd832e6a78797be10af2994061Ken Wakasa    safeGetOrFillZeroFloatArrayRegion(env, sweetSpotRadii, KEY_COUNT, mSweetSpotRadii);
956b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka    initializeG();
960e1f656c1be7f2916cf57c94d99b001795856270Yusuke Nojima}
970e1f656c1be7f2916cf57c94d99b001795856270Yusuke Nojima
988fbd55229243cb66c03d5ea1f79dfb39f596590dsatokProximityInfo::~ProximityInfo() {
998fbd55229243cb66c03d5ea1f79dfb39f596590dsatok    delete[] mProximityCharsArray;
1008fbd55229243cb66c03d5ea1f79dfb39f596590dsatok}
101817e517e463cb32726ff5a62196ac8744848e29bsatok
102817e517e463cb32726ff5a62196ac8744848e29bsatokbool ProximityInfo::hasSpaceProximity(const int x, const int y) const {
103744dab691e45ff8c5ca9745ee673f50060bcb7a9satok    if (x < 0 || y < 0) {
104744dab691e45ff8c5ca9745ee673f50060bcb7a9satok        if (DEBUG_DICT) {
1059fb6f47a6a11f62d134d4d6259181ac987fc1ad3satok            AKLOGI("HasSpaceProximity: Illegal coordinates (%d, %d)", x, y);
106f2789819bd005b5b0581e8439601b5501306327dKen Wakasa            // TODO: Enable this assertion.
107ccebd5cefe0b6b17676edd8639f62bb708a7dd2eKen Wakasa            //ASSERT(false);
108744dab691e45ff8c5ca9745ee673f50060bcb7a9satok        }
109744dab691e45ff8c5ca9745ee673f50060bcb7a9satok        return false;
110744dab691e45ff8c5ca9745ee673f50060bcb7a9satok    }
111744dab691e45ff8c5ca9745ee673f50060bcb7a9satok
1126e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa    const int startIndex = ProximityInfoUtils::getStartIndexFromCoordinates(x, y,
1136e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa            CELL_HEIGHT, CELL_WIDTH, GRID_WIDTH);
114817e517e463cb32726ff5a62196ac8744848e29bsatok    if (DEBUG_PROXIMITY_INFO) {
1159fb6f47a6a11f62d134d4d6259181ac987fc1ad3satok        AKLOGI("hasSpaceProximity: index %d, %d, %d", startIndex, x, y);
116817e517e463cb32726ff5a62196ac8744848e29bsatok    }
1171d516fb1b08002cea6db060c9f8196d96ba5e428Ken Wakasa    int *proximityCharsArray = mProximityCharsArray;
118817e517e463cb32726ff5a62196ac8744848e29bsatok    for (int i = 0; i < MAX_PROXIMITY_CHARS_SIZE; ++i) {
119817e517e463cb32726ff5a62196ac8744848e29bsatok        if (DEBUG_PROXIMITY_INFO) {
1209fb6f47a6a11f62d134d4d6259181ac987fc1ad3satok            AKLOGI("Index: %d", mProximityCharsArray[startIndex + i]);
121817e517e463cb32726ff5a62196ac8744848e29bsatok        }
1223e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka        if (proximityCharsArray[startIndex + i] == KEYCODE_SPACE) {
123817e517e463cb32726ff5a62196ac8744848e29bsatok            return true;
124817e517e463cb32726ff5a62196ac8744848e29bsatok        }
125817e517e463cb32726ff5a62196ac8744848e29bsatok    }
126817e517e463cb32726ff5a62196ac8744848e29bsatok    return false;
1278fbd55229243cb66c03d5ea1f79dfb39f596590dsatok}
128ce9e52a12a6af8fca0eba42aaae24602fbd5c998Ken Wakasa
1290edab9d2fcc30667c79aa9221dbb27f042d8b455Satoshi Kataokafloat ProximityInfo::getNormalizedSquaredDistanceFromCenterFloatG(
1300052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi        const int keyId, const int x, const int y, const bool isGeometric) const {
1310052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi    const float centerX = static_cast<float>(getKeyCenterXOfKeyIdG(keyId, x, isGeometric));
1320052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi    const float centerY = static_cast<float>(getKeyCenterYOfKeyIdG(keyId, y, isGeometric));
133e7398cdb2b48eb52dc9676c8efa75bc7cb9af3e9Satoshi Kataoka    const float touchX = static_cast<float>(x);
134e7398cdb2b48eb52dc9676c8efa75bc7cb9af3e9Satoshi Kataoka    const float touchY = static_cast<float>(y);
1350c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa    return ProximityInfoUtils::getSquaredDistanceFloat(centerX, centerY, touchX, touchY)
1360052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi            / GeometryUtils::SQUARE_FLOAT(static_cast<float>(getMostCommonKeyWidth()));
137e7398cdb2b48eb52dc9676c8efa75bc7cb9af3e9Satoshi Kataoka}
138e7398cdb2b48eb52dc9676c8efa75bc7cb9af3e9Satoshi Kataoka
139f2789819bd005b5b0581e8439601b5501306327dKen Wakasaint ProximityInfo::getCodePointOf(const int keyIndex) const {
1406b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka    if (keyIndex < 0 || keyIndex >= KEY_COUNT) {
141f2789819bd005b5b0581e8439601b5501306327dKen Wakasa        return NOT_A_CODE_POINT;
1426b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka    }
1432fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    return mKeyIndexToLowerCodePointG[keyIndex];
1442fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa}
1452fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa
1462fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasaint ProximityInfo::getOriginalCodePointOf(const int keyIndex) const {
1472fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    if (keyIndex < 0 || keyIndex >= KEY_COUNT) {
1482fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        return NOT_A_CODE_POINT;
1492fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    }
1502fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    return mKeyIndexToOriginalCodePoint[keyIndex];
1516b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka}
1526b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka
1536b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataokavoid ProximityInfo::initializeG() {
154e7398cdb2b48eb52dc9676c8efa75bc7cb9af3e9Satoshi Kataoka    // TODO: Optimize
1556b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka    for (int i = 0; i < KEY_COUNT; ++i) {
156f2789819bd005b5b0581e8439601b5501306327dKen Wakasa        const int code = mKeyCodePoints[i];
157464d3ba43257da34ab165da8ba0af11e928aae5cKen Wakasa        const int lowerCode = CharUtils::toLowerCase(code);
1586b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka        mCenterXsG[i] = mKeyXCoordinates[i] + mKeyWidths[i] / 2;
1596b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka        mCenterYsG[i] = mKeyYCoordinates[i] + mKeyHeights[i] / 2;
1600052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi        if (hasTouchPositionCorrectionData()) {
1610052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi            // Computes sweet spot center points for geometric input.
1620052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi            const float verticalScale = ProximityInfoParams::VERTICAL_SWEET_SPOT_SCALE_G;
1630052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi            const float sweetSpotCenterY = static_cast<float>(mSweetSpotCenterYs[i]);
1640052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi            const float gapY = sweetSpotCenterY - mCenterYsG[i];
1650052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi            mSweetSpotCenterYsG[i] = static_cast<int>(mCenterYsG[i] + gapY * verticalScale);
1660052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi        }
1672fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        mLowerCodePointToKeyMap[lowerCode] = i;
1682fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        mKeyIndexToOriginalCodePoint[i] = code;
1692fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        mKeyIndexToLowerCodePointG[i] = lowerCode;
1706b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka    }
1716b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka    for (int i = 0; i < KEY_COUNT; i++) {
1726b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka        mKeyKeyDistancesG[i][i] = 0;
1736b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka        for (int j = i + 1; j < KEY_COUNT; j++) {
1740052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi            if (hasTouchPositionCorrectionData()) {
1750052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi                // Computes distances using sweet spots if they exist.
1760052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi                // We have two types of Y coordinate sweet spots, for geometric and for the others.
1770052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi                // The sweet spots for geometric input are used for calculating key-key distances
1780052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi                // here.
1790052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi                mKeyKeyDistancesG[i][j] = GeometryUtils::getDistanceInt(
1800052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi                        mSweetSpotCenterXs[i], mSweetSpotCenterYsG[i],
1810052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi                        mSweetSpotCenterXs[j], mSweetSpotCenterYsG[j]);
1820052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi            } else {
1830052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi                mKeyKeyDistancesG[i][j] = GeometryUtils::getDistanceInt(
1840052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi                        mCenterXsG[i], mCenterYsG[i], mCenterXsG[j], mCenterYsG[j]);
1850052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi            }
1866b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka            mKeyKeyDistancesG[j][i] = mKeyKeyDistancesG[i][j];
1876b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka        }
1886b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka    }
1896b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka}
1906b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka
1910052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi// referencePointX is used only for keys wider than most common key width. When the referencePointX
1920052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi// is NOT_A_COORDINATE, this method calculates the return value without using the line segment.
1930052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi// isGeometric is currently not used because we don't have extra X coordinates sweet spots for
1940052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi// geometric input.
1950052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagiint ProximityInfo::getKeyCenterXOfKeyIdG(
1960052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi        const int keyId, const int referencePointX, const bool isGeometric) const {
1970052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi    if (keyId < 0) {
1980052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi        return 0;
1990052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi    }
2000052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi    int centerX = (hasTouchPositionCorrectionData()) ? static_cast<int>(mSweetSpotCenterXs[keyId])
2010052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi            : mCenterXsG[keyId];
2020052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi    const int keyWidth = mKeyWidths[keyId];
2030052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi    if (referencePointX != NOT_A_COORDINATE
2040052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi            && keyWidth > getMostCommonKeyWidth()) {
2050052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi        // For keys wider than most common keys, we use a line segment instead of the center point;
2060052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi        // thus, centerX is adjusted depending on referencePointX.
2070052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi        const int keyWidthHalfDiff = (keyWidth - getMostCommonKeyWidth()) / 2;
2080052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi        if (referencePointX < centerX - keyWidthHalfDiff) {
2090052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi            centerX -= keyWidthHalfDiff;
2100052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi        } else if (referencePointX > centerX + keyWidthHalfDiff) {
2110052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi            centerX += keyWidthHalfDiff;
2120052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi        } else {
2130052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi            centerX = referencePointX;
2140052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi        }
2156b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka    }
2160052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi    return centerX;
2176b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka}
2186b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka
21977ec8713cef76a14bf7df27a1f669711afa88f54Keisuke Kuroynagi// When the referencePointY is NOT_A_COORDINATE, this method calculates the return value without
22077ec8713cef76a14bf7df27a1f669711afa88f54Keisuke Kuroynagi// using the line segment.
2210052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagiint ProximityInfo::getKeyCenterYOfKeyIdG(
222d0d0113983f000fadc9da89271200620330b0356Keisuke Kuroyanagi        const int keyId, const int referencePointY, const bool isGeometric) const {
2230052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi    // TODO: Remove "isGeometric" and have separate "proximity_info"s for gesture and typing.
2240052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi    if (keyId < 0) {
2250052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi        return 0;
2260052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi    }
22777ec8713cef76a14bf7df27a1f669711afa88f54Keisuke Kuroynagi    int centerY;
2280052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi    if (!hasTouchPositionCorrectionData()) {
22977ec8713cef76a14bf7df27a1f669711afa88f54Keisuke Kuroynagi        centerY = mCenterYsG[keyId];
2300052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi    } else if (isGeometric) {
23177ec8713cef76a14bf7df27a1f669711afa88f54Keisuke Kuroynagi        centerY = static_cast<int>(mSweetSpotCenterYsG[keyId]);
2320052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi    } else {
23377ec8713cef76a14bf7df27a1f669711afa88f54Keisuke Kuroynagi        centerY = static_cast<int>(mSweetSpotCenterYs[keyId]);
2346b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka    }
23577ec8713cef76a14bf7df27a1f669711afa88f54Keisuke Kuroynagi    if (referencePointY != NOT_A_COORDINATE &&
23677ec8713cef76a14bf7df27a1f669711afa88f54Keisuke Kuroynagi            centerY + mKeyHeights[keyId] > KEYBOARD_HEIGHT && centerY < referencePointY) {
23777ec8713cef76a14bf7df27a1f669711afa88f54Keisuke Kuroynagi        // When the distance between center point and bottom edge of the keyboard is shorter than
23877ec8713cef76a14bf7df27a1f669711afa88f54Keisuke Kuroynagi        // the key height, we assume the key is located at the bottom row of the keyboard.
23977ec8713cef76a14bf7df27a1f669711afa88f54Keisuke Kuroynagi        // The center point is extended to the bottom edge for such keys.
24077ec8713cef76a14bf7df27a1f669711afa88f54Keisuke Kuroynagi        return referencePointY;
24177ec8713cef76a14bf7df27a1f669711afa88f54Keisuke Kuroynagi    }
24277ec8713cef76a14bf7df27a1f669711afa88f54Keisuke Kuroynagi    return centerY;
2436b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka}
2446b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka
245ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagiint ProximityInfo::getKeyKeyDistanceG(const int keyId0, const int keyId1) const {
2466b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka    if (keyId0 >= 0 && keyId1 >= 0) {
2476b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka        return mKeyKeyDistancesG[keyId0][keyId1];
2486b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka    }
249830ba67498c6da53b38212dd9ac5ba318a00de11Satoshi Kataoka    return MAX_VALUE_FOR_WEIGHTING;
2506b4a1d79eba19a55715e20b4ee75b3934f397db2Satoshi Kataoka}
251ce9e52a12a6af8fca0eba42aaae24602fbd5c998Ken Wakasa} // namespace latinime
252