Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.util;
     18 
     19 import android.annotation.UnsupportedAppUsage;
     20 import android.graphics.Rect;
     21 
     22 /**
     23  * A class that contains utility methods related to numbers.
     24  *
     25  * @hide Pending API council approval
     26  */
     27 public final class MathUtils {
     28     private static final float DEG_TO_RAD = 3.1415926f / 180.0f;
     29     private static final float RAD_TO_DEG = 180.0f / 3.1415926f;
     30 
     31     private MathUtils() {
     32     }
     33 
     34     @UnsupportedAppUsage
     35     public static float abs(float v) {
     36         return v > 0 ? v : -v;
     37     }
     38 
     39     @UnsupportedAppUsage
     40     public static int constrain(int amount, int low, int high) {
     41         return amount < low ? low : (amount > high ? high : amount);
     42     }
     43 
     44     public static long constrain(long amount, long low, long high) {
     45         return amount < low ? low : (amount > high ? high : amount);
     46     }
     47 
     48     @UnsupportedAppUsage
     49     public static float constrain(float amount, float low, float high) {
     50         return amount < low ? low : (amount > high ? high : amount);
     51     }
     52 
     53     public static float log(float a) {
     54         return (float) Math.log(a);
     55     }
     56 
     57     public static float exp(float a) {
     58         return (float) Math.exp(a);
     59     }
     60 
     61     public static float pow(float a, float b) {
     62         return (float) Math.pow(a, b);
     63     }
     64 
     65     public static float sqrt(float a) {
     66         return (float) Math.sqrt(a);
     67     }
     68 
     69     public static float max(float a, float b) {
     70         return a > b ? a : b;
     71     }
     72 
     73     @UnsupportedAppUsage
     74     public static float max(int a, int b) {
     75         return a > b ? a : b;
     76     }
     77 
     78     public static float max(float a, float b, float c) {
     79         return a > b ? (a > c ? a : c) : (b > c ? b : c);
     80     }
     81 
     82     public static float max(int a, int b, int c) {
     83         return a > b ? (a > c ? a : c) : (b > c ? b : c);
     84     }
     85 
     86     public static float min(float a, float b) {
     87         return a < b ? a : b;
     88     }
     89 
     90     public static float min(int a, int b) {
     91         return a < b ? a : b;
     92     }
     93 
     94     public static float min(float a, float b, float c) {
     95         return a < b ? (a < c ? a : c) : (b < c ? b : c);
     96     }
     97 
     98     public static float min(int a, int b, int c) {
     99         return a < b ? (a < c ? a : c) : (b < c ? b : c);
    100     }
    101 
    102     public static float dist(float x1, float y1, float x2, float y2) {
    103         final float x = (x2 - x1);
    104         final float y = (y2 - y1);
    105         return (float) Math.hypot(x, y);
    106     }
    107 
    108     public static float dist(float x1, float y1, float z1, float x2, float y2, float z2) {
    109         final float x = (x2 - x1);
    110         final float y = (y2 - y1);
    111         final float z = (z2 - z1);
    112         return (float) Math.sqrt(x * x + y * y + z * z);
    113     }
    114 
    115     public static float mag(float a, float b) {
    116         return (float) Math.hypot(a, b);
    117     }
    118 
    119     public static float mag(float a, float b, float c) {
    120         return (float) Math.sqrt(a * a + b * b + c * c);
    121     }
    122 
    123     public static float sq(float v) {
    124         return v * v;
    125     }
    126 
    127     public static float dot(float v1x, float v1y, float v2x, float v2y) {
    128         return v1x * v2x + v1y * v2y;
    129     }
    130 
    131     public static float cross(float v1x, float v1y, float v2x, float v2y) {
    132         return v1x * v2y - v1y * v2x;
    133     }
    134 
    135     public static float radians(float degrees) {
    136         return degrees * DEG_TO_RAD;
    137     }
    138 
    139     public static float degrees(float radians) {
    140         return radians * RAD_TO_DEG;
    141     }
    142 
    143     public static float acos(float value) {
    144         return (float) Math.acos(value);
    145     }
    146 
    147     public static float asin(float value) {
    148         return (float) Math.asin(value);
    149     }
    150 
    151     public static float atan(float value) {
    152         return (float) Math.atan(value);
    153     }
    154 
    155     public static float atan2(float a, float b) {
    156         return (float) Math.atan2(a, b);
    157     }
    158 
    159     public static float tan(float angle) {
    160         return (float) Math.tan(angle);
    161     }
    162 
    163     @UnsupportedAppUsage
    164     public static float lerp(float start, float stop, float amount) {
    165         return start + (stop - start) * amount;
    166     }
    167 
    168     /**
    169      * Returns the interpolation scalar (s) that satisfies the equation: {@code value = }{@link
    170      * #lerp}{@code (a, b, s)}
    171      *
    172      * <p>If {@code a == b}, then this function will return 0.
    173      */
    174     public static float lerpInv(float a, float b, float value) {
    175         return a != b ? ((value - a) / (b - a)) : 0.0f;
    176     }
    177 
    178     /** Returns the single argument constrained between [0.0, 1.0]. */
    179     public static float saturate(float value) {
    180         return constrain(value, 0.0f, 1.0f);
    181     }
    182 
    183     /** Returns the saturated (constrained between [0, 1]) result of {@link #lerpInv}. */
    184     public static float lerpInvSat(float a, float b, float value) {
    185         return saturate(lerpInv(a, b, value));
    186     }
    187 
    188     /**
    189      * Returns an interpolated angle in degrees between a set of start and end
    190      * angles.
    191      * <p>
    192      * Unlike {@link #lerp(float, float, float)}, the direction and distance of
    193      * travel is determined by the shortest angle between the start and end
    194      * angles. For example, if the starting angle is 0 and the ending angle is
    195      * 350, then the interpolated angle will be in the range [0,-10] rather
    196      * than [0,350].
    197      *
    198      * @param start the starting angle in degrees
    199      * @param end the ending angle in degrees
    200      * @param amount the position between start and end in the range [0,1]
    201      *               where 0 is the starting angle and 1 is the ending angle
    202      * @return the interpolated angle in degrees
    203      */
    204     public static float lerpDeg(float start, float end, float amount) {
    205         final float minAngle = (((end - start) + 180) % 360) - 180;
    206         return minAngle * amount + start;
    207     }
    208 
    209     public static float norm(float start, float stop, float value) {
    210         return (value - start) / (stop - start);
    211     }
    212 
    213     public static float map(float minStart, float minStop, float maxStart, float maxStop, float value) {
    214         return maxStart + (maxStop - maxStart) * ((value - minStart) / (minStop - minStart));
    215     }
    216 
    217     /**
    218      * Calculates a value in [rangeMin, rangeMax] that maps value in [valueMin, valueMax] to
    219      * returnVal in [rangeMin, rangeMax].
    220      * <p>
    221      * Always returns a constrained value in the range [rangeMin, rangeMax], even if value is
    222      * outside [valueMin, valueMax].
    223      * <p>
    224      * Eg:
    225      *    constrainedMap(0f, 100f, 0f, 1f, 0.5f) = 50f
    226      *    constrainedMap(20f, 200f, 10f, 20f, 20f) = 200f
    227      *    constrainedMap(20f, 200f, 10f, 20f, 50f) = 200f
    228      *    constrainedMap(10f, 50f, 10f, 20f, 5f) = 10f
    229      *
    230      * @param rangeMin minimum of the range that should be returned.
    231      * @param rangeMax maximum of the range that should be returned.
    232      * @param valueMin minimum of range to map {@code value} to.
    233      * @param valueMax maximum of range to map {@code value} to.
    234      * @param value to map to the range [{@code valueMin}, {@code valueMax}]. Note, can be outside
    235      *              this range, resulting in a clamped value.
    236      * @return the mapped value, constrained to [{@code rangeMin}, {@code rangeMax}.
    237      */
    238     public static float constrainedMap(
    239             float rangeMin, float rangeMax, float valueMin, float valueMax, float value) {
    240         return lerp(rangeMin, rangeMax, lerpInvSat(valueMin, valueMax, value));
    241     }
    242 
    243     /**
    244      * Perform Hermite interpolation between two values.
    245      * Eg:
    246      *   smoothStep(0, 0.5f, 0.5f) = 1f
    247      *   smoothStep(0, 0.5f, 0.25f) = 0.5f
    248      *
    249      * @param start Left edge.
    250      * @param end Right edge.
    251      * @param x A value between {@code start} and {@code end}.
    252      * @return A number between 0 and 1 representing where {@code x} is in the interpolation.
    253      */
    254     public static float smoothStep(float start, float end, float x) {
    255         return constrain((x - start) / (end - start), 0f, 1f);
    256     }
    257 
    258     /**
    259      * Returns the sum of the two parameters, or throws an exception if the resulting sum would
    260      * cause an overflow or underflow.
    261      * @throws IllegalArgumentException when overflow or underflow would occur.
    262      */
    263     public static int addOrThrow(int a, int b) throws IllegalArgumentException {
    264         if (b == 0) {
    265             return a;
    266         }
    267 
    268         if (b > 0 && a <= (Integer.MAX_VALUE - b)) {
    269             return a + b;
    270         }
    271 
    272         if (b < 0 && a >= (Integer.MIN_VALUE - b)) {
    273             return a + b;
    274         }
    275         throw new IllegalArgumentException("Addition overflow: " + a + " + " + b);
    276     }
    277 
    278     /**
    279      * Resize a {@link Rect} so one size would be {@param largestSide}.
    280      *
    281      * @param outToResize Rectangle that will be resized.
    282      * @param largestSide Size of the largest side.
    283      */
    284     public static void fitRect(Rect outToResize, int largestSide) {
    285         if (outToResize.isEmpty()) {
    286             return;
    287         }
    288         float maxSize = Math.max(outToResize.width(), outToResize.height());
    289         outToResize.scale(largestSide / maxSize);
    290     }
    291 }
    292