Java曲线拟合库

我希望找到一个简单的库,它可以采用一系列2维点,并给我一些更大的点来模拟曲线。 基本上,我想从JFreeChart获得像这个样本一样的曲线拟合效果:

替代文字http://sofzh.miximages.com/java/XYSplineRendererDemo1a.png

JFreeChart的问题是代码不提供这种类型的api。 我甚至看过源,算法与实际绘图紧密耦合。

Apache Commons Math有一系列很好的算法,特别是“SplineInterpolator”,请参阅API文档

我们从Groovy中调用alpha(x),beta(x)的插值函数的示例:

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" } } } 

结果输出,绘制在LibreOffice Calc中

现在,对于EXTRAPOLATIONS的一个偏离主题的例子,因为它很有趣。 这里我们使用与上面相同的数据,但使用二次多项式进行外推。 当然还有适当的课程。 再次,在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" } } } 

结果输出,绘制在LibreOffice Calc中

我从来没有这样做,但谷歌的快速搜索显示,Bezier曲线是在http://java.sun.com/j2se/1.5.0/docs/api/java/awt/geom/QuadCurve2D.Double.html中实现的。

然后,您可以从此曲线中获取getPathIterator(),根据文档说明,您可以获得“形状边界的坐标”,我认为这是您正在寻找的。