Android Open Source - HzGrapher Spline






From Project

Back to project page HzGrapher.

License

The source code is released under:

Apache License

If you think the Android project HzGrapher listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Copyright (C) 2012 The Android Open Source Project
 *//from ww w  . j  a v a 2s. c  om
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.handstudio.android.hzgrapherlib.util;

import android.annotation.SuppressLint;

/**
 * Performs spline interpolation given a set of control points.
 * @hide
 */
public final class Spline {
    private final float[] mX;
    private final float[] mY;
    private final float[] mM;

    private Spline(float[] x, float[] y, float[] m) {
        mX = x;
        mY = y;
        mM = m;
    }

    /**
     * Creates a monotone cubic spline from a given set of control points.
     *
     * The spline is guaranteed to pass through each control point exactly.
     * Moreover, assuming the control points are monotonic (Y is non-decreasing or
     * non-increasing) then the interpolated values will also be monotonic.
     *
     * This function uses the Fritsch-Carlson method for computing the spline parameters.
     * http://en.wikipedia.org/wiki/Monotone_cubic_interpolation
     *
     * @param x The X component of the control points, strictly increasing.
     * @param y The Y component of the control points, monotonic.
     * @return
     *
     * @throws IllegalArgumentException if the X or Y arrays are null, have
     * different lengths or have fewer than 2 values.
     * @throws IllegalArgumentException if the control points are not monotonic.
     */
  @SuppressLint("NewApi")
  public static Spline createMonotoneCubicSpline(float[] x, float[] y) {
        if (x == null || y == null || x.length != y.length || x.length < 2) {
            throw new IllegalArgumentException("There must be at least two control "
                    + "points and the arrays must be of equal length.");
        }

        final int n = x.length;
        float[] d = new float[n - 1]; // could optimize this out
        float[] m = new float[n];

        // Compute slopes of secant lines between successive points.
        for (int i = 0; i < n - 1; i++) {
            float h = x[i + 1] - x[i];
            if (h <= 0f) {
                throw new IllegalArgumentException("The control points must all "
                        + "have strictly increasing X values.");
            }
            d[i] = (y[i + 1] - y[i]) / h;
        }

        // Initialize the tangents as the average of the secants.
        m[0] = d[0];
        for (int i = 1; i < n - 1; i++) {
            m[i] = (d[i - 1] + d[i]) * 0.5f;
        }
        m[n - 1] = d[n - 2];

        // Update the tangents to preserve monotonicity.
        for (int i = 0; i < n - 1; i++) {
            if (d[i] == 0f) { // successive Y values are equal
                m[i] = 0f;
                m[i + 1] = 0f;
            } else {
                float a = m[i] / d[i];
                float b = m[i + 1] / d[i];
//                float h = FloatMath.hypot(a, b);
                float h = (a*a) + (b*b);
                
                if (h > 9f) {
                    float t = 3f / h;
                    m[i] = t * a * d[i];
                    m[i + 1] = t * b * d[i];
                }
            }
        }
        return new Spline(x, y, m);
    }

    /**
     * Interpolates the value of Y = f(X) for given X.
     * Clamps X to the domain of the spline.
     *
     * @param x The X value.
     * @return The interpolated Y = f(X) value.
     */
    public float interpolate(float x) {
        // Handle the boundary cases.
        final int n = mX.length;
        if (Float.isNaN(x)) {
            return x;
        }
        if (x <= mX[0]) {
            return mY[0];
        }
        if (x >= mX[n - 1]) {
            return mY[n - 1];
        }

        // Find the index 'i' of the last point with smaller X.
        // We know this will be within the spline due to the boundary tests.
        int i = 0;
        while (x >= mX[i + 1]) {
            i += 1;
            if (x == mX[i]) {
                return mY[i];
            }
        }

        // Perform cubic Hermite spline interpolation.
        float h = mX[i + 1] - mX[i];
        float t = (x - mX[i]) / h;
        return (mY[i] * (1 + 2 * t) + h * mM[i] * t) * (1 - t) * (1 - t)
                + (mY[i + 1] * (3 - 2 * t) + h * mM[i + 1] * (t - 1)) * t * t;
    }

    // For debugging.
    @Override
    public String toString() {
        StringBuilder str = new StringBuilder();
        final int n = mX.length;
        str.append("[");
        for (int i = 0; i < n; i++) {
            if (i != 0) {
                str.append(", ");
            }
            str.append("(").append(mX[i]);
            str.append(", ").append(mY[i]);
            str.append(": ").append(mM[i]).append(")");
        }
        str.append("]");
        return str.toString();
    }
}




Java Source Code List

