| /* |
| * Copyright (C) 2013 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.inputmethod.keyboard.internal; |
| |
| import com.android.inputmethod.annotations.UsedForTesting; |
| |
| /** |
| * Interpolates XY-coordinates using Cubic Hermite Curve. |
| */ |
| public final class HermiteInterpolator { |
| private int[] mXCoords; |
| private int[] mYCoords; |
| private int mMinPos; |
| private int mMaxPos; |
| |
| // Working variable to calculate interpolated value. |
| /** The coordinates of the start point of the interval. */ |
| public int mP1X, mP1Y; |
| /** The coordinates of the end point of the interval. */ |
| public int mP2X, mP2Y; |
| /** The slope of the tangent at the start point. */ |
| public float mSlope1X, mSlope1Y; |
| /** The slope of the tangent at the end point. */ |
| public float mSlope2X, mSlope2Y; |
| /** The interpolated coordinates. |
| * The return variables of {@link #interpolate(float)} to avoid instantiations. |
| */ |
| public float mInterpolatedX, mInterpolatedY; |
| |
| public HermiteInterpolator() { |
| // Nothing to do with here. |
| } |
| |
| /** |
| * Reset this interpolator to point XY-coordinates data. |
| * @param xCoords the array of x-coordinates. Valid data are in left-open interval |
| * <code>[minPos, maxPos)</code>. |
| * @param yCoords the array of y-coordinates. Valid data are in left-open interval |
| * <code>[minPos, maxPos)</code>. |
| * @param minPos the minimum index of left-open interval of valid data. |
| * @param maxPos the maximum index of left-open interval of valid data. |
| */ |
| @UsedForTesting |
| public void reset(final int[] xCoords, final int[] yCoords, final int minPos, |
| final int maxPos) { |
| mXCoords = xCoords; |
| mYCoords = yCoords; |
| mMinPos = minPos; |
| mMaxPos = maxPos; |
| } |
| |
| /** |
| * Set interpolation interval. |
| * <p> |
| * The start and end coordinates of the interval will be set in {@link #mP1X}, {@link #mP1Y}, |
| * {@link #mP2X}, and {@link #mP2Y}. The slope of the tangents at start and end points will be |
| * set in {@link #mSlope1X}, {@link #mSlope1Y}, {@link #mSlope2X}, and {@link #mSlope2Y}. |
| * |
| * @param p0 the index just before interpolation interval. If <code>p1</code> points the start |
| * of valid points, <code>p0</code> must be less than <code>minPos</code> of |
| * {@link #reset(int[],int[],int,int)}. |
| * @param p1 the start index of interpolation interval. |
| * @param p2 the end index of interpolation interval. |
| * @param p3 the index just after interpolation interval. If <code>p2</code> points the end of |
| * valid points, <code>p3</code> must be equal or greater than <code>maxPos</code> of |
| * {@link #reset(int[],int[],int,int)}. |
| */ |
| @UsedForTesting |
| public void setInterval(final int p0, final int p1, final int p2, final int p3) { |
| mP1X = mXCoords[p1]; |
| mP1Y = mYCoords[p1]; |
| mP2X = mXCoords[p2]; |
| mP2Y = mYCoords[p2]; |
| // A(ax,ay) is the vector p1->p2. |
| final int ax = mP2X - mP1X; |
| final int ay = mP2Y - mP1Y; |
| |
| // Calculate the slope of the tangent at p1. |
| if (p0 >= mMinPos) { |
| // p1 has previous valid point p0. |
| // The slope of the tangent is half of the vector p0->p2. |
| mSlope1X = (mP2X - mXCoords[p0]) / 2.0f; |
| mSlope1Y = (mP2Y - mYCoords[p0]) / 2.0f; |
| } else if (p3 < mMaxPos) { |
| // p1 has no previous valid point, but p2 has next valid point p3. |
| // B(bx,by) is the slope vector of the tangent at p2. |
| final float bx = (mXCoords[p3] - mP1X) / 2.0f; |
| final float by = (mYCoords[p3] - mP1Y) / 2.0f; |
| final float crossProdAB = ax * by - ay * bx; |
| final float dotProdAB = ax * bx + ay * by; |
| final float normASquare = ax * ax + ay * ay; |
| final float invHalfNormASquare = 1.0f / normASquare / 2.0f; |
| // The slope of the tangent is the mirror image of vector B to vector A. |
| mSlope1X = invHalfNormASquare * (dotProdAB * ax + crossProdAB * ay); |
| mSlope1Y = invHalfNormASquare * (dotProdAB * ay - crossProdAB * ax); |
| } else { |
| // p1 and p2 have no previous valid point. (Interval has only point p1 and p2) |
| mSlope1X = ax; |
| mSlope1Y = ay; |
| } |
| |
| // Calculate the slope of the tangent at p2. |
| if (p3 < mMaxPos) { |
| // p2 has next valid point p3. |
| // The slope of the tangent is half of the vector p1->p3. |
| mSlope2X = (mXCoords[p3] - mP1X) / 2.0f; |
| mSlope2Y = (mYCoords[p3] - mP1Y) / 2.0f; |
| } else if (p0 >= mMinPos) { |
| // p2 has no next valid point, but p1 has previous valid point p0. |
| // B(bx,by) is the slope vector of the tangent at p1. |
| final float bx = (mP2X - mXCoords[p0]) / 2.0f; |
| final float by = (mP2Y - mYCoords[p0]) / 2.0f; |
| final float crossProdAB = ax * by - ay * bx; |
| final float dotProdAB = ax * bx + ay * by; |
| final float normASquare = ax * ax + ay * ay; |
| final float invHalfNormASquare = 1.0f / normASquare / 2.0f; |
| // The slope of the tangent is the mirror image of vector B to vector A. |
| mSlope2X = invHalfNormASquare * (dotProdAB * ax + crossProdAB * ay); |
| mSlope2Y = invHalfNormASquare * (dotProdAB * ay - crossProdAB * ax); |
| } else { |
| // p1 and p2 has no previous valid point. (Interval has only point p1 and p2) |
| mSlope2X = ax; |
| mSlope2Y = ay; |
| } |
| } |
| |
| /** |
| * Calculate interpolation value at <code>t</code> in unit interval <code>[0,1]</code>. |
| * <p> |
| * On the unit interval [0,1], given a starting point p1 at t=0 and an ending point p2 at t=1 |
| * with the slope of the tangent m1 at p1 and m2 at p2, the polynomial of cubic Hermite curve |
| * can be defined by |
| * p(t) = (1+2t)(1-t)(1-t)*p1 + t(1-t)(1-t)*m1 + (3-2t)t^2*p2 + (t-1)t^2*m2 |
| * where t is an element of [0,1]. |
| * <p> |
| * The interpolated XY-coordinates will be set in {@link #mInterpolatedX} and |
| * {@link #mInterpolatedY}. |
| * |
| * @param t the interpolation parameter. The value must be in close interval <code>[0,1]</code>. |
| */ |
| @UsedForTesting |
| public void interpolate(final float t) { |
| final float omt = 1.0f - t; |
| final float tm2 = 2.0f * t; |
| final float k1 = 1.0f + tm2; |
| final float k2 = 3.0f - tm2; |
| final float omt2 = omt * omt; |
| final float t2 = t * t; |
| mInterpolatedX = (k1 * mP1X + t * mSlope1X) * omt2 + (k2 * mP2X - omt * mSlope2X) * t2; |
| mInterpolatedY = (k1 * mP1Y + t * mSlope1Y) * omt2 + (k2 * mP2Y - omt * mSlope2Y) * t2; |
| } |
| } |