Java/2D Graphics GUI/Curve

Материал из Java эксперт
Перейти к: навигация, поиск

A spline factory instance

<source lang="java"> /*

* This code is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public 
* License as published by the Free Software Foundation; either 
* version 2.1 of the License, or (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public 
* License along with this program; if not, write to the Free 
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, 
* MA  02111-1307, USA.
*/

//package no.geosoft.cc.geometry.spline;

/**

* A spline factory instance.
* 
* @author 
*/   

class CatmullRomSpline extends CubicSpline {

 /**
  * Construct a Catmull-Rom spline. Package local; Use the SplineFactory
  * to create splines of this type. The control points are used according
  * to the definition of Catmull-Rom splines.
  * 
  * @param controlPoints  Control points of spline (x0,y0,z0,x1,y1,z1,...)
  * @param nParts         Number of parts in generated spline.
  */
 CatmullRomSpline (double controlPoints[], int nParts)
 {
   super (controlPoints, nParts);
 }


 protected void initialize (double controlPoints[], int nParts)
 {
   nParts_ = nParts;
   // Endpoints are added twice to force in the generated array
   controlPoints_ = new double[controlPoints.length + 6];
   System.arraycopy (controlPoints, 0, controlPoints_, 3,
                     controlPoints.length);
   
   controlPoints_[0] = controlPoints_[3];
   controlPoints_[1] = controlPoints_[4];
   controlPoints_[2] = controlPoints_[5];
   
   controlPoints_[controlPoints_.length - 3] = controlPoints_[controlPoints_.length - 6];
   controlPoints_[controlPoints_.length - 2] = controlPoints_[controlPoints_.length - 5];
   controlPoints_[controlPoints_.length - 1] = controlPoints_[controlPoints_.length - 4];
 }
 
 
 protected double blend (int i, double t)
 {
   if      (i == -2) return ((-t + 2) * t - 1) * t / 2;
   else if (i == -1) return (((3 * t - 5) * t) * t + 2) / 2;
   else if (i ==  0) return ((-3 * t + 4) * t + 1) * t / 2;
   else              return ((t - 1) * t * t) / 2;
 }

}



 </source>   



Curve with QuadCurve2D

<source lang="java"> import java.awt.Canvas; import java.awt.Color; import java.awt.Container; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.geom.QuadCurve2D; import java.awt.geom.Rectangle2D; import java.util.Vector; import javax.swing.JApplet; import javax.swing.JFrame; public class QuadCurve extends JApplet {

 DrawingCanvas canvas;
 public static void main(String[] a){
     JFrame f = new JFrame();
     QuadCurve curve = new QuadCurve();
     curve.init();
     f.getContentPane().add(curve);
     f.setDefaultCloseOperation(1);
     f.setSize(650,250);
     f.setVisible(true);
 }
 
 public void init() {
   Container container = getContentPane();
   canvas = new DrawingCanvas();
   container.add(canvas);
 }
 class DrawingCanvas extends Canvas {
   Vector quadCurves;
   QuadCurve2D selectedCurve = null;
   Rectangle2D boundingRec = null;
   public DrawingCanvas() {
     setBackground(Color.white);
     setSize(400, 200); // width and height of canvas
     quadCurves = new Vector();
     quadCurves.addElement(new QuadCurve2D.Float(20, 20, 80, 160, 120,
         20));
     quadCurves.addElement(new QuadCurve2D.Float(120, 100, 160, 40, 200,
         180));
     quadCurves.addElement(new QuadCurve2D.Float(240, 20, 220, 60, 260,
         120));
     quadCurves.addElement(new QuadCurve2D.Float(250, 160, 260, 140,
         280, 180));
     quadCurves.addElement(new QuadCurve2D.Float(300, 180, 340, 40, 380,
         120));
     quadCurves.addElement(new QuadCurve2D.Float(20, 180, 80, 170, 120,
         190));
   }
   public void paint(Graphics g) {
     Graphics2D g2D = (Graphics2D) g;
     for (int i = 0; i < quadCurves.size(); i++) {
       g2D.draw((QuadCurve2D) quadCurves.elementAt(i));
     }
   }
 }

}


 </source>   



