使用android.graphics.Path构造样条曲线

使用android.graphics.Path构造样条曲线,android,path,spline,Android,Path,Spline,我有一个2d点数组,我需要创建一个通过所有点的路径。我想我应该使用Path.cubicTo()方法,使用指定的控制点在两点之间创建贝塞尔曲线。问题是我不知道曲线的控制点。我如何计算它们 也许有更好的方法?也许有某种图书馆可以帮助我?在我读了文章之后,它变得非常简单 这就是你在安卓上的做法。运行此代码后,路径p将通过knotsArr数组中的所有点 Point[] knotsArr = {new Point(0, 0), new Point(5, 5),

我有一个2d点数组,我需要创建一个通过所有点的路径。我想我应该使用
Path.cubicTo()
方法,使用指定的控制点在两点之间创建贝塞尔曲线。问题是我不知道曲线的控制点。我如何计算它们

也许有更好的方法?也许有某种图书馆可以帮助我?

在我读了文章之后,它变得非常简单

这就是你在安卓上的做法。运行此代码后,路径
p
将通过
knotsArr
数组中的所有点

Point[] knotsArr = {new Point(0, 0),
                    new Point(5, 5),
                    new Point(10, 0),
                    new Point(15, 5)};
Point[][] controlPoints = BezierSplineUtil.getCurveControlPoints(knotsArr);
Point[] firstCP = controlPoints[0];
Point[] secondCP = controlPoints[1];

Path p = new Path();
p.moveTo(knots.get(0).x, knots.get(0).y);

for (int i = 0; i < firstCP.length; i++) {
    p.cubicTo(firstCP[i].x, firstCP[i].y,
              secondCP[i].x, secondCP[i].y,
              knots.get(i + 1).x, knots.get(i + 1).y);
}
Point[]knotsArr={新点(0,0),
新的点(5,5),
新点(10,0),
新的第(15,5)点};
点[][]控制点=BezierSplineUtil.GetCurveControl点(knotsArr);
点[]第一个CP=控制点[0];
点[]秒Cp=控制点[1];
路径p=新路径();
p、 移动到(节数。获取(0.x),节数。获取(0.y);
for(int i=0;i
BezierSplineUtil.java

public class BezierSplineUtil {

    public static class Point {

        public final float x;
        public final float y;

        public Point(float x, float y) {
            this.x = x;
            this.y = y;
        }

    }

    /**
     * Get open-ended bezier spline control points.
     * 
     * @param knots bezier spline points.
     * @return [2 x knots.length - 1] matrix. First row of the matrix = first
     *         control points. Second row of the matrix = second control points.
     * @throws IllegalArgumentException if less than two knots are passed.
     */
    public static Point[][] getCurveControlPoints(Point[] knots) {
        if (knots == null || knots.length < 2) {
            throw new IllegalArgumentException("At least two knot points are required");
        }

        final int n = knots.length - 1;
        final Point[] firstControlPoints = new Point[n];
        final Point[] secondControlPoints = new Point[n];

        // Special case: bezier curve should be a straight line
        if (n == 1) {
            // 3P1 = 2P0 + P3
            float x = (2 * knots[0].x + knots[1].x) / 3;
            float y = (2 * knots[0].y + knots[1].y) / 3;
            firstControlPoints[0] = new Point(x, y);

            // P2 = 2P1 - P0
            x = 2 * firstControlPoints[0].x - knots[0].x;
            y = 2 * firstControlPoints[0].y - knots[0].y;
            secondControlPoints[0] = new Point(x, y);

            return new Point[][] { firstControlPoints, secondControlPoints };
        }

        // Calculate first bezier control points
        // Right hand side vector
        float[] rhs = new float[n];

        // Set right hand side X values
        for (int i = 1; i < n - 1; i++) {
            rhs[i] = 4 * knots[i].x + 2 * knots[i + 1].x;
        }
        rhs[0] = knots[0].x + 2 * knots[1].x;
        rhs[n - 1] = (8 * knots[n - 1].x + knots[n].x) / 2f;

        // Get first control points X-values
        float[] x = getFirstControlPoints(rhs);

        // Set right hand side Y values
        for (int i = 1; i < n - 1; i++) {
            rhs[i] = 4 * knots[i].y + 2 * knots[i + 1].y;
        }
        rhs[0] = knots[0].y + 2 * knots[1].y;
        rhs[n - 1] = (8 * knots[n - 1].y + knots[n].y) / 2f;

        // Get first control points Y-values
        float[] y = getFirstControlPoints(rhs);

        for (int i = 0; i < n; i++) {
            // First control point
            firstControlPoints[i] = new Point(x[i], y[i]);

            // Second control point
            if (i < n - 1) {
                float xx = 2 * knots[i + 1].x - x[i + 1];
                float yy = 2 * knots[i + 1].y - y[i + 1];
                secondControlPoints[i] = new Point(xx, yy);
            } else {
                float xx = (knots[n].x + x[n - 1]) / 2;
                float yy = (knots[n].y + y[n - 1]) / 2;
                secondControlPoints[i] = new Point(xx, yy);
            }
        }

        return new Point[][] { firstControlPoints, secondControlPoints };
    }

    /**
     * Solves a tridiagonal system for one of coordinates (x or y) of first
     * bezier control points.
     * 
     * @param rhs right hand side vector.
     * @return Solution vector.
     */
    private static float[] getFirstControlPoints(float[] rhs) {
        int n = rhs.length;
        float[] x = new float[n]; // Solution vector
        float[] tmp = new float[n]; // Temp workspace

        float b = 2.0f;
        x[0] = rhs[0] / b;

        // Decomposition and forward substitution
        for (int i = 1; i < n; i++) {
            tmp[i] = 1 / b;
            b = (i < n - 1 ? 4.0f : 3.5f) - tmp[i];
            x[i] = (rhs[i] - x[i - 1]) / b;
        }

        // Backsubstitution
        for (int i = 1; i < n; i++) {
            x[n - i - 1] -= tmp[n - i] * x[n - i];
        }

        return x;
    }

}
公共类BezierSplineUtil{
公共静态类点{
公开最终浮动x;
公开最终浮动;
公共点(浮动x、浮动y){
这个.x=x;
这个。y=y;
}
}
/**
*获取开放式bezier样条曲线控制点。
* 
*@param结是贝塞尔样条曲线点。
*@return[2 x knots.length-1]矩阵。矩阵的第一行=第一行
*控制点。矩阵的第二行=第二个控制点。
*@如果通过的速度小于两节,则抛出IllegalArgumentException。
*/
公共静态点[][]GetCurveControl点(点[]节){
如果(节点==null | |节点长度<2){
抛出新的IllegalArgumentException(“至少需要两个节点”);
}
最终整数n=节。长度-1;
终点[]第一个控制点=新点[n];
最终点[]第二控制点=新点[n];
//特殊情况:贝塞尔曲线应该是一条直线
如果(n==1){
//3P1=2P0+P3
浮动x=(2*节[0]。x+节[1]。x)/3;
浮动y=(2*节[0]。y+节[1]。y)/3;
firstControlPoints[0]=新点(x,y);
//P2=2P1-P0
x=2*firstControlPoints[0].x-knots[0].x;
y=2*firstControlPoints[0]。y-节点[0]。y;
第二控制点[0]=新点(x,y);
返回新点[][{firstControlPoints,secondControlPoints};
}
//计算第一个贝塞尔控制点
//右侧向量
浮动[]rhs=新浮动[n];
//设置右侧的X值
对于(int i=1;i