Android 贝塞尔曲线

什么是贝塞尔曲线(Bézier曲线)?

贝塞尔曲线,又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲线。一般的矢量图形软件通过它来精确画出曲线,贝兹曲线由线段与节点组成,节点是可拖动的支点,线段像可伸缩的皮筋,我们在绘图工具上看到的钢笔工具就是来做这种矢量曲线的。贝塞尔曲线是计算机图形学中相当重要的参数曲线,在一些比较成熟的位图软件中也有贝塞尔曲线工具,如PhotoShop等。贝赛尔曲线是电脑图形学中相当重要的参数曲线。可以这么说基本上任何的曲线和曲面都可以用贝塞尔公式来解决。

贝塞尔曲线分为一阶贝塞尔曲线、二阶贝塞尔曲线、三阶贝塞尔曲线.......n阶贝塞尔曲线,而一阶贝塞尔曲线就是一条直线,在Android中可以通过Path的quadTo方法和cubicTo方法分别绘制出二阶贝塞尔曲线和三阶贝塞尔曲线。

一阶贝塞尔曲线

一阶贝塞尔曲线没有控制点,仅有两个数据点,也就是一条直线

二阶贝塞尔曲线

二阶贝塞尔曲线仅有一个控制点,其表示公式:

二阶贝塞尔曲线的路径由给定点P0、P1、P2的函数B(t)追踪,P0和P2是曲线的始点和终点,P1是控制点。

我们看下t的变化:

t的变化直接影响到曲线的弧度。绘制二阶贝塞尔曲线在Android中使用Path提供的quadTo方法绘制。

三阶贝塞尔曲线

P0、P1、P2、P3四个点在平面或在三维空间中定义了三次方贝兹曲线。曲线起始于P0走向P1,并从P2的方向来到P3。一般不会经过P1或P2;这两个点只是在那里提供方向资讯。P0和P1之间的间距,决定了曲线在转而趋进P3之前,走向P2方向的“长度有多长”。

Android中绘制三阶的贝塞尔曲线,对应Path的cubicTo方法。

N阶贝塞尔曲线

N阶贝塞尔曲线更加复杂,其表示的公式如下:

如上公式可如下递归表达: 用表示由点P0、P1、…、Pn所决定的贝兹曲线。

动态演示过程:

看了以上的公式,是不是已经头晕脑胀了,没关系,能够看明白贝塞尔曲线的演示过程就行了。如果还不是很明白,推荐可以The Bézier Game来玩一下,也可以参考《贝塞尔曲线扫盲》这篇文章,里面的图形讲解更加形象。 那么贝塞尔曲线有什么用呢?贝塞尔曲线在平时的APP中随处可见,如:qq的提示红点拖拽时的粘性过程、直播中的爱心的浮动路径、手机充电时的图形等等。

关于贝塞尔去曲线的应用,网上搜索以下一大堆demo,本文看一个简单的应用:模仿水波上涨的情况。

public class WaveView extends View {

	private Paint paint;
	private Path path;
	private int waveLength = 800;
	private int dx;
	private int dy;

	public WaveView(Context context) {
		this(context, null);
		init();
	}
	public WaveView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}

	private void init() {
		paint = new Paint();
		paint.setColor(0xff84C1ff);
		paint.setStyle(Style.FILL_AND_STROKE);

		path = new Path();
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		path.reset();
		int originY = 1000;
		if(dy<originY + 150){
			dy += 5;
		}
		int halfWaveLength = waveLength/2;
		path.moveTo(-waveLength+dx, originY-dy);
		//屏幕的宽度里面放多少个波长
		for (int i = -waveLength; i < getWidth() + waveLength; i += waveLength) {
			//相对绘制二阶贝塞尔曲线(相对于自己的起始点--也即是上一个曲线的终点  的距离dx1)
			path.rQuadTo(halfWaveLength/2, -150, halfWaveLength, 0);
			path.rQuadTo(halfWaveLength/2, 150, halfWaveLength, 0);
		}
		//颜色填充
		//画一个封闭的空间
		path.lineTo(getWidth(), getHeight());
		path.lineTo(0, getHeight());
		path.close();

		canvas.drawPath(path, paint);
	}

	public void startAnimation(){
		ValueAnimator animator = ValueAnimator.ofInt(0,waveLength);
		animator.setDuration(3000);
		animator.setInterpolator(new LinearInterpolator());
		//无限循环
		animator.setRepeatCount(ValueAnimator.INFINITE);
		animator.addUpdateListener(new AnimatorUpdateListener() {

			@Override
			public void onAnimationUpdate(ValueAnimator animation) {
				dx = (int) animation.getAnimatedValue();
				postInvalidate();
			}
		});
		animator.start();
	}

}
复制代码

使用rQuadTo绘制二阶的贝塞尔曲线,调用两次,一个绘制波峰,一个绘制波谷。然后使用动画来改变dx和dy来模拟上涨和水波运动的情况。

上面用到的动画来改变dx,也可以使用以下写法:

    private class MoveAnimation extends Animation {

        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            super.applyTransformation(interpolatedTime, t);
            mInterpolatedTime = interpolatedTime;
            Log.i("lwj","mInterpolatedTime:"+mInterpolatedTime);
            invalidate();
        }
    }

    public void startAnimation() {
        mPath.reset();
        mInterpolatedTime = 0;
        MoveAnimation move = new MoveAnimation();
        move.setDuration(1000);
        move.setInterpolator(new AccelerateDecelerateInterpolator());
//        move.setRepeatCount(Animation.INFINITE);
//        move.setRepeatMode(Animation.REVERSE);
        startAnimation(move);
    }
复制代码

这里拿到的数值mInterpolatedTime范围式[0,1]。

使用:

public class GallaryHorizonalScrollViewActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        WaveView view = new WaveView(this);
        setContentView(view);
        view.startAnimation();

    }
}
复制代码

关于贝塞尔曲线的介绍和使用,大家可以参考: 《Android 自定义View高级特效,神奇的贝塞尔曲线》 《Android-贝塞尔曲线》 《三次贝塞尔曲线练习之弹性的圆》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值