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>
224ef27c035892888df82d9c9f32ac12ed48c8308fJean Chalard#include <vector>
230c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa
24bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka#include "defines.h"
2594da44e43eac54047fb690c753d3af2a7d3a03c8Ken Wakasa#include "suggest/core/layout/additional_proximity_chars.h"
2629432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa#include "suggest/core/layout/geometry_utils.h"
27addea83bad5751308fef508d79c6989b8872f050Ken Wakasa#include "utils/char_utils.h"
28bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka
29bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataokanamespace latinime {
30bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataokaclass ProximityInfoUtils {
31bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka public:
32d74214d7266bdd53fc69971fd82b59a7a92d8c63Ken Wakasa    static AK_FORCE_INLINE int getKeyIndexOf(const int keyCount, const int c,
338ca9be17db2f1845c7c7a3b584507cf60c9ca53dKen Wakasa            const std::unordered_map<int, int> *const codeToKeyMap) {
34bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        if (keyCount == 0) {
35bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            // We do not have the coordinate data
36bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            return NOT_AN_INDEX;
37bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        }
38bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        if (c == NOT_A_CODE_POINT) {
39bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            return NOT_AN_INDEX;
40bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        }
41464d3ba43257da34ab165da8ba0af11e928aae5cKen Wakasa        const int lowerCode = CharUtils::toLowerCase(c);
428ca9be17db2f1845c7c7a3b584507cf60c9ca53dKen Wakasa        std::unordered_map<int, int>::const_iterator mapPos = codeToKeyMap->find(lowerCode);
43bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        if (mapPos != codeToKeyMap->end()) {
44bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            return mapPos->second;
45bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        }
46bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        return NOT_AN_INDEX;
47bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka    }
48bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka
49d74214d7266bdd53fc69971fd82b59a7a92d8c63Ken Wakasa    static AK_FORCE_INLINE void initializeProximities(const int *const inputCodes,
50bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            const int *const inputXCoordinates, const int *const inputYCoordinates,
51bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            const int inputSize, const int *const keyXCoordinates,
52bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            const int *const keyYCoordinates, const int *const keyWidths, const int *keyHeights,
536e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa            const int *const proximityCharsArray, const int cellHeight, const int cellWidth,
546e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa            const int gridWidth, const int mostCommonKeyWidth, const int keyCount,
554ef27c035892888df82d9c9f32ac12ed48c8308fJean Chalard            const std::vector<int> *locale,
568ca9be17db2f1845c7c7a3b584507cf60c9ca53dKen Wakasa            const std::unordered_map<int, int> *const codeToKeyMap, int *inputProximities) {
57bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        // Initialize
58bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        // - mInputCodes
59bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        // - mNormalizedSquaredDistances
60bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        // TODO: Merge
61bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        for (int i = 0; i < inputSize; ++i) {
62bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            const int primaryKey = inputCodes[i];
63bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            const int x = inputXCoordinates[i];
64bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            const int y = inputYCoordinates[i];
656c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa            int *proximities = &inputProximities[i * MAX_PROXIMITY_CHARS_SIZE];
66bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            calculateProximities(keyXCoordinates, keyYCoordinates, keyWidths, keyHeights,
676e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa                    proximityCharsArray, cellHeight, cellWidth, gridWidth, mostCommonKeyWidth,
684ef27c035892888df82d9c9f32ac12ed48c8308fJean Chalard                    keyCount, x, y, primaryKey, locale, codeToKeyMap, proximities);
69bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        }
70bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka
71bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        if (DEBUG_PROXIMITY_CHARS) {
72bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            for (int i = 0; i < inputSize; ++i) {
73bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                AKLOGI("---");
746c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa                for (int j = 0; j < MAX_PROXIMITY_CHARS_SIZE; ++j) {
75bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    int proximityChar =
766c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa                            inputProximities[i * MAX_PROXIMITY_CHARS_SIZE + j];
77bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    proximityChar += 0;
78bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    AKLOGI("--- (%d)%c", i, proximityChar);
79bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                }
80bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            }
81bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        }
82bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka    }
83bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka
846e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa    static AK_FORCE_INLINE int getStartIndexFromCoordinates(const int x, const int y,
856e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa            const int cellHeight, const int cellWidth, const int gridWidth) {
866e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa        return ((y / cellHeight) * gridWidth + (x / cellWidth)) * MAX_PROXIMITY_CHARS_SIZE;
87bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka    }
88bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka
890c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa    static inline float getSquaredDistanceFloat(const float x1, const float y1, const float x2,
900c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa            const float y2) {
9129432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa        return GeometryUtils::SQUARE_FLOAT(x1 - x2) + GeometryUtils::SQUARE_FLOAT(y1 - y2);
920c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa    }
930c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa
940c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa    static inline float pointToLineSegSquaredDistanceFloat(const float x, const float y,
950c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        const float x1, const float y1, const float x2, const float y2, const bool extend) {
960c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        const float ray1x = x - x1;
970c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        const float ray1y = y - y1;
980c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        const float ray2x = x2 - x1;
990c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        const float ray2y = y2 - y1;
1000c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa
1010c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        const float dotProduct = ray1x * ray2x + ray1y * ray2y;
10229432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa        const float lineLengthSqr = GeometryUtils::SQUARE_FLOAT(ray2x)
10329432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa                + GeometryUtils::SQUARE_FLOAT(ray2y);
104a1e0ef4836f59a9fd5a2b44ecb94c27227e159c6Keisuke Kuroyanagi        if (lineLengthSqr <= 0.0f) {
105a1e0ef4836f59a9fd5a2b44ecb94c27227e159c6Keisuke Kuroyanagi            // Return point to the point distance.
106a1e0ef4836f59a9fd5a2b44ecb94c27227e159c6Keisuke Kuroyanagi            return getSquaredDistanceFloat(x, y, x1, y1);
107a1e0ef4836f59a9fd5a2b44ecb94c27227e159c6Keisuke Kuroyanagi        }
1080c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        const float projectionLengthSqr = dotProduct / lineLengthSqr;
1090c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa
1100c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        float projectionX;
1110c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        float projectionY;
1120c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        if (!extend && projectionLengthSqr < 0.0f) {
1130c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa            projectionX = x1;
1140c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa            projectionY = y1;
1150c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        } else if (!extend && projectionLengthSqr > 1.0f) {
1160c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa            projectionX = x2;
1170c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa            projectionY = y2;
1180c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        } else {
1190c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa            projectionX = x1 + projectionLengthSqr * ray2x;
1200c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa            projectionY = y1 + projectionLengthSqr * ray2y;
1210c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        }
1220c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        return getSquaredDistanceFloat(x, y, projectionX, projectionY);
1230c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa    }
1240c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa
1257a06a792871c38517264fcb63b80a9c09bfe4766Keisuke Kuroynagi     static AK_FORCE_INLINE bool isMatchOrProximityChar(const ProximityType type) {
1267a06a792871c38517264fcb63b80a9c09bfe4766Keisuke Kuroynagi         return type == MATCH_CHAR || type == PROXIMITY_CHAR || type == ADDITIONAL_PROXIMITY_CHAR;
1277a06a792871c38517264fcb63b80a9c09bfe4766Keisuke Kuroynagi     }
1287a06a792871c38517264fcb63b80a9c09bfe4766Keisuke Kuroynagi
129bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka private:
130bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka    DISALLOW_IMPLICIT_CONSTRUCTORS(ProximityInfoUtils);
131bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka
132bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka    static bool isOnKey(const int *const keyXCoordinates, const int *const keyYCoordinates,
133bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            const int *const keyWidths, const int *keyHeights, const int keyId, const int x,
134bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            const int y) {
135bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        if (keyId < 0) return true; // NOT_A_ID is -1, but return whenever < 0 just in case
136bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int left = keyXCoordinates[keyId];
137bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int top = keyYCoordinates[keyId];
138bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int right = left + keyWidths[keyId] + 1;
139bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int bottom = top + keyHeights[keyId];
140bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        return left < right && top < bottom && x >= left && x < right && y >= top && y < bottom;
141bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka    }
142bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka
143d74214d7266bdd53fc69971fd82b59a7a92d8c63Ken Wakasa    static AK_FORCE_INLINE void calculateProximities(const int *const keyXCoordinates,
1446e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa            const int *const keyYCoordinates, const int *const keyWidths, const int *keyHeights,
1456e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa            const int *const proximityCharsArray, const int cellHeight, const int cellWidth,
146bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            const int gridWidth, const int mostCommonKeyWidth, const int keyCount,
1474ef27c035892888df82d9c9f32ac12ed48c8308fJean Chalard            const int x, const int y, const int primaryKey, const std::vector<int> *locale,
1488ca9be17db2f1845c7c7a3b584507cf60c9ca53dKen Wakasa            const std::unordered_map<int, int> *const codeToKeyMap, int *proximities) {
149bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int mostCommonKeyWidthSquare = mostCommonKeyWidth * mostCommonKeyWidth;
150bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        int insertPos = 0;
151bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        proximities[insertPos++] = primaryKey;
1529fd50e34a863c18da42d6cfc8f62986a387dd5f8Keisuke Kuroyanagi        if (x == NOT_A_COORDINATE || y == NOT_A_COORDINATE) {
1539fd50e34a863c18da42d6cfc8f62986a387dd5f8Keisuke Kuroyanagi            for (int i = insertPos; i < MAX_PROXIMITY_CHARS_SIZE; ++i) {
1549fd50e34a863c18da42d6cfc8f62986a387dd5f8Keisuke Kuroyanagi                proximities[i] = NOT_A_CODE_POINT;
1559fd50e34a863c18da42d6cfc8f62986a387dd5f8Keisuke Kuroyanagi            }
1569fd50e34a863c18da42d6cfc8f62986a387dd5f8Keisuke Kuroyanagi            return;
1579fd50e34a863c18da42d6cfc8f62986a387dd5f8Keisuke Kuroyanagi        }
1586e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa        const int startIndex = getStartIndexFromCoordinates(x, y, cellHeight, cellWidth, gridWidth);
159bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        if (startIndex >= 0) {
1606e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa            for (int i = 0; i < MAX_PROXIMITY_CHARS_SIZE; ++i) {
161bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                const int c = proximityCharsArray[startIndex + i];
162bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                if (c < KEYCODE_SPACE || c == primaryKey) {
163bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    continue;
164bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                }
165bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                const int keyIndex = getKeyIndexOf(keyCount, c, codeToKeyMap);
166bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                const bool onKey = isOnKey(keyXCoordinates, keyYCoordinates, keyWidths, keyHeights,
167bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        keyIndex, x, y);
168bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                const int distance = squaredLengthToEdge(keyXCoordinates, keyYCoordinates,
169bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        keyWidths, keyHeights, keyIndex, x, y);
170bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                if (onKey || distance < mostCommonKeyWidthSquare) {
171bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    proximities[insertPos++] = c;
1726e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa                    if (insertPos >= MAX_PROXIMITY_CHARS_SIZE) {
173bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        if (DEBUG_DICT) {
174bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                            ASSERT(false);
175bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        }
176bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        return;
177bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    }
178bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                }
179bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            }
180bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            const int additionalProximitySize =
1814ef27c035892888df82d9c9f32ac12ed48c8308fJean Chalard                    AdditionalProximityChars::getAdditionalCharsSize(locale, primaryKey);
182bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            if (additionalProximitySize > 0) {
183bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                proximities[insertPos++] = ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE;
1846e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa                if (insertPos >= MAX_PROXIMITY_CHARS_SIZE) {
185bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    if (DEBUG_DICT) {
186bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        ASSERT(false);
187bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    }
188bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    return;
189bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                }
190bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka
191bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                const int *additionalProximityChars =
1924ef27c035892888df82d9c9f32ac12ed48c8308fJean Chalard                        AdditionalProximityChars::getAdditionalChars(locale, primaryKey);
193bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                for (int j = 0; j < additionalProximitySize; ++j) {
194bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    const int ac = additionalProximityChars[j];
195bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    int k = 0;
196bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    for (; k < insertPos; ++k) {
197bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        if (ac == proximities[k]) {
198bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                            break;
199bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        }
200bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    }
201bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    if (k < insertPos) {
202bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        continue;
203bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    }
204bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    proximities[insertPos++] = ac;
2056e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa                    if (insertPos >= MAX_PROXIMITY_CHARS_SIZE) {
206bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        if (DEBUG_DICT) {
207bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                            ASSERT(false);
208bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        }
209bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        return;
210bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    }
211bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                }
212bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            }
213bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        }
214bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        // Add a delimiter for the proximity characters
2156e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa        for (int i = insertPos; i < MAX_PROXIMITY_CHARS_SIZE; ++i) {
216bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            proximities[i] = NOT_A_CODE_POINT;
217bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        }
218bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka    }
219bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka
220bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka    static int squaredLengthToEdge(const int *const keyXCoordinates,
221bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            const int *const keyYCoordinates, const int *const keyWidths, const int *keyHeights,
222bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            const int keyId, const int x, const int y) {
223bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        // NOT_A_ID is -1, but return whenever < 0 just in case
224830ba67498c6da53b38212dd9ac5ba318a00de11Satoshi Kataoka        if (keyId < 0) return MAX_VALUE_FOR_WEIGHTING;
225bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int left = keyXCoordinates[keyId];
226bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int top = keyYCoordinates[keyId];
227bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int right = left + keyWidths[keyId];
228bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int bottom = top + keyHeights[keyId];
229bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int edgeX = x < left ? left : (x > right ? right : x);
230bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int edgeY = y < top ? top : (y > bottom ? bottom : y);
231bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int dx = x - edgeX;
232bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int dy = y - edgeY;
233bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        return dx * dx + dy * dy;
234bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka    }
235bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka};
236bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka} // namespace latinime
237bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka#endif // LATINIME_PROXIMITY_INFO_UTILS_H
238