1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.inputmethod.keyboard.internal; 18 19 import com.android.inputmethod.annotations.UsedForTesting; 20 import com.android.inputmethod.keyboard.internal.MatrixUtils.MatrixOperationFailedException; 21 22 import android.util.Log; 23 24 import java.util.Arrays; 25 26 /** 27 * Utilities to smooth coordinates. Currently, we calculate 3d least squares formula by using 28 * Lagrangian smoothing 29 */ 30 @UsedForTesting 31 public class SmoothingUtils { 32 private static final String TAG = SmoothingUtils.class.getSimpleName(); 33 private static final boolean DEBUG = false; 34 SmoothingUtils()35 private SmoothingUtils() { 36 // not allowed to instantiate publicly 37 } 38 39 /** 40 * Find a most likely 3d least squares formula for specified coordinates. 41 * "retval" should be a 1x4 size matrix. 42 */ 43 @UsedForTesting get3DParameters(final float[] xs, final float[] ys, final float[][] retval)44 public static void get3DParameters(final float[] xs, final float[] ys, 45 final float[][] retval) throws MatrixOperationFailedException { 46 final int COEFF_COUNT = 4; // Coefficient count for 3d smoothing 47 if (retval.length != COEFF_COUNT || retval[0].length != 1) { 48 Log.d(TAG, "--- invalid length of 3d retval " + retval.length + ", " 49 + retval[0].length); 50 return; 51 } 52 final int N = xs.length; 53 // TODO: Never isntantiate the matrix 54 final float[][] m0 = new float[COEFF_COUNT][COEFF_COUNT]; 55 final float[][] m0Inv = new float[COEFF_COUNT][COEFF_COUNT]; 56 final float[][] m1 = new float[COEFF_COUNT][N]; 57 final float[][] m2 = new float[N][1]; 58 59 // m0 60 for (int i = 0; i < COEFF_COUNT; ++i) { 61 Arrays.fill(m0[i], 0); 62 for (int j = 0; j < COEFF_COUNT; ++j) { 63 final int pow = i + j; 64 for (int k = 0; k < N; ++k) { 65 m0[i][j] += (float) Math.pow(xs[k], pow); 66 } 67 } 68 } 69 // m0Inv 70 MatrixUtils.inverse(m0, m0Inv); 71 if (DEBUG) { 72 MatrixUtils.dump("m0-1", m0Inv); 73 } 74 75 // m1 76 for (int i = 0; i < COEFF_COUNT; ++i) { 77 for (int j = 0; j < N; ++j) { 78 m1[i][j] = (i == 0) ? 1.0f : m1[i - 1][j] * xs[j]; 79 } 80 } 81 82 // m2 83 for (int i = 0; i < N; ++i) { 84 m2[i][0] = ys[i]; 85 } 86 87 final float[][] m0Invxm1 = new float[COEFF_COUNT][N]; 88 if (DEBUG) { 89 MatrixUtils.dump("a0", m0Inv); 90 MatrixUtils.dump("a1", m1); 91 } 92 MatrixUtils.multiply(m0Inv, m1, m0Invxm1); 93 if (DEBUG) { 94 MatrixUtils.dump("a2", m0Invxm1); 95 MatrixUtils.dump("a3", m2); 96 } 97 MatrixUtils.multiply(m0Invxm1, m2, retval); 98 if (DEBUG) { 99 MatrixUtils.dump("result", retval); 100 } 101 } 102 } 103