proximity_info_utils.h revision 830ba67498c6da53b38212dd9ac5ba318a00de11
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>
210c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa
22bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka#include "additional_proximity_chars.h"
23bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka#include "char_utils.h"
24bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka#include "defines.h"
250c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa#include "geometry_utils.h"
26bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka#include "hash_map_compat.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,
32bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            const hash_map_compat<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        }
40bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int lowerCode = toLowerCase(c);
41bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        hash_map_compat<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,
55bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            const hash_map_compat<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) {
900c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        return SQUARE_FLOAT(x1 - x2) + 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;
1010c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        const float lineLengthSqr = SQUARE_FLOAT(ray2x) + SQUARE_FLOAT(ray2y);
1020c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        const float projectionLengthSqr = dotProduct / lineLengthSqr;
1030c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa
1040c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        float projectionX;
1050c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        float projectionY;
1060c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        if (!extend && projectionLengthSqr < 0.0f) {
1070c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa            projectionX = x1;
1080c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa            projectionY = y1;
1090c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        } else if (!extend && projectionLengthSqr > 1.0f) {
1100c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa            projectionX = x2;
1110c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa            projectionY = y2;
1120c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        } else {
1130c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa            projectionX = x1 + projectionLengthSqr * ray2x;
1140c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa            projectionY = y1 + projectionLengthSqr * ray2y;
1150c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        }
1160c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        return getSquaredDistanceFloat(x, y, projectionX, projectionY);
1170c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa    }
1180c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa
1190c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa    // Normal distribution N(u, sigma^2).
1200c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa    struct NormalDistribution {
1210c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa     public:
1220c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        NormalDistribution(const float u, const float sigma)
1230c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa                : mU(u), mSigma(sigma),
1240c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa                  mPreComputedNonExpPart(1.0f / sqrtf(2.0f * M_PI_F * SQUARE_FLOAT(sigma))),
1250c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa                  mPreComputedExponentPart(-1.0f / (2.0f * SQUARE_FLOAT(sigma))) {}
1260c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa
1270c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        float getProbabilityDensity(const float x) const {
1280c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa            const float shiftedX = x - mU;
1290c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa            return mPreComputedNonExpPart * expf(mPreComputedExponentPart * SQUARE_FLOAT(shiftedX));
1300c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        }
1310c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa
1320c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa     private:
1330c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        DISALLOW_IMPLICIT_CONSTRUCTORS(NormalDistribution);
1340c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        const float mU; // mean value
1350c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        const float mSigma; // standard deviation
1360c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        const float mPreComputedNonExpPart; // = 1 / sqrt(2 * PI * sigma^2)
1370c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa        const float mPreComputedExponentPart; // = -1 / (2 * sigma^2)
1380c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa    }; // struct NormalDistribution
1390c2227ab991774768414d8ea60a469f005eb9f1aKen Wakasa
140bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka private:
141bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka    DISALLOW_IMPLICIT_CONSTRUCTORS(ProximityInfoUtils);
142bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka
143bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka    static bool isOnKey(const int *const keyXCoordinates, const int *const keyYCoordinates,
144bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            const int *const keyWidths, const int *keyHeights, const int keyId, const int x,
145bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            const int y) {
146bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        if (keyId < 0) return true; // NOT_A_ID is -1, but return whenever < 0 just in case
147bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int left = keyXCoordinates[keyId];
148bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int top = keyYCoordinates[keyId];
149bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int right = left + keyWidths[keyId] + 1;
150bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int bottom = top + keyHeights[keyId];
151bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        return left < right && top < bottom && x >= left && x < right && y >= top && y < bottom;
152bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka    }
153bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka
154d74214d7266bdd53fc69971fd82b59a7a92d8c63Ken Wakasa    static AK_FORCE_INLINE void calculateProximities(const int *const keyXCoordinates,
1556e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa            const int *const keyYCoordinates, const int *const keyWidths, const int *keyHeights,
1566e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa            const int *const proximityCharsArray, const int cellHeight, const int cellWidth,
157bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            const int gridWidth, const int mostCommonKeyWidth, const int keyCount,
158bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            const int x, const int y, const int primaryKey, const char *const localeStr,
159bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            const hash_map_compat<int, int> *const codeToKeyMap, int *proximities) {
160bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int mostCommonKeyWidthSquare = mostCommonKeyWidth * mostCommonKeyWidth;
161bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        int insertPos = 0;
162bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        proximities[insertPos++] = primaryKey;
1636e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa        const int startIndex = getStartIndexFromCoordinates(x, y, cellHeight, cellWidth, gridWidth);
164bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        if (startIndex >= 0) {
1656e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa            for (int i = 0; i < MAX_PROXIMITY_CHARS_SIZE; ++i) {
166bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                const int c = proximityCharsArray[startIndex + i];
167bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                if (c < KEYCODE_SPACE || c == primaryKey) {
168bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    continue;
169bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                }
170bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                const int keyIndex = getKeyIndexOf(keyCount, c, codeToKeyMap);
171bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                const bool onKey = isOnKey(keyXCoordinates, keyYCoordinates, keyWidths, keyHeights,
172bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        keyIndex, x, y);
173bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                const int distance = squaredLengthToEdge(keyXCoordinates, keyYCoordinates,
174bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        keyWidths, keyHeights, keyIndex, x, y);
175bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                if (onKey || distance < mostCommonKeyWidthSquare) {
176bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    proximities[insertPos++] = c;
1776e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa                    if (insertPos >= MAX_PROXIMITY_CHARS_SIZE) {
178bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        if (DEBUG_DICT) {
179bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                            ASSERT(false);
180bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        }
181bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        return;
182bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    }
183bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                }
184bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            }
185bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            const int additionalProximitySize =
186bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    AdditionalProximityChars::getAdditionalCharsSize(localeStr, primaryKey);
187bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            if (additionalProximitySize > 0) {
188bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                proximities[insertPos++] = ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE;
1896e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa                if (insertPos >= MAX_PROXIMITY_CHARS_SIZE) {
190bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    if (DEBUG_DICT) {
191bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        ASSERT(false);
192bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    }
193bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    return;
194bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                }
195bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka
196bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                const int *additionalProximityChars =
197bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        AdditionalProximityChars::getAdditionalChars(localeStr, primaryKey);
198bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                for (int j = 0; j < additionalProximitySize; ++j) {
199bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    const int ac = additionalProximityChars[j];
200bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    int k = 0;
201bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    for (; k < insertPos; ++k) {
202bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        if (ac == proximities[k]) {
203bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                            break;
204bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        }
205bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    }
206bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    if (k < insertPos) {
207bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        continue;
208bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    }
209bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    proximities[insertPos++] = ac;
2106e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa                    if (insertPos >= MAX_PROXIMITY_CHARS_SIZE) {
211bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        if (DEBUG_DICT) {
212bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                            ASSERT(false);
213bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        }
214bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                        return;
215bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                    }
216bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                }
217bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            }
218bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        }
219bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        // Add a delimiter for the proximity characters
2206e2ba9b01e61d214e8d6fad8d7093a80a97dd243Ken Wakasa        for (int i = insertPos; i < MAX_PROXIMITY_CHARS_SIZE; ++i) {
221bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            proximities[i] = NOT_A_CODE_POINT;
222bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        }
223bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka    }
224bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka
225bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka    static int squaredLengthToEdge(const int *const keyXCoordinates,
226bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            const int *const keyYCoordinates, const int *const keyWidths, const int *keyHeights,
227bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka            const int keyId, const int x, const int y) {
228bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        // NOT_A_ID is -1, but return whenever < 0 just in case
229830ba67498c6da53b38212dd9ac5ba318a00de11Satoshi Kataoka        if (keyId < 0) return MAX_VALUE_FOR_WEIGHTING;
230bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int left = keyXCoordinates[keyId];
231bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int top = keyYCoordinates[keyId];
232bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int right = left + keyWidths[keyId];
233bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int bottom = top + keyHeights[keyId];
234bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int edgeX = x < left ? left : (x > right ? right : x);
235bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int edgeY = y < top ? top : (y > bottom ? bottom : y);
236bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int dx = x - edgeX;
237bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        const int dy = y - edgeY;
238bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        return dx * dx + dy * dy;
239bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka    }
240bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka};
241bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka} // namespace latinime
242bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka#endif // LATINIME_PROXIMITY_INFO_UTILS_H
243