获取二维贝塞尔曲线的法线
Get normal of bezier curve in 2D
我正在尝试用贝塞尔曲线包裹文本,并遵循此 link、http://www.planetclegg.com/projects/WarpingTextToSplines.html
中的教程
我通过这段代码得到导数:
function Derivative(x0,x1,x2,t)
{
var mt = 1-t;
var a = mt * mt;
var b = mt * t * 2;
var c = t * t;
var result=a * x0 + b * x1 + c * x2;
return result;
}
所以我用这段代码计算法线:
function Normal(x0,x1,x2,y0,y1,y2,t)
{
var dx = Derivative(x0,x1,x2,t);
var dy = Derivative(y0,y1,y2,t);
var q = Math.sqrt(dx*dx + dy*dy)
return { x: -dy/q, y: dx/q };
};
所以这是结果:有些地方错了,但我不知道在哪里。
谢谢大家!
"what I want"图像看起来很像我的bezierjs documentation,所以:你的想法是正确的(取导数得到切向量,然后旋转得到法线),但是一定要把那些衍生品弄对。
如果您使用由三个二维点 P1、P2 和 P3 组成的二次贝塞尔曲线,则贝塞尔函数为:
P1 * (1-t)² + P2 * 2 * (1-t)t + P3 * t²
导数(仅以多种方式之一编写)为:
P1 * (2t-2) + (2*P3-4*P2) * t + 2 * P2
你显示的导数计算代码实际上是常规的二次贝塞尔函数,所以这会给你相当错误的结果。将代码更新为正确的导数,应该没问题。
Pomax 的答案就是您所需要的,但如果您需要一些代码,这里有一些在 Javascript:
中实现的实用方法
// these methods are only for quadratic curves
// p1: {x,y} start point
// pc: {x,y} control point
// p2: {x,y} end point
// t: (float between 0 and 1) time in the curve
getPointAt(t, p1, pc, p2) {
const x = (1 - t) * (1 - t) * p1.x + 2 * (1 - t) * t * pc.x + t * t * p2.x
const y = (1 - t) * (1 - t) * p1.y + 2 * (1 - t) * t * pc.y + t * t * p2.y
return { x, y };
}
getDerivativeAt(t, p1, pc, p2) {
const d1 = { x: 2 * (pc.x - p1.x), y: 2 * (pc.y - p1.y) };
const d2 = { x: 2 * (p2.x - pc.x), y: 2 * (p2.y - pc.y) };
const x = (1 - t) * d1.x + t * d2.x;
const y = (1 - t) * d1.y + t * d2.y;
return { x, y };
}
getNormalAt(t, p1, pc, p2) {
const d = getDerivativeAt(t, p1, pc, p2);
const q = sqrt(d.x * d.x + d.y * d.y);
const x = -d.y / q;
const y = d.x / q;
return { x, y };
}
https://jsfiddle.net/Lupq8ejm/1/
我正在尝试用贝塞尔曲线包裹文本,并遵循此 link、http://www.planetclegg.com/projects/WarpingTextToSplines.html
中的教程我通过这段代码得到导数:
function Derivative(x0,x1,x2,t)
{
var mt = 1-t;
var a = mt * mt;
var b = mt * t * 2;
var c = t * t;
var result=a * x0 + b * x1 + c * x2;
return result;
}
所以我用这段代码计算法线:
function Normal(x0,x1,x2,y0,y1,y2,t)
{
var dx = Derivative(x0,x1,x2,t);
var dy = Derivative(y0,y1,y2,t);
var q = Math.sqrt(dx*dx + dy*dy)
return { x: -dy/q, y: dx/q };
};
所以这是结果:有些地方错了,但我不知道在哪里。
谢谢大家!
"what I want"图像看起来很像我的bezierjs documentation,所以:你的想法是正确的(取导数得到切向量,然后旋转得到法线),但是一定要把那些衍生品弄对。
如果您使用由三个二维点 P1、P2 和 P3 组成的二次贝塞尔曲线,则贝塞尔函数为:
P1 * (1-t)² + P2 * 2 * (1-t)t + P3 * t²
导数(仅以多种方式之一编写)为:
P1 * (2t-2) + (2*P3-4*P2) * t + 2 * P2
你显示的导数计算代码实际上是常规的二次贝塞尔函数,所以这会给你相当错误的结果。将代码更新为正确的导数,应该没问题。
Pomax 的答案就是您所需要的,但如果您需要一些代码,这里有一些在 Javascript:
中实现的实用方法// these methods are only for quadratic curves
// p1: {x,y} start point
// pc: {x,y} control point
// p2: {x,y} end point
// t: (float between 0 and 1) time in the curve
getPointAt(t, p1, pc, p2) {
const x = (1 - t) * (1 - t) * p1.x + 2 * (1 - t) * t * pc.x + t * t * p2.x
const y = (1 - t) * (1 - t) * p1.y + 2 * (1 - t) * t * pc.y + t * t * p2.y
return { x, y };
}
getDerivativeAt(t, p1, pc, p2) {
const d1 = { x: 2 * (pc.x - p1.x), y: 2 * (pc.y - p1.y) };
const d2 = { x: 2 * (p2.x - pc.x), y: 2 * (p2.y - pc.y) };
const x = (1 - t) * d1.x + t * d2.x;
const y = (1 - t) * d1.y + t * d2.y;
return { x, y };
}
getNormalAt(t, p1, pc, p2) {
const d = getDerivativeAt(t, p1, pc, p2);
const q = sqrt(d.x * d.x + d.y * d.y);
const x = -d.y / q;
const y = d.x / q;
return { x, y };
}
https://jsfiddle.net/Lupq8ejm/1/