貝塞爾曲線

貝塞爾曲線工具類

先上一張效果圖看效果
在這裏插入圖片描述

貝塞爾曲線

用於計算N階貝塞爾曲線上的點,根據傳入控制點的個數判定階數N
貝塞爾曲線計算公式:
在這裏插入圖片描述

public class BezierUtils {
    /**
     * 獲取二項式係數
     *
     * @param l 行(楊輝三角)
     * @param c 列(楊輝三角)
     * @return 係數
     */
    private static int getBinomialCoefficient(@IntRange(from = 0) int l, @IntRange(from = 0) int c) {
        int lotteryOdds = 1;
        for (int i = 1; i <= c; i++)
            lotteryOdds = lotteryOdds * (l - i + 1) / i;
        return lotteryOdds;
    }

    /**
     * 獲取貝塞爾曲線上t位置的點
     *
     * @param t      變化值
     * @param points 控制點
     * @return 當前t對應的點
     */
    public static PointF getBezierPoint(@FloatRange(from = 0, to = 1) float t, List<PointF> points) {
        if (points == null || points.size() < 2)
            return null;
        PointF result = new PointF();
        int n = points.size() - 1;//N階
        for (int i = 0; i <= n; i++) {
            int binomialCoefficient = getBinomialCoefficient(n, i);
            double v = Math.pow(1 - t, n - i) * Math.pow(t, i);
            result.x += binomialCoefficient * (points.get(i).x * v);
            result.y += binomialCoefficient * (points.get(i).y * v);
        }
        return result;
    }

    /**
     * 獲取貝塞爾曲線上t位置的點
     *
     * @param t      變化值
     * @param points 控制點
     * @return 當前t對應的點
     */
    public static PointF getBezierPoint(@FloatRange(from = 0, to = 1) float t, PointF... points) {
        if (points == null || points.length < 2)
            return null;
        return getBezierPoint(t, Arrays.asList(points));
    }

    /**
     * 獲取貝塞爾曲線路徑
     *
     * @param precision  生成路徑分段的精度
     * @param points 控制點
     * @return 貝塞爾曲線路徑
     */
	 public static Path getBezierPath(@IntRange(from = 1) int precision, List<PointF> points) {
        if (precision < 1 || points == null || points.size() < 2)
            return null;
        float division = 1f / precision;
        float t = division;
        PointF lastP = points.get(0);
        Path path = new Path();
        path.moveTo(lastP.x, lastP.y);
        while (t < 1) {
            PointF point = getBezierPoint(t, points);
            path.lineTo(point.x, point.y);
            t += division;
        }
        PointF endP = points.get(points.size() - 1);
        path.lineTo(endP.x, endP.y);
        return path;
    }
    
    /**
     * 獲取貝塞爾曲線路徑
     *
     * @param precision  生成路徑分段的精度
     * @param points 控制點
     * @return 貝塞爾曲線路徑
     */
    public static Path getBezierPath(@IntRange(from = 1) int precision, PointF... points) {
        if (precision < 1 || points == null || points.length < 2)
            return null;
        return getBezierPath(precision, Arrays.asList(points));
    }
}

示例代碼

public class MyView extends View {

    private PointF f1;
    private PointF f2;
    private PointF f3;
    private PointF f4;

    private Paint paint;
    private Paint paint2;
    private Paint paint3;

    private Path path1;
    private Path path2;
    private Path path3;

    private PointF point;
    private PointF point1;
    private PointF point2;

    public MyView(Context context) {
        this(context, null);
    }

    public MyView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        paint = new Paint();
        paint.setStrokeWidth(20);
        paint.setColor(Color.RED);
        paint.setAntiAlias(true);
        paint.setDither(true);

        paint2 = new Paint();
        paint2.setStrokeWidth(10);
        paint2.setColor(Color.BLUE);
        paint2.setStyle(Paint.Style.STROKE);
        paint2.setAntiAlias(true);
        paint2.setDither(true);

        paint3 = new Paint();
        paint3.setStrokeWidth(15);
        paint3.setColor(Color.YELLOW);
        paint3.setAntiAlias(true);
        paint3.setDither(true);

        path1 = new Path();
        path2 = new Path();
        path3 = new Path();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        int measuredHeight = getMeasuredHeight();
        int measuredWidth = getMeasuredWidth();
        f1 = new PointF(measuredWidth / 3, measuredHeight / 3);
        f2 = new PointF(measuredWidth / 3, measuredHeight / 3 * 2);
        f3 = new PointF(measuredWidth / 3 * 2, measuredHeight / 3);
        f4 = new PointF(measuredWidth / 3 * 2, measuredHeight / 3 * 2);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        
		//畫四個控制點(圖中黑色的四個點)
        canvas.drawPoint(f1.x, f1.y, paint);
        canvas.drawPoint(f2.x, f2.y, paint);
        canvas.drawPoint(f3.x, f3.y, paint);
        canvas.drawPoint(f4.x, f4.y, paint);
        
		//系統API畫3階貝塞爾曲線(圖中藍色線條)
        path1.moveTo(f1.x, f1.y);
        path1.cubicTo(f1.x, f1.y, f2.x, f2.y, f3.x, f3.y);
        paint2.setColor(Color.BLUE);
        canvas.drawPath(path1, paint2);
        
		//系統API畫3階貝塞爾曲線(圖中綠色線條)
        path2.moveTo(f1.x, f1.y);
        path2.cubicTo(f2.x, f2.y, f3.x, f3.y, f4.x, f4.y);
        paint2.setColor(Color.GREEN);
        canvas.drawPath(path2, paint2);
        
		//系統API畫2階貝塞爾曲線(圖中灰色線條)
        path3.moveTo(f1.x, f1.y);
        paint2.setColor(Color.LTGRAY);
        path3.quadTo(f2.x, f2.y, f4.x, f4.y);
        canvas.drawPath(path3, paint2);

		//畫圖中三個黃色變動的點(取自灰色線條)
        if (point != null) {
            canvas.drawPoint(point.x, point.y, paint3);
        }
		//畫圖中三個黃色變動的點(取自藍色線條)
        if (point1 != null) {
            canvas.drawPoint(point1.x, point1.y, paint3);
        }
		//畫圖中三個黃色變動的點(取自綠色線條)
        if (point2 != null) {
            canvas.drawPoint(point2.x, point2.y, paint3);
        }
    }

	//畫圖中三個黃色變動的點(取自灰色線條)
    public void drawPoint(@FloatRange(from = 0, to = 1) float t) {
        point = BezierUtils.getBezierPoint(t, f1, f2, f4);
        invalidate();
    }
	//畫圖中三個黃色變動的點(取自綠色線條)
    public void drawPoint2(@FloatRange(from = 0, to = 1) float t) {
        point2 = BezierUtils.getBezierPoint(t, f1, f2, f3, f4);
        invalidate();
    }

	//畫圖中三個黃色變動的點(取自藍色線條)
    public void drawPoint1(@FloatRange(from = 0, to = 1) float t) {
        point1 = BezierUtils.getBezierPoint(t, f1, f1, f2, f3);
        invalidate();
    }
}
參考

貝塞爾曲線
楊輝三角

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章