All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jcamp.math.IrregularGrid1D Maven / Gradle / Ivy

package org.jcamp.math;

/**
 * generic 1-dimensional grid.
 * linear interpolation between grid samples.
 * @author Thomas Weber
 */
public class IrregularGrid1D extends Grid1D {
    private double[] samples;
    private boolean ascending;
    private Range1D.Double range = new Range1D.Double();
    /**
     * default ctor.
     */
    public IrregularGrid1D() {
        this.samples = new double[] {
        };
    }
    /**
     * IrregularGrid1D constructor comment.
     * @param length int
     */
    public IrregularGrid1D(double[] samples) {
        this(samples, true);
    }
    /**
     * IrregularGrid1D internal copy constructor.
     */
    IrregularGrid1D(double[] samples, Range1D range, boolean ascending) {
        super(samples.length);
        this.samples = (double[]) samples.clone();
        this.range.set(range);
        this.ascending = ascending;
    }
    /**
     * IrregularGrid1D constructor comment.
     */
    public IrregularGrid1D(double[] samples, boolean copy) {
        super(samples.length);
        setSamples(samples, copy);
    }
    /**
     * IrregularGrid1D constructor comment.
     * @param length int
     */
    public IrregularGrid1D(IOrderedArray1D samples) {
        this(samples.toArray(), false);
    }
    /**
     * resampling to wider or narrower grid range (extrapolation)
     * @param length int
     */
    public IrregularGrid1D(IrregularGrid1D from, Range1D range) {
        super();
        double gleft = from.coordinateAt(range.getXMinAsDouble());
        double gright = from.coordinateAt(range.getXMaxAsDouble());
        int length = 0;
        if (from.ascending) {
            double l = Math.floor(gleft);
            double r = Math.ceil(gright);
            length = (int) (r - l) + 1;
            this.samples = new double[length];
            for (int i = 0; i < length; i++) {
                this.samples[i] = from.valueAt((int) l + i);
            }
        } else {
            double l = Math.floor(gright);
            double r = Math.ceil(gleft);
            length = (int) (r - l) + 1;
            this.samples = new double[length];
            for (int i = 0; i < length; i++) {
                this.samples[i] = from.valueAt((int) l + i);
            }
        }
        setLength(length);
        if (length < 2)
            throw new RuntimeException("samples do not form a valid grid");
        this.range.set(samples[0], samples[0]);
        this.ascending = (samples[length - 1] > samples[0]);
        // check for strict monotony
        if (this.ascending) {
            for (int i = 1; i < length; i++) {
                if (this.samples[i] < this.range.getXMin())
                    this.range.set(this.samples[i], this.range.getXMax());
                if (this.samples[i] > this.range.getXMax())
                    this.range.set(this.range.getXMin(), samples[i]);
                if (samples[i] <= samples[i - 1]) {
                    throw new RuntimeException("samples do not form a valid grid");
                }
            }
        } else {
            for (int i = 1; i < length; i++) {
                if (this.samples[i] < this.range.getXMin())
                    this.range.set(this.samples[i], this.range.getXMax());
                if (this.samples[i] > this.range.getXMax())
                    this.range.set(this.range.getXMin(), this.samples[i]);
                if (this.samples[i] >= this.samples[i - 1]) {
                    throw new RuntimeException("samples do not form a valid grid");
                }
            }
        }
    }
    /**
     * cloning.
     * @return Object
     */
    public Object clone() {
        return new IrregularGrid1D(samples, range, ascending);
    }
    /**
     * 
     */
    public double coordinateAt(double x) {
        double grid;
        if (Double.isNaN(x))
            grid = Double.NaN;
        else {
            int left = 0;
            int right = getLength() - 1;
            int mid;
            double sleft = samples[left];
            double sright = samples[right];
            if (ascending) {
                if (x < sleft) { // extrapolate
                    grid = left + (x - sleft) / (samples[left + 1] - sleft);
                    return grid;
                } else if (x > sright) { // extrapolate
                    grid = right + (x - sright) / (sright - samples[right - 1]);
                    return grid;
                }
                while (right - left > 1) {
                    mid = (right + left) / 2;
                    double sx = samples[mid];
                    if (x > sx)
                        left = mid;
                    else if (x < sx)
                        right = mid;
                    else {
                        left = mid;
                        break;
                    }
                }
                grid = left + (x - samples[left]) / (samples[left + 1] - samples[left]);
            } else {
                if (x < sright) { // extrapolate
                    grid = right + (sright - x) / (samples[right - 1] - sright);
                    return grid;
                } else if (x > sleft) { // extrapolate
                    grid = left + (sleft - x) / (sleft - samples[left + 1]);
                    return grid;
                }
                while (right - left > 1) {
                    mid = (right + left) / 2;
                    double sx = samples[mid];
                    if (x < sx)
                        left = mid;
                    else if (x > sx)
                        right = mid;
                    else {
                        left = mid;
                        break;
                    }
                }
                grid = left + (samples[left] - x) / (samples[left] - samples[left + 1]);
            }
        }
        return grid;
    }
    /**
     * 
     */
    public double[] coordinatesAt(double[] value) {
        int n = value.length;
        double[] grid = new double[n];
        for (int i = 0; i < n; i++) {
            double x = value[i];
            if (Double.isNaN(x))
                grid[i] = Double.NaN;
            else {
                int left = 0;
                int right = getLength() - 1;
                int mid;
                double sleft = samples[left];
                double sright = samples[right];
                if (ascending) {
                    if (x < sleft) { // extrapolate
                        grid[i] = left + (x - sleft) / (samples[left + 1] - sleft);
                        continue;
                    } else if (x > sright) { // extrapolate
                        grid[i] = right + (x - sright) / (sright - samples[right - 1]);
                        continue;
                    }
                    while (right - left > 1) {
                        mid = (right + left) / 2;
                        double sx = samples[mid];
                        if (x > sx)
                            left = mid;
                        else if (x < sx)
                            right = mid;
                        else {
                            left = mid;
                            break;
                        }
                    }
                    grid[i] = left + (x - samples[left]) / (samples[left + 1] - samples[left]);
                } else {
                    if (x < sright) { // extrapolate
                        grid[i] = right + (sright - x) / (samples[right - 1] - sright);
                        continue;
                    } else if (x > sleft) { // extrapolate
                        grid[i] = left + (sleft - x) / (sleft - samples[left + 1]);
                        continue;
                    }
                    while (right - left > 1) {
                        mid = (right + left) / 2;
                        double sx = samples[mid];
                        if (x < sx)
                            left = mid;
                        else if (x > sx)
                            right = mid;
                        else {
                            left = mid;
                            break;
                        }
                    }
                    grid[i] = left + (samples[left] - x) / (samples[left] - samples[left + 1]);
                }
            }
        }
        return grid;
    }
    /**
     * getArray method comment.
     */
    public IArray1D getArray(int index) throws java.lang.ArrayIndexOutOfBoundsException {
        if (index == 0)
            return this;
        else
            throw new ArrayIndexOutOfBoundsException();
    }
    /**
     * gets range of grid.
     */
    public Range.Double getRange() {
        return (Range.Double) range.clone();
    }
    /**
     * gets range of grid.
     */
    public Range1D.Double getRange1D() {
        return (Range1D.Double) range.clone();
    }
    /**
     * Insert the method's description here.
     * Creation date: (01/06/00 16:51:44)
     * @return double
     */
    public double[] getSamples() {
        return samples;
    }
    /**
     * flag if grid has ascending values
     * @return boolean
     */
    public boolean isAscending() {
        return ascending;
    }
    /**
     * getValue method comment.
     */
    public double pointAt(int index) {
        int length = getLength();
        if (index >= 0 && index < length) {
            return samples[index];
        } else if (index < 0) { // extrapolation
            return samples[0] + index * (samples[1] - samples[0]);
        } else { // (index>=length)
            return samples[length - 1] + (index - length + 1) * (samples[length - 1] - samples[length - 2]);
        }
    }
    public void scale(double amount) {
        for (int i = 0; i < samples.length; i++)
            samples[i] *= amount;
        range = new Range1D.Double(range.getXMin() * amount, range.getXMax() * amount);
        if (amount < 0)
            ascending = !ascending;
    }
    /**
     * set sample array.
     * @param newSamples double[]
     */
    public void setSamples(double[] newSamples) {
        setSamples(newSamples, true);
    }
    /**
     * sets the grid array.
     * @param newSamples double[]
     * @param copy boolean
     */
    public void setSamples(double[] newSamples, boolean copy) {
        this.samples = newSamples;
        if (copy) {
            this.samples = (double[]) newSamples.clone();
        } else
            this.samples = newSamples;
        this.range.set(samples[0], samples[0]);
        int length = getLength();
        ascending = (samples[length - 1] > samples[0]);
        // check for strict monotony
        if (ascending) {
            for (int i = 1; i < length; i++) {
                if (samples[i] < range.getXMin())
                    range.set(samples[i], range.getXMax());
                if (samples[i] > range.getXMax())
                    range.set(range.getXMin(), samples[i]);
                if (samples[i] <= samples[i - 1]) {
                    throw new RuntimeException("samples do not form a valid grid");
                }
            }
        } else {
            for (int i = 1; i < length; i++) {
                if (samples[i] < range.getXMin())
                    range.set(samples[i], range.getXMax());
                if (samples[i] > range.getXMax())
                    range.set(range.getXMin(), samples[i]);
                if (samples[i] >= samples[i - 1]) {
                    throw new RuntimeException("samples do not form a valid grid");
                }
            }
        }
    }
    /**
     * convert grid to double array.
     * 
     * @return double[]
     */
    public double[] toArray() {
        double[] a = new double[samples.length];
        System.arraycopy(samples, 0, a, 0, samples.length);
        return a;
    }
    public void translate(double amount) {
        for (int i = 0; i < samples.length; i++)
            samples[i] += amount;
        range.translate(amount);
    }
    /**
     * getValueFromGrid method comment.
     */
    public double valueAt(double gx) {
        double value;
        int length = getLength();
        if (gx < 0) {
            double dx = samples[1] - samples[0];
            value = samples[0] + dx * gx;
        } else if (gx > length - 1) {
            double dx = samples[length - 1] - samples[length - 2];
            value = samples[length - 1] + dx * (gx - length + 1);
        } else {
            // find nearest integer lesser than g
            int gx0 = (int) Math.floor(gx + 0.5);
            if (gx0 < 0)
                gx0 = 0;
            if (gx0 > length - 2)
                gx0 = length - 2;
            double dx = gx - gx0;
            value = (1 - dx) * samples[gx0] + dx * samples[gx0 + 1];
        }
        return value;
    }
    /**
     * getValueFromGrid method comment.
     */
    public double[] valuesAt(double[] grid) {
        int n = grid.length;
        double[] value = new double[n];
        int length = getLength();
        for (int i = 0; i < n; i++) {
            double gx = grid[i];
            if (gx < 0) {
                double dx = samples[1] - samples[0];
                value[i] = samples[0] + dx * gx;
            } else if (gx > length - 1) {
                double dx = samples[length - 1] - samples[length - 2];
                value[i] = samples[length - 1] + dx * (gx - length + 1);
            } else {
                // find nearest integer lesser than g
                int gx0 = (int) Math.floor(gx + 0.5);
                if (gx0 < 0)
                    gx0 = 0;
                if (gx0 > length - 2)
                    gx0 = length - 2;
                double dx = gx - gx0;
                value[i] = (1 - dx) * samples[gx0] + dx * samples[gx0 + 1];
            }
        }
        return value;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy