blob: 5b12d0a610cd847cae2489a2cb7aa57ed00371e6 [file] [log] [blame]
package com.android.gallery3d.filtershow.filters;
public class SplineMath {
double[][] mPoints = new double[6][2];
double[] mDerivatives;
SplineMath(int n) {
mPoints = new double[n][2];
}
public void setPoint(int index, double x, double y) {
mPoints[index][0] = x;
mPoints[index][1] = y;
mDerivatives = null;
}
public float[][] calculatetCurve(int n) {
float[][] curve = new float[n][2];
double[][] points = new double[mPoints.length][2];
for (int i = 0; i < mPoints.length; i++) {
points[i][0] = mPoints[i][0];
points[i][1] = mPoints[i][1];
}
double[] derivatives = solveSystem(points);
float start = (float) points[0][0];
float end = (float) (points[points.length - 1][0]);
curve[0][0] = (float) (points[0][0]);
curve[0][1] = (float) (points[0][1]);
int last = curve.length - 1;
curve[last][0] = (float) (points[points.length - 1][0]);
curve[last][1] = (float) (points[points.length - 1][1]);
for (int i = 0; i < curve.length; i++) {
double[] cur = null;
double[] next = null;
double x = start + i * (end - start) / (curve.length - 1);
int pivot = 0;
for (int j = 0; j < points.length - 1; j++) {
if (x >= points[j][0] && x <= points[j + 1][0]) {
pivot = j;
}
}
cur = points[pivot];
next = points[pivot + 1];
if (x <= next[0]) {
double x1 = cur[0];
double x2 = next[0];
double y1 = cur[1];
double y2 = next[1];
// Use the second derivatives to apply the cubic spline
// equation:
double delta = (x2 - x1);
double delta2 = delta * delta;
double b = (x - x1) / delta;
double a = 1 - b;
double ta = a * y1;
double tb = b * y2;
double tc = (a * a * a - a) * derivatives[pivot];
double td = (b * b * b - b) * derivatives[pivot + 1];
double y = ta + tb + (delta2 / 6) * (tc + td);
curve[i][0] = (float) (x);
curve[i][1] = (float) (y);
} else {
curve[i][0] = (float) (next[0]);
curve[i][1] = (float) (next[1]);
}
}
return curve;
}
public double getValue(double x) {
double[] cur = null;
double[] next = null;
if (mDerivatives == null)
mDerivatives = solveSystem(mPoints);
int pivot = 0;
for (int j = 0; j < mPoints.length - 1; j++) {
pivot = j;
if (x <= mPoints[j][0]) {
break;
}
}
cur = mPoints[pivot];
next = mPoints[pivot + 1];
double x1 = cur[0];
double x2 = next[0];
double y1 = cur[1];
double y2 = next[1];
// Use the second derivatives to apply the cubic spline
// equation:
double delta = (x2 - x1);
double delta2 = delta * delta;
double b = (x - x1) / delta;
double a = 1 - b;
double ta = a * y1;
double tb = b * y2;
double tc = (a * a * a - a) * mDerivatives[pivot];
double td = (b * b * b - b) * mDerivatives[pivot + 1];
double y = ta + tb + (delta2 / 6) * (tc + td);
return y;
}
double[] solveSystem(double[][] points) {
int n = points.length;
double[][] system = new double[n][3];
double[] result = new double[n]; // d
double[] solution = new double[n]; // returned coefficients
system[0][1] = 1;
system[n - 1][1] = 1;
double d6 = 1.0 / 6.0;
double d3 = 1.0 / 3.0;
// let's create a tridiagonal matrix representing the
// system, and apply the TDMA algorithm to solve it
// (see http://en.wikipedia.org/wiki/Tridiagonal_matrix_algorithm)
for (int i = 1; i < n - 1; i++) {
double deltaPrevX = points[i][0] - points[i - 1][0];
double deltaX = points[i + 1][0] - points[i - 1][0];
double deltaNextX = points[i + 1][0] - points[i][0];
double deltaNextY = points[i + 1][1] - points[i][1];
double deltaPrevY = points[i][1] - points[i - 1][1];
system[i][0] = d6 * deltaPrevX; // a_i
system[i][1] = d3 * deltaX; // b_i
system[i][2] = d6 * deltaNextX; // c_i
result[i] = (deltaNextY / deltaNextX) - (deltaPrevY / deltaPrevX); // d_i
}
// Forward sweep
for (int i = 1; i < n; i++) {
// m = a_i/b_i-1
double m = system[i][0] / system[i - 1][1];
// b_i = b_i - m(c_i-1)
system[i][1] = system[i][1] - m * system[i - 1][2];
// d_i = d_i - m(d_i-1)
result[i] = result[i] - m * result[i - 1];
}
// Back substitution
solution[n - 1] = result[n - 1] / system[n - 1][1];
for (int i = n - 2; i >= 0; --i) {
solution[i] = (result[i] - system[i][2] * solution[i + 1]) / system[i][1];
}
return solution;
}
public static void main(String[] args) {
SplineMath s = new SplineMath(10);
for (int i = 0; i < 10; i++) {
s.setPoint(i, i, i);
}
float[][] curve = s.calculatetCurve(40);
for (int j = 0; j < curve.length; j++) {
System.out.println(curve[j][0] + "," + curve[j][1]);
}
}
}