Draw curve with mouse

<source lang="java"> import java.awt.BasicStroke; import java.awt.BorderLayout; import java.awt.Canvas; import java.awt.Color; import java.awt.Container; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GridLayout; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.geom.CubicCurve2D; import java.awt.geom.Line2D; import java.awt.geom.QuadCurve2D; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; public class CubicCurveMouse extends JFrame {

 DrawingCanvas canvas;
 JLabel label = new JLabel("Mouse Location (x, y):  "); 
 JLabel coords = new JLabel("");
 public CubicCurveMouse() {
   super();
   Container container = getContentPane();
   JPanel panel = new JPanel();
   panel.setLayout(new GridLayout(1, 2));
   
   panel.add(label);
   panel.add(label);
   panel.add(coords);
   container.add(panel, BorderLayout.SOUTH);
   canvas = new DrawingCanvas();
   container.add(canvas);
   addWindowListener(new WindowEventHandler());
       setSize(300,300);
   setVisible(true);
 }
 class WindowEventHandler extends WindowAdapter {
   public void windowClosing(WindowEvent e) {
     System.exit(0);
   }
 }
 public static void main(String arg[]) {
   new CubicCurveMouse();
 }
 class DrawingCanvas extends Canvas {
   float x1, y1, xc1cur, yc1cur, xc1new, yc1new, xc2cur, yc2cur, xc2new,
       yc2new, x4cur, y4cur, x4new, y4new;
   int pressNo = 0;
   int dragFlag1 = -1;
   int dragFlag2 = -1;
   boolean clearFlag = false;
   float dashes[] = { 5f, 5f };
   BasicStroke stroke;
   public DrawingCanvas() {
     setBackground(Color.white);
     addMouseListener(new MyMouseListener());
     addMouseMotionListener(new MyMouseListener());
     setSize(400, 400);
     stroke = new BasicStroke(1f, BasicStroke.CAP_BUTT,
         BasicStroke.JOIN_BEVEL, 10f, dashes, 0f);
   }
   public void update(Graphics g) {
     paint(g);
   }
   public void paint(Graphics g) {
     Graphics2D g2D = (Graphics2D) g;
     if (pressNo == 1) {
       g2D.setXORMode(getBackground());
       g2D.setColor(Color.black);
       g2D.setStroke(stroke);
       // Erase the currently existing line
       g2D.draw(new Line2D.Float(x1, y1, x4cur, y4cur));
       // Draw the new line
       g2D.draw(new Line2D.Float(x1, y1, x4new, y4new));
       // Update the currently existing coordinate values
       x4cur = x4new;
       y4cur = y4new;
     }else if (pressNo == 2) {
       g2D.setXORMode(getBackground());
       g2D.setColor(Color.black);
       g2D.setStroke(stroke);
       if (dragFlag1 != -1) {
         g2D.draw(new QuadCurve2D.Float(x1, y1, xc1cur, yc1cur,
             x4new, y4new));
       }
       dragFlag1++; // Reset the drag-flag
       g2D.draw(new QuadCurve2D.Float(x1, y1, xc1new, yc1new, x4new,
           y4new));
       xc1cur = xc1new;
       yc1cur = yc1new;
     }else if (pressNo == 3) {
       g2D.setXORMode(getBackground());
       g2D.setColor(Color.black);
       if (dragFlag2 != -1) {
         g2D.draw(new CubicCurve2D.Float(x1, y1, xc1new, yc1new,
             xc2cur, yc2cur, x4new, y4new));
       }
       dragFlag2++; // Reset the drag flag
       g2D.draw(new CubicCurve2D.Float(x1, y1, xc1new, yc1new, xc2new,
           yc2new, x4new, y4new));
       xc2cur = xc2new;
       yc2cur = yc2new;
     }
     if (clearFlag) {
       g2D.setXORMode(getBackground());
       g2D.setColor(Color.black);
       g2D.setStroke(stroke);
       g2D.draw(new Line2D.Float(x1, y1, x4new, y4new));
       g2D.draw(new QuadCurve2D.Float(x1, y1, xc1new, yc1new, x4new,
           y4new));
       clearFlag = false;
     }
   }
   class MyMouseListener extends MouseAdapter implements MouseMotionListener {
     public void mousePressed(MouseEvent e) {
       if (pressNo == 0) { 
         pressNo++;
         x1 = x4cur = e.getX();
         y1 = y4cur = e.getY();
       } else if (pressNo == 1) {
         pressNo++;
         xc1cur = e.getX();
         yc1cur = e.getY();
       } else if (pressNo == 2) {
         pressNo++;
         xc2cur = e.getX();
         yc2cur = e.getY();
       }
     }
     public void mouseReleased(MouseEvent e) {
       if (pressNo == 1) {
         x4new = e.getX();
         y4new = e.getY();
         canvas.repaint();
       } else if (pressNo == 2) {
         xc1new = e.getX();
         yc1new = e.getY();
         canvas.repaint();
       } else if (pressNo == 3) {
         xc2new = e.getX();
         yc2new = e.getY();
         canvas.repaint();
         pressNo = 0;
         dragFlag1 = -1;
         dragFlag2 = -1;
         clearFlag = true;
       }
     }
     public void mouseDragged(MouseEvent e) {
       if (pressNo == 1) {
         x4new = e.getX();
         y4new = e.getY();
         String string = "(" + Integer.toString(e.getX()) + ", "
             + Integer.toString(e.getY()) + ")";
         coords.setText(string);
         canvas.repaint();
       } else if (pressNo == 2) {
         xc1new = e.getX();
         yc1new = e.getY();
         String string = "(" + Integer.toString(e.getX()) + ", "
             + Integer.toString(e.getY()) + ")";
         coords.setText(string);
         canvas.repaint();
       } else if (pressNo == 3) {
         xc2new = e.getX();
         yc2new = e.getY();
         String string = "(" + Integer.toString(e.getX()) + ", "
             + Integer.toString(e.getY()) + ")";
         coords.setText(string);
         canvas.repaint();
       }
     }
     public void mouseMoved(MouseEvent e) {
       String string = "(" + Integer.toString(e.getX()) + ", "
           + Integer.toString(e.getY()) + ")";
       coords.setText(string);
     }
   }
 }

}


 </source>   



