Java/2D Graphics GUI/Curve
Содержание
A spline factory instance
/*
* 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;
}
}
Curve with QuadCurve2D
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));
}
}
}
}
Draw curve with mouse
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);
}
}
}
}
Interpolates given points by a bezier curve
/*
* 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];
}
}
Move the curve control point and redraw the curve
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;
}
}
Spline 2D
/*
* @(#)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];
}
}
}