Coverage Report - com.buckosoft.fibs.BuckoFIBS.gui.boardTab.boardPane.animateType._Spline2D
 
Classes in this File Line Coverage Branch Coverage Complexity
Spline
0%
0/86
0%
0/50
4.909
_Spline2D
0%
0/29
0%
0/12
4.909
 
 1  
 /******************************************************************************
 2  
  * _Spline2D.java - Spline Math in Java
 3  
  * $Id$
 4  
  * 
 5  
  * BuckoFIBS - Backgammon by BuckoSoft
 6  
  * Copyright© 2011 - Dick Balaska - BuckoSoft, Corp.
 7  
  * 
 8  
  * Jave Spline algorithm from <a href="http://www.java2s.com/Code/Java/2D-Graphics-GUI/Spline2D.htm">Spline2D.htm</a>
 9  
  * 
 10  
  * $Log$
 11  
  */
 12  
 
 13  
 ///////////////////////////////////////////
 14  
 /*
 15  
  * @(#)Spline2D.java
 16  
  * 
 17  
  * Copyright (c) 2003 Martin Krueger
 18  
  * Copyright (c) 2005 David Benson
 19  
  *  
 20  
  */
 21  
 
 22  
 package com.buckosoft.fibs.BuckoFIBS.gui.boardTab.boardPane.animateType;
 23  
 
 24  
 import java.util.Arrays;
 25  
 
 26  
 /**
 27  
  * Interpolates points given in the 2D plane. The resulting spline
 28  
  * is a function s: R -> R^2 with parameter t in [0,1].
 29  
  * 
 30  
  * @author krueger
 31  
  * @see <a href="http://www.java2s.com/Code/Java/2D-Graphics-GUI/Spline2D.htm">Spline2D.htm</a>
 32  
  * @see <a href="http://cvs.buckosoft.com/Projects/BuckoFIBS/BuckoFIBS/src/main/java/com/buckosoft/fibs/BuckoFIBS/gui/boardTab/boardPane/animateType/_Spline2D.java">cvs _Spline2D.java</a>
 33  
  */
 34  
 /*protected*/
 35  
 class _Spline2D {
 36  
         /** 
 37  
          *  Array representing the relative proportion of the total distance
 38  
          *  of each point in the line ( i.e. first point is 0.0, end point is
 39  
          *  1.0, a point halfway on line is 0.5 ).
 40  
          */
 41  
         private double[] t;
 42  
         private Spline splineX;
 43  
         private Spline splineY;
 44  
         /**
 45  
          * Total length tracing the points on the spline
 46  
          */
 47  
         private double length;
 48  
 
 49  
         /**
 50  
          * Creates a new Spline2D.
 51  
          * @param points
 52  
          */
 53  
 /*
 54  
         public _Spline2D(Point2D[] points) {
 55  
                 double[] x = new double[points.length];
 56  
                 double[] y = new double[points.length];
 57  
 
 58  
                 for(int i = 0; i< points.length; i++) {
 59  
                         x[i] = points[i].getX();
 60  
                         y[i] = points[i].getY(); 
 61  
                 }
 62  
 
 63  
                 init(x, y);
 64  
         }
 65  
 */
 66  
         /**
 67  
          * Creates a new Spline2D.
 68  
          * @param x
 69  
          * @param y
 70  
          */
 71  0
         public _Spline2D(double[] x, double[] y) {
 72  0
                 init(x, y);
 73  0
         }
 74  
 
 75  
         /** Get the x/y coordinates at this offset into the spline.
 76  
          * @param t 0 <= t <= 1
 77  
          * @return The x/y pair
 78  
          */
 79  
         public int[] getPoint(double t) {
 80  0
                 int[] result = new int[2];
 81  0
                 result[0] = (int)splineX.getValue(t);
 82  0
                 result[1] = (int)splineY.getValue(t);
 83  
 
 84  0
                 return result;
 85  
         }
 86  
 
 87  
         private void init(double[] x, double[] y) {
 88  0
                 if (x.length != y.length) {
 89  0
                         throw new IllegalArgumentException("Arrays must have the same length.");
 90  
                 }
 91  
 
 92  0
                 if (x.length < 2) {
 93  0
                         throw new IllegalArgumentException("Spline edges must have at least two points.");
 94  
                 }
 95  
 
 96  0
                 t = new double[x.length];
 97  0
                 t[0] = 0.0; // start point is always 0.0
 98  
 
 99  
                 // Calculate the partial proportions of each section between each set
 100  
                 // of points and the total length of sum of all sections
 101  0
                 for (int i = 1; i < t.length; i++) {
 102  0
                         double lx = x[i] - x[i-1];
 103  0
                         double ly = y[i] - y[i-1];
 104  
                         // If either diff is zero there is no point performing the square root
 105  0
                         if ( 0.0 == lx ) {
 106  0
                                 t[i] = Math.abs(ly);
 107  0
                         } else if ( 0.0 == ly ) {
 108  0
                                 t[i] = Math.abs(lx);
 109  
                         } else {
 110  0
                                 t[i] = Math.sqrt(lx*lx+ly*ly);
 111  
                         }
 112  
 
 113  0
                         length += t[i];
 114  0
                         t[i] += t[i-1];
 115  
                 }
 116  
 
 117  0
                 for(int i = 1; i< (t.length)-1; i++) {
 118  0
                         t[i] = t[i] / length;
 119  
                 }
 120  
 
 121  0
                 t[(t.length)-1] = 1.0; // end point is always 1.0
 122  
 
 123  0
                 splineX = new Spline(t, x);
 124  0
                 splineY = new Spline(t, y);
 125  0
         }
 126  
 
 127  
         /**
 128  
          * Used to check the correctness of this spline
 129  
          */
 130  
         /*
 131  
         public boolean checkValues() {
 132  
                 return (splineX.checkValues() && splineY.checkValues());
 133  
         }
 134  
 
 135  
         public double getDx(double t) {
 136  
                 return splineX.getDx(t);
 137  
         }
 138  
 
 139  
         public double getDy(double t) {
 140  
                 return splineY.getDx(t);
 141  
         }
 142  
 
 143  
         public Spline getSplineX() {
 144  
                 return splineX;
 145  
         }
 146  
 
 147  
         public Spline getSplineY() {
 148  
                 return splineY;
 149  
         }
 150  
 
 151  
         public double getLength() {
 152  
                 return length;
 153  
         }
 154  
         */
 155  
 }
 156  
 
 157  
 /* This code is PUBLIC DOMAIN */
 158  
 
 159  
 
 160  
 /**
 161  
  * Interpolates given values by B-Splines.
 162  
  * 
 163  
  * @author krueger
 164  
  */
 165  
 class Spline {
 166  
 
 167  
         private double[] xx;
 168  
         private double[] yy;
 169  
 
 170  
         private double[] a;
 171  
         private double[] b;
 172  
         private double[] c;
 173  
         private double[] d;
 174  
 
 175  
         /** tracks the last index found since that is mostly commonly the next one used */
 176  0
         private int storageIndex = 0;
 177  
 
 178  
         /**
 179  
          * Creates a new Spline.
 180  
          * @param xx
 181  
          * @param yy
 182  
          */
 183  0
         public Spline(double[] xx, double[] yy) {
 184  0
                 setValues(xx, yy);
 185  0
         }
 186  
 
 187  
         /**
 188  
          * Set values for this Spline.
 189  
          * @param xx
 190  
          * @param yy
 191  
          */
 192  
         public void setValues(double[] xx, double[] yy) {
 193  0
                 this.xx = xx;
 194  0
                 this.yy = yy;
 195  0
                 if (xx.length > 1) {
 196  0
                         calculateCoefficients();
 197  
                 }
 198  0
         }
 199  
 
 200  
         /**
 201  
          * Returns an interpolated value.
 202  
          * @param x
 203  
          * @return the interpolated value
 204  
          */
 205  
         public double getValue(double x) {
 206  0
                 if (xx.length == 0) {
 207  0
                         return Double.NaN;
 208  
                 }
 209  
 
 210  0
                 if (xx.length == 1) {
 211  0
                         if (xx[0] == x) {
 212  0
                                 return yy[0];
 213  
                         } else {
 214  0
                                 return Double.NaN;
 215  
                         }
 216  
                 }
 217  
 
 218  0
                 int index = Arrays.binarySearch(xx, x);
 219  0
                 if (index > 0) {
 220  0
                         return yy[index];
 221  
                 }
 222  
 
 223  0
                 index = - (index + 1) - 1;
 224  
                 // TO DO linear interpolation or extrapolation
 225  0
                 if (index < 0) {
 226  0
                         return yy[0];
 227  
                 }
 228  
 
 229  0
                 return a[index]
 230  
                          + b[index] * (x - xx[index])
 231  0
                          + c[index] * Math.pow(x - xx[index], 2)
 232  0
                          + d[index] * Math.pow(x - xx[index], 3);
 233  
         }
 234  
 
 235  
         /**
 236  
          * Returns an interpolated value. To be used when a long sequence of values
 237  
          * are required in order, but ensure checkValues() is called beforehand to
 238  
          * ensure the boundary checks from getValue() are made
 239  
          * @param x
 240  
          * @return the interpolated value
 241  
          */
 242  
         public double getFastValue(double x) {
 243  
                 // Fast check to see if previous index is still valid
 244  0
                 if (storageIndex > -1 && storageIndex < xx.length-1 && x > xx[storageIndex] && x < xx[storageIndex + 1]) {
 245  
 
 246  
                 } else {
 247  0
                         int index = Arrays.binarySearch(xx, x);
 248  0
                         if (index > 0) {
 249  0
                                 return yy[index];
 250  
                         }
 251  0
                         index = - (index + 1) - 1;
 252  0
                         storageIndex = index;
 253  
                 }
 254  
 
 255  
                 // TO DO linear interpolation or extrapolation
 256  0
                 if (storageIndex < 0) {
 257  0
                         return yy[0];
 258  
                 }
 259  0
                 double value = x - xx[storageIndex];
 260  0
                 return a[storageIndex]
 261  
                          + b[storageIndex] * value
 262  
                          + c[storageIndex] * (value * value)
 263  
                          + d[storageIndex] * (value * value * value);
 264  
         }
 265  
 
 266  
         /**
 267  
          * Used to check the correctness of this spline
 268  
          */
 269  
         public boolean checkValues() {
 270  0
                 if (xx.length < 2) {
 271  0
                         return false;
 272  
                 } else {
 273  0
                         return true;
 274  
                 }
 275  
         }
 276  
 
 277  
         /**
 278  
          * Returns the first derivation at x.
 279  
          * @param x
 280  
          * @return the first derivation at x
 281  
          */
 282  
         public double getDx(double x) {
 283  0
                 if (xx.length == 0 || xx.length == 1) {
 284  0
                         return 0;
 285  
                 }
 286  
 
 287  0
                 int index = Arrays.binarySearch(xx, x);
 288  0
                 if (index < 0) {
 289  0
                         index = - (index + 1) - 1;
 290  
                 }
 291  
 
 292  0
                 return b[index]
 293  
                          + 2 * c[index] * (x - xx[index])
 294  0
                          + 3 * d[index] * Math.pow(x - xx[index], 2);
 295  
         }
 296  
 
 297  
         /**
 298  
          * Calculates the Spline coefficients.
 299  
          */
 300  
         private void calculateCoefficients() {
 301  0
                 int N = yy.length;
 302  0
                 a = new double[N];
 303  0
                 b = new double[N];
 304  0
                 c = new double[N];
 305  0
                 d = new double[N];
 306  
 
 307  0
                 if (N == 2) {
 308  0
                         a[0] = yy[0];
 309  0
                         b[0] = yy[1] - yy[0];
 310  0
                         return;
 311  
                 }
 312  
 
 313  0
                 double[] h = new double[N - 1];
 314  0
                 for (int i = 0; i < N - 1; i++) {
 315  0
                         a[i] = yy[i];
 316  0
                         h[i] = xx[i + 1] - xx[i];
 317  
                         // h[i] is used for division later, avoid a NaN
 318  0
                         if (h[i] == 0.0) {
 319  0
                                 h[i] = 0.01;
 320  
                         }
 321  
                 }
 322  0
                 a[N - 1] = yy[N - 1];
 323  
 
 324  0
                 double[][] A = new double[N - 2][N - 2];
 325  0
                 double[] y = new double[N - 2];
 326  0
                 for (int i = 0; i < N - 2; i++) {
 327  0
                         y[i] =
 328  
                                 3
 329  
                                 * ((yy[i + 2] - yy[i + 1]) / h[i
 330  
                                                                + 1]
 331  
                                                                - (yy[i + 1] - yy[i]) / h[i]);
 332  
 
 333  0
                         A[i][i] = 2 * (h[i] + h[i + 1]);
 334  
 
 335  0
                         if (i > 0) {
 336  0
                                 A[i][i - 1] = h[i];
 337  
                         }
 338  
 
 339  0
                         if (i < N - 3) {
 340  0
                                 A[i][i + 1] = h[i + 1];
 341  
                         }
 342  
                 }
 343  0
                 solve(A, y);
 344  
 
 345  0
                 for (int i = 0; i < N - 2; i++) {
 346  0
                         c[i + 1] = y[i];
 347  0
                         b[i] = (a[i + 1] - a[i]) / h[i] - (2 * c[i] + c[i + 1]) / 3 * h[i];
 348  0
                         d[i] = (c[i + 1] - c[i]) / (3 * h[i]);
 349  
                 }
 350  0
                 b[N - 2] =
 351  
                         (a[N - 1] - a[N - 2]) / h[N
 352  
                                                   - 2]
 353  
                                                   - (2 * c[N - 2] + c[N - 1]) / 3 * h[N
 354  
                                                                                       - 2];
 355  0
                 d[N - 2] = (c[N - 1] - c[N - 2]) / (3 * h[N - 2]);
 356  0
         }
 357  
 
 358  
         /**
 359  
          * Solves Ax=b and stores the solution in b.
 360  
          */
 361  
         public void solve(double[][] A, double[] b) {
 362  0
                 int n = b.length;
 363  0
                 for (int i = 1; i < n; i++) {
 364  0
                         A[i][i - 1] = A[i][i - 1] / A[i - 1][i - 1];
 365  0
                         A[i][i] = A[i][i] - A[i - 1][i] * A[i][i - 1];
 366  0
                         b[i] = b[i] - A[i][i - 1] * b[i - 1];
 367  
                 }
 368  
 
 369  0
                 b[n - 1] = b[n - 1] / A[n - 1][n - 1];
 370  0
                 for (int i = b.length - 2; i >= 0; i--) {
 371  0
                         b[i] = (b[i] - A[i][i + 1] * b[i + 1]) / A[i][i];
 372  
                 }
 373  0
         }
 374  
 }