StepCurve.java

/*
 * Copyright (C) 2020 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 androidx.constraintlayout.core.motion.utils;

import java.text.DecimalFormat;
import java.util.Arrays;

/**
 * This class translates a series of floating point values into a continuous
 * curve for use in an easing function including quantize functions
 * it is used with the "spline(0,0.3,0.3,0.5,...0.9,1)" it should start at 0 and end at one 1
 */
public class StepCurve extends Easing {
    private final static boolean DEBUG = false;
    MonotonicCurveFit mCurveFit;

    StepCurve(String configString) {
        // done this way for efficiency
        str = configString;
        double[] values = new double[str.length() / 2];
        int start = configString.indexOf('(') + 1;
        int off1 = configString.indexOf(',', start);
        int count = 0;
        while (off1 != -1) {
            String tmp = configString.substring(start, off1).trim();
            values[count++] = Double.parseDouble(tmp);
            off1 = configString.indexOf(',', start = off1 + 1);
        }
        off1 = configString.indexOf(')', start);
        String tmp = configString.substring(start, off1).trim();
        values[count++] = Double.parseDouble(tmp);

        mCurveFit = genSpline(Arrays.copyOf(values, count));
    }

    private static MonotonicCurveFit genSpline(String str) {
        String wave = str;
        String[] sp = wave.split("\s+");
        double[] values = new double[sp.length];
        for (int i = 0; i < values.length; i++) {
            values[i] = Double.parseDouble(sp[i]);
        }
        return genSpline(values);
    }

    private static MonotonicCurveFit genSpline(double[] values) {
        int length = values.length * 3 - 2;
        int len = values.length - 1;
        double gap = 1.0 / len;
        double[][] points = new double[length][1];
        double[] time = new double[length];
        for (int i = 0; i < values.length; i++) {
            double v = values[i];
            points[i + len][0] = v;
            time[i + len] = i * gap;
            if (i > 0) {
                points[i + len * 2][0] = v + 1;
                time[i + len * 2] = i * gap + 1;

                points[i - 1][0] = v - 1 - gap;
                time[i - 1] = i * gap + -1 - gap;
            }
        }
        if (DEBUG) {
            String t = "t ";
            String v = "v ";
            DecimalFormat df = new DecimalFormat("#.00");
            for (int i = 0; i < time.length; i++) {
                t += df.format(time[i]) + " ";
                v += df.format(points[i][0]) + " ";
            }
            System.out.println(t);
            System.out.println(v);
        }
        MonotonicCurveFit ms = new MonotonicCurveFit(time, points);
        System.out.println(" 0 " + ms.getPos(0, 0));
        System.out.println(" 1 " + ms.getPos(1, 0));
        return ms;
    }

    public double getDiff(double x) {
        return mCurveFit.getSlope(x, 0);
    }

    public double get(double x) {
        return mCurveFit.getPos(x, 0);
    }
}