Interpolates given points by a bezier curve

<source lang="java"> /*

* Copyright (c) 2005 David Benson
*  
* See LICENSE file in distribution for licensing details of this source file
*/

import java.awt.Point; import java.awt.geom.Point2D; /**

* Interpolates given points by a bezier curve. The first
* and the last two points are interpolated by a quadratic
* bezier curve; the other points by a cubic bezier curve.
* 
* Let p a list of given points and b the calculated bezier points,
* then one get the whole curve by:
* 
* sharedPath.moveTo(p[0])
* sharedPath.quadTo(b[0].x, b[0].getY(), p[1].x, p[1].getY());
* 
* for(int i = 2; i < p.length - 1; i++ ) {
*    Point b0 = b[2*i-3];
*    Point b1 = b[2*i-2];
*    sharedPath.curveTo(b0.x, b0.getY(), b1.x, b1.getY(), p[i].x, p[i].getY());
* }
* 
* sharedPath.quadTo(b[b.length-1].x, b[b.length-1].getY(), p[n - 1].x, p[n - 1].getY());
* 
* @author krueger
*/

public class Bezier {

 private static final float AP = 0.5f;
 private Point2D[] bPoints;
 /**
  * Creates a new Bezier curve.
  * @param points
  */
 public Bezier(Point2D[] points) {
   int n = points.length;
   if (n < 3) {
     // Cannot create bezier with less than 3 points
     return;
   }
   bPoints = new Point[2 * (n - 2)];
   double paX, paY;
   double pbX = points[0].getX();
   double pbY = points[0].getY();
   double pcX = points[1].getX();
   double pcY = points[1].getY();
   for (int i = 0; i < n - 2; i++) {
     paX = pbX;
     paY = pbY;
     pbX = pcX;
     pbY = pcY;
     pcX = points[i + 2].getX();
     pcY = points[i + 2].getY();
     double abX = pbX - paX;
     double abY = pbY - paY;
     double acX = pcX - paX;
     double acY = pcY - paY;
     double lac = Math.sqrt(acX * acX + acY * acY);
     acX = acX /lac;
     acY = acY /lac;
     double proj = abX * acX + abY * acY;
     proj = proj < 0 ? -proj : proj;
     double apX = proj * acX;
     double apY = proj * acY;
     double p1X = pbX - AP * apX;
     double p1Y = pbY - AP * apY;
     bPoints[2 * i] = new Point((int) p1X, (int) p1Y);
     acX = -acX;
     acY = -acY;
     double cbX = pbX - pcX;
     double cbY = pbY - pcY;
     proj = cbX * acX + cbY * acY;
     proj = proj < 0 ? -proj : proj;
     apX = proj * acX;
     apY = proj * acY;
     double p2X = pbX - AP * apX;
     double p2Y = pbY - AP * apY;
     bPoints[2 * i + 1] = new Point((int) p2X, (int) p2Y);
   }
 }
 /**
  * Returns the calculated bezier points.
  * @return the calculated bezier points
  */
 public Point2D[] getPoints() {
   return bPoints;
 }
 /**
  * Returns the number of bezier points.
  * @return number of bezier points
  */
 public int getPointCount() {
   return bPoints.length;
 }
 /**
  * Returns the bezier points at position i.
  * @param i
  * @return the bezier point at position i
  */
 public Point2D getPoint(int i) {
   return bPoints[i];
 }

}


 </source>   



