/*
* Copyright 2015 Daniel Dittmar
*
* 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 dan.dit.whatsthat.util.general;
import android.support.annotation.NonNull;
import android.view.animation.Interpolator;
/**
* Mathematical helper class to create continuous functions that can be evaluated at every given
* double value. The functions are immutable objects. The functions may be any kind of function, most likely
* though this will be linear or quadratic functions.
* Created by daniel on 06.09.15.
*/
public abstract class MathFunction {
/**
* Evaluates this function at the given argument value.
* @param at The argument value to evaluate.
* @return The function value at the given value.
*/
public abstract double evaluate(double at);
public static class AnimationInterpolator extends MathFunction {
private final Interpolator mInterpolator;
public AnimationInterpolator(@NonNull android.view.animation.Interpolator interpolator) {
mInterpolator = interpolator;
}
@Override
public double evaluate(double at) {
return mInterpolator.getInterpolation((float) at);
}
}
public static class Max extends MathFunction {
private final MathFunction mOtherValueFunction;
private final double mMinimalAllowedValue;
public Max(double minimalAllowedValue, @NonNull MathFunction otherValueFunction) {
mOtherValueFunction = otherValueFunction;
mMinimalAllowedValue = minimalAllowedValue;
}
@Override
public double evaluate(double at) {
return Math.max(mMinimalAllowedValue, mOtherValueFunction.evaluate(at));
}
}
/**
* A modified basic sinus function. That is f(x)= a*sin(b*x)+c. The period is 2 * PI / b.
*/
public static class Sinus extends MathFunction {
private final double mAmplitude;
private final double mPeriodFactor;
private final double mOffset;
/**
* Creates a new sinus function. Will take values between (-amplitue and +amplitude) +
* offset for any given input.
* @param amplitude The amplitude.
* @param period Sinus period.
* @param offset Offset of the sinus values.
*/
public Sinus(double amplitude, double period, double offset) {
mAmplitude = amplitude;
mPeriodFactor = 2. * Math.PI / period;
mOffset = offset;
}
@Override
public double evaluate(double at) {
return mAmplitude * Math.sin(mPeriodFactor * at) + mOffset;
}
}
/**
* A linear one dimensional function. That is f(x) = a*x + c for some double
* values a and c.
*/
public static class LinearInterpolation extends MathFunction {
private final double mStartArg;
private final double mStartValue;
private final double mAscend;
/**
* Creates a linear function interpolating the given pair of argument-value pairs.
* The function will be linear and pass through the points (startArg,startValue) and
* (endArg, endValue). The order and signum of all values is arbitrary.
* @param startArg The first argument value.
* @param startValue The first target value.
* @param endArg The second argument value.
* @param endValue The second target value.
*/
public LinearInterpolation(double startArg, double startValue, double endArg, double endValue) {
mStartArg = startArg;
mStartValue = startValue;
mAscend = (endValue - mStartValue) / (endArg - mStartArg);
}
@Override
public double evaluate(double at) {
return mStartValue + mAscend * (at - mStartArg);
}
public static double evaluate(double startArg, double startValue, double endArg, double
endValue, double at) {
return startValue + (endValue - startValue) / (endArg - startArg) * (at - startArg);
}
public static float evaluate(float startArg, float startValue, float endArg, float
endValue,float at) {
return startValue + (endValue - startValue) / (endArg - startArg) * (at - startArg);
}
}
/**
* A quadratic one dimensional function. That is f(x)=a*x² + b*x + c for some
* double values a, b and c.
*/
public static class QuadraticInterpolation extends MathFunction {
private final double mA;
private final double mExtremalValue;
private final double mExtremalArg;
/**
* Creates a quadratic function from the following constraints:
* f'(extremalArg)=0, that means the extremal value will be at the extremalArg value.
* f(extremalArg)=extremalValue and f(otherArg)=otherValue for interpolating.
* @param extremalArg The first argument value that is also the point of a local minimum or maximum.
* @param extremalValue The evaluated value at the given extremal argument value.
* @param otherArg The second argument value.
* @param otherValue The second target value.
*/
public QuadraticInterpolation(double extremalArg, double extremalValue, double otherArg, double otherValue) {
// a(x - mx)² + mv , es gilt a(ox - mx)² + mv = ov also (ov - mv) / (ox - mx)² = a
mA = (otherValue - extremalValue) / ((otherArg - extremalArg) * (otherArg - extremalArg));
mExtremalArg = extremalArg;
mExtremalValue = extremalValue;
}
@Override
public double evaluate(double at) {
return mA * (at - mExtremalArg) * (at - mExtremalArg) + mExtremalValue;
}
public static float evaluate(float extremalArg, float extremalValue, float otherArg,
float otherValue, float at) {
return (otherValue - extremalValue) / ((otherArg - extremalArg) * (otherArg - extremalArg))
* (at - extremalArg) * (at - extremalArg) + extremalValue;
}
public static double evaluate(double extremalArg, double extremalValue, double otherArg,
double otherValue, double at) {
return (otherValue - extremalValue) / ((otherArg - extremalArg) * (otherArg - extremalArg))
* (at - extremalArg) * (at - extremalArg) + extremalValue;
}
}
}