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}