Move the curve control point and redraw the curve

<source lang="java"> import java.awt.BorderLayout; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.event.MouseEvent; import java.awt.geom.CubicCurve2D; import java.awt.geom.Ellipse2D; import java.awt.geom.Line2D; import java.awt.geom.Point2D; import java.awt.geom.QuadCurve2D; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.event.MouseInputAdapter; public class MainClass {

 public static void main(String[] args){
   JFrame frame = new JFrame();
   frame.getContentPane().add(new CurveApplet());
   frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
   frame.setSize(200, 200);
   frame.setVisible(true);
 }

} class CurveApplet extends JPanel {

 public CurveApplet() {
   super(new BorderLayout());
   pane = new CurvePane();
   add(pane,"Center");
   MouseHandler handler = new MouseHandler();
   pane.addMouseListener(handler);
   pane.addMouseMotionListener(handler);
 }
 class CurvePane extends JComponent {
   public CurvePane() {
     quadCurve = new QuadCurve2D.Double( 
         startQ.x, startQ.y, 
         control.x, control.y,
         endQ.x, endQ.y);
     cubicCurve = new CubicCurve2D.Double(
         startC.x, startC.y, 
         controlStart.x, controlStart.y,
         controlEnd.x, controlEnd.y,
         endC.x, endC.y);
   }
   public void paint(Graphics g) {
     Graphics2D g2D = (Graphics2D) g;
     quadCurve.ctrlx = ctrlQuad.getCenter().x;
     quadCurve.ctrly = ctrlQuad.getCenter().y;
     cubicCurve.ctrlx1 = ctrlCubic1.getCenter().x;
     cubicCurve.ctrly1 = ctrlCubic1.getCenter().y;
     cubicCurve.ctrlx2 = ctrlCubic2.getCenter().x;
     cubicCurve.ctrly2 = ctrlCubic2.getCenter().y;
     g2D.setPaint(Color.BLUE);
     g2D.draw(quadCurve);
     g2D.draw(cubicCurve);
     g2D.setPaint(Color.RED);
     ctrlQuad.draw(g2D);
     ctrlCubic1.draw(g2D);
     ctrlCubic2.draw(g2D);
     Line2D.Double tangent = new Line2D.Double(startQ, ctrlQuad.getCenter());
     g2D.draw(tangent);
     tangent = new Line2D.Double(endQ, ctrlQuad.getCenter());
     g2D.draw(tangent);
     tangent = new Line2D.Double(startC, ctrlCubic1.getCenter());
     g2D.draw(tangent);
     tangent = new Line2D.Double(endC, ctrlCubic2.getCenter());
     g2D.draw(tangent);
   }
 }

 Point2D.Double startQ = new Point2D.Double(50, 75);
 Point2D.Double endQ = new Point2D.Double(150, 75);
 Point2D.Double control = new Point2D.Double(80, 25); 
 Point2D.Double startC = new Point2D.Double(50, 150); 
 Point2D.Double endC = new Point2D.Double(150, 150); 
 Point2D.Double controlStart = new Point2D.Double(80, 100);
 Point2D.Double controlEnd = new Point2D.Double(160, 100); 
 Marker ctrlQuad = new Marker(control);
 Marker ctrlCubic1 = new Marker(controlStart);
 Marker ctrlCubic2 = new Marker(controlEnd);
 QuadCurve2D.Double quadCurve; 
 CubicCurve2D.Double cubicCurve; 
 CurvePane pane = new CurvePane();
 class Marker {
   public Marker(Point2D.Double control) {
     center = control; 
     circle = new Ellipse2D.Double(control.x - radius, control.y - radius, 2.0 * radius,
         2.0 * radius);
   }
   public void draw(Graphics2D g2D) {
     g2D.draw(circle);
   }
   Point2D.Double getCenter() {
     return center;
   }
   public boolean contains(double x, double y) {
     return circle.contains(x, y);
   }
   public void setLocation(double x, double y) {
     center.x = x; 
     center.y = y; 
     circle.x = x - radius; 
     circle.y = y - radius; 
   }
   Ellipse2D.Double circle; 
   Point2D.Double center; 
   static final double radius = 3;
 }
 class MouseHandler extends MouseInputAdapter {
   public void mousePressed(MouseEvent e) {
     if (ctrlQuad.contains(e.getX(), e.getY()))
       selected = ctrlQuad;
     else if (ctrlCubic1.contains(e.getX(), e.getY()))
       selected = ctrlCubic1;
     else if (ctrlCubic2.contains(e.getX(), e.getY()))
       selected = ctrlCubic2;
   }
   public void mouseReleased(MouseEvent e) {
     selected = null;
   }
   public void mouseDragged(MouseEvent e) {
     if (selected != null) {
       selected.setLocation(e.getX(), e.getY());
       pane.repaint(); 
     }
   }
   Marker selected = null;
 }

}


 </source>   