com.handstudio.android.hzgrapher.BarGraphActivity.java
com.handstudio.android.hzgrapher.BubbleGraphActivity.java
com.handstudio.android.hzgrapher.BubbleGraphActivity.java
com.handstudio.android.hzgrapher.CircleGraphActivity.java
com.handstudio.android.hzgrapher.CircleGraphActivity.java
com.handstudio.android.hzgrapher.CurveCompareGraphActivity.java
com.handstudio.android.hzgrapher.CurveCompareGraphActivity.java
com.handstudio.android.hzgrapher.CurveGraphActivity.java
com.handstudio.android.hzgrapher.CurveGraphActivity.java
com.handstudio.android.hzgrapher.CurveGraphWithRegionActivity.java
com.handstudio.android.hzgrapher.CurveGraphWithRegionActivity.java
com.handstudio.android.hzgrapher.LineCompareGraphActivity.java
com.handstudio.android.hzgrapher.LineCompareGraphActivity.java
com.handstudio.android.hzgrapher.LineGraphActivity.java
com.handstudio.android.hzgrapher.LineGraphActivity.java
com.handstudio.android.hzgrapher.LineGraphWithRegionActivity.java
com.handstudio.android.hzgrapher.LineGraphWithRegionActivity.java
com.handstudio.android.hzgrapher.MainActivity.java
com.handstudio.android.hzgrapher.MainActivity.java
com.handstudio.android.hzgrapher.PieGraphActivity.java
com.handstudio.android.hzgrapher.PieGraphActivity.java
com.handstudio.android.hzgrapher.RadarGraphActivity.java
com.handstudio.android.hzgrapher.RadarGraphActivity.java
com.handstudio.android.hzgrapher.ScatterGraphActivity.java
com.handstudio.android.hzgrapher.ScatterGraphActivity.java
com.handstudio.android.hzgrapherlib.animation.GraphAnimation.java
com.handstudio.android.hzgrapherlib.canvas.GraphCanvasWrapper.java
com.handstudio.android.hzgrapherlib.error.ErrorCode.java
com.handstudio.android.hzgrapherlib.error.ErrorDetector.java
com.handstudio.android.hzgrapherlib.graphview.BarGraphView.java
com.handstudio.android.hzgrapherlib.graphview.BubbleGraphView.java
com.handstudio.android.hzgrapherlib.graphview.CircleGraphView.java
com.handstudio.android.hzgrapherlib.graphview.CurveCompareGraphView.java
com.handstudio.android.hzgrapherlib.graphview.CurveGraphView.java
com.handstudio.android.hzgrapherlib.graphview.LineCompareGraphView.java
com.handstudio.android.hzgrapherlib.graphview.LineGraphView.java
com.handstudio.android.hzgrapherlib.graphview.RadarGraphView.java
com.handstudio.android.hzgrapherlib.graphview.ScatterGraphView.java
com.handstudio.android.hzgrapherlib.path.GraphPath.java
com.handstudio.android.hzgrapherlib.util.Converter.java
com.handstudio.android.hzgrapherlib.util.EuclidLine.java
com.handstudio.android.hzgrapherlib.util.EuclidPoint.java
com.handstudio.android.hzgrapherlib.util.IntersectFinder.java
com.handstudio.android.hzgrapherlib.util.MatrixTranslator.java
com.handstudio.android.hzgrapherlib.util.Spline.java
com.handstudio.android.hzgrapherlib.vo.GraphNameBox.java
com.handstudio.android.hzgrapherlib.vo.Graph.java
com.handstudio.android.hzgrapherlib.vo.bargraph.BarGraphVO.java
com.handstudio.android.hzgrapherlib.vo.bargraph.BarGraph.java
com.handstudio.android.hzgrapherlib.vo.bubblegraph.BubbleGraphVO.java
com.handstudio.android.hzgrapherlib.vo.bubblegraph.BubbleGraph.java
com.handstudio.android.hzgrapherlib.vo.circlegraph.CircleGraphVO.java
com.handstudio.android.hzgrapherlib.vo.circlegraph.CircleGraph.java
com.handstudio.android.hzgrapherlib.vo.curvegraph.CurveGraphVO.java
com.handstudio.android.hzgrapherlib.vo.curvegraph.CurveGraph.java
com.handstudio.android.hzgrapherlib.vo.linegraph.LineGraphVO.java
com.handstudio.android.hzgrapherlib.vo.linegraph.LineGraph.java
com.handstudio.android.hzgrapherlib.vo.radargraph.RadarGraphVO.java
com.handstudio.android.hzgrapherlib.vo.radargraph.RadarGraph.java
com.handstudio.android.hzgraphlib.vo.scattergraph.ScatterGraphVO.java
com.handstudio.android.hzgraphlib.vo.scattergraph.ScatterGraph.java