/***************************************************************************** * Copyright (c) 2009-2013 CWI * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * * Bert Lisser - Bert.Lisser@cwi.nl (CWI) * * Paul Klint - Paul.Klint@cwi.nl - CWI *******************************************************************************/ /* * See http://en.wikipedia.org/wiki/Tridiagonal_matrix_algorithm * and * Forcing Bezier Interpolation * http://people.sc.fsu.edu/~jburkardt/html/bezier_interpolation.html * * Cubic Spline Interpolation (Sky McKinley and Megan Levine) * http://online.redwoods.cc.ca.us/instruct/darnold/laproj/fall98/Skymeg/proj.pdf * * */ package org.rascalmpl.eclipse.library.vis.graphics; import java.util.ArrayList; public class Interpolation { final static boolean debug = false; public static double[] lD, uD, D, z, v, h, x, y; public static TypedPoint[] P0, P1, P2, P3; // Tridiagonal matrix algorithm Solve Av = c; static void solveMatrix(double[] a, double[] b, double[] c, double[] v, double[] x) { /** * n - number of equations a - sub-diagonal (means it is the diagonal * below the main diagonal) b - the main diagonal c - sup-diagonal * (means it is the diagonal above the main diagonal) v - right part x - * the answer */ int n = b.length; if (debug) System.err.println("Sizes:" + x.length + " " + v.length + " " + b.length); for (int i = 1; i < n; i++) { double m = a[i] / b[i - 1]; if (debug) { System.err.println("solveMatrix: m=" + m + "b[" + i + "]=" + b[i]); } b[i] = b[i] - m * c[i - 1]; if (debug) { System.err.println("solveMatrix2: m=" + m + "b[" + i + "]=" + b[i]); System.err.println("v[" + (i - 1) + "]=" + v[i - 1]); System.err.println("v[" + (i) + "]=" + v[i]); } v[i] = v[i] - m * v[i - 1]; } x[n - 1] = v[n - 1] / b[n - 1]; if (debug) System.err.println("1:x[" + (n-1) + "]=" + x[n-1]); for (int i = n - 2; i >= 0; i--) { x[i] = (v[i] - c[i] * x[i + 1]) / b[i]; if (debug) { System.err.println("c[" + (i) + "]=" + c[i]); System.err.println("b[" + (i) + "]=" + b[i]); System.err.println("v[" + (i) + "]=" + v[i]); System.err.println("2:x[" + (i+1) + "]=" + x[i+1]); System.err.println("2:x[" + (i) + "]=" + x[i]); } } } static boolean computeMatrix(ArrayList<TypedPoint> r) { x = new double[r.size()]; y = new double[r.size()]; int n = 0; // System.err.println("r.size=" + r.size()); while (!r.isEmpty()) { TypedPoint p = r.get(0); if (p.curved == TypedPoint.kind.CURVED) { x[n] = p.x; y[n] = p.y; if (debug) System.err.println("p.x=" + x[n] + " p.y=" + y[n] + " " + p.curved); r.remove(0); n++; } else break; } if (n == 0) return false; // System.err.println("n=" + n); h = new double[n - 1]; for (int i = 0; i < h.length; i++) { h[i] = x[i + 1] - x[i]; // System.err.println("x[" + i + "]" + x[i] + " " + x[i + 1]); } n = h.length - 1; // n-2 if n points D = new double[n]; lD = new double[n]; uD = new double[n]; v = new double[n]; z = new double[n]; for (int i = 0; i < n; i++) { D[i] = 2 * (h[i] + h[i + 1]); lD[i] = h[i + 1]; uD[i] = h[i + 1]; if (debug) System.err.println("y[" + (i + 2) + "]=" + y[i + 2] + " h[" + (i + 1) + "]=" + h[i + 1]); v[i] = 6 * ((y[i + 2] - y[i + 1]) / h[i + 1] - (y[i + 1] - y[i]) / h[i]); // System.err.println("v[" + i + "]=" + v[i] + " D[" + i + "]=" + // D[i] // + " " + lD[i] + " " + uD[i]); } return true; } public static void solve(ArrayList<TypedPoint> r, boolean closed) { if (!computeMatrix(r)) return; solveMatrix(lD, D, uD, v, z); int n = z.length; double[] S = new double[n + 2]; for (int i = 0; i < n; i++) { S[i + 1] = z[i]; if (debug) System.err.println("z[" + i + "]" + " z[i]" + z[i]); } // if (closed) { // S[0] = -S[n]; // S[n + 1] = -S[1]; // } else { S[0] = 0; S[n + 1] = 0; } n = S.length; double[] a = new double[n - 1]; double[] b = new double[n - 1]; double[] c = new double[n - 1]; double[] d = new double[n - 1]; for (int i = 0; i < n - 1; i++) { a[i] = (S[i + 1] - S[i]) / (6 * h[i]) * (h[i] * h[i] * h[i]); b[i] = (S[i] / 2) * (h[i] * h[i]); c[i] = ((y[i + 1] - y[i]) / h[i] - (2 * h[i] * S[i] + h[i] * S[i + 1]) / 6) * h[i]; d[i] = y[i]; // System.err.println("i=" + i + " a=" + a[i] + " b=" + b[i] + " c=" // + c[i] + " d=" + d[i] + "h=" + h[i]); if (debug) System.err.println("Check:" + (a[i] + b[i] + c[i] + d[i])); } n = a.length; P0 = new TypedPoint[n]; P1 = new TypedPoint[n]; P2 = new TypedPoint[n]; P3 = new TypedPoint[n]; for (int i = 0; i < n; i++) { P0[i] = new TypedPoint(x[i], d[i], TypedPoint.kind.NORMAL); // System.err.println("i=" + i + " " + P0[i].x + " " + P0[i].y); P1[i] = new TypedPoint(x[i] + h[i] / 3, c[i] / 3 + d[i], TypedPoint.kind.NORMAL); P2[i] = new TypedPoint(x[i] + 2 * h[i] / 3, b[i] / 3 + 2 * c[i] / 3 + d[i], TypedPoint.kind.NORMAL); P3[i] = new TypedPoint(x[i + 1], a[i] + b[i] + c[i] + d[i], TypedPoint.kind.NORMAL); // System.err.println("i=" + i + " " + P3[i].x + " " + P3[i].y); } } }