二次貝塞爾曲線繪制原理講解

二次貝塞爾曲線

貝塞爾曲線簡介

貝塞爾曲線(Bézier curve),又稱貝茲曲線或貝濟埃曲線,是應用于二維圖形應用程序的數(shù)學曲線。一般的矢量圖形軟件通過它來精確畫出曲線,貝茲曲線由線段節(jié)點組成,節(jié)點是可拖動的支點,線段像可伸縮的皮筋,我們在繪圖工具上看到的鋼筆工具就是來做這種矢量曲線的。貝塞爾曲線是計算機圖形學中相當重要的參數(shù)曲線,在一些比較成熟的位圖軟件中也有貝塞爾曲線工具,如PhotoShop等。在Flash4中還沒有完整的曲線工具,而在Flash5里面已經(jīng)提供出貝塞爾曲線工具。

貝塞爾曲線于1962,由法國工程師皮埃爾·貝塞爾(Pierre Bézier)所廣泛發(fā)表,他運用貝塞爾曲線來為汽車的主體進行設計。貝塞爾曲線最初由Paul de Casteljau于1959年運用de Casteljau演算法開發(fā),以穩(wěn)定數(shù)值的方法求出貝茲曲線。

以上內容從采取自百度百科

貝塞爾曲線目前被廣泛應用于計算機制圖中,可以說貝塞爾曲線奠定了計算機制圖的基礎。

Android中繪制Path的API

Android中繪制Path常用方法:

作用 相關方法 備注
移動起點 moveTo 移動下一次操作的起點位置
設置終點 setLastPoint 重置當前path中最后一個點位置,如果在繪制之前調用,效果和moveTo相同
連接直線 lineTo 添加上一個點到當前點之間的直線到Path
閉合路徑 close 連接第一個點連接到最后一個點,形成一個閉合區(qū)域
添加內容 addRect, addRoundRect, addOval, addCircle, addPath, addArc, arcTo 添加(矩形, 圓角矩形, 橢圓, 圓, 路徑, 圓弧) 到當前Path (注意addArc和arcTo的區(qū)別)
是否為空 isEmpty 判斷Path是否為空
是否為矩形 isRect 判斷path是否是一個矩形
替換路徑 set 用新的路徑替換到當前路徑所有內容
偏移路徑 offset 對當前路徑之前的操作進行偏移(不會影響之后的操作)
貝塞爾曲線 quadTo, cubicTo 分別為二次和三次貝塞爾曲線的方法
rXxx方法 rMoveTo, rLineTo, rQuadTo, rCubicTo 不帶r的方法是基于原點的坐標系(偏移量), rXxx方法是基于當前點坐標系(偏移量)
填充模式 setFillType, getFillType, isInverseFillType, toggleInverseFillType 設置,獲取,判斷和切換填充模式
提示方法 incReserve 提示Path還有多少個點等待加入(這個方法貌似會讓Path優(yōu)化存儲結構)
布爾操作(API19) op 對兩個Path進行布爾運算(即取交集、并集等操作)
計算邊界 computeBounds 計算Path的邊界
重置路徑 reset, rewind 清除Path中的內容

reset不保留內部數(shù)據(jù)結構,但會保留FillType.
rewind會保留內部的數(shù)據(jù)結構,但不保留FillType |
| 矩陣操作 | transform | 矩陣變換 |

貝塞爾曲線應用簡單場景:

  • QQ小紅點拖拽效果
  • 平滑的折線圖的制作
  • 閱讀軟件的翻書效果

繪制貝塞爾曲線

一階貝塞爾曲線

一階貝塞爾曲線的原理就是一條直線,其實就是直接畫了一個Path出來,在這里不做過多的介紹,本文主要介紹的是二階的貝塞爾曲線。

二階貝塞爾曲線

二階貝塞爾曲線效果圖:

bezier

實現(xiàn)原理

二階曲線由兩個數(shù)據(jù)點(A 和 C),一個控制點(B)來描述曲線狀態(tài),大致如下:

image

上圖中紅色曲線部分就是傳說中的二階貝塞爾曲線,那么這條紅色曲線是如何生成的呢?接下來我們就以其中的一個狀態(tài)分析一下:

image

連接AB BC,并在AB上取點D,BC上取點E,使其滿足條件:


image.png
image

連接DE,取點F,使得:

AD/AB = BE/BC = DF/DE

這樣獲取到的點F就是貝塞爾曲線上的一個點,動態(tài)過程如下:

image

實現(xiàn)代碼

public class Bezier2 extends View {

    private Paint mPaint;
    private int centerX, centerY;

    private PointF start, end, control;

    public Bezier2(Context context) {
        super(context);
        mPaint = new Paint();
        mPaint.setColor(Color.BLACK);
        mPaint.setStrokeWidth(8);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setTextSize(60);

        start = new PointF(0,0);
        end = new PointF(0,0);
        control = new PointF(0,0);
    }

    public Bezier2(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        mPaint = new Paint();
        mPaint.setColor(Color.BLACK);
        mPaint.setStrokeWidth(8);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setTextSize(60);

        start = new PointF(0,0);
        end = new PointF(0,0);
        control = new PointF(0,0);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        centerX = w/2;
        centerY = h/2;

        // 初始化數(shù)據(jù)點和控制點的位置
        start.x = centerX-200;
        start.y = centerY;
        end.x = centerX+200;
        end.y = centerY;
        control.x = centerX;
        control.y = centerY-100;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // 根據(jù)觸摸位置更新控制點,并提示重繪
        control.x = event.getX();
        control.y = event.getY();
        invalidate();
        return true;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        // 繪制數(shù)據(jù)點和控制點
        mPaint.setColor(Color.GRAY);
        mPaint.setStrokeWidth(20);
        canvas.drawPoint(start.x,start.y,mPaint);
        canvas.drawPoint(end.x,end.y,mPaint);
        canvas.drawPoint(control.x,control.y,mPaint);

        // 繪制輔助線
        mPaint.setStrokeWidth(4);
        canvas.drawLine(start.x,start.y,control.x,control.y,mPaint);
        canvas.drawLine(end.x,end.y,control.x,control.y,mPaint);

        // 繪制貝塞爾曲線
        mPaint.setColor(Color.RED);
        mPaint.setStrokeWidth(8);

        Path path = new Path();

        path.moveTo(start.x,start.y);
        path.quadTo(control.x,control.y,end.x,end.y);

        canvas.drawPath(path, mPaint);
    }
}

項目地址:https://github.com/pengMaster/Bezier

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容