貝塞爾曲線學(xué)習(xí)總結(jié)

前言

貝塞爾曲線是一個強大而又神秘的東西锥惋。今天有時間徹底梳理了一下淆两,神秘的面紗被揭下來了,剩下了只有強大膀跌。下面就一步一步來了解一下貝塞爾曲線奠涌。

貝塞爾曲線是什么

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

上面是網(wǎng)上找的定義淫茵,算了還是看圖體會吧爪瓜。

0.gif

看了這圖后對貝塞爾曲線差不多就有點數(shù)了。

Android中實現(xiàn)貝塞爾曲線的API

了解自定義View的小伙伴匙瘪,肯定知道 canvas.drawPath()铆铆,這個方法。該方法接受的第一個對象是Path丹喻,這個Path薄货,提供了兩個方法:quadTo()、cubicTo()驻啤,分別實現(xiàn)二階貝塞爾曲線菲驴、三階貝塞爾曲線。接下來我們就寫代碼來看看效果骑冗。

quadTo()的使用

代碼:

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

        Path path = new Path();
        path.moveTo(50, 200);
        path.quadTo(150, 50, 400, 200);
        canvas.drawPath(path, paint);
    }

效果:


Paste_Image.png

標(biāo)注有點簡陋赊瞬,聰明的你先煎,應(yīng)該看得懂的哈。

cubicTo()的使用

代碼:

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

        Path path = new Path();
        path.moveTo(50, 200);
        path.cubicTo(100, 50, 350, 50, 500, 200);
        canvas.drawPath(path, paint);
    }

效果:


Paste_Image.png

以上就是用Android API實現(xiàn)二階貝塞爾曲線和三階貝塞爾取消巧涧,是不是很簡單呢薯蝎。

作為一名有夢想的程序員,你一定不會滿足的谤绳。接下來就研究一下貝塞爾曲線的原理占锯。

貝塞爾曲線公式。

1.貝塞爾曲線的通用公式
Paste_Image.png

在網(wǎng)上查資料得到這個公式缩筛,這個公式是貝塞爾曲線的通用公式消略,通過這個公式可以得到一階、二階瞎抛、三階艺演。。桐臊。胎撤。N階貝塞爾曲線。
第一眼看到這個公式断凶,說實話我是一臉懵逼伤提,心想這好像是微積分吧,當(dāng)年的高數(shù)都是睡過來的认烁。于是求助了在上研究生的同學(xué)肿男。
于是得到了下面的圖片:

Paste_Image.png

好吧,還是有點懵逼砚著,主要是字太丑次伶。

不管推導(dǎo)過程了,直接把結(jié)果拿來用吧稽穆。

一階貝塞爾公式

給定p0冠王、p1兩個點。得到如下公式

Paste_Image.png
二階貝塞爾公式

二階貝塞爾曲線可以理解為兩個一階貝塞爾曲線的連線上舌镶,動態(tài)的劃出一階貝塞爾曲線柱彻。

Paste_Image.png
Paste_Image.png
三階貝塞爾曲線

按照二階的推導(dǎo)原理,以此類推餐胀,由四個控制點定義的三階貝塞爾曲線P03可被定義為分別由(P0哟楷,P1,P2)和(P1否灾,P2卖擅,P3)確定的兩條二階貝塞爾曲線的線性組合:P03 = (1-t)P02 + tP12

可遞歸代入得出三階貝塞爾曲線公式:

Paste_Image.png

0.gif

貝塞爾曲線原理部分借鑒于:http://mp.weixin.qq.com/s/l0ABkX3IzBk_s8-nWkUJig
在此對大神表示感謝。

計算貝塞爾曲線的路徑

通過上面的學(xué)習(xí),我們可以很輕松的畫出二階惩阶、三階貝塞爾曲線挎狸。那么,我們想畫出高階的貝塞爾曲線呢断楷?我們只是需要貝塞爾曲線的路徑而不只是畫出細(xì)線呢?
那么我們就需要得到貝塞爾曲線的繪制過程锨匆,也就是說要得到貝塞爾曲線上的每一個點。

