canvas繪制貝塞爾曲線

需要掌握的內(nèi)容

  1. 難度應(yīng)該大多都在數(shù)學(xué)的三角函數(shù)中赁项,如果對這個知識點有問題的可以自行去學(xué)習(xí)一下


    直角三角形.png
  • sin角度=a/c
  • cos角度=b/c
  • tan角度=a/b
  • cot角度=b/a
  • sec角度=c/b
  • csc角度=c/a
  1. 數(shù)學(xué)坐標(biāo)系和Android坐標(biāo)系的區(qū)別


    數(shù)學(xué)坐標(biāo)系.png

    y軸朝上是+吐根,x軸朝右是+


    Android坐標(biāo)系.png

    x軸朝右是+弯淘,y軸朝下是+

Demo代碼

class LinePathView : View{
    //坐標(biāo)軸的paint
    val paint: Paint=Paint()
        val path: Path=Path()
        //貝塞爾曲線的畫筆
    val pPaint:Paint=Paint()
        lateinit var center:PointF
        constructor(context: Context) : super(context){
        init()
    }
    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs){
        init()
    }
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: int) : super(
            context,
            attrs,
            defStyleAttr
        ){
        init()
    }
    private fun init() {
        paint.isAntiAlias=true
                paint.isDither=true
                paint.color=Color.BLACK
                paint.strokeWidth=3f
                paint.style=Paint.Style.FILL
                pPaint.isAntiAlias=true
                pPaint.isDither=true
                pPaint.color=Color.RED
                pPaint.strokeWidth=3f
            }
            override fun onSizeChanged(w: int, h: int, oldw: int, oldh: int) {
            super.onSizeChanged(w, h, oldw, oldh)
                    center=PointF((measuredWidth/2).tofloat(), (measuredHeight/2).tofloat())
        }
        override fun onDraw(canvas: Canvas) {
            super.onDraw(canvas)
                    canvas.drawLine((measuredWidth/2).tofloat(), 0F, (measuredWidth/2).tofloat(),
                        measuredHeight.tofloat(),paint)
                    canvas.drawLine(0f,(measuredHeight/2).tofloat(),  measuredWidth.tofloat(),
                        (measuredHeight/2).tofloat(),paint)
                    //計算x軸上頂點的坐標(biāo)
            val top = calPoint(center, (measuredHeight / 2).tofloat(), 90F)
                    val rightTop = calPoint(top, 80f, -45f)
                    canvas.drawLine(top.x,top.y,rightTop.x,rightTop.y,paint)
                    val leftTop = calPoint(top, 80f, -135f)
                    canvas.drawLine(top.x,top.y,leftTop.x,leftTop.y,paint)
                    //計算y軸右頂點的坐標(biāo)
            val rightY = calPoint(center, (measuredWidth / 2).tofloat(), 360F)
                    val yTopLeft = calPoint(rightY, 80f, 135f)
                    canvas.drawLine(rightY.x,rightY.y,yTopLeft.x,yTopLeft.y,paint)
                    val yTopRight = calPoint(rightY, 80f, -135f)
                    canvas.drawLine(rightY.x,rightY.y,yTopRight.x,yTopRight.y,paint)
                    //計算貝塞爾曲線的一段的終點坐標(biāo)(起點是中心點)
            val lastPoint = calPoint(center, 200f, 0f)
                    //計算貝塞爾曲線控制點的坐標(biāo)
            val controlPoint = calPoint(center, 200f, 60f)
                    path.reset()
                    path.moveTo(center.x,center.y)
                    path.quadTo(controlPoint.x,controlPoint.y,lastPoint.x,lastPoint.y)
                    canvas.drawPath(path,pPaint)
                    //根據(jù)第一個貝塞爾曲線的終點畫第二個
            val secondLastPoint = calPoint(lastPoint, 200f, 0f)
                    //第二個貝塞爾曲線的控制點
            val secondControl = calPoint(lastPoint, 200f, -60f)
                    path.reset()
                    path.moveTo(lastPoint.x,lastPoint.y)
                    path.quadTo(secondControl.x,secondControl.y,secondLastPoint.x,secondLastPoint.y)
                    canvas.drawPath(path,pPaint)
                    //繪制梯形(以中心點為坐標(biāo)在第二象限找一個點作為梯形底邊的一個頂點)
            val rightBottomPoint = calPoint(center, 200f, 135f)
                    val leftBottomPoint = calPoint(rightBottomPoint, 300f, -180f)
                    val leftTopPoint = calPoint(leftBottomPoint, 80f, 45f)
                    val rightTopPoint = calPoint(leftTopPoint, 200f, 0f)
                    path.reset()
                    path.moveTo(rightBottomPoint.x,rightBottomPoint.y)
                    path.lineTo(leftBottomPoint.x,leftBottomPoint.y)
                    path.lineTo(leftTopPoint.x,leftTopPoint.y)
                    path.lineTo(rightTopPoint.x,rightTopPoint.y)
                    canvas.drawPath(path,pPaint)
                    //在第三象限找一個點作為三角形的頂點
            val sanTopPoint = calPoint(center, 300f, -135f)
                    val sanRightBottom = calPoint(sanTopPoint, 200f, -45f)
                    val sanLeftBottom = calPoint(sanRightBottom, 300f, 180f)
                    path.reset()
                    path.moveTo(sanTopPoint.x,sanTopPoint.y)
                    path.lineTo(sanLeftBottom.x,sanLeftBottom.y)
                    path.lineTo(sanRightBottom.x,sanRightBottom.y)
                    canvas.drawPath(path,pPaint)
        }
        fun calPoint(start: PointF,lineLength: float,angel: float): PointF {
            //根據(jù)角度的cos值和斜邊的長度求出相鄰邊的長度,也就是x的偏移量
            val x:float= (Math.cos(Math.toRadians(angel.todouble()))*lineLength).tofloat()
                    //根據(jù)角度的sin值和斜邊的長度求出相對邊的長度,也就是y的偏移量
            val y:float= (Math.sin(Math.toRadians(angel.todouble()-180))*lineLength).tofloat()
                    return PointF(start.x+x,start.y+y)
        }
    }

