1376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen/* 2376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen * Copyright (C) 2015 The Android Open Source Project 3376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen * 4376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen * Licensed under the Apache License, Version 2.0 (the "License"); 5376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen * you may not use this file except in compliance with the License. 6376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen * You may obtain a copy of the License at 7376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen * 8376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen * http://www.apache.org/licenses/LICENSE-2.0 9376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen * 10376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen * Unless required by applicable law or agreed to in writing, software 11376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen * distributed under the License is distributed on an "AS IS" BASIS, 12376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen * See the License for the specific language governing permissions and 14376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen * limitations under the License. 15376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen */ 16376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen 17376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassenpackage android.support.v4.view.animation; 18376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen 19376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassenimport android.graphics.Path; 20376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassenimport android.graphics.PathMeasure; 21376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassenimport android.view.animation.Interpolator; 22376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen 23376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen/** 24376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen * A path interpolator implementation compatible with API 4+. 25376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen */ 26376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassenclass PathInterpolatorDonut implements Interpolator { 27376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen 28376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen /** 29376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen * Governs the accuracy of the approximation of the {@link Path}. 30376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen */ 31376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen private static final float PRECISION = 0.002f; 32376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen 33376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen private final float[] mX; 34376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen private final float[] mY; 35376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen 36376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen public PathInterpolatorDonut(Path path) { 37376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen final PathMeasure pathMeasure = new PathMeasure(path, false /* forceClosed */); 38376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen 39376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen final float pathLength = pathMeasure.getLength(); 40376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen final int numPoints = (int) (pathLength / PRECISION) + 1; 41376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen 42376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen mX = new float[numPoints]; 43376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen mY = new float[numPoints]; 44376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen 45376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen final float[] position = new float[2]; 46376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen for (int i = 0; i < numPoints; ++i) { 47376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen final float distance = (i * pathLength) / (numPoints - 1); 48376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen pathMeasure.getPosTan(distance, position, null /* tangent */); 49376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen 50376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen mX[i] = position[0]; 51376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen mY[i] = position[1]; 52376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen } 53376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen } 54376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen 55376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen public PathInterpolatorDonut(float controlX, float controlY) { 56376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen this(createQuad(controlX, controlY)); 57376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen } 58376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen 59376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen public PathInterpolatorDonut(float controlX1, float controlY1, 60376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen float controlX2, float controlY2) { 61376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen this(createCubic(controlX1, controlY1, controlX2, controlY2)); 62376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen } 63376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen 64376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen @Override 65376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen public float getInterpolation(float t) { 66376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen if (t <= 0.0f) { 67376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen return 0.0f; 68376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen } else if (t >= 1.0f) { 69376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen return 1.0f; 70376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen } 71376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen 72376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen // Do a binary search for the correct x to interpolate between. 73376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen int startIndex = 0; 74376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen int endIndex = mX.length - 1; 75376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen while (endIndex - startIndex > 1) { 76376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen int midIndex = (startIndex + endIndex) / 2; 77376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen if (t < mX[midIndex]) { 78376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen endIndex = midIndex; 79376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen } else { 80376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen startIndex = midIndex; 81376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen } 82376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen } 83376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen 84376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen final float xRange = mX[endIndex] - mX[startIndex]; 85376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen if (xRange == 0) { 86376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen return mY[startIndex]; 87376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen } 88376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen 89376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen final float tInRange = t - mX[startIndex]; 90376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen final float fraction = tInRange / xRange; 91376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen 92376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen final float startY = mY[startIndex]; 93376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen final float endY = mY[endIndex]; 94376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen 95376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen return startY + (fraction * (endY - startY)); 96376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen } 97376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen 98376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen private static Path createQuad(float controlX, float controlY) { 99376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen final Path path = new Path(); 100376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen path.moveTo(0.0f, 0.0f); 101376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen path.quadTo(controlX, controlY, 1.0f, 1.0f); 102376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen return path; 103376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen } 104376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen 105376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen private static Path createCubic(float controlX1, float controlY1, 106376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen float controlX2, float controlY2) { 107376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen final Path path = new Path(); 108376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen path.moveTo(0.0f, 0.0f); 109376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen path.cubicTo(controlX1, controlY1, controlX2, controlY2, 1.0f, 1.0f); 110376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen return path; 111376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen } 112376f90c159c74a267a5b5e13a5d71273980a72dfJustin Klaassen} 113