content: /*
   * Copyright (C) 2019 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.motionlayout.cycleEditor;
  
  import java.util.Arrays;
  
  /**
   * This produces oscillation patterns
   */
  public class Oscillator {
  
      float[] mPeriod = {20, 2, 4, 8, 200f};
      double[] mPosition = {0.0f, .3f, .5f, .8f, 1};
      double[] mArea;
      public static final int SIN_WAVE = 0;
      public static final int SQUARE_WAVE = 1;
      public static final int TRIANGLE_WAVE = 2;
      public static final int SAW_WAVE = 3;
      public static final int REVERSE_SAW_WAVE = 4;
      private int mType;
      double PI2 = Math.PI * 2;
  
      public Oscillator(float[] period, double[] pos, int type) {
          mType = type;
          mPeriod = period;
          mPosition = pos;
          mArea = new double[mPosition.length];
          mArea[0] = 0;
          for (int i = 1; i < mPeriod.length; i++) {
              float h = (mPeriod[i - 1] + mPeriod[i]) / 2;
              double w = mPosition[i] - mPosition[i - 1];
              mArea[i] = mArea[i - 1] + w * h;
          }
      }
  
      public Oscillator() {
          mArea = new double[mPosition.length];
          mArea[0] = 0;
          for (int i = 1; i < mPeriod.length; i++) {
              float h = (mPeriod[i - 1] + mPeriod[i]) / 2;
              double w = mPosition[i] - mPosition[i - 1];
              mArea[i] = mArea[i - 1] + w * h;
          }
      }
  
      double getP(double time) {
          if (time <= 0.0) {
              return 0.0;
          } else if (time >= 1) {
              return 1.0;
          }
          int index = Arrays.binarySearch(mPosition, time);
          if (index < 0) {
              index = -index - 1;
          }
  
          double t = time;
          double m =
                  (mPeriod[index] - mPeriod[index - 1]) / (mPosition[index] - mPosition[index - 1]);
          return mArea[index - 1]
                  + (mPeriod[index - 1] - m * mPosition[index - 1]) * (t - mPosition[index - 1])
                  + m * (t * t - mPosition[index - 1] * mPosition[index - 1]) / 2;
      }
  
      public double getValue(double time) {
  
          switch (mType) {
              default:
              case SIN_WAVE:
                  return Math.sin(PI2 * getP(time));
              case SQUARE_WAVE:
                  return Math.signum(0.5 - getP(time) % 1);
              case TRIANGLE_WAVE:
                  return 1 - Math.abs(((getP(time)) * 4 + 1) % 4 - 2);
              case SAW_WAVE:
                  return ((getP(time) * 2 + 1) % 2) - 1;
              case REVERSE_SAW_WAVE:
                  return (1 - ((getP(time) * 2 + 1) % 2));
  
          }
      }
  
      double getSinValue(double time) {
          return Math.sin(PI2 * getP(time));
      }
  
      double getSquareValue(double time) {
          return Math.signum(0.5 - getP(time) % 1);
      }
  
      double getTriangle(double time) {
          return 1 - Math.abs(((getP(time)) * 4 + 1) % 4 - 2);
      }
  
      double getSawValue(double time) {
          return ((getP(time) * 2 + 1) % 2) - 1;
      }
  
      double getReverseSawValue(double time) {
          return (1 - ((getP(time) * 2 + 1) % 2));
      }
  
  }
  