Loading core/java/android/util/Spline.java +233 −92 Original line number Diff line number Diff line Loading @@ -20,15 +20,34 @@ package android.util; * Performs spline interpolation given a set of control points. * @hide */ public final class Spline { private final float[] mX; private final float[] mY; private final float[] mM; public abstract class Spline { private Spline(float[] x, float[] y, float[] m) { mX = x; mY = y; mM = m; /** * Interpolates the value of Y = f(X) for given X. * Clamps X to the domain of the spline. * * @param x The X value. * @return The interpolated Y = f(X) value. */ public abstract float interpolate(float x); /** * Creates an appropriate spline based on the properties of the control points. * * If the control points are monotonic then the resulting spline will preserve that and * otherwise optimize for error bounds. */ public static Spline createSpline(float[] x, float[] y) { if (!isStrictlyIncreasing(x)) { throw new IllegalArgumentException("The control points must all have strictly " + "increasing X values."); } if (isMonotonic(y)) { return createMonotoneCubicSpline(x, y); } else { return createLinearSpline(x, y); } } /** Loading @@ -50,6 +69,64 @@ public final class Spline { * @throws IllegalArgumentException if the control points are not monotonic. */ public static Spline createMonotoneCubicSpline(float[] x, float[] y) { return new MonotoneCubicSpline(x, y); } /** * Creates a linear spline from a given set of control points. * * Like a monotone cubic spline, the interpolated curve will be monotonic if the control points * are monotonic. * * @param x The X component of the control points, strictly increasing. * @param y The Y component of the control points. * @return * * @throws IllegalArgumentException if the X or Y arrays are null, have * different lengths or have fewer than 2 values. * @throws IllegalArgumentException if the X components of the control points are not strictly * increasing. */ public static Spline createLinearSpline(float[] x, float[] y) { return new LinearSpline(x, y); } private static boolean isStrictlyIncreasing(float[] x) { if (x == null || x.length < 2) { throw new IllegalArgumentException("There must be at least two control points."); } float prev = x[0]; for (int i = 1; i < x.length; i++) { float curr = x[i]; if (curr <= prev) { return false; } prev = curr; } return true; } private static boolean isMonotonic(float[] x) { if (x == null || x.length < 2) { throw new IllegalArgumentException("There must be at least two control points."); } float prev = x[0]; for (int i = 1; i < x.length; i++) { float curr = x[i]; if (curr < prev) { return false; } prev = curr; } return true; } public static class MonotoneCubicSpline extends Spline { private float[] mX; private float[] mY; private float[] mM; public MonotoneCubicSpline(float[] x, float[] y) { if (x == null || y == null || x.length != y.length || x.length < 2) { throw new IllegalArgumentException("There must be at least two control " + "points and the arrays must be of equal length."); Loading Loading @@ -96,16 +173,13 @@ public final class Spline { } } } return new Spline(x, y, m); mX = x; mY = y; mM = m; } /** * Interpolates the value of Y = f(X) for given X. * Clamps X to the domain of the spline. * * @param x The X value. * @return The interpolated Y = f(X) value. */ @Override public float interpolate(float x) { // Handle the boundary cases. final int n = mX.length; Loading Loading @@ -141,7 +215,7 @@ public final class Spline { public String toString() { StringBuilder str = new StringBuilder(); final int n = mX.length; str.append("["); str.append("MonotoneCubicSpline{["); for (int i = 0; i < n; i++) { if (i != 0) { str.append(", "); Loading @@ -150,7 +224,74 @@ public final class Spline { str.append(", ").append(mY[i]); str.append(": ").append(mM[i]).append(")"); } str.append("]"); str.append("]}"); return str.toString(); } } public static class LinearSpline extends Spline { private final float[] mX; private final float[] mY; private final float[] mM; public LinearSpline(float[] x, float[] y) { if (x == null || y == null || x.length != y.length || x.length < 2) { throw new IllegalArgumentException("There must be at least two control " + "points and the arrays must be of equal length."); } final int N = x.length; mM = new float[N-1]; for (int i = 0; i < N-1; i++) { mM[i] = (y[i+1] - y[i]) / (x[i+1] - x[i]); } mX = x; mY = y; } @Override public float interpolate(float x) { // Handle the boundary cases. final int n = mX.length; if (Float.isNaN(x)) { return x; } if (x <= mX[0]) { return mY[0]; } if (x >= mX[n - 1]) { return mY[n - 1]; } // Find the index 'i' of the last point with smaller X. // We know this will be within the spline due to the boundary tests. int i = 0; while (x >= mX[i + 1]) { i += 1; if (x == mX[i]) { return mY[i]; } } return mY[i] + mM[i] * (x - mX[i]); } @Override public String toString() { StringBuilder str = new StringBuilder(); final int n = mX.length; str.append("LinearSpline{["); for (int i = 0; i < n; i++) { if (i != 0) { str.append(", "); } str.append("(").append(mX[i]); str.append(", ").append(mY[i]); if (i < n-1) { str.append(": ").append(mM[i]); } str.append(")"); } str.append("]}"); return str.toString(); } } } services/core/java/com/android/server/display/DisplayPowerController.java +1 −1 Original line number Diff line number Diff line Loading @@ -438,7 +438,7 @@ final class DisplayPowerController { y[i] = normalizeAbsoluteBrightness(brightness[i]); } Spline spline = Spline.createMonotoneCubicSpline(x, y); Spline spline = Spline.createSpline(x, y); if (DEBUG) { Slog.d(TAG, "Auto-brightness spline: " + spline); for (float v = 1f; v < lux[lux.length - 1] * 1.25f; v *= 1.25f) { Loading Loading
core/java/android/util/Spline.java +233 −92 Original line number Diff line number Diff line Loading @@ -20,15 +20,34 @@ package android.util; * Performs spline interpolation given a set of control points. * @hide */ public final class Spline { private final float[] mX; private final float[] mY; private final float[] mM; public abstract class Spline { private Spline(float[] x, float[] y, float[] m) { mX = x; mY = y; mM = m; /** * Interpolates the value of Y = f(X) for given X. * Clamps X to the domain of the spline. * * @param x The X value. * @return The interpolated Y = f(X) value. */ public abstract float interpolate(float x); /** * Creates an appropriate spline based on the properties of the control points. * * If the control points are monotonic then the resulting spline will preserve that and * otherwise optimize for error bounds. */ public static Spline createSpline(float[] x, float[] y) { if (!isStrictlyIncreasing(x)) { throw new IllegalArgumentException("The control points must all have strictly " + "increasing X values."); } if (isMonotonic(y)) { return createMonotoneCubicSpline(x, y); } else { return createLinearSpline(x, y); } } /** Loading @@ -50,6 +69,64 @@ public final class Spline { * @throws IllegalArgumentException if the control points are not monotonic. */ public static Spline createMonotoneCubicSpline(float[] x, float[] y) { return new MonotoneCubicSpline(x, y); } /** * Creates a linear spline from a given set of control points. * * Like a monotone cubic spline, the interpolated curve will be monotonic if the control points * are monotonic. * * @param x The X component of the control points, strictly increasing. * @param y The Y component of the control points. * @return * * @throws IllegalArgumentException if the X or Y arrays are null, have * different lengths or have fewer than 2 values. * @throws IllegalArgumentException if the X components of the control points are not strictly * increasing. */ public static Spline createLinearSpline(float[] x, float[] y) { return new LinearSpline(x, y); } private static boolean isStrictlyIncreasing(float[] x) { if (x == null || x.length < 2) { throw new IllegalArgumentException("There must be at least two control points."); } float prev = x[0]; for (int i = 1; i < x.length; i++) { float curr = x[i]; if (curr <= prev) { return false; } prev = curr; } return true; } private static boolean isMonotonic(float[] x) { if (x == null || x.length < 2) { throw new IllegalArgumentException("There must be at least two control points."); } float prev = x[0]; for (int i = 1; i < x.length; i++) { float curr = x[i]; if (curr < prev) { return false; } prev = curr; } return true; } public static class MonotoneCubicSpline extends Spline { private float[] mX; private float[] mY; private float[] mM; public MonotoneCubicSpline(float[] x, float[] y) { if (x == null || y == null || x.length != y.length || x.length < 2) { throw new IllegalArgumentException("There must be at least two control " + "points and the arrays must be of equal length."); Loading Loading @@ -96,16 +173,13 @@ public final class Spline { } } } return new Spline(x, y, m); mX = x; mY = y; mM = m; } /** * Interpolates the value of Y = f(X) for given X. * Clamps X to the domain of the spline. * * @param x The X value. * @return The interpolated Y = f(X) value. */ @Override public float interpolate(float x) { // Handle the boundary cases. final int n = mX.length; Loading Loading @@ -141,7 +215,7 @@ public final class Spline { public String toString() { StringBuilder str = new StringBuilder(); final int n = mX.length; str.append("["); str.append("MonotoneCubicSpline{["); for (int i = 0; i < n; i++) { if (i != 0) { str.append(", "); Loading @@ -150,7 +224,74 @@ public final class Spline { str.append(", ").append(mY[i]); str.append(": ").append(mM[i]).append(")"); } str.append("]"); str.append("]}"); return str.toString(); } } public static class LinearSpline extends Spline { private final float[] mX; private final float[] mY; private final float[] mM; public LinearSpline(float[] x, float[] y) { if (x == null || y == null || x.length != y.length || x.length < 2) { throw new IllegalArgumentException("There must be at least two control " + "points and the arrays must be of equal length."); } final int N = x.length; mM = new float[N-1]; for (int i = 0; i < N-1; i++) { mM[i] = (y[i+1] - y[i]) / (x[i+1] - x[i]); } mX = x; mY = y; } @Override public float interpolate(float x) { // Handle the boundary cases. final int n = mX.length; if (Float.isNaN(x)) { return x; } if (x <= mX[0]) { return mY[0]; } if (x >= mX[n - 1]) { return mY[n - 1]; } // Find the index 'i' of the last point with smaller X. // We know this will be within the spline due to the boundary tests. int i = 0; while (x >= mX[i + 1]) { i += 1; if (x == mX[i]) { return mY[i]; } } return mY[i] + mM[i] * (x - mX[i]); } @Override public String toString() { StringBuilder str = new StringBuilder(); final int n = mX.length; str.append("LinearSpline{["); for (int i = 0; i < n; i++) { if (i != 0) { str.append(", "); } str.append("(").append(mX[i]); str.append(", ").append(mY[i]); if (i < n-1) { str.append(": ").append(mM[i]); } str.append(")"); } str.append("]}"); return str.toString(); } } }
services/core/java/com/android/server/display/DisplayPowerController.java +1 −1 Original line number Diff line number Diff line Loading @@ -438,7 +438,7 @@ final class DisplayPowerController { y[i] = normalizeAbsoluteBrightness(brightness[i]); } Spline spline = Spline.createMonotoneCubicSpline(x, y); Spline spline = Spline.createSpline(x, y); if (DEBUG) { Slog.d(TAG, "Auto-brightness spline: " + spline); for (float v = 1f; v < lux[lux.length - 1] * 1.25f; v *= 1.25f) { Loading