zoukankan      html  css  js  c++  java
  • Android

    概述

    贝塞尔曲线于1962,由法国工程师皮埃尔·贝塞尔所广泛发表,他运用贝塞尔曲线来为汽车的主体进行设计。贝塞尔曲线最初由Paul de Casteljau于1959年运用de Casteljau演算法开发,以稳定数值的方法求出贝兹曲线。
    在计算机图形学中贝赛尔曲线的运用也很广泛,Photoshop中的钢笔效果,Flash5的贝塞尔曲线工具,在软件GUI开发中一般也会提供对应的方法来实现贝赛尔曲线。

    线性公式

    给定点P0、P1,线性贝兹曲线只是一条两点之间的直线。这条线由下式给出:
    B(t) = P0 + (P1 - P0) * t = (1 - t) * P0 + t * P1, t ∈ [0, 1]
    且其等同于线性插值。

    二次方公式

    二次方贝兹曲线的路径由给定点P0、P1、P2的函数B(t)追踪:
    B(t) = (1 - t)^2 * P0 + 2t * (1 - t) * P1 + t^2 * P2, t ∈ [0,1]
    TrueType字型就运用了以贝兹样条组成的二次贝兹曲线。

    百度百科 详细资料

    Android上实现贝赛尔曲线

    在Android实现贝赛尔曲线,要借助android.graphics.Path,其中绘制贝赛尔曲线的方法在Api v1就已经提供了,下面来认识一下吧。

    初识Path类

    1
    2
    3
    4
    5
    Path.moveTo(float x, float y) // Path的初始点
    Path.lineTo(float x, float y) // 线性公式的贝赛尔曲线, 其实就是直线
    Path.quadTo(float x1, float y1, float x2, float y2) // 二次方公式的贝赛尔曲线
    Path.cubicTo(float x1, float y1, float x2, float y2, float x3, float y3) // 三次方公式的贝赛尔曲线
    ...

    这是上面是Java层调用的代码,最终调用的是Skia库的一系列方法,Skia是一个C++2D向量图形处理函数库,感兴趣的可以继续深入研究研究。

    绘制贝赛尔曲线

    BezierViewBezierView

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @Override
    protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    mPath.moveTo(100, 100);
    mPath.cubicTo(800, 100, 100, 800, 800, 800);
    // 一共四个点,(100, 100)和(800, 800)分别为起点和终点,(800, 100)和(100, 800)为操作点

    canvas.drawPath(mPath, mPaint);
    }

     

    实现一个BezierEvaluator

    BezierEvaluatorBezierEvaluator
    实现一个三次方贝赛尔曲线Evaluator,已知公式为:
    B(t) = P0 * (1-t)^3 + 3 * P1 * t * (1-t)^2 + 3 * P2 * t^2 * (1-t) + P3 * t^3 代码如下:

    BezierEvaluator.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    public class BezierEvaluator implements TypeEvaluator<PointF> {

    private PointF points[];

    public BezierEvaluator(PointF... points) {
    if (points.length != 4) {
    throw new IllegalArgumentException("只演示三次方贝赛尔曲线");
    }
    this.points = points;
    }

    @Override
    public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
    // B(t) = P0 * (1-t)^3 + 3 * P1 * t * (1-t)^2 + 3 * P2 * t^2 * (1-t) + P3 * t^3

    float t = fraction;
    float one_t = 1.0f - t;

    PointF P0 = points[0];
    PointF P1 = points[1];
    PointF P2 = points[2];
    PointF P3 = points[3];

    float x = (float) (P0.x * Math.pow(one_t, 3) + 3 * P1.x * t * Math.pow(one_t, 2) + 3 * P2.x * Math.pow(t, 2) * one_t + P3.x * Math.pow(t, 3));
    float y = (float) (P0.y * Math.pow(one_t, 3) + 3 * P1.y * t * Math.pow(one_t, 2) + 3 * P2.y * Math.pow(t, 2) * one_t + P3.y * Math.pow(t, 3));

    PointF pointF = new PointF(x, y);

    return pointF;
    }

    }

     

    一种ViewPager指示器的实现

    Morning Routine 中有个ViewPager的指示器效果,非常炫酷,类似于下图,是怎么实现的呢?其实也用到了贝塞尔曲线。

    DropPagerIndicatorDropPagerIndicator

    先绘制两个圆

    1
    2
    canvas.drawCircle(leftCircleX, mHeight / 2, leftCircleRadius, mPaint);
    canvas.drawCircle(rightCircleX, mHeight / 2, rightCircleRadius, mPaint);

    再绘制两个圆中间的部分

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    private void drawModeBend(Canvas canvas) {
    float middleOffset = (leftCircleX - rightCircleX) / (mPoints.get(1).x - mPoints.get(0).x) * (mHeight / 10);

    mPath.reset();

    mPath.moveTo(rightCircleX, mHeight / 2);

    mPath.lineTo(rightCircleX, mHeight / 2 - rightCircleRadius);

    mPath.cubicTo(rightCircleX,
    mHeight / 2 - rightCircleRadius,

    rightCircleX + (leftCircleX - rightCircleX) / 2.0F,
    mHeight / 2 + middleOffset,

    leftCircleX,
    mHeight / 2 - leftCircleRadius);

    mPath.lineTo(leftCircleX, mHeight / 2 + leftCircleRadius);

    mPath.cubicTo(leftCircleX,
    mHeight / 2 + leftCircleRadius,

    rightCircleX + (leftCircleX - rightCircleX) / 2.0F,
    mHeight / 2 - middleOffset,

    rightCircleX,
    mHeight / 2 + rightCircleRadius);

    mPath.close();
    canvas.drawPath(mPath, mPaint);
    }

    圆和中间颜色不同用来看看圆和中间颜色不同用来看看
    换成一样的,看起来还不错换成一样的,看起来还不错

    然后加上Property Animation即可,了解 Property Animation

    博客Demo代码:https://github.com/gavinliu/BeautifulOfBezier

    结语

    贝赛尔曲线能非常方便的绘制光滑的曲线,加以运用可以实现很多复杂的效果,实现的时候多和设计师沟通,设计师使用的PS中的钢笔其实也就是贝赛尔曲线,了解下设计师是如何绘制的,自己用代码来实现思路就很明了。

  • 相关阅读:
    计算机病毒的认识
    计算机病毒的认识
    围棋知多少
    围棋知多少
    工业相机基础知识(一)
    辨异 —— 逻辑之辨、人文社科观念
    辨异 —— 逻辑之辨、人文社科观念
    telnet 的使用(ping 与 telnet)
    HDU 2437 Jerboas (剪枝搜索)
    设计模式
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/4745165.html
Copyright © 2011-2022 走看看