1bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka/*
2bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka * Copyright (C) 2013 The Android Open Source Project
3bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka *
4bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka * Licensed under the Apache License, Version 2.0 (the "License");
5bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka * you may not use this file except in compliance with the License.
6bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka * You may obtain a copy of the License at
7bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka *
8bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka *      http://www.apache.org/licenses/LICENSE-2.0
9bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka *
10bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka * Unless required by applicable law or agreed to in writing, software
11bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka * distributed under the License is distributed on an "AS IS" BASIS,
12bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka * See the License for the specific language governing permissions and
14bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka * limitations under the License.
15bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka */
16bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka
17bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka#ifndef LATINIME_PROXIMITY_INFO_UTILS_H
18bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka#define LATINIME_PROXIMITY_INFO_UTILS_H
19bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka
200c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa#include <cmath>
218ca9be17db2f1845c7c7a3b584507cf60c9ca53dKen Wakasa#include <unordered_map>
220c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa
23bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka#include "defines.h"
2494da44e43eac54047fb690c753d3af2a7d3a03c8Ken Wakasa#include "suggest/core/layout/additional_proximity_chars.h"
2529432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa#include "suggest/core/layout/geometry_utils.h"
26addea83bad5751308fef508d79c6989b8872f050Ken Wakasa#include "utils/char_utils.h"
27bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka
28bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataokanamespace latinime {
29bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataokaclass ProximityInfoUtils {
30bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka public:
31d74214d7266bdd53fc69971fd82b59a7a92d8c63Ken Wakasa    static AK_FORCE_INLINE int getKeyIndexOf(const int keyCount, const int c,
328ca9be17db2f1845c7c7a3b584507cf60c9ca53dKen Wakasa            const std::unordered_map<int, int> *const codeToKeyMap) {
33bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        if (keyCount == 0) {
34bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            // We do not have the coordinate data
35bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            return NOT_AN_INDEX;
36bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        }
37bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        if (c == NOT_A_CODE_POINT) {
38bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            return NOT_AN_INDEX;
39bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        }
40464d3ba43257da34ab165da8ba0af11e928aae5cKen Wakasa        const int lowerCode = CharUtils::toLowerCase(c);
418ca9be17db2f1845c7c7a3b584507cf60c9ca53dKen Wakasa        std::unordered_map<int, int>::const_iterator mapPos = codeToKeyMap->find(lowerCode);
42bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        if (mapPos != codeToKeyMap->end()) {
43bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            return mapPos->second;
44bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        }
45bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        return NOT_AN_INDEX;
46bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka    }
47bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka
48d74214d7266bdd53fc69971fd82b59a7a92d8c63Ken Wakasa    static AK_FORCE_INLINE void initializeProximities(const int *const inputCodes,
49bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            const int *const inputXCoordinates, const int *const inputYCoordinates,
50bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            const int inputSize, const int *const keyXCoordinates,
51bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            const int *const keyYCoordinates, const int *const keyWidths, const int *keyHeights,
526e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa            const int *const proximityCharsArray, const int cellHeight, const int cellWidth,
536e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa            const int gridWidth, const int mostCommonKeyWidth, const int keyCount,
546e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa            const char *const localeStr,
558ca9be17db2f1845c7c7a3b584507cf60c9ca53dKen Wakasa            const std::unordered_map<int, int> *const codeToKeyMap, int *inputProximities) {
56bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        // Initialize
57bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        // - mInputCodes
58bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        // - mNormalizedSquaredDistances
59bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        // TODO: Merge
60bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        for (int i = 0; i < inputSize; ++i) {
61bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            const int primaryKey = inputCodes[i];
62bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            const int x = inputXCoordinates[i];
63bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            const int y = inputYCoordinates[i];
646c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa            int *proximities = &inputProximities[i * MAX_PROXIMITY_CHARS_SIZE];
65bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            calculateProximities(keyXCoordinates, keyYCoordinates, keyWidths, keyHeights,
666e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa                    proximityCharsArray, cellHeight, cellWidth, gridWidth, mostCommonKeyWidth,
676e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa                    keyCount, x, y, primaryKey, localeStr, codeToKeyMap, proximities);
68bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        }
69bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka
70bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        if (DEBUG_PROXIMITY_CHARS) {
71bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            for (int i = 0; i < inputSize; ++i) {
72bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                AKLOGI("---");
736c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa                for (int j = 0; j < MAX_PROXIMITY_CHARS_SIZE; ++j) {
74bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    int proximityChar =
756c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa                            inputProximities[i * MAX_PROXIMITY_CHARS_SIZE + j];
76bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    proximityChar += 0;
77bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    AKLOGI("--- (%d)%c", i, proximityChar);
78bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                }
79bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            }
80bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        }
81bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka    }
82bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka
836e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa    static AK_FORCE_INLINE int getStartIndexFromCoordinates(const int x, const int y,
846e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa            const int cellHeight, const int cellWidth, const int gridWidth) {
856e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa        return ((y / cellHeight) * gridWidth + (x / cellWidth)) * MAX_PROXIMITY_CHARS_SIZE;
86bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka    }
87bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka
880c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa    static inline float getSquaredDistanceFloat(const float x1, const float y1, const float x2,
890c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa            const float y2) {
9029432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa        return GeometryUtils::SQUARE_FLOAT(x1 - x2) + GeometryUtils::SQUARE_FLOAT(y1 - y2);
910c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa    }
920c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa
930c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa    static inline float pointToLineSegSquaredDistanceFloat(const float x, const float y,
940c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        const float x1, const float y1, const float x2, const float y2, const bool extend) {
950c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        const float ray1x = x - x1;
960c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        const float ray1y = y - y1;
970c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        const float ray2x = x2 - x1;
980c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        const float ray2y = y2 - y1;
990c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa
1000c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        const float dotProduct = ray1x * ray2x + ray1y * ray2y;
10129432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa        const float lineLengthSqr = GeometryUtils::SQUARE_FLOAT(ray2x)
10229432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa                + GeometryUtils::SQUARE_FLOAT(ray2y);
103a1e0ef4836f59a9fd5a2b44ecb94c27227e159c6Keisuke Kuroyanagi        if (lineLengthSqr <= 0.0f) {
104a1e0ef4836f59a9fd5a2b44ecb94c27227e159c6Keisuke Kuroyanagi            // Return point to the point distance.
105a1e0ef4836f59a9fd5a2b44ecb94c27227e159c6Keisuke Kuroyanagi            return getSquaredDistanceFloat(x, y, x1, y1);
106a1e0ef4836f59a9fd5a2b44ecb94c27227e159c6Keisuke Kuroyanagi        }
1070c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        const float projectionLengthSqr = dotProduct / lineLengthSqr;
1080c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa
1090c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        float projectionX;
1100c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        float projectionY;
1110c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        if (!extend && projectionLengthSqr < 0.0f) {
1120c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa            projectionX = x1;
1130c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa            projectionY = y1;
1140c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        } else if (!extend && projectionLengthSqr > 1.0f) {
1150c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa            projectionX = x2;
1160c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa            projectionY = y2;
1170c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        } else {
1180c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa            projectionX = x1 + projectionLengthSqr * ray2x;
1190c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa            projectionY = y1 + projectionLengthSqr * ray2y;
1200c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        }
1210c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        return getSquaredDistanceFloat(x, y, projectionX, projectionY);
1220c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa    }
1230c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa
1247a06a792871c38517264fcb63b80a9c09bfe4766Keisuke Kuroynagi     static AK_FORCE_INLINE bool isMatchOrProximityChar(const ProximityType type) {
1257a06a792871c38517264fcb63b80a9c09bfe4766Keisuke Kuroynagi         return type == MATCH_CHAR || type == PROXIMITY_CHAR || type == ADDITIONAL_PROXIMITY_CHAR;
1267a06a792871c38517264fcb63b80a9c09bfe4766Keisuke Kuroynagi     }
1277a06a792871c38517264fcb63b80a9c09bfe4766Keisuke Kuroynagi
128bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka private:
129bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka    DISALLOW_IMPLICIT_CONSTRUCTORS(ProximityInfoUtils);
130bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka
131bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka    static bool isOnKey(const int *const keyXCoordinates, const int *const keyYCoordinates,
132bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            const int *const keyWidths, const int *keyHeights, const int keyId, const int x,
133bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            const int y) {
134bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        if (keyId < 0) return true; // NOT_A_ID is -1, but return whenever < 0 just in case
135bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int left = keyXCoordinates[keyId];
136bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int top = keyYCoordinates[keyId];
137bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int right = left + keyWidths[keyId] + 1;
138bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int bottom = top + keyHeights[keyId];
139bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        return left < right && top < bottom && x >= left && x < right && y >= top && y < bottom;
140bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka    }
141bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka
142d74214d7266bdd53fc69971fd82b59a7a92d8c63Ken Wakasa    static AK_FORCE_INLINE void calculateProximities(const int *const keyXCoordinates,
1436e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa            const int *const keyYCoordinates, const int *const keyWidths, const int *keyHeights,
1446e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa            const int *const proximityCharsArray, const int cellHeight, const int cellWidth,
145bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            const int gridWidth, const int mostCommonKeyWidth, const int keyCount,
146bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            const int x, const int y, const int primaryKey, const char *const localeStr,
1478ca9be17db2f1845c7c7a3b584507cf60c9ca53dKen Wakasa            const std::unordered_map<int, int> *const codeToKeyMap, int *proximities) {
148bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int mostCommonKeyWidthSquare = mostCommonKeyWidth * mostCommonKeyWidth;
149bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        int insertPos = 0;
150bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        proximities[insertPos++] = primaryKey;
1519fd50e34a863c18da42d6cfc8f62986a387dd5f8Keisuke Kuroyanagi        if (x == NOT_A_COORDINATE || y == NOT_A_COORDINATE) {
1529fd50e34a863c18da42d6cfc8f62986a387dd5f8Keisuke Kuroyanagi            for (int i = insertPos; i < MAX_PROXIMITY_CHARS_SIZE; ++i) {
1539fd50e34a863c18da42d6cfc8f62986a387dd5f8Keisuke Kuroyanagi                proximities[i] = NOT_A_CODE_POINT;
1549fd50e34a863c18da42d6cfc8f62986a387dd5f8Keisuke Kuroyanagi            }
1559fd50e34a863c18da42d6cfc8f62986a387dd5f8Keisuke Kuroyanagi            return;
1569fd50e34a863c18da42d6cfc8f62986a387dd5f8Keisuke Kuroyanagi        }
1576e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa        const int startIndex = getStartIndexFromCoordinates(x, y, cellHeight, cellWidth, gridWidth);
158bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        if (startIndex >= 0) {
1596e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa            for (int i = 0; i < MAX_PROXIMITY_CHARS_SIZE; ++i) {
160bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                const int c = proximityCharsArray[startIndex + i];
161bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                if (c < KEYCODE_SPACE || c == primaryKey) {
162bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    continue;
163bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                }
164bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                const int keyIndex = getKeyIndexOf(keyCount, c, codeToKeyMap);
165bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                const bool onKey = isOnKey(keyXCoordinates, keyYCoordinates, keyWidths, keyHeights,
166bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        keyIndex, x, y);
167bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                const int distance = squaredLengthToEdge(keyXCoordinates, keyYCoordinates,
168bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        keyWidths, keyHeights, keyIndex, x, y);
169bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                if (onKey || distance < mostCommonKeyWidthSquare) {
170bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    proximities[insertPos++] = c;
1716e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa                    if (insertPos >= MAX_PROXIMITY_CHARS_SIZE) {
172bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        if (DEBUG_DICT) {
173bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                            ASSERT(false);
174bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        }
175bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        return;
176bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    }
177bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                }
178bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            }
179bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            const int additionalProximitySize =
180bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    AdditionalProximityChars::getAdditionalCharsSize(localeStr, primaryKey);
181bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            if (additionalProximitySize > 0) {
182bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                proximities[insertPos++] = ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE;
1836e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa                if (insertPos >= MAX_PROXIMITY_CHARS_SIZE) {
184bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    if (DEBUG_DICT) {
185bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        ASSERT(false);
186bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    }
187bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    return;
188bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                }
189bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka
190bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                const int *additionalProximityChars =
191bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        AdditionalProximityChars::getAdditionalChars(localeStr, primaryKey);
192bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                for (int j = 0; j < additionalProximitySize; ++j) {
193bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    const int ac = additionalProximityChars[j];
194bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    int k = 0;
195bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    for (; k < insertPos; ++k) {
196bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        if (ac == proximities[k]) {
197bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                            break;
198bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        }
199bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    }
200bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    if (k < insertPos) {
201bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        continue;
202bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    }
203bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    proximities[insertPos++] = ac;
2046e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa                    if (insertPos >= MAX_PROXIMITY_CHARS_SIZE) {
205bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        if (DEBUG_DICT) {
206bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                            ASSERT(false);
207bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        }
208bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        return;
209bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    }
210bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                }
211bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            }
212bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        }
213bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        // Add a delimiter for the proximity characters
2146e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa        for (int i = insertPos; i < MAX_PROXIMITY_CHARS_SIZE; ++i) {
215bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            proximities[i] = NOT_A_CODE_POINT;
216bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        }
217bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka    }
218bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka
219bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka    static int squaredLengthToEdge(const int *const keyXCoordinates,
220bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            const int *const keyYCoordinates, const int *const keyWidths, const int *keyHeights,
221bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            const int keyId, const int x, const int y) {
222bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        // NOT_A_ID is -1, but return whenever < 0 just in case
223830ba67498c6da53b38212dd9ac5ba318a00de11Satoshi Kataoka        if (keyId < 0) return MAX_VALUE_FOR_WEIGHTING;
224bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int left = keyXCoordinates[keyId];
225bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int top = keyYCoordinates[keyId];
226bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int right = left + keyWidths[keyId];
227bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int bottom = top + keyHeights[keyId];
228bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int edgeX = x < left ? left : (x > right ? right : x);
229bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int edgeY = y < top ? top : (y > bottom ? bottom : y);
230bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int dx = x - edgeX;
231bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int dy = y - edgeY;
232bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        return dx * dx + dy * dy;
233bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka    }
234bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka};
235bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka} // namespace latinime
236bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka#endif // LATINIME_PROXIMITY_INFO_UTILS_H
237