关于贝塞尔曲线的故事

概述

  • 在开始本故事的之前,先来介绍下故事的背景。话说几百年前,从天而降一座神山,远远看去像一天光滑的丝带,它的名字叫做:“贝塞尔曲线"。有大法师预言登上这座神山可以发现天地大秘但是前途艰险。

定义

  • 摘自百科 贝塞尔曲线(Bézier curve),又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲线。一般的矢量图形软件通过它来精确画出曲线,贝兹曲线由线段与节点组成,节点是可拖动的支点,线段像可伸缩的皮筋,我们在绘图工具上看到的钢笔工具就是来做这种矢量曲线的。 “贝赛尔曲线”是由法国数学家Pierre Bézier所发明,由此为计算机矢量图形学奠定了基础。它的主要意义在于无论是直线或曲线都能在数学上予以描述。

公式

  • 由于应用用到主要以二阶贝塞尔曲线为主,贴下二阶的公式: 二次方公式 二次方贝兹曲线的路径由给定点P0、P1、P2的函数B(t):

如何应用?

  • 为了前往"贝塞尔曲线山",向那些从前登上神山的老前辈请教;

所需的Android知识

  • 画笔(paint),路径(path),画布(canvas)类的api要熟悉
  • View绘制的生命周期 简单来看:测量-measure 摆放-layout 绘制-draw
  • Android触摸事件 这里需要了解onTouchEvent方法可以捕捉到触屏的事件

用手势画光滑的曲线

  • 路途艰险,在这里我碰到了大白虎,史前巨兽猛犸象,海天鲲鹏,经历了生死考验终于登上神山,恍然大悟,天地大秘原来在此。
  • 让我们想一想画东西需要什么?答案:一块白板,一只笔。
  • 这里的关键是手势与光滑,处理手势的话就是前面讲的重写Android触摸事件,聪明的你一定想到了通过二阶贝塞尔曲线去做到光滑。
  • 画一条二阶贝塞尔曲线需要3个点,两个数据点一个控制点,那么手势落下的点--起始点(x1,y1)与不断移动的手的触点是数据点,控制点需要自己创造,那线段的中点是最好计算的,假设第一个手滑动到的点(x2,y2),那么中点就是((x1+x2)/2,(y1+y2)/2)。
  • 重写Android触摸事件需要捕捉MOVE类型与DOWN类型的事件,DOWN类型的事件中需要记录起始点的位置,而MOVE类型事件需要缓冲上一次移动的位置。
  • 1.声明控制点,曲线,起始点,以及判定滑动的距离
private  Paint controlPaint;

private Path mCurrentPath;

private float startPointX;
private float startPointY;
//画贝塞尔曲线的标识--可以自定义值
private float offset = ViewConfiguration.get(getContext()).getScaledTouchSlop();
  • 2.初始化画笔与路径
  public PaintBeSaiErView(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
    //建立路径
    mCurrentPath = new Path();
    //绘制时抗锯齿
    controlPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    //设置画笔样式
    controlPaint.setStyle(Paint.Style.STROKE);
    //设置画笔的粗细
    controlPaint.setStrokeWidth(8);
    //设置画笔颜色
    controlPaint.setColor(Color.RED);

}
  • 3.重写onTouchEvent,记录手势起始点与移动位置并绘制贝塞尔曲线,通过invalidate方法更新UI视图
  @Override
public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()){
        case MotionEvent.ACTION_DOWN:
            //为了方便测试,每次下落之前清空路径
            mCurrentPath.reset();
            float x = event.getX();
            float y = event.getY();
            startPointX = x;
            startPointY = y;
            //移动到起始点
            mCurrentPath.moveTo(x, y);
            invalidate();
            break;
        case MotionEvent.ACTION_MOVE:
            float curX= event.getX();
            float curY= event.getY();
            float preX= startPointX;
            float preY= startPointY;
            if(Math.abs(preX-curX)>=offset||Math.abs(preX-curY)>=offset) {
                mCurrentPath.quadTo((curX + preX) / 2, (curY + preY) / 2, curX, curY);
                startPointX = curX;
                startPointY = curY;
            }
            invalidate();
            break;
    }
    return  true;
}
  • 4.下面对比使用线段画lineTo(curX, curY)与贝塞尔曲线画quadTo(avgX,avgY)的效果 左图为线段画的,右图为贝塞尔曲线画的,看起来更圆润!why?其实,用线段画基本上看是一个折线图,而贝塞尔函数画是一段段曲线
  • 当然,贝塞尔曲线的应用十分广泛,上面是简单的例子,后面将讲如何应用模拟翻页。

总结

  • 总以为登上神山才是最大的收获,原来一路走来更有收获。
  • 去了解一个事物的时候,要善于思考,记忆中越来越深刻的,往往思考的越透彻。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏工科狗和生物喵

【机器视觉与图像处理】基于MATLAB+Hough的圆检测

本次文章,没有太多好写的,就是最近做的一个机器视觉的课程设计作业,是要做一个流水线的生产线建模以及对于产品的检测识别,我个人承包了圆心半径检测的内容,熬了好几天...

2761
来自专栏天天P图攻城狮

iOS多边形马赛克的实现(上)

马赛克(英语:Mosaic)是镶嵌艺术的音译,原本是指一种装饰艺术,通常使用许多小石块或有色玻璃碎片拼成图案,在教堂中的玻璃艺品,又称为花窗玻璃(stained...

53910
来自专栏WOLFRAM

如何利用图形基元?

1193
来自专栏天天P图攻城狮

Android图像处理系列:OpenGL深度测试的应用

什么是深度测试? 深度测试是指检测从某个方向看过去时,两个点A和B谁在谁的前面,以便知道谁挡住了谁,被挡住的点一般不会进行绘制,以达到和真实世界一样的遮挡效...

2102
来自专栏数据小魔方

创意雷达图(Round Rador Chart)

今天给大家分享的图表是创意雷达图! ▽▼▽ 既然是创意雷达图,肯定是有难度的啦,单纯的雷达图太没有挑战了! 首先看成品,怎么样,还不错吧,想不想自己也做一个,如...

6265
来自专栏前端那些事

过渡与动画 - 逐帧动画&steps调速函数

写在前面 上一篇中我们熟悉五种内置的缓动曲线和(三次)贝塞尔曲线,并且基于此完成了缓动效果. 但是如果我们想要实现逐帧动画,基于贝塞尔曲线的调速函数就显得有些无...

2507
来自专栏章鱼的慢慢技术路

OpenGL透明与混色效果

2076
来自专栏数据小魔方

绩效管理工具(二)——温度计风格图表!

今天跟大家分享另一种用作绩效管理的图表工具——温度计风格图表! ▽ 这种图表看起来简洁、直观。数据表达清晰、无冗余。今天主要介绍两种做法,都不是特别复杂,但是需...

3188
来自专栏HTML5学堂

一步步教你弹性框架-上篇

HTML5学堂:本系列主要在于跟大家分享弹性运动框架的制作方式。弹性运动框架的运动方式类似于弹簧,有一种回弹的效果,在网站中的一些特效当中还是有一些应用的。实现...

3598
来自专栏yl 成长笔记

three.js 相机

图形学中的相机定义了三维空间到二维屏幕的投影方式,根据投影方式的不同,相机可分为 正交投影相机 与 透视投影相机。

1162

扫码关注云+社区

领取腾讯云代金券