cn.liutils.vis.animation.CubicSplineCurve.java Source code

Java tutorial

Introduction

Here is the source code for cn.liutils.vis.animation.CubicSplineCurve.java

Source

/**
 * Copyright (c) Lambda Innovation, 2013-2015
 * ??Lambda Innovation
 * http://www.li-dev.cn/
 *
 * This project is open-source, and it is distributed under
 * the terms of GNU General Public License. You can modify
 * and distribute freely as long as you follow the license.
 * ??GNU???
 * ????
 * http://www.gnu.org/licenses/gpl.html
 */
package cn.liutils.vis.animation;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

import org.apache.commons.lang3.tuple.Pair;

/**
 * @author WeAthFolD
 */
public class CubicSplineCurve implements ICurve {

    private List<Pair<Double, Double>> pts = new ArrayList();

    public void addPoint(double x, double y) {
        pts.add(Pair.of(x, y));
        pts.sort((Pair<Double, Double> a, Pair<Double, Double> b) -> {
            return a.getLeft().compareTo(b.getLeft());
        });
    }

    @Override
    public double valueAt(double x) {
        // Find last point whose value <= x
        int index = 0;
        for (; index < pts.size() && pts.get(index).getLeft() < x; ++index)
            ;
        if (index > 0)
            --index;
        if (index >= pts.size() - 1)
            index = pts.size() - 2;

        // Generate 4 refpoints' vals
        Pair<Double, Double> pt1 = pts.get(index), pt2 = pts.get(index + 1),
                pt0 = index == 0 ? pt1 : pts.get(index - 1);
        double dist = pt2.getLeft() - pt1.getLeft(), ldist = pt0 == pt1 ? dist : pt1.getRight() - pt0.getLeft();
        double p0 = pt1.getRight(), p1 = pt2.getRight(), m0 = kval(index) * ldist, m1 = kval(index + 1) * dist;

        double u = (x - pt1.getLeft()) / dist, u2 = u * u, u3 = u2 * u;

        // Apply calculation
        return (2 * u3 - 3 * u2 + 1) * p0 + (u3 - 2 * u2 + u) * m0 + (-2 * u3 + 3 * u2) * p1 + (u3 - u2) * m1;
    }

    private double kval(int index) {
        Pair<Double, Double> pt1 = null, pt2 = null, pt3 = null;

        boolean flag = false;
        if (index == 0) {
            pt1 = pts.get(0);
            pt2 = pts.get(1);
            flag = true;
        }
        if (index == pts.size() - 1) {
            pt1 = pts.get(pts.size() - 2);
            pt2 = pts.get(index);
            flag = true;
        }
        if (flag)
            return (pt2.getRight() - pt1.getRight()) / (pt2.getLeft() - pt1.getLeft());

        pt1 = pts.get(index - 1);
        pt2 = pts.get(index);
        pt3 = pts.get(index + 1);

        return ((pt2.getRight() - pt1.getRight()) / (pt2.getLeft() - pt1.getLeft())
                + (pt3.getRight() - pt2.getRight()) / (pt3.getLeft() - pt2.getLeft())) / 2;
    }

}