javascript - 如何使用 HTML5 Canvas 平滑连续地加入 2 条贝塞尔曲线
问题描述
我正在尝试将两条单独的贝塞尔曲线连接成一条连续曲线。目前,我所拥有的看起来像这样:
问题是它们没有连接,因此它们相遇的点看起来很尖/尖锐,而不是弯曲和光滑。我查看了在 P5.js 中加入贝塞尔曲线的文档,但不确定如何将其转换为 HTML5 Canvas。如何连接这两条贝塞尔曲线,使它们看起来像一条平滑连续的曲线?
这是我的代码:
const canvas = document.getElementById('canvas');
const c = canvas.getContext("2d");
width = 800;
height = 500;
canvas.width = width;
canvas.height = height;
let face;
let centerX = width / 2;
let centerY = height / 3;
setup();
function setup() {
c.clearRect(0, 0, canvas.width, canvas.height);
face = new Face();
draw();
};
function draw() {
setBackground(`rgba(250, 250, 250, 1)`);
c.beginPath();
c.moveTo(centerX - face.hsx, centerY + face.hsy);
c.bezierCurveTo(centerX - face.hcp1x / 10, centerY - face.hsy2,
centerX + face.hcp1x / 10, centerY - face.hsy2,
centerX + face.hsx, centerY + face.hsy);
c.moveTo(centerX - face.hsx, centerY + face.hsy);
c.bezierCurveTo(centerX - face.hcp1x, centerY + face.hcp1y,
centerX + face.hcp1x, centerY + face.hcp1y,
centerX + face.hsx, centerY + face.hsy);
c.stroke();
c.fillStyle = (`rgba(25, 250, 211, 0)`);
c.fill();
}
function setBackground(color) {
c.fillStyle = color;
c.fillRect(0, 0, width, height);
}
function Face() {
this.hsx = 150;
this.hsy = 0;
this.hsy2 = 120;
this.hcp1x = 120;
this.hcp1y = 250;
}
解决方案
公切线
要平滑地连接两个贝塞尔曲线,您需要使公共点的线平行,从而将两个贝塞尔曲线末端和起点的切线定义为相同。
下图说明了这一点
由两个控制点 (C 2 , C 1 ) 和公共点 (P) 定义的线是曲线在 P 处的切线。线段的长度没有约束。
如何?
有很多方法可以做到这一点,你如何做到这一点取决于曲线的要求、曲线的类型等等。
例子
我不打算给出一个完整的例子,因为它需要对向量数学的理解和一个涵盖所有解决方案的假设你不熟悉向量数学会很大。
因此最基本的伪代码示例使用前一个控制点和端点来计算下一个控制点。?
表示不受保持线平行所需约束的未知数
// From illustration in answer
corner = ? // Distance to next control point as fraction of distance
// from previous control point
C2 = {x:?, y:?} // Last control point of previous bezier
P = {x:?, y:?} // Start of next bezier
C1 = { // Next control point along line from previous and scaled
x: P.x + (P.x - C2.x) * corner,
y: P.y + (P.y - C2.y) * corner,
}
// two beziers with common point P
ctx.bezierCurveTo(?,?, C2.x, C2.y, P.x, P.y)
ctx.bezierCurveTo(C1.x, C1.y, ?, ?, ?, ?)
推荐阅读
- excel - 带舍入的 Excel 日期计算
- java - 为什么当消费者线程全部退出时所有生产者线程也退出
- ios - 按下uicollectionViewCell上的按钮时如何获取产品代码?
- mysql - Cron 作业 VS MySql 事件
- javascript - 验证“整数”的“介于”规则——javascript
- php - 如何仅显示此数组中的 billing_id?
- sql - 如何通过 COLLATION 整理空格和撇号?
- javascript - dygraph 仅显示上个月的数据
- css - scale3d+translate3d 与 scale+translate 的不同结果
- c# - 从 informix 到 C# 获取列表/多集