Spline 2D

<source lang="java"> /*

* @(#)Spline2D.java
* 
* Copyright (c) 2003 Martin Krueger
* Copyright (c) 2005 David Benson
*  
*/

import java.awt.geom.Point2D; import java.util.Arrays; /**

* Interpolates points given in the 2D plane. The resulting spline
* is a function s: R -> R^2 with parameter t in [0,1].
* 
* @author krueger
*/

public class Spline2D {

 /** 
  *  Array representing the relative proportion of the total distance
  *  of each point in the line ( i.e. first point is 0.0, end point is
  *  1.0, a point halfway on line is 0.5 ).
  */
 private double[] t;
 private Spline splineX;
 private Spline splineY;
 /**
  * Total length tracing the points on the spline
  */
 private double length;
 
 /**
  * Creates a new Spline2D.
  * @param points
  */
 public Spline2D(Point2D[] points) {
   double[] x = new double[points.length];
   double[] y = new double[points.length];
   
   for(int i = 0; i< points.length; i++) {
     x[i] = points[i].getX();
     y[i] = points[i].getY(); 
   }
   
   init(x, y);
 }
 /**
  * Creates a new Spline2D.
  * @param x
  * @param y
  */
 public Spline2D(double[] x, double[] y) {
   init(x, y);
 }
 private void init(double[] x, double[] y) {
   if (x.length != y.length) {
     throw new IllegalArgumentException("Arrays must have the same length.");
   }
   
   if (x.length < 2) {
     throw new IllegalArgumentException("Spline edges must have at least two points.");
   }
   t = new double[x.length];
   t[0] = 0.0; // start point is always 0.0
   
   // Calculate the partial proportions of each section between each set
   // of points and the total length of sum of all sections
   for (int i = 1; i < t.length; i++) {
     double lx = x[i] - x[i-1];
     double ly = y[i] - y[i-1];
     // If either diff is zero there is no point performing the square root
     if ( 0.0 == lx ) {
       t[i] = Math.abs(ly);
     } else if ( 0.0 == ly ) {
       t[i] = Math.abs(lx);
     } else {
       t[i] = Math.sqrt(lx*lx+ly*ly);
     }
     
     length += t[i];
     t[i] += t[i-1];
   }
   
   for(int i = 1; i< (t.length)-1; i++) {
     t[i] = t[i] / length;
   }
   
   t[(t.length)-1] = 1.0; // end point is always 1.0
   
   splineX = new Spline(t, x);
   splineY = new Spline(t, y);
 }
 /**
  * @param t 0 <= t <= 1
  */
 public double[] getPoint(double t) {
   double[] result = new double[2];
   result[0] = splineX.getValue(t);
   result[1] = splineY.getValue(t);
   return result;
 }
 
