Java Curve Binding Library

I hope to find a simple library that can take a series of 2-dimensional points and return me a large series of points that model the curve. Basically, I want to get a curve effect similar to this sample from JFreeChart:

alt text http://www.jfree.org/jfreechart/images/XYSplineRendererDemo1a.png

The problem with JFreeChart is that the code does not provide this type of api. I even looked at the source, and the algorithm is closely related to the actual drawing.

+18
java curve-fitting
May 18, '09 at 15:07
source share
2 answers

Apache Commons Math has an excellent series of algorithms, in particular "SplineInterpolator", see API docs

An example in which we call the interpolation functions for alpha (x), beta (x) from Groovy:

package example.com import org.apache.commons.math3.analysis.interpolation.SplineInterpolator import org.apache.commons.math3.analysis.polynomials.PolynomialSplineFunction import statec.Extrapolate.Value; class Interpolate { enum Value { ALPHA, BETA } def static xValues = [ -284086, -94784, 31446, 354837, 667782, 982191 ] def static alphaValues = [ 71641, 78245, 80871, 94045, 105780, 119616 ] def static betaValues = [ 95552, 103413, 108667, 128456, 144686, 171953 ] static def getValueByName(Value value, int i) { def res switch (value) { case Value.ALPHA: res = alphaValues[i] break case Value.BETA: res = betaValues[i] break default: assert false } return res } static PolynomialSplineFunction interpolate(Value value) { def yValues = [] int i = 0 xValues.each { def y = getValueByName(value, i++) yValues << (y as Double) } SplineInterpolator spi = new SplineInterpolator() return spi.interpolate(xValues as double[], yValues as double[]) } static void main(def argv) { // // Create a map mapping a Value instance to its interpolating function // def interpolations = [:] Value.values().each { interpolations[it] = interpolate(it) } // // Create an array of new x values to compute display. // Make sure the last "original" value is in there! // Note that the newxValues MUST stay within the range of the original xValues! // def newxValues = [] for (long x = xValues[0] ; x < xValues[-1] ; x+=25000) { newxValues << x } newxValues << xValues[-1] // // Write interpolated values for ALPHA and BETA, adding the original values in columns 4 and 5 // System.out << "X , ALPHA, BETA, X_orig, ALPHA_orig, BETA_orig" << "\n" int origIndex = 0 newxValues.each { long x -> def alpha_ipol = interpolations[Value.ALPHA].value(x) def beta_ipol = interpolations[Value.BETA].value(x) String out = "${x} , ${alpha_ipol} , ${beta_ipol}" if (x >= xValues[origIndex]) { out += ", ${xValues[origIndex]}, ${alphaValues[origIndex]}, ${betaValues[origIndex]}" origIndex++ } System.out << out << "\n" } } } 

The resulting output, plotted in LibreOffice Calc

And now for a custom example for EXTRAPOLATIONS, because it's fun. Here we use the same data as above, but extrapolate using a polynomial of the 2nd degree. And the corresponding classes, of course. Again, in Groovy:

 package example.com import org.apache.commons.math3.analysis.polynomials.PolynomialFunction import org.apache.commons.math3.fitting.PolynomialFitter import org.apache.commons.math3.fitting.WeightedObservedPoint import org.apache.commons.math3.optim.SimpleVectorValueChecker import org.apache.commons.math3.optim.nonlinear.vector.jacobian.GaussNewtonOptimizer class Extrapolate { enum Value { ALPHA, BETA } def static xValues = [ -284086, -94784, 31446, 354837, 667782, 982191 ] def static alphaValues = [ 71641, 78245, 80871, 94045, 105780, 119616 ] def static betaValues = [ 95552, 103413, 108667, 128456, 144686, 171953 ] static def getValueByName(Value value, int i) { def res switch (value) { case Value.ALPHA: res = alphaValues[i] break case Value.BETA: res = betaValues[i] break default: assert false } return res } static PolynomialFunction extrapolate(Value value) { // // how to check that we converged // def checker A: { double relativeThreshold = 0.01 double absoluteThreshold = 10 int maxIter = 1000 checker = new SimpleVectorValueChecker(relativeThreshold, absoluteThreshold, maxIter) } // // how to fit // def fitter B: { def useLUdecomposition = true def optimizer = new GaussNewtonOptimizer(useLUdecomposition, checker) fitter = new PolynomialFitter(optimizer) int i = 0 xValues.each { def weight = 1.0 def y = getValueByName(value, i++) fitter.addObservedPoint(new WeightedObservedPoint(weight, it, y)) } } // // fit using a 2-degree polynomial; guess at a linear function at first // "a0 + (a1 * x) + (a2 * xยฒ)"; a linear guess mean a2 == 0 // def params C: { def mStart = getValueByName(value,0) def mEnd = getValueByName(value,-1) def xStart = xValues[0] def xEnd = xValues[-1] def a2 = 0 def a1 = (mEnd - mStart) / (xEnd - xStart) // slope def a0 = mStart - (xStart * a1) // 0-intersection def guess = [a0 , a1 , a2] params = fitter.fit(guess as double[]) } // // make polynomial // return new PolynomialFunction(params) } static void main(def argv) { // // Create a map mapping a Value instance to its interpolating function // def extrapolations = [:] Value.values().each { extrapolations[it] = extrapolate(it) } // // New x, this times reaching out past the range of the original xValues // def newxValues = [] for (long x = xValues[0] - 400000L ; x < xValues[-1] + 400000L ; x += 10000) { newxValues << x } // // Write the extrapolated series ALPHA and BETA, adding the original values in columns 4 and 5 // System.out << "X , ALPHA, BETA, X_orig, ALPHA_orig, BETA_orig" << "\n" int origIndex = 0 newxValues.each { long x -> def alpha_xpol = extrapolations[Value.ALPHA].value(x) def beta_xpol = extrapolations[Value.BETA].value(x) String out = "${x} , ${alpha_xpol} , ${beta_xpol}" if (origIndex < xValues.size() && x >= xValues[origIndex]) { out += ", ${xValues[origIndex]}, ${alphaValues[origIndex]}, ${betaValues[origIndex]}" origIndex++ } System.out << out << "\n" } } } 

The resulting output, plotted in LibreOffice Calc

+4
Aug 13 '13 at 9:34 on
source share

I never did this, but a quick Google search showed that the Bezier curves are implemented in http://java.sun.com/j2se/1.5.0/docs/api/java/awt/geom/QuadCurve2D.Double.html

Then you can getPathIterator () with this curve, and with this, according to the documentation, you get the โ€œcoordinates of the borders of the formโ€, which, I suppose, are what you are looking for.

0
May 18 '09 at
source share



All Articles