前言
前篇我们已经见过贝塞尔曲线的功能,原理,公式,和推导过程
这节课我们来讲实际应用:如何通过贝塞尔曲线,绘制经过若干固定点的平滑曲线
首先,我们要明确需求,我们的目标是画一条平滑曲线,不是求一条贝塞尔曲线,经过所有点
可以是通过多条贝塞尔曲线来拼接成一条平滑曲线
然后,经过若干点的贝塞尔曲线,可能是有无数条的,并不是唯一解
所以我们的目标,是找一个简单的方案,能画出平滑曲线就行
并不是由曲线上的点,求一个万能的曲线公式,千万别弄错了
方案
- 每两个点之间画一条贝塞尔曲线,然后所有曲线连接成一条平滑曲线(之所以这么设计,是因为这个想法最简单)
- 多条曲线想要连成一条平滑曲线,那么在曲线交点,也就是顶点两侧,曲线的斜率或切线方向,一定得是一致的
- 我们就用x方向,作为所有顶点处,曲线切线的方向(之所以这么设计,是因为这样最简单)
- 第一个控制点,一定在起点切线上,最后一个控制点,一定在终点切线上(贝塞尔曲线特性决定的)
- 选用三阶贝塞尔曲线,在起点和终点切线上,随便选个点作为控制点(之所以这么设计,是因为这样最简单)
- 让曲线两端,控制点到顶点的距离相等(这样曲线就比较匀称,不会出现很突兀的情况)
- 画出所有顶点之间的贝塞尔曲线,得到最终的平滑曲线
流程示意图
确定切线和控制点 画三阶贝塞尔曲线
最终结果
方案说明
- 由于所有切线方向,都是沿x方向,看起来会像是沿x方向的波形图,所以实际应用中,最好是根据数据实际走向来确定切线方向
- 控制点离顶点越近,曲线越接趋于直线
- 控制点离顶点越远,曲线越接趋于波形
- 两端控制点离顶点距离,相差越小,曲线越对称(我们是完全相等,则完全对称)
Android平滑曲线绘制代码
package com.android.architecture;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.View;
import com.easing.commons.android.value.color.Colors;
import com.easing.commons.android.value.measure.FPos;
import java.util.ArrayList;
import java.util.List;
@SuppressWarnings("all")
public class BezierCurve extends View {
final List posList = new ArrayList();
final List controlPosList = new ArrayList();
final Paint posPaint = new Paint();
final Paint linePaint = new Paint();
final Paint tangentPaint = new Paint();
final Paint bezierPaint = new Paint();
public BezierCurve(Context context) {
this(context, null);
}
public BezierCurve(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
init(context, attributeSet);
}
protected void init(Context context, AttributeSet attributeSet) {
//创建初始点
posList.add(new FPos(100, 100));
posList.add(new FPos(300, 200));
posList.add(new FPos(560, 300));
posList.add(new FPos(720, 350));
posList.add(new FPos(900, 600));
posList.add(new FPos(1200, 650));
posList.add(new FPos(1300, 700));
//初始化点画笔
posPaint.setColor(Colors.RED);
posPaint.setStrokeWidth(10);
posPaint.setStyle(Paint.Style.STROKE);
posPaint.setStrokeCap(Paint.Cap.ROUND);
//初始化折线画笔
linePaint.setColor(Colors.LIGHT_BLUE);
linePaint.setStrokeWidth(2);
linePaint.setStyle(Paint.Style.STROKE);
//初始化切线画笔
tangentPaint.setColor(Colors.LIGHT_GREY);
tangentPaint.setStrokeWidth(4);
tangentPaint.setStyle(Paint.Style.STROKE);
tangentPaint.setPathEffect(new DashPathEffect(new float[]{4, 4}, 0));
//初始化曲线画笔
bezierPaint.setColor(Colors.ORANGE);
bezierPaint.setStrokeWidth(2);
bezierPaint.setStyle(Paint.Style.STROKE);
//计算控制点
final float ratio = 0.3F;
for (int i = 0; i
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?