电竞比分网-中国电竞赛事及体育赛事平台

分享

【算法分析】

 leafit 2019-02-23

相信很多朋友和我一樣很喜歡QQ上“一鍵退朝”的功能,就是把紅點(diǎn)從它原本的地方拉走,消息提醒也就沒(méi)有了。

一鍵退朝功能示意圖

直到如今我還是覺(jué)得這個(gè)功能很酷炫!于是想自己實(shí)現(xiàn)一番,經(jīng)過(guò)一番調(diào)查知道拉伸其實(shí)就是由兩個(gè)圓加上兩條貝塞爾曲線組成的形狀。

來(lái)看看騰訊設(shè)計(jì)師是怎么設(shè)計(jì)出來(lái)的吧:《QQ手機(jī)版 5.0“一鍵下班”設(shè)計(jì)小結(jié)》

看完了這個(gè)對(duì)實(shí)現(xiàn)思路有很大的幫助,可是我還是不能知道具體是怎么計(jì)算實(shí)現(xiàn)的,網(wǎng)上大部分的教程都是假想成了兩個(gè)同樣大小的圓來(lái)計(jì)算,這太取巧了!因?yàn)橥瑯哟笮〉膱A兩條外公切線是平行的,同一個(gè)圓上的公切點(diǎn)相連是會(huì)垂直于連心線的,但是大小不同的圓并沒(méi)有這個(gè)特殊性!

另外網(wǎng)上也有很多仿照的項(xiàng)目,可是看算法看得頭都大了也不明白為什么是這樣算的!經(jīng)過(guò)兩天的研究,把初中數(shù)學(xué)(圓、三角函數(shù)等相關(guān)知識(shí))好好復(fù)習(xí)了一遍,終于搞清楚了其中算法,現(xiàn)在跟我一起來(lái)看看吧!


1.得到連心線

通過(guò)觀察可以發(fā)現(xiàn),在“一鍵退朝”這個(gè)功能當(dāng)中,有一個(gè)小圓固定在原來(lái)坐標(biāo)位置不動(dòng)的,只是半徑會(huì)發(fā)生變化,另一個(gè)大圓是跟隨著我們手指滑動(dòng)到屏幕的位置來(lái)確定圓心坐標(biāo)的,一般大圓的半徑是固定的。

建立兩圓的相對(duì)坐標(biāo)系:

PS:在移動(dòng)端的坐標(biāo)系 y 軸是向下的。

假設(shè)某一個(gè)時(shí)刻,兩圓的狀態(tài)如圖,我們現(xiàn)在可以確定的是小圓的圓心坐標(biāo) O 為(startX, startY),大圓的圓心坐標(biāo) P0 為 (x0, y0),以及小圓的半徑 r 和大圓的半徑 R 。

那么首先可以把連心線求出來(lái)!也就是 O P0 的距離。

2.求切點(diǎn)坐標(biāo)

復(fù)習(xí)一下初中數(shù)學(xué):

兩個(gè)外離的圓,一定有兩條外公切線。若兩圓半徑相同,則兩外公切線平行;否則相交于一點(diǎn),且該點(diǎn)與兩圓心在同一直線。

我們?cè)僮饕粡堄泄芯€的圖:

切點(diǎn)為 P1、P2、P3、P4,我們現(xiàn)在目的就要求出這四個(gè)點(diǎn),然后就能夠在程序中畫(huà)出切線。

整個(gè)算法最難的地方恐怕就是求這四個(gè)點(diǎn)了,我們需要借助作圖來(lái)幫助計(jì)算,這之前還需要先復(fù)習(xí)下定理:

圓心和切點(diǎn)的連線一定垂直于過(guò)該點(diǎn)的公切線

再作幾個(gè)輔助點(diǎn) A、B、C、D,AB 表示以大圓圓心為原點(diǎn)的坐標(biāo)系的 x 軸的兩端,CD 表示以小圓圓心為原點(diǎn)的坐標(biāo)系的 x 軸的兩端,

3.求剩下兩個(gè)切點(diǎn)的坐標(biāo)

一開(kāi)始我以為 P3、P4 的算法和 P1、P2 一樣,就是把上面的減號(hào)換成加號(hào)就可以了。可是后來(lái)驗(yàn)證后發(fā)現(xiàn)不對(duì), P3、P4 不能直接使用 β 進(jìn)行運(yùn)算。

 為了能愉快閱讀,再來(lái)復(fù)習(xí)一下各種拉丁希臘符號(hào)叫法:

 α 阿爾法 β 貝塔 γ 伽瑪 δ 德?tīng)査?ε 伊普西隆 ζ 澤塔

