001/* 002 * Copyright 2010-2015 Institut Pasteur. 003 * 004 * This file is part of Icy. 005 * 006 * Icy is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * Icy is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with Icy. If not, see <http://www.gnu.org/licenses/>. 018 */ 019package icy.math; 020 021import java.awt.Point; 022import java.util.ArrayList; 023import java.util.List; 024 025/** 026 * @author stephane 027 */ 028public class Interpolator 029{ 030 private static double[][] pointsToXY(List<Point> points) 031 { 032 final int len = points.size(); 033 final double[][] xy = new double[2][len]; 034 final double[] x = xy[0]; 035 final double[] y = xy[1]; 036 037 for (int i = 0; i < len; i++) 038 { 039 final Point p = points.get(i); 040 x[i] = p.x; 041 y[i] = p.y; 042 } 043 044 return xy; 045 } 046 047 private static double[] prepareYInterpolation(double[] x, double[] y, double xinc) 048 { 049 if ((x.length == 0) || (y.length == 0)) 050 throw new IllegalArgumentException("x[] and y[] should not be empty."); 051 if (x.length != y.length) 052 throw new IllegalArgumentException("x[] and y[] should have the same length."); 053 if (xinc == 0) 054 throw new IllegalArgumentException("step must be > 0"); 055 056 return new double[(int) ((x[x.length - 1] - x[0]) / xinc) + 1]; 057 } 058 059 /** 060 * Return Y linear interpolated coordinates from specified points and given X increment 061 */ 062 public static double[] doYLinearInterpolation(List<Point> points, double xinc) 063 { 064 final double[][] xy = pointsToXY(points); 065 return doYLinearInterpolation(xy[0], xy[1], xinc); 066 } 067 068 /** 069 * Return Y linear interpolated coordinates from specified points and given X increment 070 */ 071 public static double[] doYLinearInterpolation(double[] x, double[] y, double xinc) 072 { 073 final double[] result = prepareYInterpolation(x, y, xinc); 074 final int len = result.length; 075 076 if (len == 1) 077 result[0] = x[0]; 078 else 079 { 080 final int xlen = x.length - 1; 081 int index = 0; 082 int offset = 0; 083 double xvalue = x[0]; 084 double yvalue = y[0]; 085 double yinc = 0; 086 087 while (offset < len) 088 { 089 while ((index < xlen) && (xvalue >= x[index])) 090 { 091 index++; 092 final double dx = x[index] - xvalue; 093 094 if (dx != 0) 095 yinc = (y[index] - yvalue) / dx; 096 else 097 yinc = 0; 098 } 099 100 result[offset++] = yvalue; 101 yvalue += yinc; 102 xvalue += xinc; 103 } 104 } 105 106 return result; 107 } 108 109 /** 110 * Return Y spline interpolated coordinates from specified points and given X increment 111 */ 112 public static double[] doYSplineInterpolation(ArrayList<Point> points, double xstep) 113 { 114 final double[][] xy = pointsToXY(points); 115 return doYSplineInterpolation(xy[0], xy[1], xstep); 116 } 117 118 /** 119 * Return Y spline interpolated coordinates from specified points and given X increment.<br> 120 * Not yet implemented ! 121 */ 122 public static double[] doYSplineInterpolation(double[] x, double[] y, double xstep) 123 { 124 final double[] result = prepareYInterpolation(x, y, xstep); 125 final int len = result.length; 126 127 if (len > 1) 128 { 129 130 } 131 132 return result; 133 } 134 135 /** 136 * Do linear interpolation from start to end with specified increment step 137 */ 138 public static double[] doLinearInterpolation(double start, double end, double step) 139 { 140 int size; 141 142 if (step == 0) 143 size = 1; 144 else 145 size = (int) ((end - start) / step) + 1; 146 147 // size should be at least 1 148 if (size < 1) 149 size = 1; 150 151 final double[] result = new double[size]; 152 153 double value = start; 154 for (int i = 0; i < size; i++) 155 { 156 result[i] = value; 157 value += step; 158 } 159 160 return result; 161 } 162 163 /** 164 * Do linear interpolation from start to end with specified size (step number) 165 */ 166 public static double[] doLinearInterpolation(double start, double end, int size) 167 { 168 if (size < 1) 169 return null; 170 171 // special case 172 if (size == 1) 173 { 174 final double[] result = new double[size]; 175 result[0] = end; 176 return result; 177 } 178 179 return doLinearInterpolation(start, end, (end - start) / (size - 1)); 180 } 181 182 /** 183 * Do logarithmic interpolation from start to end with specified size (step number) 184 */ 185 public static double[] doLogInterpolation(double start, double end, int size) 186 { 187 // get linear interpolation 188 final double[] result = doLinearInterpolation(start, end, size); 189 190 // define input and output scaler 191 final Scaler scalerIn = new Scaler(start, end, 2, 20, true, true); 192 final Scaler scalerOut = new Scaler(Math.log(2), Math.log(20), start, end, true, true); 193 194 final int len = result.length; 195 196 // log scaling 197 for (int i = 0; i < len; i++) 198 result[i] = scalerOut.scale(Math.log(scalerIn.scale(result[i]))); 199 200 return result; 201 } 202 203 /** 204 * Do exponential interpolation from start to end with specified size (step number) 205 */ 206 public static double[] doExpInterpolation(double start, double end, int size) 207 { 208 // get linear interpolation 209 final double[] result = doLinearInterpolation(start, end, size); 210 211 // define input and output scaler 212 final Scaler scalerIn = new Scaler(start, end, 0, 2, false, true); 213 final Scaler scalerOut = new Scaler(Math.exp(0), Math.exp(2), start, end, false, true); 214 215 final int len = result.length; 216 217 // exp scaling 218 for (int i = 0; i < len; i++) 219 result[i] = scalerOut.scale(Math.exp(scalerIn.scale(result[i]))); 220 221 return result; 222 } 223 224}