java 三次样条插值 画光滑曲线 例子
主要是做数值拟合,根据sin函数采点,取得数据后在java中插值并在swing中画出曲线,下面为截图 不光滑和光滑曲线前后对比:
代码:
执行类:
1 package com.yang.logic; 2 3 import java.util.ArrayList; 4 import java.util.Collections; 5 import java.util.Comparator; 6 import java.util.List; 7 8 import com.yang.logic.Drawlineforspline.Mypanel; 9 10 public class Testspline { 11 12 // 根据X排序 13 class SortByX implements Comparator { 14 public int compare(Object obj1, Object obj2) { 15 PointStruct point1 = (PointStruct) obj1; 16 PointStruct point2 = (PointStruct) obj2; 17 if (point1.dx > point2.dx) 18 return 1; 19 else 20 return 0; 21 } 22 } 23 //转化成数组 24 public static ArrayList<Double> getArrayfList(List<PointStruct> l, String type) { 25 ArrayList<Double> tmplist = new ArrayList<Double>(); 26 for (PointStruct p : l) { 27 if (type == "ix") { 28 tmplist.add((double) p.ix); 29 } else if (type == "iy") { 30 tmplist.add((double) p.iy); 31 } else if (type == "dx") { 32 tmplist.add(p.dx); 33 } else if (type == "dy") { 34 tmplist.add(p.dy); 35 } 36 } 37 return tmplist; 38 } 39 40 public static void main(String[] args) { 41 42 //将来做插值的点列表 43 List <PointStruct> pl=new ArrayList<PointStruct>(); 44 45 //【1】 模拟 sin函数值 做初始化特定点(插值点或样条), 曲线将来就穿过下面几点 46 // 0.1 1 2 3 4 47 // 0.099833417 0.841470985 0.909297427 0.141120008 0.61802 48 49 pl.add(new PointStruct(0.1,0.099833417)); 50 pl.add(new PointStruct(1,0.841470985)); 51 pl.add(new PointStruct(2,0.909297427)); 52 pl.add(new PointStruct(3,0.141120008)); 53 pl.add(new PointStruct(4,0.61802)); 54 55 //【2】 添加 需要的未知点(新插值点), 为了使曲线光滑 采用小的步长 填充在已知点之间 56 List <PointStruct> target=new ArrayList<PointStruct>(); 57 double step=0.1; 58 for(int k=0;k<pl.size();k++){ 59 60 if((k+1)<pl.size()){ 61 double tmpd=0; 62 while(tmpd<pl.get(k+1).dx){ 63 tmpd=tmpd+step; 64 target.add(new PointStruct(tmpd,0.0)); 65 } 66 } 67 } 68 69 //把点集合转化成为 x,y 各自的坐标点 Double[]集合 70 ArrayList tmp_x = getArrayfList(pl,"dx"); 71 ArrayList tmp_y = getArrayfList(pl,"dy"); 72 Double[] xspline=new Double[tmp_x.size()]; 73 Double[] yspline=new Double[tmp_x.size()]; 74 for(int e=0;e<tmp_x.size();e++){ 75 xspline[e]=(Double) tmp_x.get(e); 76 yspline[e]=(Double) tmp_y.get(e); 77 } 78 79 //【3】根据 插值点初始化插值对象,并用spline样条函数进行计算(做三次样条插值运算) 80 Interpolation ip = new Interpolation(xspline, yspline); 81 for(int j=0;j<target.size();j++){ 82 target.get(j).dy=ip.spline(target.get(j).dx); 83 } 84 85 //把新生成的样条添加到点集合中 做以后画图用 86 pl.addAll(target); 87 88 //根据x点的大小进行点集合的排序 89 Testspline t2=new Testspline(); 90 Collections.sort(pl, t2.new SortByX()); 91 92 //因为结果太小,所有必要放大一定度数,同时 Java画图最像是整数,所有把双精度转成整形 93 int intScale=100; 94 for(PointStruct p:pl){ 95 p.ix=(int) (p.dx*intScale); 96 p.iy=(int) (p.dy*intScale); 97 } 98 99 //查看中间结果 即画图所用到的所有点 100 int times=0; 101 for(PointStruct p:pl){ 102 System.out.println(" order: :"+times++ +" p.ix:"+p.ix+" p.iy:"+p.iy); 103 } 104 105 //【4】 调用画图类 画图 106 Drawlineforspline dlfs=new Drawlineforspline(pl); 107 Mypanel myp=dlfs.new Mypanel(); 108 dlfs.add(myp); 109 110 } 111 }
依赖类:
PointStruct
1 package com.yang.logic; 2 3 public class PointStruct { 4 5 double dx; 6 double dy; 7 8 int ix; 9 int iy; 10 11 public PointStruct(double dx, double dy) { 12 this.dx = dx; 13 this.dy = dy; 14 } 15 16 public PointStruct(int ix, int iy) { 17 this.ix = ix; 18 this.iy = iy; 19 } 20 21 public PointStruct(double dx, double dy,boolean round) { 22 this.ix = RoundF(dx); 23 this.iy = RoundF(dy); 24 } 25 26 public int RoundF(double a){ 27 return (int) Math.round(a); 28 } 29 }
Interpolation
1 package com.yang.logic; 2 3 import java.util.Arrays; 4 5 public class Interpolation { 6 7 private int n; 8 private Double[] xs; 9 private Double[] ys; 10 11 private boolean sp_initialized; 12 private double[] sp_y2s; 13 14 public Interpolation(Double[] _xs, Double[] _ys) { 15 16 this.n = _xs.length; 17 this.xs = Arrays.copyOf(_xs, _xs.length); 18 this.ys = Arrays.copyOf(_ys, _ys.length); 19 20 this.sp_initialized = false; 21 } 22 23 public double spline(double x) 24 { 25 if (!this.sp_initialized) { 26 // Assume Natural Spline Interpolation 27 double p, qn, sig, un; 28 double[] us; 29 30 us = new double[n-1]; 31 sp_y2s = new double[n]; 32 us[0] = sp_y2s[0] = 0.0; 33 34 for (int i=1; i<=n-2; i++) { 35 sig = (xs[i] - xs[i-1]) / (xs[i+1] - xs[i-1]); 36 p = sig * sp_y2s[i-1] + 2.0; 37 sp_y2s[i] = (sig - 1.0) / p; 38 us[i] = (ys[i+1] - ys[i]) / (xs[i+1] - xs[i]) - (ys[i] - ys[i-1]) / (xs[i] - xs[i-1]); 39 us[i] = (6.0 * us[i] / (xs[i+1] - xs[i-1]) - sig * us[i-1]) / p; 40 } 41 qn = un = 0.0; 42 43 sp_y2s[n-1] = (un - qn * us[n-2]) / (qn * sp_y2s[n-2] + 1.0); 44 for (int k=n-2; k>=0; k--) { 45 sp_y2s[k] = sp_y2s[k] * sp_y2s[k+1] + us[k]; 46 } 47 48 this.sp_initialized = true; 49 } 50 51 int klo, khi, k; 52 double h, b, a; 53 54 klo = 0; 55 khi = n-1; 56 while (khi-klo > 1) { 57 k = (khi+klo) >> 1; 58 if (xs[k] > x) 59 khi = k; 60 else 61 klo = k; 62 } 63 h = xs[khi] - xs[klo]; 64 if (h == 0.0) { 65 throw new ArithmeticException(); 66 } 67 a = (xs[khi] - x) / h; 68 b = (x - xs[klo]) / h; 69 return a*ys[klo] + b*ys[khi] + ((a*a*a-a)*sp_y2s[klo]+(b*b*b-b)*sp_y2s[khi])*(h*h)/6.0; 70 } 71 72 }
Drawlineforspline
1 package com.yang.logic; 2 3 import java.awt.Color; 4 import java.awt.Graphics; 5 import java.util.List; 6 7 import javax.swing.JFrame; 8 import javax.swing.JPanel; 9 10 public class Drawlineforspline extends JFrame{ 11 12 private static final long serialVersionUID = 1L; 13 List <PointStruct>plist; 14 15 public Drawlineforspline(){ 16 init(); 17 } 18 public Drawlineforspline(List<PointStruct> plist){ 19 init(); 20 this.plist=plist; 21 } 22 23 private void init(){ 24 this.setTitle("drawline"); 25 this.setBounds(200, 200, 500, 400); 26 this.setBackground(Color.white); 27 this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 28 this.setLocationRelativeTo(null); 29 this.setVisible(true); 30 } 31 32 public class Mypanel extends JPanel{ 33 public void paint(Graphics g){ 34 g.setColor(Color.red); 35 //System.out.println(plist.size()); 36 for(int i=0;i<plist.size()-1;i++){ 37 g.drawLine(plist.get(i).ix, plist.get(i).iy, plist.get(i+1).ix, plist.get(i+1).iy); 38 } 39 } 40 } 41 }
代码下载 地址