// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.util;
/**
* Contains various math utilities used throughout Chrome Mobile.
*/
public class MathUtils {
private MathUtils() {}
/**
* Returns the passed in value if it resides within the specified range (inclusive). If not,
* it will return the closest boundary from the range. The ordering of the boundary values does
* not matter.
*
* @param value The value to be compared against the range.
* @param a First boundary range value.
* @param b Second boundary range value.
* @return The passed in value if it is within the range, otherwise the closest boundary value.
*/
public static int clamp(int value, int a, int b) {
int min = (a > b) ? b : a;
int max = (a > b) ? a : b;
if (value < min) {
value = min;
} else if (value > max) {
value = max;
}
return value;
}
/**
* Returns the passed in value if it resides within the specified range (inclusive). If not,
* it will return the closest boundary from the range. The ordering of the boundary values does
* not matter.
*
* @param value The value to be compared against the range.
* @param a First boundary range value.
* @param b Second boundary range value.
* @return The passed in value if it is within the range, otherwise the closest boundary value.
*/
public static long clamp(long value, long a, long b) {
long min = (a > b) ? b : a;
long max = (a > b) ? a : b;
if (value < min) {
value = min;
} else if (value > max) {
value = max;
}
return value;
}
/**
* Returns the passed in value if it resides within the specified range (inclusive). If not,
* it will return the closest boundary from the range. The ordering of the boundary values does
* not matter.
*
* @param value The value to be compared against the range.
* @param a First boundary range value.
* @param b Second boundary range value.
* @return The passed in value if it is within the range, otherwise the closest boundary value.
*/
public static float clamp(float value, float a, float b) {
float min = (a > b) ? b : a;
float max = (a > b) ? a : b;
if (value < min) {
value = min;
} else if (value > max) {
value = max;
}
return value;
}
/**
* Computes a%b that is positive. Note that result of % operation is not always positive.
* @return a%b >= 0 ? a%b : a%b + b
*/
public static int positiveModulo(int a, int b) {
int mod = a % b;
return mod >= 0 ? mod : mod + b;
}
/**
* Moves {@code value} forward to {@code target} based on {@code speed}.
* @param value The current value.
* @param target The target value.
* @param speed How far to move {@code value} to {@code target}. 0 doesn't move it at all. 1
* moves it to {@code target}.
* @return The new interpolated value.
*/
public static float interpolate(float value, float target, float speed) {
return (value + (target - value) * speed);
}
/**
* Smooth a value between 0 and 1.
* @param t The value to smooth.
* @return The smoothed value between 0 and 1.
*/
public static float smoothstep(float t) {
return t * t * (3.0f - 2.0f * t);
}
/**
* Scales the provided dimension such that it is just large enough to fit
* the target width and height.
*
* @param dimensions The dimensions to scale
* @param targetWidth The target width
* @param targetHeight The target height
* @return The scale factor applied to dimensions
*/
public static float scaleToFitTargetSize(
int [] dimensions, int targetWidth, int targetHeight) {
if (dimensions.length < 2 || dimensions[0] <= 0 || dimensions[1] <= 0) {
throw new IllegalArgumentException(
"Expected dimensions to have length >= 2 && dimensions[0] > 0 && "
+ "dimensions[1] > 0");
}
float scale = Math.max(
(float) targetWidth / dimensions[0],
(float) targetHeight / dimensions[1]);
dimensions[0] *= scale;
dimensions[1] *= scale;
return scale;
}
/**
* Flips {@code value} iff {@code flipSign} is {@code true}.
* @param value The value to flip.
* @param flipSign Whether or not to flip the value.
* @return {@code value} iff {@code flipSign} is {@code false}, otherwise negative
* {@code value}.
*/
public static int flipSignIf(int value, boolean flipSign) {
return flipSign ? -value : value;
}
/**
* Flips {@code value} iff {@code flipSign} is {@code true}.
* @param value The value to flip.
* @param flipSign Whether or not to flip the value.
* @return {@code value} iff {@code flipSign} is {@code false}, otherwise negative
* {@code value}.
*/
public static float flipSignIf(float value, boolean flipSign) {
return flipSign ? -value : value;
}
/**
* Compares two long values. Same as {@link Long#compare}, but available on all API levels.
*
* TODO(newt): replace this with Long.compare() once Chrome only supports API level 19+.
*/
public static int compareLongs(long lhs, long rhs) {
return lhs < rhs ? -1 : (lhs == rhs ? 0 : 1);
}
}