Mega Code Archive

 
Categories / Java / Collections Data Structure
 

A numerical interval

//package com.ryanm.droid.rugl.util.math; /**  * A numerical interval  *   * @author ryanm  */ public class Range {   /**    * The lower value    */   private float min = 0;   /**    * The upper value    */   private float max = 0;   /**    * @param min    * @param max    */   public Range(float min, float max) {     set(min, max);   }   /**    * @param r    * @param dest    * @return <code>true</code> if the intersection exists    */   public boolean intersection(Range r, Range dest) {     if (intersects(r)) {       dest.set(Math.max(min, r.min), Math.min(max, r.max));       return true;     }     return false;   }   /**    * @param value    * @return true if the value lies between the min and max values,    *         inclusively    */   public boolean contains(float value) {     return min <= value && max >= value;   }   /**    * @param min    * @param max    */   public void set(float min, float max) {     this.min = min;     this.max = max;     sort();   }   /**    * @param r    */   public void set(Range r) {     set(r.getMin(), r.getMax());   }   /**    * @return The difference between min and max    */   public float getSpan() {     return max - min;   }   /**    * @return The lower range boundary    */   public float getMin() {     return min;   }   /**    * @param min    */   public void setMin(float min) {     this.min = min;     sort();   }   /**    * @return The upper range boundary    */   public float getMax() {     return max;   }   /**    * @param max    */   public void setMax(float max) {     this.max = max;     sort();   }   private void sort() {     if (min > max) {       float t = min;       min = max;       max = t;     }   }   /**    * Limits a value to lie within this range    *     * @param v    *            The value to limit    * @return min if v < min, max if v > max, otherwise v    */   public float limit(float v) {     return limit(v, min, max);   }   /**    * Wraps a value into this range, modular arithmetic style    *     * @param v    * @return The wrapped value    */   public float wrap(float v) {     return wrap(v, min, max);   }   /**    * @param value    * @return The proportion of the distance between min and max that value    *         lies from min    */   public float toRatio(float value) {     return toRatio(value, min, max);   }   /**    * @param ratio    * @return min + ratio * ( max - min )    */   public float toValue(float ratio) {     return toValue(ratio, min, max);   }   /**    * @param r    * @return <code>true</code> if the ranges have values in common    */   public boolean intersects(Range r) {     return overlaps(min, max, r.min, r.max);   }   /**    * Alters this range such that {@link #contains(float)} returns    * <code>true</code> for f    *     * @param f    */   public void encompass(float f) {     if (f < min) {       min = f;     } else if (f > max) {       max = f;     }   }   /**    * Alters this range such that {@link #contains(float)} returns    * <code>true</code> for all values in r    *     * @param r    */   public void encompass(Range r) {     encompass(r.min);     encompass(r.max);   }   @Override   public String toString() {     return "[ " + min + " : " + max + " ]";   }   /**    * Limits a value to lie within some range    *     * @param v    * @param min    * @param max    * @return min if v < min, max if v > max, otherwise v    */   public static float limit(float v, float min, float max) {     if (v < min) {       v = min;     } else if (v > max) {       v = max;     }     return v;   }   /**    * Wraps a value into a range, in a modular arithmetic style (but it works    * for negatives too)    *     * @param v    * @param min    * @param max    * @return the wrapped value    */   public static float wrap(float v, float min, float max) {     v -= min;     max -= min;     if (v < 0) {       v += max * ((int) (-v / max) + 1);     }     v %= max;     return v + min;   }   /**    * @param v    * @param min    * @param max    * @return The proportion of the distance between min and max that v lies    *         from min    */   public static float toRatio(float v, float min, float max) {     float d = v - min;     float e = max - min;     return d / e;   }   /**    * @param ratio    * @param min    * @param max    * @return min + ratio * ( max - min )    */   public static float toValue(float ratio, float min, float max) {     return min + ratio * (max - min);   }   /**    * @param value    * @param min    * @param max    * @return <code>true</code> if value lies within min and max, inclusively    */   public static boolean inRange(float value, float min, float max) {     return value >= min && value <= max;   }   /**    * @param minA    * @param maxA    * @param minB    * @param maxB    * @return <code>true</code> if the ranges overlap    */   public static boolean overlaps(float minA, float maxA, float minB,       float maxB) {     assert minA <= maxA;     assert minB <= maxB;     return !(minA > maxB || maxA < minB);   }   /**    * @param a    *            a static range    * @param b    *            a mobile range    * @param bv    *            The velocity of b    * @return The time period over which a and b intersect, or    *         <code>null</code> if they never do    */   public static Range intersectionTime(Range a, Range b, float bv) {     if (bv == 0) { // nobody likes division by zero       if (a.intersects(b)) { // continual intersection         return new Range(-Float.MAX_VALUE, Float.MAX_VALUE);       } else { // no intersection         return null;       }     }     // time when low edge of a meets high edge of b     float t1 = (a.getMin() - b.getMax()) / bv;     // time when high edge of a meets low edge of b     float t2 = (a.getMax() - b.getMin()) / bv;     // constructor sorts the times into proper order     return new Range(t1, t2);   }   /**    * @param minA    * @param maxA    * @param minB    * @param maxB    * @return <code>true</code> if rangeA contains rangeB    */   public static boolean contains(float minA, float maxA, float minB,       float maxB) {     return minA <= minB && maxA >= maxB;   }   /**    * @param minA    * @param maxA    * @param minB    * @param maxB    * @return The size of the intersection of the two ranges    */   public static float intersection(float minA, float maxA, float minB,       float maxB) {     float highMin = Math.max(minA, minB);     float lowMax = Math.min(maxA, maxB);     if (lowMax > highMin) {       return lowMax - highMin;     }     return 0;   }   /**    * Shifts the range    *     * @param d    */   public void translate(float d) {     min += d;     max += d;   }   /**    * Scales the range around the origin    *     * @param s    */   public void scale(float s) {     min *= s;     max *= s;   }   /**    * Smooth interpolation between min and max. Copy the following into gnuplot    * to see the difference between {@link #smooth(float, float, float)} and    * {@link #smooth2(float, float, float)} <br>    * set xrange [0:1] <br>    * set yrange [0:1] <br>    * plot (x**2*(3-2*x)) title "smooth", x**3*(10+x*(-15+6*x)) title "smooth2"    *     * @param ratio    *            in range 0-1    * @param min    *            minimum output value    * @param max    *            maximum output value    * @return first-order continuous graduation between min and max    * @see #smooth2(float, float, float)    */   public static final float smooth(float ratio, float min, float max) {     return toValue(ratio * ratio * (3.0f - (ratio + ratio)), min, max);   }   /**    * Smooth interpolation between min and max    *     * @param ratio    *            in range 0-1    * @param min    *            minimum output value    * @param max    *            maximum output value    * @return all-derivation continuous graduation between min and max    * @see Range#smooth(float, float, float)    */   public static final float smooth2(float ratio, float min, float max) {     float t3 = ratio * ratio * ratio;     return toValue(t3 * (10.f + ratio * (-15.f + 6.f * ratio)), min, max);   } }