運行結(jié)果

可能有點丑,但是只要內(nèi)部原理知道了狂丝,花點時間可以自己調(diào)一下角度和線的長度。


運行結(jié)果.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末哗总,一起剝皮案震驚了整個濱河市几颜,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌讯屈,老刑警劉巖蛋哭,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異涮母,居然都是意外死亡谆趾,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門叛本,熙熙樓的掌柜王于貴愁眉苦臉地迎上來沪蓬,“玉大人,你說我怎么就攤上這事来候□尾妫” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵营搅,是天一觀的道長云挟。 經(jīng)常有香客問我,道長转质,這世上最難降的妖魔是什么园欣? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮休蟹,結(jié)果婚禮上沸枯,老公的妹妹穿的比我還像新娘。我一直安慰自己鸡挠,他們只是感情好辉饱,可當(dāng)我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布搬男。 她就那樣靜靜地躺著拣展,像睡著了一般。 火紅的嫁衣襯著肌膚如雪缔逛。 梳的紋絲不亂的頭發(fā)上备埃,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天姓惑,我揣著相機與錄音,去河邊找鬼按脚。 笑死于毙,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的辅搬。 我是一名探鬼主播唯沮,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼堪遂!你這毒婦竟也來了介蛉?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤溶褪,失蹤者是張志新(化名)和其女友劉穎币旧,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體猿妈,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡吹菱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了彭则。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鳍刷。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖贰剥,靈堂內(nèi)的尸體忽然破棺而出倾剿,到底是詐尸還是另有隱情,我是刑警寧澤蚌成,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布前痘,位于F島的核電站,受9級特大地震影響担忧,放射性物質(zhì)發(fā)生泄漏芹缔。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一瓶盛、第九天 我趴在偏房一處隱蔽的房頂上張望最欠。 院中可真熱鬧,春花似錦惩猫、人聲如沸芝硬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拌阴。三九已至,卻和暖如春奶镶,著一層夾襖步出監(jiān)牢的瞬間迟赃,已是汗流浹背陪拘。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留纤壁,地道東北人左刽。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像酌媒,于是被迫代替她去往敵國和親欠痴。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,762評論 2 345