如上圖作輔助線。

4.畫(huà)貝塞爾曲線

把四個(gè)切點(diǎn)坐標(biāo)求出來(lái)了,后面就簡(jiǎn)單了,現(xiàn)在就是以切線為原軸,畫(huà)貝塞爾曲線了,不過(guò)我們還缺少一個(gè)控制點(diǎn)的坐標(biāo)。

4.1 科普貝塞爾

怕有不清楚貝塞爾曲線的朋友,我科普一下先,簡(jiǎn)單來(lái)說(shuō)就是求一段平滑曲線的公式。

如果我們把畫(huà)一條直線分為進(jìn)度100%的話,那么當(dāng)進(jìn)度為0%,12%,58%,74%時(shí),畫(huà)線的狀態(tài)為(注意紅色部分末的黑色端點(diǎn),灰色部分為路徑指示)

那么把所有時(shí)刻的黑點(diǎn)連接起來(lái)就構(gòu)成了直線:

這個(gè)概念應(yīng)該比較容易接受,好了繼續(xù)。

二次貝塞爾曲線(最簡(jiǎn)單的貝塞爾曲線)的作法首先需要兩個(gè)點(diǎn)確定一條直線,另外在直線外確定一點(diǎn)(即控制點(diǎn)),然后此時(shí)三點(diǎn)會(huì)形成三個(gè)線段,即下圖的P0 P2、P0 P1和 P1 P2$(其實(shí)不用關(guān)注 P0 P2)

這只是進(jìn)度為0時(shí)候的狀態(tài),按照上面概念,當(dāng)進(jìn)度 t 從 0 變化到 100 時(shí)的某一個(gè)時(shí)刻,比如 30, 66 ,99,那么各個(gè)時(shí)刻 P0 P1 和 P1 P2 的狀態(tài)為

t=30
t=66
t=99

可以發(fā)現(xiàn),在 P0 P1 和 P1 P2 上有一直運(yùn)動(dòng)的兩個(gè)點(diǎn),我們將這兩個(gè)點(diǎn)連接起來(lái)又形成一段新的線段,而在不同時(shí)刻,在這個(gè)新線段上同樣會(huì)有一個(gè)運(yùn)動(dòng)的點(diǎn),這個(gè)點(diǎn)也遵守 t 的變化。

t=30
t=66
t=99

把所有時(shí)刻的黃色點(diǎn)連接起來(lái),就形成了二階貝塞爾曲線。

還不能理解的可以看下這個(gè)視頻 - > 《bezier curve原理》- > 只要看就好,聽(tīng)不懂英文的可以把聲音關(guān)掉。

費(fèi)這么大勁把二階貝塞爾講了一遍,我們這里其實(shí)也只用到了二階,高階我就不講了,一通百通。

4.2.尋找控制點(diǎn)

那么現(xiàn)在線段已經(jīng)能確定了,就是兩條公切線線段(P1P2、P3P4),那么控制點(diǎn)在哪呢?

這個(gè)其實(shí)有點(diǎn)靠猜了=。= 一開(kāi)始我覺(jué)得應(yīng)該在連心線的中點(diǎn),其實(shí)實(shí)現(xiàn)后效果也還行,后來(lái)參照騰訊設(shè)計(jì)師的想法效果更好,他令 P1P2 的控制點(diǎn)為 P1P4 的中點(diǎn),令 P3P4 的控制點(diǎn)為 P2P3 的中點(diǎn)。

軟件實(shí)現(xiàn)效果對(duì)比(上邊控制點(diǎn)是連心線的中點(diǎn),下邊是騰訊設(shè)計(jì)師提出的控制點(diǎn)):

我個(gè)人覺(jué)得下邊效果更好,也不得不佩服TX設(shè)計(jì)師的聰明才智,讓我自己想可能永遠(yuǎn)也想不到。

至于求 P1P4 和  P2P3 的中點(diǎn)不難吧?連四個(gè)坐標(biāo)點(diǎn)都求出來(lái)了,直接算就可以了!

---

源碼地址:https://github.com/Xieyupeng520/AZMetaBall(還會(huì)不斷完善的,求星星^3^)

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多