 /**
  * Used to check the correctness of this spline
  */
 public boolean checkValues() {
   return (splineX.checkValues() && splineY.checkValues());
 }
 public double getDx(double t) {
   return splineX.getDx(t);
 }
 
 public double getDy(double t) {
   return splineY.getDx(t);
 }
 
 public Spline getSplineX() {
   return splineX;
 }
 
 public Spline getSplineY() {
   return splineY;
 }
 
 public double getLength() {
   return length;
 }

} /* This code is PUBLIC DOMAIN */

/**

* Interpolates given values by B-Splines.
* 
* @author krueger
*/
class Spline {
 private double[] xx;
 private double[] yy;
 private double[] a;
 private double[] b;
 private double[] c;
 private double[] d;
 /** tracks the last index found since that is mostly commonly the next one used */
 private int storageIndex = 0;
 /**
  * Creates a new Spline.
  * @param xx
  * @param yy
  */
 public Spline(double[] xx, double[] yy) {
   setValues(xx, yy);
 }
 /**
  * Set values for this Spline.
  * @param xx
  * @param yy
  */
 public void setValues(double[] xx, double[] yy) {
   this.xx = xx;
   this.yy = yy;
   if (xx.length > 1) {
     calculateCoefficients();
   }
 }
 /**
  * Returns an interpolated value.
  * @param x
  * @return the interpolated value
  */
 public double getValue(double x) {
   if (xx.length == 0) {
     return Double.NaN;
   }
   if (xx.length == 1) {
     if (xx[0] == x) {
       return yy[0];
     } else {
       return Double.NaN;
     }
   }
   int index = Arrays.binarySearch(xx, x);
   if (index > 0) {
     return yy[index];
   }
   index = - (index + 1) - 1;
   //TODO linear interpolation or extrapolation
   if (index < 0) {
     return yy[0];
   }
   return a[index]
     + b[index] * (x - xx[index])
     + c[index] * Math.pow(x - xx[index], 2)
     + d[index] * Math.pow(x - xx[index], 3);
 }
 /**
  * Returns an interpolated value. To be used when a long sequence of values
  * are required in order, but ensure checkValues() is called beforehand to
  * ensure the boundary checks from getValue() are made
  * @param x
  * @return the interpolated value
  */
 public double getFastValue(double x) {
   // Fast check to see if previous index is still valid
   if (storageIndex > -1 && storageIndex < xx.length-1 && x > xx[storageIndex] && x < xx[storageIndex + 1]) {
   } else {
     int index = Arrays.binarySearch(xx, x);
     if (index > 0) {
       return yy[index];
     }
     index = - (index + 1) - 1;
     storageIndex = index;
   }
 
   //TODO linear interpolation or extrapolation
   if (storageIndex < 0) {
     return yy[0];
   }
   double value = x - xx[storageIndex];
   return a[storageIndex]
         + b[storageIndex] * value
         + c[storageIndex] * (value * value)
         + d[storageIndex] * (value * value * value);
 }
 /**
  * Used to check the correctness of this spline
  */
 public boolean checkValues() {
   if (xx.length < 2) {
     return false;
   } else {
     return true;
   }
 }
 /**
  * Returns the first derivation at x.
  * @param x
  * @return the first derivation at x
  */
 public double getDx(double x) {
   if (xx.length == 0 || xx.length == 1) {
     return 0;
   }
   int index = Arrays.binarySearch(xx, x);
   if (index < 0) {
     index = - (index + 1) - 1;
   }
   return b[index]
     + 2 * c[index] * (x - xx[index])
     + 3 * d[index] * Math.pow(x - xx[index], 2);
 }
 /**
  * Calculates the Spline coefficients.
  */
 private void calculateCoefficients() {
   int N = yy.length;
   a = new double[N];
   b = new double[N];
   c = new double[N];
   d = new double[N];
   if (N == 2) {
     a[0] = yy[0];
     b[0] = yy[1] - yy[0];
     return;
   }
   double[] h = new double[N - 1];
   for (int i = 0; i < N - 1; i++) {
     a[i] = yy[i];
     h[i] = xx[i + 1] - xx[i];
     // h[i] is used for division later, avoid a NaN
     if (h[i] == 0.0) {
       h[i] = 0.01;
     }
   }
   a[N - 1] = yy[N - 1];
   double[][] A = new double[N - 2][N - 2];
   double[] y = new double[N - 2];
   for (int i = 0; i < N - 2; i++) {
     y[i] =
       3
         * ((yy[i + 2] - yy[i + 1]) / h[i
           + 1]
           - (yy[i + 1] - yy[i]) / h[i]);
     A[i][i] = 2 * (h[i] + h[i + 1]);
     if (i > 0) {
       A[i][i - 1] = h[i];
     }
     if (i < N - 3) {
       A[i][i + 1] = h[i + 1];
     }
   }
   solve(A, y);
   for (int i = 0; i < N - 2; i++) {
     c[i + 1] = y[i];
     b[i] = (a[i + 1] - a[i]) / h[i] - (2 * c[i] + c[i + 1]) / 3 * h[i];
     d[i] = (c[i + 1] - c[i]) / (3 * h[i]);
   }
   b[N - 2] =
     (a[N - 1] - a[N - 2]) / h[N
       - 2]
       - (2 * c[N - 2] + c[N - 1]) / 3 * h[N
       - 2];
   d[N - 2] = (c[N - 1] - c[N - 2]) / (3 * h[N - 2]);
 }
 /**
  * Solves Ax=b and stores the solution in b.
  */
 public void solve(double[][] A, double[] b) {
   int n = b.length;
   for (int i = 1; i < n; i++) {
     A[i][i - 1] = A[i][i - 1] / A[i - 1][i - 1];
     A[i][i] = A[i][i] - A[i - 1][i] * A[i][i - 1];
     b[i] = b[i] - A[i][i - 1] * b[i - 1];
   }
   b[n - 1] = b[n - 1] / A[n - 1][n - 1];
   for (int i = b.length - 2; i >= 0; i--) {
     b[i] = (b[i] - A[i][i + 1] * b[i + 1]) / A[i][i];
   }
 }

}


 </source>