什么是贝塞尔曲线
贝塞尔曲线基本上是控制点之间的插值,在本文中,我们将研究线性、二次和三次贝塞尔曲线。
线性贝塞尔曲线
贝塞尔曲线只是控制点之间的插值,因此我们可以说线性贝塞尔曲线只是两点之间的插值。
插值是什么意思?插值是在直线或曲线上的两点之间找到值的过程。在这种情况下,该“值”取决于一个在 0 和 1 之间变化的因子t。我们可以将t传到数学函数中,从而得到它的值。
线性贝塞尔曲线是贝塞尔曲线的最简单形式,以下的线性插值公式显示了L0在不同值时的值t。
从公式和图像中,我们看到对每个点 (P0和P1) 的影响取决于t (moves from 0 to 1)。
二次贝塞尔曲线
二次贝塞尔曲线是两个线性插值之间的插值。看以下方程图解如下:图像显示特定t值处的二次贝塞尔曲线。
t的值从 0 递增到 1 随着值t的增加,L0从P0移动到P1 同时,L1从P1移动到P2 同时,Q0(蓝点)从L0移动到L1 当Q0(蓝点)移动时,其路径形成一条曲线。
接下来我们使用flutter的CustomPainter
画一个二次曲线。
知识点:quadraticBezierTo(x1, y1, x2, y2)
绘制一条二次贝塞尔曲线。
代码如下:
import 'package:flutter/material.dart';
class BezierCurvePage extends StatefulWidget {
const BezierCurvePage({Key? key}) : super(key: key);
@override
State<BezierCurvePage> createState() => _BezierCurvePageState();
}
class _BezierCurvePageState extends State<BezierCurvePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('贝塞尔曲线')),
body: Center(
child: CustomPaint(
painter: BezierCurvePainter(),
child: Container(
),
),
),
);
}
}
/// 二次曲线
class BezierCurvePainter extends CustomPainter {
const BezierCurvePainter();
@override
void paint(Canvas canvas, Size size) {
// 将整个画布的颜色涂成白色
Paint paint = Paint()
..color = Colors.white;
canvas.drawPaint(paint);
// 画贝塞尔曲线
Path bezierPath = Path()
..moveTo(0, size.height)//移动起点到(0, size.height)
..lineTo(0, size.height*0.8)//画线
..quadraticBezierTo(
size.width / 2,
size.height * 0.6,
size.width,
size.height * 0.8
)
..lineTo(size.width, size.height);
final bezierPaint = Paint()
// 添加渐变色
..shader = const LinearGradient(
colors: [Colors.blue,Colors.green]
).createShader(Offset(0,size.height * 0.8) & size);
canvas.drawPath(bezierPath, bezierPaint);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return false;
}
}
效果:
三次贝塞尔曲线
三次贝塞尔曲线是两条二次贝塞尔曲线之间的插值。我们将引入三个新的变量:L2,Q1,C0和第四个点P3。
-
P3 是第四个点 -
L2是P2和P3之间的线性插值 -
Q1是L1和L2之间的插值 -
C0,是Q0和Q1之间的插值
以下是三次贝塞尔曲线的公式:
图解:
从图上可知随着t的值从 0 增加到 1的变化:当蓝点移动时,它会沿其路径绘制一条贝塞尔曲线。
-
L0从P0移动到P1 -
L1从P1移动到P2 -
L2从P2移动到P3 -
Q0从L0移动到L1 -
Q1从L1移动到L2 -
C0(蓝点)从Q0移动到Q1
下面我们用flutter 绘制三次贝塞尔曲线。应用cubicTo(x1, y1, x2, y2, x3, y3)
/// 三次曲线
class CubicBezierCurvePainter extends CustomPainter {
const CubicBezierCurvePainter();
@override
void paint(Canvas canvas, Size size) {
//画布背景色
Paint paint = Paint()..color = Colors.white;
canvas.drawPaint(paint);
// 使用Translate方法移动画布的坐标
// 起始点是在画布的顶点正中心
canvas.translate(size.width / 2, 0);
final width = size.width / 2;
Path bezierPath = Path()
..moveTo(-width, size.height)
..lineTo(-width, size.height * 0.6)
..cubicTo(
-width * 0.2,
size.height * 0.4,
0,
size.height * 0.8,
width,
size.height * 0.6
)
..lineTo(width, size.height);
final bezierPaint = Paint()
..shader = const LinearGradient(
colors: [Colors.blue,Colors.green]
).createShader(Offset(-width,size.height) & size);
canvas.drawPath(bezierPath, bezierPaint);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return false;
}
}
效果:
什么是 CatmulRomSpline
Catmull-RomSpline是一种 2D 样条曲线,可以平滑地通过其控制点。如下图是具有四个控制点 PO、P1、P2、P3 的 Catmull-Rom 样条曲线。
要在 flutter 中绘制CatmulRomSpline,将一个Offset列表传递给CatmulRomSpline
构造函数,调用方法generateSamples()
返回一个Offset值列表,平滑地通过这些控制点。
/// CatmulRomSpline
class SplinePainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()..color = Colors.white;
canvas.drawPaint(paint);
//控制点宽
const controlWidthSingle = 50;
final random = math.Random();
//生成控制点
final controlPoints = List.generate(size.width ~/ controlWidthSingle, (index) {
return Offset(
controlWidthSingle * (index + 1),
random.nextDouble() * (size.height - size.height / 2) + size.height /2
);
}).toList();
//返回一个Offset值列表
final spline = CatmullRomSpline(controlPoints);
final bezierPaint = Paint()
..strokeCap = StrokeCap.round
..strokeWidth = 10
..shader = const LinearGradient(
colors: [Colors.blue,Colors.green]
).createShader(Offset(0, size.height) & size);
//绘制所有offset点
canvas.drawPoints(
PointMode.points,
spline.generateSamples().map((e) => e.value).toList(),
bezierPaint
);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return false;
}
}
效果:
原文始发于微信公众号(大前端编程教学):Flutter CustomPaint 绘制贝塞尔曲线和样条曲线(CatmulRomSpline)
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/224307.html