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

二次貝塞爾曲線

貝塞爾曲線簡介

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

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

以上內(nèi)容從采取自百度百科

貝塞爾曲線目前被廣泛應(yīng)用于計算機制圖中萎津,可以說貝塞爾曲線奠定了計算機制圖的基礎(chǔ)。

Android中繪制Path的API

Android中繪制Path常用方法:

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

reset不保留內(nèi)部數(shù)據(jù)結(jié)構(gòu)绍豁,但會保留FillType.
rewind會保留內(nèi)部的數(shù)據(jù)結(jié)構(gòu),但不保留FillType |
| 矩陣操作 | transform | 矩陣變換 |

貝塞爾曲線應(yīng)用簡單場景:

  • 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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市哥牍,隨后出現(xiàn)的幾起案子毕泌,更是在濱河造成了極大的恐慌,老刑警劉巖嗅辣,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件撼泛,死亡現(xiàn)場離奇詭異,居然都是意外死亡澡谭,警方通過查閱死者的電腦和手機愿题,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蛙奖,“玉大人潘酗,你說我怎么就攤上這事⊙阒伲” “怎么了仔夺?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長伯顶。 經(jīng)常有香客問我囚灼,道長,這世上最難降的妖魔是什么祭衩? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任灶体,我火速辦了婚禮,結(jié)果婚禮上掐暮,老公的妹妹穿的比我還像新娘蝎抽。我一直安慰自己,他們只是感情好路克,可當(dāng)我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布樟结。 她就那樣靜靜地躺著,像睡著了一般精算。 火紅的嫁衣襯著肌膚如雪瓢宦。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天灰羽,我揣著相機與錄音驮履,去河邊找鬼鱼辙。 笑死,一個胖子當(dāng)著我的面吹牛玫镐,可吹牛的內(nèi)容都是我干的倒戏。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼恐似,長吁一口氣:“原來是場噩夢啊……” “哼杜跷!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起矫夷,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤葛闷,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后双藕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體孵运,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年蔓彩,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片驳概。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡赤嚼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出顺又,到底是詐尸還是另有隱情更卒,我是刑警寧澤,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布稚照,位于F島的核電站蹂空,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏果录。R本人自食惡果不足惜上枕,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望弱恒。 院中可真熱鬧辨萍,春花似錦、人聲如沸返弹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽义起。三九已至拉背,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間默终,已是汗流浹背椅棺。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工犁罩, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人土陪。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓昼汗,卻偏偏與公主長得像,于是被迫代替她去往敵國和親鬼雀。 傳聞我的和親對象是個殘疾皇子顷窒,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容