這里不多將直接上代碼來冬筒,看效果好了恐锣。
核心代碼,計算貝塞爾曲線上的點集:
借鑒于https://github.com/venshine/BezierMaker
這是真大神舞痰,給跪了土榴。

    /**
     * 創(chuàng)建Bezier點集
     *
     * @return
     */
    private ArrayList<PointF> buildBezierPoints() {
        ArrayList<PointF> points = new ArrayList<>();
        int order = mControlPoints.size() - 1;
        float delta = 1.0f / FRAME;
        for (float t = 0; t <= 1; t += delta) {
            // Bezier點集
            points.add(new PointF(deCasteljauX(order, 0, t), deCasteljauY(order, 0, t)));
        }
        return points;
    }

    /**
     * deCasteljau算法
     *
     * @param i 階數(shù)
     * @param j 點
     * @param t 時間
     * @return
     */
    private float deCasteljauX(int i, int j, float t) {
        if (i == 1) {
            return (1 - t) * mControlPoints.get(j).x + t * mControlPoints.get(j + 1).x;
        }
        return (1 - t) * deCasteljauX(i - 1, j, t) + t * deCasteljauX(i - 1, j + 1, t);
    }

    /**
     * deCasteljau算法
     *
     * @param i 階數(shù)
     * @param j 點
     * @param t 時間
     * @return
     */
    private float deCasteljauY(int i, int j, float t) {
        if (i == 1) {
            return (1 - t) * mControlPoints.get(j).y + t * mControlPoints.get(j + 1).y;
        }
        return (1 - t) * deCasteljauY(i - 1, j, t) + t * deCasteljauY(i - 1, j + 1, t);
    }

初始化控制點:

void init() {
        mControlPoints = new ArrayList<>(MAX_COUNT + 1);
        int w = getResources().getDisplayMetrics().widthPixels;
        mControlPoints.add(new PointF(144, 144));
        mControlPoints.add(new PointF(266, 51));
        mControlPoints.add(new PointF(500, 83));
        mControlPoints.add(new PointF(650, 212));
        mControlPoints.add(new PointF(689, 491));
        mControlPoints.add(new PointF(485, 747));
        mControlPoints.add(new PointF(185, 577));
        mControlPoints.add(new PointF(45, 180));
        mControlPoints.add(new PointF(48, 747));
        mControlPoints.add(new PointF(689, 747));
//在這里初始化控制點的集合,可以任意添加控制點响牛,從而得到N階貝塞爾曲線鞭衩。

        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.STROKE);
        paint.setColor(getResources().getColor(R.color.colorAccent));
    }

在onDraw方法中調(diào)用:

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Path path = new Path();
        ArrayList<PointF> list = buildBezierPoints();
        for (int i = 1; i < list.size(); i++) {
            path.moveTo(list.get(i - 1).x, list.get(i - 1).y);
            path.lineTo(list.get(i).x, list.get(i).y);
            canvas.drawPath(path, paint);
        }
    }

好了看下效果,由于控制點是隨便添加的娃善,所以就是這樣的鬼樣子:

Paste_Image.png

看到這里大家覺得沒什么了不起的。大家可以發(fā)揮想象力瑞佩。
1.坐標(biāo)規(guī)劃的夠好聚磺,就可以畫出各種各樣的圖案,畫個汽車不成問題炬丸。
2.得到貝塞爾曲線的點集后瘫寝,我們不一次性畫出來,而是延時的畫稠炬,那么就可以讓線條動起來焕阿,那么就是動畫了
3.得到貝塞爾曲線后,我們不劃線首启,而是在這個路徑上畫圖案暮屡,那么就可以實現(xiàn),圖案在這路徑上飄動毅桃。就想直播里面點贊出現(xiàn)的動畫一樣褒纲。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市钥飞,隨后出現(xiàn)的幾起案子莺掠,更是在濱河造成了極大的恐慌,老刑警劉巖读宙,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件彻秆,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)唇兑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進(jìn)店門酒朵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人幔亥,你說我怎么就攤上這事耻讽。” “怎么了帕棉?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵针肥,是天一觀的道長。 經(jīng)常有香客問我香伴,道長慰枕,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任即纲,我火速辦了婚禮具帮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘低斋。我一直安慰自己蜂厅,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布膊畴。 她就那樣靜靜地躺著掘猿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪唇跨。 梳的紋絲不亂的頭發(fā)上稠通,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天,我揣著相機(jī)與錄音买猖,去河邊找鬼改橘。 笑死,一個胖子當(dāng)著我的面吹牛玉控,可吹牛的內(nèi)容都是我干的飞主。 我是一名探鬼主播,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼奸远,長吁一口氣:“原來是場噩夢啊……” “哼既棺!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起懒叛,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤丸冕,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后薛窥,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體胖烛,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡眼姐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了佩番。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片众旗。...
    茶點故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖趟畏,靈堂內(nèi)的尸體忽然破棺而出贡歧,到底是詐尸還是另有隱情,我是刑警寧澤赋秀,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布利朵,位于F島的核電站,受9級特大地震影響猎莲,放射性物質(zhì)發(fā)生泄漏绍弟。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一著洼、第九天 我趴在偏房一處隱蔽的房頂上張望樟遣。 院中可真熱鬧,春花似錦身笤、人聲如沸豹悬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽屿衅。三九已至,卻和暖如春莹弊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背涡尘。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工忍弛, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人考抄。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓细疚,卻偏偏與公主長得像,于是被迫代替她去往敵國和親川梅。 傳聞我的和親對象是個殘疾皇子疯兼,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,976評論 2 355

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